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 1viGcp-001xcT-3D for pgsql-hackers@arkaria.postgresql.org; Tue, 20 Jan 2026 18:38:48 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1viGcp-002Nhu-0N for pgsql-hackers@arkaria.postgresql.org; Tue, 20 Jan 2026 18:38:47 +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 1viGco-002Nhd-0y for pgsql-hackers@lists.postgresql.org; Tue, 20 Jan 2026 18:38:47 +0000 Received: from fhigh-b6-smtp.messagingengine.com ([202.12.124.157]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1viGcl-001ZLy-29 for pgsql-hackers@lists.postgresql.org; Tue, 20 Jan 2026 18:38:46 +0000 Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id CAE017A0049; Tue, 20 Jan 2026 13:38:40 -0500 (EST) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Tue, 20 Jan 2026 13:38:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anarazel.de; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1768934320; x=1769020720; bh=Wi0vwKRLjr Qt/3Py3I7KLNQKTf9tWnZB62CnXWUKKVs=; b=Qdc3mOeJF483AZgmDxniDV5Jft Nakxz6Nb4G6xIZXgSLa84vVxoyhBDIebfDDJOTCNaoiCSOxmtVJcNlr5HG35IvoV TJ0xfshwt6AD4pgyOAPPFuZFjVctXb7Tou+V2d3z2LQEliy7S0hSPJiF0dPJuygl 3l29xYG20L+F4K9+GtWBrDlNpe2hicAqljjioaGCJoyGmzza+UROD5qjFH4sE7Pq deomsZGFF351mmzzVn2hxHMCstWa5vAUaAOo4pg3Saueta/gNd1MWaSgrXOrAX+I QgpO5b8QF2x5xLaPBxTR3uhigfbyUCw/cJLXXj0C8UiBHx+lq8i+qMcajiDg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1768934320; x=1769020720; bh=Wi0vwKRLjrQt/3Py3I7KLNQKTf9tWnZB62C nXWUKKVs=; b=IJqGPMvkC15VyIzUjYOQppE3C09B07RDopzUiW8jHDW5Ec5zMB6 JgQDnBzDrRQ6+H5d1FsqhI9Q0Qau8jJqFqJ99elRAxhHht9H+6+SZ3BOuSTri4zw D5wZ8NINIillhdbGgNt/Jg0KQZMlCfnPXnUFruGXvW5kQJBQ8t56K7dQNiNTOaV7 ZjwhxD6m5KcHVphSBbrVwuSnNgsMjG2HNL0RTwQvz/hSEQmhL9U97jx/K2gU171q qyBwndSFC1BtEnHz3kIZBGodC+yXjKEyAfkMoADbAezfi6gbANdtuBg+CDfqodVf cfh0/LC4GBRC7hMb9hR4LZ86kgL7TYKSsCw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddugeduudehucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucenucfjughrpeffhffvvefukfhfgggtuggjsehttdfstd dttddvnecuhfhrohhmpeetnhgurhgvshcuhfhrvghunhguuceorghnughrvghssegrnhgr rhgriigvlhdruggvqeenucggtffrrghtthgvrhhnpeeffffgledvffegtdevlefgtdeggf fhvdekgfegteeiveejkeetudelveejhfeugeenucevlhhushhtvghrufhiiigvpedtnecu rfgrrhgrmhepmhgrihhlfhhrohhmpegrnhgurhgvshesrghnrghrrgiivghlrdguvgdpnh gspghrtghpthhtohepfedpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepughgrhho fihlvgihmhhlsehgmhgrihhlrdgtohhmpdhrtghpthhtoheplhhirdgvvhgrnhdrtghhrg hosehgmhgrihhlrdgtohhmpdhrtghpthhtohepphhgshhqlhdqhhgrtghkvghrsheslhhi shhtshdrphhoshhtghhrvghsqhhlrdhorhhg X-ME-Proxy: Feedback-ID: id4a34324:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 20 Jan 2026 13:38:40 -0500 (EST) Date: Tue, 20 Jan 2026 13:38:39 -0500 From: Andres Freund To: David Rowley Cc: Chao Li , PostgreSQL Developers Subject: Re: More speedups for tuple deformation Message-ID: References: <9A17C43D-7A28-4885-8974-555A40C9523E@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, On 2026-01-20 13:11:55 +1300, David Rowley wrote: > I've attached the v4 patch, which also fixes the LLVM compiler warning > that I introduced. I wonder if it's possible to split the patch - it's big enough to be nontrivial to review... Perhaps the finalization could be introduced separately from the patch actually making use of it? I wonder if we should somehow change the API of tupledesc creation, to make old code that doesn't have TupleDescFinalize() fail to compile, instead of just warn... > diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c > index dcba3fb5473..2fdf5a341f6 100644 > --- a/contrib/pg_buffercache/pg_buffercache_pages.c > +++ b/contrib/pg_buffercache/pg_buffercache_pages.c > @@ -174,6 +174,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) > TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends", > INT4OID, -1, 0); > > + TupleDescFinalize(tupledesc); > fctx->tupdesc = BlessTupleDesc(tupledesc); > Think it'd be worth adding an assertion to BlessTupleDesc that TupleDescFinalize has been called, I think that'll lead to easier to understand backtraces in a lot of cases. Particularly if you consider cases where BlessTupleDesc() will create a tupdesc in shared memory, that could then trigger an assertion failure in a parallel worker or such. > /* > * slot_deform_heap_tuple > * Given a TupleTableSlot, extract data from the slot's physical tuple > @@ -1122,78 +1010,167 @@ static pg_attribute_always_inline void > slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, > int natts) > { > + CompactAttribute *cattr; > + TupleDesc tupleDesc = slot->tts_tupleDescriptor; > bool hasnulls = HeapTupleHasNulls(tuple); > + HeapTupleHeader tup = tuple->t_data; > + bits8 *bp; /* ptr to null bitmap in tuple */ > int attnum; > + int firstNonCacheOffsetAttr; > + > +#ifdef OPTIMIZE_BYVAL > + int firstByRefAttr; > +#endif > + int firstNullAttr; > + Datum *values; > + bool *isnull; > + char *tp; /* ptr to tuple data */ > uint32 off; /* offset in tuple data */ > - bool slow; /* can we use/set attcacheoff? */ > + > + /* Did someone forget to call TupleDescFinalize()? */ > + Assert(tupleDesc->firstNonCachedOffAttr >= 0); > > /* We can only fetch as many attributes as the tuple has. */ > - natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts); > + natts = Min(HeapTupleHeaderGetNatts(tup), natts); > + attnum = slot->tts_nvalid; > + firstNonCacheOffsetAttr = Min(tupleDesc->firstNonCachedOffAttr, natts); > + > + if (hasnulls) > + { > + bp = tup->t_bits; > + firstNullAttr = first_null_attr(bp, natts); > + firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr); > + } > + else > + { > + bp = NULL; > + firstNullAttr = natts; > + } > + > +#ifdef OPTIMIZE_BYVAL > + firstByRefAttr = Min(firstNonCacheOffsetAttr, tupleDesc->firstByRefAttr); > +#endif > + values = slot->tts_values; > + isnull = slot->tts_isnull; > + tp = (char *) tup + tup->t_hoff; > + > +#ifdef OPTIMIZE_BYVAL > > /* > - * Check whether the first call for this tuple, and initialize or restore > - * loop state. > + * Many tuples have leading byval attributes, try and process as many of > + * those as possible with a special loop that can't handle byref types. > */ > - attnum = slot->tts_nvalid; > - if (attnum == 0) > + if (attnum < firstByRefAttr) > + { > + /* Use do/while as we already know we need to loop at least once. */ > + do > + { > + cattr = TupleDescCompactAttr(tupleDesc, attnum); > + > + Assert(cattr->attcacheoff >= 0); > + > + /* > + * Hard code byval == true to allow the compiler to remove the > + * byval check when inlining fetch_att(). > + */ Maybe add an assert for cattr->attbyval? Just to avoid a bad debugging experience if somebody tries to extend this logic to e.g. non-null-fixed-width-byref columns? I also wonder if we could have assert-only crosschecking of the "real" offsets against the cached ones? Greetings, Andres Freund