Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vl3TI-006JsQ-2d for pgsql-hackers@arkaria.postgresql.org; Wed, 28 Jan 2026 11:12:29 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vl3TH-000uUn-22 for pgsql-hackers@arkaria.postgresql.org; Wed, 28 Jan 2026 11:12:27 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vl3TH-000uUf-0r for pgsql-hackers@lists.postgresql.org; Wed, 28 Jan 2026 11:12:27 +0000 Received: from mail-lf1-x129.google.com ([2a00:1450:4864:20::129]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1vl3TD-00000000rih-4AzY for pgsql-hackers@lists.postgresql.org; Wed, 28 Jan 2026 11:12:26 +0000 Received: by mail-lf1-x129.google.com with SMTP id 2adb3069b0e04-59b679cff1fso6629872e87.0 for ; Wed, 28 Jan 2026 03:12:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1769598742; cv=none; d=google.com; s=arc-20240605; b=PtMiF8I6sm1vjil9bSZBrgreovm1fziFKsAJdAZlljs9TUg2xv4wtWwZ4VmqiPa33f f+8FSkKUp+LU3B4UALRvqlA4d0nHaGzQqCNyRSIEAZ82bDsmsTidBh+rj1dKsPjGoXVR 63H+YSTqdbBVLAWOCVfzjgDa+lfgmB+HXJtYANS6gLJza/FHSa4L9ypQ4tCfJBtHkZtg xDDLs+roU9CE5vkldiF19N1zWdy7XQOIeIjPV2zefS4qFoAzwy3d/6X/eioev/OxAMCR 77OOb2cXV8TP2vzW2sXlMQ0Q3/WAN7falVE+dyAE2l6ABBCsffu0IlVdLOrqrwROy1+B /RbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=mx1XKr7r/QLdw1fGIYSOIPcQvjj/MuXPHk5j26e2USc=; fh=5lisVc/SdZrXESFhj6i3cPQivKRq2wrqq/p4/OVduqw=; b=Hcvey2dj1vugrSXNhJXqhK7k4+tXnbo7lCGnvP8Di1IINFTm5tLfSMPoS91v6dXRgs 2CzM6ZXSX+rtTDEkXBGHjU/vTA5ofA1/mN8GzqiQQWhYTNnxY+Jha30TuJ7DpxPEk8mY Se6K0lk9tF+a12j0oGnCvBbsq+DDRLms0if/cV+158Slk+kGDBZP/GVZ84Up/YzZdgaz Lzbes3D/JUE+o6VNYu3VM1CdoxQNAtKtSBbxyxgBdHI2JOfc4pVKjHQ4hur6NcdfeK9O Mfmd758sY2vDgKK67NaKa6Chn4v4cOcNhPdIJ7iAaqG/kK8MlsH9h37WApBt2swLpspF O2QA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1769598742; x=1770203542; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=mx1XKr7r/QLdw1fGIYSOIPcQvjj/MuXPHk5j26e2USc=; b=Ol9xTxiMhd7DxdtotZHC5Wv3c4udrvb8Osgq0SLwP0xvbyXPFbqtUL/vAKdSPQtqLi QJvfKdBTW8Vn1Culr+QLA9+Ss8nXDYOUyHM+I/fd9fdVcJxQImH2DtUC7z2subpkS4G3 ur5USUhdIsiVxp4zgFPSbb9s6prshbEvNH7r7ADWqb4VXwZ0LH3Mkbkr0z1424tZ2U5L If5APRUqIm2nrHpu4lP+LBVdt6vm4oGD7l4Yaj38Ct0MkPPQaBZeVjmWdkYu7Zem0myO 5VjR1ZV2Bqtz7d7eJnVQuot1Pn8sjHSUvABAwMu7SFThEbJJQtKN3cEkoTXKD2RZEf9j UDqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769598742; x=1770203542; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=mx1XKr7r/QLdw1fGIYSOIPcQvjj/MuXPHk5j26e2USc=; b=nSH6rbRvhFAJQGq32zL/xoq7U/xbGXW9/3KauexeKfM7t7y6j7y4QJMRjyq2JthMo6 2ZBmJpd5qpt3VlojUpZhWSJl/3nMUbaaGlmEXDwFcfCkiYXjINxdXPx4MGt4yZx2l0lx 8LZBGyZsTuimYk39cwXctmiUlRKhsBJL5PeJT0jEJzSb6VxmEn9zewImGrKQT6pNt38A UZnd297Mqu/+P1l75/x6PRUnMN1xNEHpVJI1vPa/6aaUUx0jQ+6cPSjXiTjLJlwg7D1x iAYsqQ0agIBNYK/J/W4XlHufxOIN045R/VBv/GCD76lSyrDnxZ/0i6uDoEuHoJdzGvgG YmHw== X-Gm-Message-State: AOJu0YzrjzlhrclvZY9p3VAS8PgpS9LkC9WwCWLEq8joCWbTvkkHSP/b asSQHIynk7AZsZvnKCZnzTvcfvN+VCbIIMmLxmtuMrJ2JfTNAw8B2CMaIKO2R7j4dKwK3AvCLaj olQDvfShnJtzjIe9mbJTkvLXl+4rM8mfGqjn3lqhb X-Gm-Gg: AZuq6aI2UsKAwWyJUVR0u2XkZ74lc04qyo9ibVAjSG9oRetVLwdfM3uRgLkCDXYwTqx iH2UGac8IZpHYCjcHEr6oT4FB0FdDtXo5WQKMUlOjZAeafw2GG5H+i+JC66sAEcvPkW2vnvIL8c HEZ3Dv3DcPzEnuYf4FXwjs1HwIYHN7Achz7tZKCd5GkCDDgq4T6gqjVbXYHMeoXnTpMH72IwSsQ 0e3SuA9bDEerDmNbDA4LosN9naf/KR6aw0Rebjyp6DUpDm1dGuhkXH8/Xo+jDVB1Vqnut+dlq9r tc/rrE3PpVng3lvnjgFo+76UrYXJS/zR/DOYLr5S9Tq4h/ptqeHISWI= X-Received: by 2002:a05:6512:318b:b0:59d:dea0:34f5 with SMTP id 2adb3069b0e04-59e0402ca7bmr2119998e87.36.1769598742078; Wed, 28 Jan 2026 03:12:22 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Jakub Wartak Date: Wed, 28 Jan 2026 12:12:10 +0100 X-Gm-Features: AZwV_QgbkojFEeJDMHeDdb4iII7vhMmbiNpUPf2xOi4k10cLbetuM7bzPTgnX5A Message-ID: Subject: Re: pg_stat_io_histogram To: Andres Freund Cc: PostgreSQL Hackers Content-Type: multipart/alternative; boundary="0000000000006ab441064970d0d1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000006ab441064970d0d1 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Jan 27, 2026 at 1:06=E2=80=AFPM Jakub Wartak wrote: > [..] > > > Of course most of the I/O calls today are hitting page cache, so one > would > > > expect they'll be < 128us most of the time > > > > Have you measured whether overhead is measurable when hitting the page > cache? > > I'd hope that it doesn't, due to io combing amortizing the cost > somewhat. But > > it seems worth measuring. > > Not yet, I first wanted to hear if I'm not sailing into some plain stupid > direction somewhere with this idea or implementation (e.g. > that INSTR_TIME_GET_MICROSEC() was a really stupid omission from my side)= . > > I'll try to perform this test overhead measurement hopefully with v3 once > we settle on how to do that bit shifting/clz(). > [..] Here's the answer: on properly isolated perf test run (my old&legacy&predictiable 4s32c64t NUMA box, s_b=3D8GB, DB size 16GB, hugepages, no turboboost, prope= r warmup, no THP, cpupower D0, no physical I/O, ~22k pread64() calls/sec combined to VFS cache) and started on just using single NUMA: numactl --membind=3D0 --cpunodebind=3D0 measured using: pgbench -M prepared -c 4 -j 4 postgres -T 20 -P 1 -S master+track_io_timings=3Don, 60s warmup and then 3x runs tps =3D 44615.603668 tps =3D 44556.191492 tps =3D 44813.793981 avg =3D 44662 master+track_io_timings=3Don+patch, , 60s warmup and then 3x runs tps =3D 44441.879384 tps =3D 44403.101737 tps =3D 45036.747418 avg =3D 44627 so that's like 99.921% (so literally no overhead) and yields picture like: postgres=3D# select bucket_latency_us, bucket_count from pg_stat_io_histogram where bucket_count > 0 and backend_type =3D 'client backend' and io_type =3D 'read' and context =3D 'normal' order by bucket_latency_us; bucket_latency_us | bucket_count -------------------+-------------- [0,9) | 273455 [8,17) | 3820379 [16,33) | 29359 [32,65) | 585 [64,129) | 467 [128,257) | 419 [256,513) | 15828 [512,1025) | 89 So one can also see 0.25..0.5ms bucket being larger there (initial reading of the data from physical device) and that's hardware RAID-1 with 2x Intel D3-S4510. And if I do pg_buffercache_evict_all()+vm drop_cache+ pg_stat_reset_shared(), I get this picture (note for bulkreads): postgres=3D# select bucket_latency_us, bucket_count from pg_stat_io_histogram where bucket_count > 0 and backend_type =3D 'client backend' and context=3D'bulkread'; bucket_latency_us | bucket_count -------------------+-------------- [0,9) | 102555 [8,17) | 70 [16,33) | 3938 [32,65) | 6763 [64,129) | 5206 [128,257) | 9392 [256,513) | 10959 [512,1025) | 21372 [1024,2049) | 502 [2048,4097) | 34 [4096,8193) | 2 [8192,16385) | 2 [16384,32769) | 7 So clearly there's a distinction between reading the VFS cache and hitting physical I/O. Now we'll just probably settle on the proper get_bucket_index() impl. -J. --0000000000006ab441064970d0d1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Tue, Jan 27, 2026 at= 1:06=E2=80=AFPM Jakub Wartak <jakub.wartak@enterprisedb.com> wrote:
[..]
> > Of = course most of the I/O calls today are hitting page cache, so one would
= > > expect they'll be < 128us most of the time
>
>= Have you measured whether overhead is measurable when hitting the page cac= he?
> I'd hope that it doesn't, due to io combing amortizing = the cost somewhat. But
> it seems worth measuring.

Not yet, I = first wanted to hear if I'm not sailing into some plain stupid
direc= tion somewhere with this idea or implementation (e.g.
that INSTR_TIME_GE= T_MICROSEC() was a really stupid omission from my side).

I'll tr= y to perform this test overhead measurement hopefully with v3 once
we se= ttle on how to do that bit shifting/clz().

[..]
Here's the answer: on properly isolated perf test = run (my old&legacy&predictiable
4s32c64t NUMA box, s_b=3D8GB, D= B size 16GB, hugepages, no turboboost, proper warmup,
no THP, cpupower = D0, no physical I/O, ~22k pread64() calls/sec combined to VFS
cache)=C2=A0 =C2=A0 and started on just using single NUMA: numactl --membind=3D0= --cpunodebind=3D0
=C2=A0 =C2=A0 measured using: pgbench -M prepared -c = 4 -j 4 postgres -T 20 -P 1 -S

master+track_io_timings=3Don, 60s warm= up and then 3x runs
=C2=A0 =C2=A0 tps =3D 44615.603668
=C2=A0 =C2=A0= tps =3D 44556.191492
=C2=A0 =C2=A0 tps =3D 44813.793981
=C2=A0 =C2= =A0 avg =3D 44662

master+track_io_timings=3Don+patch, , 60s warmup a= nd then 3x runs
=C2=A0 =C2=A0 tps =3D 44441.879384 =C2=A0
=C2=A0 =C2= =A0 tps =3D 44403.101737
=C2=A0 =C2=A0 tps =3D 45036.747418
=C2=A0 = =C2=A0 avg =3D 44627

so that's like 99.921% (so literally no ove= rhead) and yields picture like:

postgres=3D# selec= t bucket_latency_us, bucket_count
from pg_stat_io_histogram =C2=A0
w= here
=C2=A0 =C2=A0 bucket_count > 0 and
=C2=A0 =C2=A0 backend_ty= pe =3D 'client backend' and
=C2=A0 =C2=A0 io_type =3D 'read= ' and
=C2=A0 =C2=A0 context =3D 'normal'
order by bucke= t_latency_us;
=C2=A0bucket_latency_us | bucket_count
---------------= ----+--------------
=C2=A0[0,9) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 | =C2=A0 =C2=A0 =C2=A0 273455
=C2=A0[8,17) =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A03820379
=C2=A0[16,33) =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A029359
=C2=A0[32,65= ) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A058= 5
=C2=A0[64,129) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0467
=C2=A0[128,257) =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0419
=C2=A0[256,513) =C2=A0 =C2=A0 =C2=A0 = =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A015828
=C2=A0[512,1025) =C2=A0 =C2=A0= =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 89=C2=A0

So one c= an also see 0.25..0.5ms bucket being larger there (initial reading
of t= he data from physical device) and that's hardware RAID-1 with 2x
In= tel D3-S4510. And if I do pg_buffercache_evict_all()+vm drop_cache+
pg_stat_reset_shared(), I get this picture (note for bulkreads):
postgres=3D# select bucket_latency_us, bucket_count
from pg_stat= _io_histogram =C2=A0
where
=C2=A0 =C2=A0 bucket_count > 0 and =C2=A0 =C2=A0 backend_type =3D 'client backend' and context=3D'= ;bulkread';
=C2=A0bucket_latency_us | bucket_count
-------------= ------+--------------
=C2=A0[0,9) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 | =C2=A0 =C2=A0 =C2=A0 102555
=C2=A0[8,17) =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 70
=C2=A0[16,33) = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A0 3938
= =C2=A0[32,65) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2= =A0 6763
=C2=A0[64,129) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2= =A0 =C2=A0 =C2=A0 5206
=C2=A0[128,257) =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2= =A0 =C2=A0 =C2=A0 =C2=A0 9392
=C2=A0[256,513) =C2=A0 =C2=A0 =C2=A0 =C2= =A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A010959
=C2=A0[512,1025) =C2=A0 =C2=A0 = =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A0 =C2=A021372
=C2=A0[1024,2049) =C2=A0= =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0502
=C2=A0[2048,4097)= =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 34
=C2=A0[409= 6,8193) =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A02=C2=A0[8192,16385) =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A02
=C2=A0[16384,32769) =C2=A0 =C2=A0 | =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A07

So clearly there's a distin= ction between reading the VFS cache and hitting physical I/O.
Now we'll just probably settle on the proper get_bucket_ind= ex() impl.

-J.
--0000000000006ab441064970d0d1--