pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Maksim.Melnikov <m.melnikov@postgrespro.ru>
To: Потапов Александр <a.potapov@postgrespro.ru>
Cc: Matthias van de Meent <boekewurm+postgres@gmail.com>
Cc: pgsql-hackers@postgresql.org
Subject: Re: Init connection time grows quadratically
Date: Wed, 3 Jun 2026 09:33:41 +0300
Message-ID: <65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru> (raw)
In-Reply-To: <3b7e5e-684fdc80-f-48e15c80@193664207>
References: <3bdba-68359800-d-249da480@139845401>
	<CAEze2WiHFA43SvV7SdQKjKyMjrSSdW+O6meaV+vk+YuwHr1UQg@mail.gmail.com>
	<2ab4be-6847f380-11-1d048f40@125133490>
	<3b7e5e-684fdc80-f-48e15c80@193664207>


On 6/16/25 11:56, Потапов Александр wrote:
>
> To be more precise I used constant number of threads (128 and 1024) to 
> compare with previous results. The quadratic dependency exists 
> everywhere, see new graph.
>
> > Q: Did you check that pgbench or the OS does not have
> > O(n_active_connections) or O(n_active_threads) overhead per worker
> > during thread creation or connection establishment, e.g. by varying
> > the number of threads used to manage these N clients? I wouldn't be
> > surprised if there are inefficiencies in e.g. the threading- or
> > synchronization model that cause O(N) per-thread overhead, or O(N^2)
> > overall when you have one thread per connection.
>
Hi, all!

I've investigated slightly different scenario then Alexander and I want 
share my thoughts in this thread too.

I found that when we run pgbench scenarios sequantially, without 
postgres restart between iterations, initial time degrades from launch 
to launch and eventually it stabilizes at the worst values then first 
run(ICT_degradation.png attached).

Scenario details:

1. postgres rev 1a51ec16db7, 0001-Fix-fast-connection-rate-issue.patch 
was applied

2. numa was disabled, swap was off, ramdisk was used for binaries and 
pg_data,Hyperthreading and cpu boost were disabled

3. server was built with -02

4.Add to the postgresql.conf:
     huge_pages = off #for the sake of test stability and reproducibility
     shared_buffers = 1GB
     max_connections = 16384

5. Cycle iteration

psql -U postgres -c 'create database bench'

pgbench -U postgres -i -s100 bench

psql -U postgres -d bench -c "checkpoint"

pgbench -U postgres -c${clients} -t100 -j6 -S bench

psql -U postgres -c "DROP DATABASE bench"

Where ${clients} is one of 512/1024/2048/4096/8192

I paid attention that ICT for the first iteration much better than for 
next ones. I investigated this behavior a little bit and found a lot of 
minor page fault events in ProcArrayAdd method(perf_without_patch-j6.txt 
attached) for code line

allProcs[procno].pgxactoff = index;

So, every proc.pgxactoff access generate page fault, because proc 
objects accessed in memory randomly and page replacement can occur. I 
have some ideas how to improve this - it seems we can put array 
of pgxactoff separately

in shmem to have only few hot pages for them. I've attached appropriate 
patch(0001-This-patch-reduce-connection-init-close-time.patch). Perf 
with minor faults for updated version also was 
attached(perf_with_patch-j6.txt attached),

as we can see, patched version fixes this. I made a series of 
measurements for all versions and attached comparison 
chart(ICT_degradation_with_patch.png attached). Also I add the table 
with results


	without_patch_first_iteration, average ICT, ms 
without_patch_after_warmup, average ICT, ms 	with_patch_first_iteration, 
average ICT, ms 	with_patch_after_warmup, average ICT, ms
512 	~480+-15 	~500+-10 	~470+-15 	~215 +-15
1024 	~920+-20 	~1000+-20 	~900+-15 	~920 +-20
2048 	~1780+-30 	~2240+-20 	~1760+-30 	~1800 +-30
4096 	~3570+-50 	~6140+-40 	~3450+-130 	~3740 +-60
8192 	~7440+-90 	~18840+-140 	~7440+-140 	~8100+-80

As we can see from attached charts, from one side there is no 
degradation for the first iterations for patched and no patched 
versions. From another side patched version is much better for next ones.

I've tried the same tests for different values of pgbench -j parameter 
to avoid effects of multithreading pgbench nature and got the same picture.

I hope it will be interesting and helpful.

Best regards,

Maksim Melnikov
# Samples: 1M of event 'minor-faults'
# Event count (approx.): 20314715
#
# Children      Self        Period  Command          Shared Object                          Symbol                                                                  
# ........  ........  ............  ...............  .....................................  ........................................................................
#
    99.79%     0.00%             0  postgres         postgres                               [.] _start
            |
            ---_start
               __libc_start_main@@GLIBC_2.34
               __libc_start_call_main
               main
               PostmasterMain
               |          
                --99.79%--ServerLoop
                          |          
                           --99.61%--BackendStartup
                                     |          
                                      --99.33%--postmaster_child_launch
                                                |          
                                                |--95.12%--BackendInitialize
                                                |          |          
                                                |           --95.08%--PostgresMain
                                                |                     |          
                                                |                     |--53.39%--InitPostgres
                                                |                     |          |          
                                                |                     |          |--35.65%--InitProcessPhase2
                                                |                     |          |          |          
                                                |                     |          |           --35.57%--ProcArrayAdd




 Percent |	Source code & Disassembly of postgres for minor-faults (103275 samples, percent: local period)
--------------------------------------------------------------------------------------------------------------
         :
         :
         :
         : 3      Disassembly of section .text:
         :
         : 5      00000000006b5720 <ProcArrayAdd>:
         : 6      /*
         : 7      * Add the specified PGPROC to the shared array.
         : 8      */
         : 9      void
         : 10     ProcArrayAdd(PGPROC *proc)
         : 11     {
    0.00 :   6b5720: endbr64
    0.00 :   6b5724: push   %rbp
    0.00 :   6b5725: mov    %rsp,%rbp
    0.00 :   6b5728: sub    $0x30,%rsp
    0.00 :   6b572c: mov    %rdi,-0x28(%rbp)
         : 17     int                     pgprocno = GetNumberFromPGProc(proc);
    0.00 :   6b5730: mov    0x686319(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5737: mov    (%rax),%rax
    0.00 :   6b573a: mov    -0x28(%rbp),%rdx
    0.00 :   6b573e: sub    %rax,%rdx
    0.00 :   6b5741: sar    $0x7,%rdx
    0.00 :   6b5745: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b574f: imul   %rdx,%rax
    0.00 :   6b5753: mov    %eax,-0x18(%rbp)
         : 26     ProcArrayStruct *arrayP = procArray;
    0.00 :   6b5756: mov    0x684043(%rip),%rax        # d397a0 <procArray>
    0.00 :   6b575d: mov    %rax,-0x8(%rbp)
         : 29     int                     index;
         : 30     int                     movecount;
         :
         : 32     /* See ProcGlobal comment explaining why both locks are held */
         : 33     LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
    0.00 :   6b5761: mov    0x6854f8(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5768: add    $0x200,%rax
    0.00 :   6b576e: mov    $0x0,%esi
    0.00 :   6b5773: mov    %rax,%rdi
    0.00 :   6b5776: call   6d454c <LWLockAcquire>
         : 39     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    0.00 :   6b577b: mov    0x6854de(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5782: add    $0x180,%rax
    0.00 :   6b5788: mov    $0x0,%esi
    0.00 :   6b578d: mov    %rax,%rdi
    0.00 :   6b5790: call   6d454c <LWLockAcquire>
         :
         : 46     if (arrayP->numProcs >= arrayP->maxProcs)
    0.00 :   6b5795: mov    -0x8(%rbp),%rax
    0.11 :   6b5799: mov    (%rax),%edx
    0.00 :   6b579b: mov    -0x8(%rbp),%rax
    0.00 :   6b579f: mov    0x4(%rax),%eax
    0.00 :   6b57a2: cmp    %eax,%edx
    0.00 :   6b57a4: jl     6b57f5 <ProcArrayAdd+0xd5>
         : 53     /*
         : 54     * Oops, no room.  (This really shouldn't happen, since there is a
         : 55     * fixed supply of PGPROC structs too, and so we should have failed
         : 56     * earlier.)
         : 57     */
         : 58     ereport(FATAL,
    0.00 :   6b57a6: mov    $0x0,%esi
    0.00 :   6b57ab: mov    $0x16,%edi
    0.00 :   6b57b0: call   8f9a0f <errstart_cold>
    0.00 :   6b57b5: test   %al,%al
    0.00 :   6b57b7: je     6b57f5 <ProcArrayAdd+0xd5>
    0.00 :   6b57b9: mov    $0x30c5,%edi
    0.00 :   6b57be: call   8fa2a6 <errcode>
    0.00 :   6b57c3: lea    0x4496ce(%rip),%rax        # afee98 <__func__.0+0x58>
    0.00 :   6b57ca: mov    %rax,%rdi
    0.00 :   6b57cd: mov    $0x0,%eax
    0.00 :   6b57d2: call   8fa559 <errmsg>
    0.00 :   6b57d7: lea    0x449b4a(%rip),%rax        # aff328 <__func__.19>
    0.00 :   6b57de: mov    %rax,%rdx
    0.00 :   6b57e1: mov    $0x1e2,%esi
    0.00 :   6b57e6: lea    0x4496cb(%rip),%rax        # afeeb8 <__func__.0+0x78>
    0.00 :   6b57ed: mov    %rax,%rdi
    0.00 :   6b57f0: call   8f9c10 <errfinish>
         : 76     * PGPROC structure in the cache.
         : 77     *
         : 78     * Since the occurrence of adding/removing a proc is much lower than the
         : 79     * access to the ProcArray itself, the overhead should be marginal
         : 80     */
         : 81     for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b57f5: movl   $0x0,-0x1c(%rbp)
    0.00 :   6b57fc: jmp    6b581f <ProcArrayAdd+0xff>
         : 84     {
         : 85     int                     this_procno = arrayP->pgprocnos[index];
    0.00 :   6b57fe: mov    -0x8(%rbp),%rax
    0.00 :   6b5802: mov    -0x1c(%rbp),%edx
    0.00 :   6b5805: movslq %edx,%rdx
    0.00 :   6b5808: add    $0x8,%rdx
    0.07 :   6b580c: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5810: mov    %eax,-0x14(%rbp)
         :
         : 93     Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 94     Assert(allProcs[this_procno].pgxactoff == index);
         :
         : 96     /* If we have found our right position in the array, break */
         : 97     if (this_procno > pgprocno)
    0.00 :   6b5813: mov    -0x14(%rbp),%eax
    0.00 :   6b5816: cmp    -0x18(%rbp),%eax
    0.00 :   6b5819: jg     6b582c <ProcArrayAdd+0x10c>
         : 101    for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b581b: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b581f: mov    -0x8(%rbp),%rax
    0.00 :   6b5823: mov    (%rax),%eax
    0.00 :   6b5825: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5828: jl     6b57fe <ProcArrayAdd+0xde>
    0.00 :   6b582a: jmp    6b582d <ProcArrayAdd+0x10d>
         : 108    break;
    0.00 :   6b582c: nop
         : 110    }
         :
         : 112    movecount = arrayP->numProcs - index;
    0.00 :   6b582d: mov    -0x8(%rbp),%rax
    0.00 :   6b5831: mov    (%rax),%eax
    0.00 :   6b5833: sub    -0x1c(%rbp),%eax
    0.00 :   6b5836: mov    %eax,-0x10(%rbp)
         : 117    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b5839: mov    -0x10(%rbp),%eax
    0.00 :   6b583c: cltq
    0.00 :   6b583e: lea    0x0(,%rax,4),%rdx
         : 121    &arrayP->pgprocnos[index],
    0.00 :   6b5846: mov    -0x1c(%rbp),%eax
    0.00 :   6b5849: cltq
    0.00 :   6b584b: add    $0x8,%rax
    0.00 :   6b584f: lea    0x0(,%rax,4),%rcx
    0.00 :   6b5857: mov    -0x8(%rbp),%rax
    0.00 :   6b585b: add    %rcx,%rax
    0.00 :   6b585e: lea    0x4(%rax),%rcx
         : 129    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b5862: mov    -0x1c(%rbp),%eax
    0.00 :   6b5865: add    $0x1,%eax
    0.00 :   6b5868: cltq
    0.00 :   6b586a: add    $0x8,%rax
    0.00 :   6b586e: lea    0x0(,%rax,4),%rsi
    0.00 :   6b5876: mov    -0x8(%rbp),%rax
    0.00 :   6b587a: add    %rsi,%rax
    0.00 :   6b587d: add    $0x4,%rax
    0.00 :   6b5881: mov    %rcx,%rsi
    0.00 :   6b5884: mov    %rax,%rdi
    0.00 :   6b5887: call   ed240 <memmove@plt>
         : 141    movecount * sizeof(*arrayP->pgprocnos));
         : 142    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b588c: mov    -0x10(%rbp),%eax
    0.00 :   6b588f: cltq
    0.00 :   6b5891: lea    0x0(,%rax,4),%rdx
         : 146    &ProcGlobal->xids[index],
    0.00 :   6b5899: mov    0x6861b0(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58a0: mov    0x8(%rax),%rax
    0.00 :   6b58a4: mov    -0x1c(%rbp),%ecx
    0.00 :   6b58a7: movslq %ecx,%rcx
    0.00 :   6b58aa: shl    $0x2,%rcx
    0.00 :   6b58ae: add    %rax,%rcx
         : 153    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b58b1: mov    0x686198(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58b8: mov    0x8(%rax),%rax
    0.00 :   6b58bc: mov    -0x1c(%rbp),%esi
    0.00 :   6b58bf: add    $0x1,%esi
    0.00 :   6b58c2: movslq %esi,%rsi
    0.00 :   6b58c5: shl    $0x2,%rsi
    0.00 :   6b58c9: add    %rsi,%rax
    0.00 :   6b58cc: mov    %rcx,%rsi
    0.00 :   6b58cf: mov    %rax,%rdi
    0.00 :   6b58d2: call   ed240 <memmove@plt>
         : 164    movecount * sizeof(*ProcGlobal->xids));
         : 165    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b58d7: mov    -0x10(%rbp),%eax
    0.00 :   6b58da: cltq
    0.00 :   6b58dc: lea    (%rax,%rax,1),%rdx
         : 169    &ProcGlobal->subxidStates[index],
    0.00 :   6b58e0: mov    0x686169(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58e7: mov    0x10(%rax),%rax
    0.00 :   6b58eb: mov    -0x1c(%rbp),%ecx
    0.00 :   6b58ee: movslq %ecx,%rcx
    0.00 :   6b58f1: add    %rcx,%rcx
    0.00 :   6b58f4: add    %rax,%rcx
         : 176    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b58f7: mov    0x686152(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58fe: mov    0x10(%rax),%rax
    0.00 :   6b5902: mov    -0x1c(%rbp),%esi
    0.00 :   6b5905: add    $0x1,%esi
    0.00 :   6b5908: movslq %esi,%rsi
    0.00 :   6b590b: add    %rsi,%rsi
    0.00 :   6b590e: add    %rsi,%rax
    0.00 :   6b5911: mov    %rcx,%rsi
    0.00 :   6b5914: mov    %rax,%rdi
    0.00 :   6b5917: call   ed240 <memmove@plt>
         : 187    movecount * sizeof(*ProcGlobal->subxidStates));
         : 188    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b591c: mov    -0x10(%rbp),%eax
    0.00 :   6b591f: cltq
         : 191    &ProcGlobal->statusFlags[index],
    0.00 :   6b5921: mov    0x686128(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5928: mov    0x18(%rdx),%rcx
         : 194    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b592c: mov    -0x1c(%rbp),%edx
    0.00 :   6b592f: movslq %edx,%rdx
         : 197    &ProcGlobal->statusFlags[index],
    0.00 :   6b5932: lea    (%rcx,%rdx,1),%rsi
         : 199    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5936: mov    0x686113(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b593d: mov    0x18(%rdx),%rcx
    0.00 :   6b5941: mov    -0x1c(%rbp),%edx
    0.00 :   6b5944: add    $0x1,%edx
    0.00 :   6b5947: movslq %edx,%rdx
    0.00 :   6b594a: add    %rdx,%rcx
    0.00 :   6b594d: mov    %rax,%rdx
    0.00 :   6b5950: mov    %rcx,%rdi
    0.00 :   6b5953: call   ed240 <memmove@plt>
         : 209    movecount * sizeof(*ProcGlobal->statusFlags));
         :
         : 211    arrayP->pgprocnos[index] = GetNumberFromPGProc(proc);
    0.00 :   6b5958: mov    0x6860f1(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b595f: mov    (%rax),%rax
    0.00 :   6b5962: mov    -0x28(%rbp),%rdx
    0.00 :   6b5966: sub    %rax,%rdx
    0.00 :   6b5969: sar    $0x7,%rdx
    0.00 :   6b596d: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b5977: imul   %rdx,%rax
    0.00 :   6b597b: mov    %eax,%ecx
    0.00 :   6b597d: mov    -0x8(%rbp),%rax
    0.00 :   6b5981: mov    -0x1c(%rbp),%edx
    0.00 :   6b5984: movslq %edx,%rdx
    0.00 :   6b5987: add    $0x8,%rdx
    0.00 :   6b598b: mov    %ecx,0x4(%rax,%rdx,4)
         : 225    proc->pgxactoff = index;
    0.00 :   6b598f: mov    -0x28(%rbp),%rax
    0.00 :   6b5993: mov    -0x1c(%rbp),%edx
    0.00 :   6b5996: mov    %edx,0x2c(%rax)
         : 229    ProcGlobal->xids[index] = proc->xid;
    0.00 :   6b5999: mov    0x6860b0(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59a0: mov    0x8(%rax),%rax
    0.00 :   6b59a4: mov    -0x1c(%rbp),%edx
    0.00 :   6b59a7: movslq %edx,%rdx
    0.00 :   6b59aa: shl    $0x2,%rdx
    0.00 :   6b59ae: add    %rax,%rdx
    0.00 :   6b59b1: mov    -0x28(%rbp),%rax
    0.00 :   6b59b5: mov    0x3c(%rax),%eax
    0.00 :   6b59b8: mov    %eax,(%rdx)
         : 239    ProcGlobal->subxidStates[index] = proc->subxidStatus;
    0.00 :   6b59ba: mov    0x68608f(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59c1: mov    0x10(%rax),%rax
    0.00 :   6b59c5: mov    -0x1c(%rbp),%edx
    0.00 :   6b59c8: movslq %edx,%rdx
    0.00 :   6b59cb: add    %rdx,%rdx
    0.00 :   6b59ce: add    %rax,%rdx
    0.00 :   6b59d1: mov    -0x28(%rbp),%rax
    0.00 :   6b59d5: movzwl 0x44(%rax),%eax
    0.00 :   6b59d9: mov    %ax,(%rdx)
         : 249    ProcGlobal->statusFlags[index] = proc->statusFlags;
    0.00 :   6b59dc: mov    0x68606d(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59e3: mov    0x18(%rax),%rdx
    0.00 :   6b59e7: mov    -0x1c(%rbp),%eax
    0.00 :   6b59ea: cltq
    0.00 :   6b59ec: add    %rax,%rdx
    0.00 :   6b59ef: mov    -0x28(%rbp),%rax
    0.00 :   6b59f3: movzbl 0x30(%rax),%eax
    0.00 :   6b59f7: mov    %al,(%rdx)
         :
         : 259    arrayP->numProcs++;
    0.00 :   6b59f9: mov    -0x8(%rbp),%rax
    0.00 :   6b59fd: mov    (%rax),%eax
    0.00 :   6b59ff: lea    0x1(%rax),%edx
    0.00 :   6b5a02: mov    -0x8(%rbp),%rax
    0.00 :   6b5a06: mov    %edx,(%rax)
         :
         : 266    /* adjust pgxactoff for all following PGPROCs */
         : 267    index++;
    0.00 :   6b5a08: addl   $0x1,-0x1c(%rbp)
         : 269    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5a0c: jmp    6b5a4c <ProcArrayAdd+0x32c>
         : 271    {
         : 272    int                     procno = arrayP->pgprocnos[index];
    0.00 :   6b5a0e: mov    -0x8(%rbp),%rax
    0.00 :   6b5a12: mov    -0x1c(%rbp),%edx
    0.00 :   6b5a15: movslq %edx,%rdx
    0.00 :   6b5a18: add    $0x8,%rdx
    0.00 :   6b5a1c: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5a20: mov    %eax,-0xc(%rbp)
         :
         : 280    Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 281    Assert(allProcs[procno].pgxactoff == index - 1);
         :
         : 283    allProcs[procno].pgxactoff = index;
    0.00 :   6b5a23: mov    0x683d7e(%rip),%rcx        # d397a8 <allProcs>
    0.00 :   6b5a2a: mov    -0xc(%rbp),%eax
    0.00 :   6b5a2d: movslq %eax,%rdx
    0.00 :   6b5a30: mov    %rdx,%rax
    0.00 :   6b5a33: shl    $0x3,%rax
    0.00 :   6b5a37: sub    %rdx,%rax
    0.00 :   6b5a3a: shl    $0x7,%rax
    0.00 :   6b5a3e: lea    (%rcx,%rax,1),%rdx
    0.00 :   6b5a42: mov    -0x1c(%rbp),%eax
   99.82 :   6b5a45: mov    %eax,0x2c(%rdx)
         : 294    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5a48: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b5a4c: mov    -0x8(%rbp),%rax
    0.00 :   6b5a50: mov    (%rax),%eax
    0.00 :   6b5a52: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5a55: jl     6b5a0e <ProcArrayAdd+0x2ee>
         :
         : 301    /*
         : 302    * Release in reversed acquisition order, to reduce frequency of having to
         : 303    * wait for XidGenLock while holding ProcArrayLock.
         : 304    */
         : 305    LWLockRelease(XidGenLock);
    0.00 :   6b5a57: mov    0x685202(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5a5e: add    $0x180,%rax
    0.00 :   6b5a64: mov    %rax,%rdi
    0.00 :   6b5a67: call   6d4da1 <LWLockRelease>
         : 310    LWLockRelease(ProcArrayLock);
    0.00 :   6b5a6c: mov    0x6851ed(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5a73: add    $0x200,%rax
    0.00 :   6b5a79: mov    %rax,%rdi
    0.00 :   6b5a7c: call   6d4da1 <LWLockRelease>
         : 315    }
    0.00 :   6b5a81: nop
    0.00 :   6b5a82: leave
    0.00 :   6b5a83: ret


     0.13%     0.10%         11727  postgres         postgres                               [.] ProcArrayAdd


 Percent |	Source code & Disassembly of postgres for minor-faults (445 samples, percent: local period)
-----------------------------------------------------------------------------------------------------------
         :
         :
         :
         : 3      Disassembly of section .text:
         :
         : 5      00000000006b58ba <ProcArrayAdd>:
         : 6      /*
         : 7      * Add the specified PGPROC to the shared array.
         : 8      */
         : 9      void
         : 10     ProcArrayAdd(PGPROC *proc)
         : 11     {
    0.00 :   6b58ba: endbr64
    0.00 :   6b58be: push   %rbp
    0.00 :   6b58bf: mov    %rsp,%rbp
    0.00 :   6b58c2: sub    $0x30,%rsp
    0.00 :   6b58c6: mov    %rdi,-0x28(%rbp)
         : 17     int                     pgprocno = GetNumberFromPGProc(proc);
    0.00 :   6b58ca: mov    0x68617f(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58d1: mov    (%rax),%rax
    0.00 :   6b58d4: mov    -0x28(%rbp),%rdx
    0.00 :   6b58d8: sub    %rax,%rdx
    0.00 :   6b58db: sar    $0x7,%rdx
    0.00 :   6b58df: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b58e9: imul   %rdx,%rax
    0.00 :   6b58ed: mov    %eax,-0x18(%rbp)
         : 26     ProcArrayStruct *arrayP = procArray;
    0.00 :   6b58f0: mov    0x683ea9(%rip),%rax        # d397a0 <procArray>
    0.00 :   6b58f7: mov    %rax,-0x8(%rbp)
         : 29     int                     index;
         : 30     int                     movecount;
         :
         : 32     /* See ProcGlobal comment explaining why both locks are held */
         : 33     LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
    0.00 :   6b58fb: mov    0x68535e(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5902: add    $0x200,%rax
    0.00 :   6b5908: mov    $0x0,%esi
    0.00 :   6b590d: mov    %rax,%rdi
    0.00 :   6b5910: call   6d48a7 <LWLockAcquire>
         : 39     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    0.00 :   6b5915: mov    0x685344(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b591c: add    $0x180,%rax
    0.00 :   6b5922: mov    $0x0,%esi
    0.00 :   6b5927: mov    %rax,%rdi
    0.00 :   6b592a: call   6d48a7 <LWLockAcquire>
         :
         : 46     if (arrayP->numProcs >= arrayP->maxProcs)
    0.00 :   6b592f: mov    -0x8(%rbp),%rax
   65.30 :   6b5933: mov    (%rax),%edx
    0.00 :   6b5935: mov    -0x8(%rbp),%rax
    0.00 :   6b5939: mov    0x4(%rax),%eax
    0.00 :   6b593c: cmp    %eax,%edx
    0.00 :   6b593e: jl     6b598f <ProcArrayAdd+0xd5>
         : 53     /*
         : 54     * Oops, no room.  (This really shouldn't happen, since there is a
         : 55     * fixed supply of PGPROC structs too, and so we should have failed
         : 56     * earlier.)
         : 57     */
         : 58     ereport(FATAL,
    0.00 :   6b5940: mov    $0x0,%esi
    0.00 :   6b5945: mov    $0x16,%edi
    0.00 :   6b594a: call   8f9e02 <errstart_cold>
    0.00 :   6b594f: test   %al,%al
    0.00 :   6b5951: je     6b598f <ProcArrayAdd+0xd5>
    0.00 :   6b5953: mov    $0x30c5,%edi
    0.00 :   6b5958: call   8fa699 <errcode>
    0.00 :   6b595d: lea    0x449534(%rip),%rax        # afee98 <__func__.0+0x58>
    0.00 :   6b5964: mov    %rax,%rdi
    0.00 :   6b5967: mov    $0x0,%eax
    0.00 :   6b596c: call   8fa94c <errmsg>
    0.00 :   6b5971: lea    0x4499b0(%rip),%rax        # aff328 <__func__.19>
    0.00 :   6b5978: mov    %rax,%rdx
    0.00 :   6b597b: mov    $0x1e4,%esi
    0.00 :   6b5980: lea    0x449531(%rip),%rax        # afeeb8 <__func__.0+0x78>
    0.00 :   6b5987: mov    %rax,%rdi
    0.00 :   6b598a: call   8fa003 <errfinish>
         : 76     * PGPROC structure in the cache.
         : 77     *
         : 78     * Since the occurrence of adding/removing a proc is much lower than the
         : 79     * access to the ProcArray itself, the overhead should be marginal
         : 80     */
         : 81     for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b598f: movl   $0x0,-0x1c(%rbp)
    0.00 :   6b5996: jmp    6b59b9 <ProcArrayAdd+0xff>
         : 84     {
         : 85     int                     this_procno = arrayP->pgprocnos[index];
    0.00 :   6b5998: mov    -0x8(%rbp),%rax
    0.00 :   6b599c: mov    -0x1c(%rbp),%edx
    0.00 :   6b599f: movslq %edx,%rdx
    0.00 :   6b59a2: add    $0x8,%rdx
   34.70 :   6b59a6: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b59aa: mov    %eax,-0x14(%rbp)
         :
         : 93     Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 94     Assert(pgxactoffs[this_procno] == index);
         :
         : 96     /* If we have found our right position in the array, break */
         : 97     if (this_procno > pgprocno)
    0.00 :   6b59ad: mov    -0x14(%rbp),%eax
    0.00 :   6b59b0: cmp    -0x18(%rbp),%eax
    0.00 :   6b59b3: jg     6b59c6 <ProcArrayAdd+0x10c>
         : 101    for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b59b5: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b59b9: mov    -0x8(%rbp),%rax
    0.00 :   6b59bd: mov    (%rax),%eax
    0.00 :   6b59bf: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b59c2: jl     6b5998 <ProcArrayAdd+0xde>
    0.00 :   6b59c4: jmp    6b59c7 <ProcArrayAdd+0x10d>
         : 108    break;
    0.00 :   6b59c6: nop
         : 110    }
         :
         : 112    movecount = arrayP->numProcs - index;
    0.00 :   6b59c7: mov    -0x8(%rbp),%rax
    0.00 :   6b59cb: mov    (%rax),%eax
    0.00 :   6b59cd: sub    -0x1c(%rbp),%eax
    0.00 :   6b59d0: mov    %eax,-0x10(%rbp)
         : 117    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b59d3: mov    -0x10(%rbp),%eax
    0.00 :   6b59d6: cltq
    0.00 :   6b59d8: lea    0x0(,%rax,4),%rdx
         : 121    &arrayP->pgprocnos[index],
    0.00 :   6b59e0: mov    -0x1c(%rbp),%eax
    0.00 :   6b59e3: cltq
    0.00 :   6b59e5: add    $0x8,%rax
    0.00 :   6b59e9: lea    0x0(,%rax,4),%rcx
    0.00 :   6b59f1: mov    -0x8(%rbp),%rax
    0.00 :   6b59f5: add    %rcx,%rax
    0.00 :   6b59f8: lea    0x4(%rax),%rcx
         : 129    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b59fc: mov    -0x1c(%rbp),%eax
    0.00 :   6b59ff: add    $0x1,%eax
    0.00 :   6b5a02: cltq
    0.00 :   6b5a04: add    $0x8,%rax
    0.00 :   6b5a08: lea    0x0(,%rax,4),%rsi
    0.00 :   6b5a10: mov    -0x8(%rbp),%rax
    0.00 :   6b5a14: add    %rsi,%rax
    0.00 :   6b5a17: add    $0x4,%rax
    0.00 :   6b5a1b: mov    %rcx,%rsi
    0.00 :   6b5a1e: mov    %rax,%rdi
    0.00 :   6b5a21: call   ed240 <memmove@plt>
         : 141    movecount * sizeof(*arrayP->pgprocnos));
         : 142    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b5a26: mov    -0x10(%rbp),%eax
    0.00 :   6b5a29: cltq
    0.00 :   6b5a2b: lea    0x0(,%rax,4),%rdx
         : 146    &ProcGlobal->xids[index],
    0.00 :   6b5a33: mov    0x686016(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a3a: mov    0x10(%rax),%rax
    0.00 :   6b5a3e: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5a41: movslq %ecx,%rcx
    0.00 :   6b5a44: shl    $0x2,%rcx
    0.00 :   6b5a48: add    %rax,%rcx
         : 153    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b5a4b: mov    0x685ffe(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a52: mov    0x10(%rax),%rax
    0.00 :   6b5a56: mov    -0x1c(%rbp),%esi
    0.00 :   6b5a59: add    $0x1,%esi
    0.00 :   6b5a5c: movslq %esi,%rsi
    0.00 :   6b5a5f: shl    $0x2,%rsi
    0.00 :   6b5a63: add    %rsi,%rax
    0.00 :   6b5a66: mov    %rcx,%rsi
    0.00 :   6b5a69: mov    %rax,%rdi
    0.00 :   6b5a6c: call   ed240 <memmove@plt>
         : 164    movecount * sizeof(*ProcGlobal->xids));
         : 165    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b5a71: mov    -0x10(%rbp),%eax
    0.00 :   6b5a74: cltq
    0.00 :   6b5a76: lea    (%rax,%rax,1),%rdx
         : 169    &ProcGlobal->subxidStates[index],
    0.00 :   6b5a7a: mov    0x685fcf(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a81: mov    0x18(%rax),%rax
    0.00 :   6b5a85: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5a88: movslq %ecx,%rcx
    0.00 :   6b5a8b: add    %rcx,%rcx
    0.00 :   6b5a8e: add    %rax,%rcx
         : 176    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b5a91: mov    0x685fb8(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a98: mov    0x18(%rax),%rax
    0.00 :   6b5a9c: mov    -0x1c(%rbp),%esi
    0.00 :   6b5a9f: add    $0x1,%esi
    0.00 :   6b5aa2: movslq %esi,%rsi
    0.00 :   6b5aa5: add    %rsi,%rsi
    0.00 :   6b5aa8: add    %rsi,%rax
    0.00 :   6b5aab: mov    %rcx,%rsi
    0.00 :   6b5aae: mov    %rax,%rdi
    0.00 :   6b5ab1: call   ed240 <memmove@plt>
         : 187    movecount * sizeof(*ProcGlobal->subxidStates));
         : 188    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ab6: mov    -0x10(%rbp),%eax
    0.00 :   6b5ab9: cltq
         : 191    &ProcGlobal->statusFlags[index],
    0.00 :   6b5abb: mov    0x685f8e(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5ac2: mov    0x20(%rdx),%rcx
         : 194    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ac6: mov    -0x1c(%rbp),%edx
    0.00 :   6b5ac9: movslq %edx,%rdx
         : 197    &ProcGlobal->statusFlags[index],
    0.00 :   6b5acc: lea    (%rcx,%rdx,1),%rsi
         : 199    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ad0: mov    0x685f79(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5ad7: mov    0x20(%rdx),%rcx
    0.00 :   6b5adb: mov    -0x1c(%rbp),%edx
    0.00 :   6b5ade: add    $0x1,%edx
    0.00 :   6b5ae1: movslq %edx,%rdx
    0.00 :   6b5ae4: add    %rdx,%rcx
    0.00 :   6b5ae7: mov    %rax,%rdx
    0.00 :   6b5aea: mov    %rcx,%rdi
    0.00 :   6b5aed: call   ed240 <memmove@plt>
         : 209    movecount * sizeof(*ProcGlobal->statusFlags));
         :
         : 211    arrayP->pgprocnos[index] = GetNumberFromPGProc(proc);
    0.00 :   6b5af2: mov    0x685f57(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5af9: mov    (%rax),%rax
    0.00 :   6b5afc: mov    -0x28(%rbp),%rdx
    0.00 :   6b5b00: sub    %rax,%rdx
    0.00 :   6b5b03: sar    $0x7,%rdx
    0.00 :   6b5b07: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b5b11: imul   %rdx,%rax
    0.00 :   6b5b15: mov    %eax,%ecx
    0.00 :   6b5b17: mov    -0x8(%rbp),%rax
    0.00 :   6b5b1b: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b1e: movslq %edx,%rdx
    0.00 :   6b5b21: add    $0x8,%rdx
    0.00 :   6b5b25: mov    %ecx,0x4(%rax,%rdx,4)
         : 225    pgxactoffs[arrayP->pgprocnos[index]] = index;
    0.00 :   6b5b29: mov    0x683c80(%rip),%rdx        # d397b0 <pgxactoffs>
    0.00 :   6b5b30: mov    -0x8(%rbp),%rax
    0.00 :   6b5b34: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5b37: movslq %ecx,%rcx
    0.00 :   6b5b3a: add    $0x8,%rcx
    0.00 :   6b5b3e: mov    0x4(%rax,%rcx,4),%eax
    0.00 :   6b5b42: cltq
    0.00 :   6b5b44: shl    $0x2,%rax
    0.00 :   6b5b48: add    %rax,%rdx
    0.00 :   6b5b4b: mov    -0x1c(%rbp),%eax
    0.00 :   6b5b4e: mov    %eax,(%rdx)
         : 237    ProcGlobal->xids[index] = proc->xid;
    0.00 :   6b5b50: mov    0x685ef9(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b57: mov    0x10(%rax),%rax
    0.00 :   6b5b5b: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b5e: movslq %edx,%rdx
    0.00 :   6b5b61: shl    $0x2,%rdx
    0.00 :   6b5b65: add    %rax,%rdx
    0.00 :   6b5b68: mov    -0x28(%rbp),%rax
    0.00 :   6b5b6c: mov    0x38(%rax),%eax
    0.00 :   6b5b6f: mov    %eax,(%rdx)
         : 247    ProcGlobal->subxidStates[index] = proc->subxidStatus;
    0.00 :   6b5b71: mov    0x685ed8(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b78: mov    0x18(%rax),%rax
    0.00 :   6b5b7c: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b7f: movslq %edx,%rdx
    0.00 :   6b5b82: add    %rdx,%rdx
    0.00 :   6b5b85: add    %rax,%rdx
    0.00 :   6b5b88: mov    -0x28(%rbp),%rax
    0.00 :   6b5b8c: movzwl 0x40(%rax),%eax
    0.00 :   6b5b90: mov    %ax,(%rdx)
         : 257    ProcGlobal->statusFlags[index] = proc->statusFlags;
    0.00 :   6b5b93: mov    0x685eb6(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b9a: mov    0x20(%rax),%rdx
    0.00 :   6b5b9e: mov    -0x1c(%rbp),%eax
    0.00 :   6b5ba1: cltq
    0.00 :   6b5ba3: add    %rax,%rdx
    0.00 :   6b5ba6: mov    -0x28(%rbp),%rax
    0.00 :   6b5baa: movzbl 0x2c(%rax),%eax
    0.00 :   6b5bae: mov    %al,(%rdx)
         :
         : 267    arrayP->numProcs++;
    0.00 :   6b5bb0: mov    -0x8(%rbp),%rax
    0.00 :   6b5bb4: mov    (%rax),%eax
    0.00 :   6b5bb6: lea    0x1(%rax),%edx
    0.00 :   6b5bb9: mov    -0x8(%rbp),%rax
    0.00 :   6b5bbd: mov    %edx,(%rax)
         :
         : 274    /* adjust pgxactoff for all following PGPROCs */
         : 275    index++;
    0.00 :   6b5bbf: addl   $0x1,-0x1c(%rbp)
         : 277    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5bc3: jmp    6b5bf7 <ProcArrayAdd+0x33d>
         : 279    {
         : 280    int                     procno = arrayP->pgprocnos[index];
    0.00 :   6b5bc5: mov    -0x8(%rbp),%rax
    0.00 :   6b5bc9: mov    -0x1c(%rbp),%edx
    0.00 :   6b5bcc: movslq %edx,%rdx
    0.00 :   6b5bcf: add    $0x8,%rdx
    0.00 :   6b5bd3: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5bd7: mov    %eax,-0xc(%rbp)
         :
         : 288    Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 289    Assert(pgxactoffs[procno] == index - 1);
         :
         : 291    pgxactoffs[procno] = index;
    0.00 :   6b5bda: mov    0x683bcf(%rip),%rax        # d397b0 <pgxactoffs>
    0.00 :   6b5be1: mov    -0xc(%rbp),%edx
    0.00 :   6b5be4: movslq %edx,%rdx
    0.00 :   6b5be7: shl    $0x2,%rdx
    0.00 :   6b5beb: add    %rax,%rdx
    0.00 :   6b5bee: mov    -0x1c(%rbp),%eax
    0.00 :   6b5bf1: mov    %eax,(%rdx)
         : 299    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5bf3: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b5bf7: mov    -0x8(%rbp),%rax
    0.00 :   6b5bfb: mov    (%rax),%eax
    0.00 :   6b5bfd: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5c00: jl     6b5bc5 <ProcArrayAdd+0x30b>
         :
         : 306    /*
         : 307    * Release in reversed acquisition order, to reduce frequency of having to
         : 308    * wait for XidGenLock while holding ProcArrayLock.
         : 309    */
         : 310    LWLockRelease(XidGenLock);
    0.00 :   6b5c02: mov    0x685057(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5c09: add    $0x180,%rax
    0.00 :   6b5c0f: mov    %rax,%rdi
    0.00 :   6b5c12: call   6d50fc <LWLockRelease>
         : 315    LWLockRelease(ProcArrayLock);
    0.00 :   6b5c17: mov    0x685042(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5c1e: add    $0x200,%rax
    0.00 :   6b5c24: mov    %rax,%rdi
    0.00 :   6b5c27: call   6d50fc <LWLockRelease>
         : 320    }
    0.00 :   6b5c2c: nop
    0.00 :   6b5c2d: leave
    0.00 :   6b5c2e: ret


Attachments:

  [image/png] ICT_degradation.png (50.4K, ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/3-ICT_degradation.png)
  download | view image

  [image/png] ICT_degradation_with_patch.png (63.6K, ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/4-ICT_degradation_with_patch.png)
  download | view image

  [text/plain] perf_without_patch-j6.txt (16.2K, ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/5-perf_without_patch-j6.txt)
  download | inline:
# Samples: 1M of event 'minor-faults'
# Event count (approx.): 20314715
#
# Children      Self        Period  Command          Shared Object                          Symbol                                                                  
# ........  ........  ............  ...............  .....................................  ........................................................................
#
    99.79%     0.00%             0  postgres         postgres                               [.] _start
            |
            ---_start
               __libc_start_main@@GLIBC_2.34
               __libc_start_call_main
               main
               PostmasterMain
               |          
                --99.79%--ServerLoop
                          |          
                           --99.61%--BackendStartup
                                     |          
                                      --99.33%--postmaster_child_launch
                                                |          
                                                |--95.12%--BackendInitialize
                                                |          |          
                                                |           --95.08%--PostgresMain
                                                |                     |          
                                                |                     |--53.39%--InitPostgres
                                                |                     |          |          
                                                |                     |          |--35.65%--InitProcessPhase2
                                                |                     |          |          |          
                                                |                     |          |           --35.57%--ProcArrayAdd




 Percent |	Source code & Disassembly of postgres for minor-faults (103275 samples, percent: local period)
--------------------------------------------------------------------------------------------------------------
         :
         :
         :
         : 3      Disassembly of section .text:
         :
         : 5      00000000006b5720 <ProcArrayAdd>:
         : 6      /*
         : 7      * Add the specified PGPROC to the shared array.
         : 8      */
         : 9      void
         : 10     ProcArrayAdd(PGPROC *proc)
         : 11     {
    0.00 :   6b5720: endbr64
    0.00 :   6b5724: push   %rbp
    0.00 :   6b5725: mov    %rsp,%rbp
    0.00 :   6b5728: sub    $0x30,%rsp
    0.00 :   6b572c: mov    %rdi,-0x28(%rbp)
         : 17     int                     pgprocno = GetNumberFromPGProc(proc);
    0.00 :   6b5730: mov    0x686319(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5737: mov    (%rax),%rax
    0.00 :   6b573a: mov    -0x28(%rbp),%rdx
    0.00 :   6b573e: sub    %rax,%rdx
    0.00 :   6b5741: sar    $0x7,%rdx
    0.00 :   6b5745: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b574f: imul   %rdx,%rax
    0.00 :   6b5753: mov    %eax,-0x18(%rbp)
         : 26     ProcArrayStruct *arrayP = procArray;
    0.00 :   6b5756: mov    0x684043(%rip),%rax        # d397a0 <procArray>
    0.00 :   6b575d: mov    %rax,-0x8(%rbp)
         : 29     int                     index;
         : 30     int                     movecount;
         :
         : 32     /* See ProcGlobal comment explaining why both locks are held */
         : 33     LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
    0.00 :   6b5761: mov    0x6854f8(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5768: add    $0x200,%rax
    0.00 :   6b576e: mov    $0x0,%esi
    0.00 :   6b5773: mov    %rax,%rdi
    0.00 :   6b5776: call   6d454c <LWLockAcquire>
         : 39     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    0.00 :   6b577b: mov    0x6854de(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5782: add    $0x180,%rax
    0.00 :   6b5788: mov    $0x0,%esi
    0.00 :   6b578d: mov    %rax,%rdi
    0.00 :   6b5790: call   6d454c <LWLockAcquire>
         :
         : 46     if (arrayP->numProcs >= arrayP->maxProcs)
    0.00 :   6b5795: mov    -0x8(%rbp),%rax
    0.11 :   6b5799: mov    (%rax),%edx
    0.00 :   6b579b: mov    -0x8(%rbp),%rax
    0.00 :   6b579f: mov    0x4(%rax),%eax
    0.00 :   6b57a2: cmp    %eax,%edx
    0.00 :   6b57a4: jl     6b57f5 <ProcArrayAdd+0xd5>
         : 53     /*
         : 54     * Oops, no room.  (This really shouldn't happen, since there is a
         : 55     * fixed supply of PGPROC structs too, and so we should have failed
         : 56     * earlier.)
         : 57     */
         : 58     ereport(FATAL,
    0.00 :   6b57a6: mov    $0x0,%esi
    0.00 :   6b57ab: mov    $0x16,%edi
    0.00 :   6b57b0: call   8f9a0f <errstart_cold>
    0.00 :   6b57b5: test   %al,%al
    0.00 :   6b57b7: je     6b57f5 <ProcArrayAdd+0xd5>
    0.00 :   6b57b9: mov    $0x30c5,%edi
    0.00 :   6b57be: call   8fa2a6 <errcode>
    0.00 :   6b57c3: lea    0x4496ce(%rip),%rax        # afee98 <__func__.0+0x58>
    0.00 :   6b57ca: mov    %rax,%rdi
    0.00 :   6b57cd: mov    $0x0,%eax
    0.00 :   6b57d2: call   8fa559 <errmsg>
    0.00 :   6b57d7: lea    0x449b4a(%rip),%rax        # aff328 <__func__.19>
    0.00 :   6b57de: mov    %rax,%rdx
    0.00 :   6b57e1: mov    $0x1e2,%esi
    0.00 :   6b57e6: lea    0x4496cb(%rip),%rax        # afeeb8 <__func__.0+0x78>
    0.00 :   6b57ed: mov    %rax,%rdi
    0.00 :   6b57f0: call   8f9c10 <errfinish>
         : 76     * PGPROC structure in the cache.
         : 77     *
         : 78     * Since the occurrence of adding/removing a proc is much lower than the
         : 79     * access to the ProcArray itself, the overhead should be marginal
         : 80     */
         : 81     for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b57f5: movl   $0x0,-0x1c(%rbp)
    0.00 :   6b57fc: jmp    6b581f <ProcArrayAdd+0xff>
         : 84     {
         : 85     int                     this_procno = arrayP->pgprocnos[index];
    0.00 :   6b57fe: mov    -0x8(%rbp),%rax
    0.00 :   6b5802: mov    -0x1c(%rbp),%edx
    0.00 :   6b5805: movslq %edx,%rdx
    0.00 :   6b5808: add    $0x8,%rdx
    0.07 :   6b580c: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5810: mov    %eax,-0x14(%rbp)
         :
         : 93     Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 94     Assert(allProcs[this_procno].pgxactoff == index);
         :
         : 96     /* If we have found our right position in the array, break */
         : 97     if (this_procno > pgprocno)
    0.00 :   6b5813: mov    -0x14(%rbp),%eax
    0.00 :   6b5816: cmp    -0x18(%rbp),%eax
    0.00 :   6b5819: jg     6b582c <ProcArrayAdd+0x10c>
         : 101    for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b581b: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b581f: mov    -0x8(%rbp),%rax
    0.00 :   6b5823: mov    (%rax),%eax
    0.00 :   6b5825: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5828: jl     6b57fe <ProcArrayAdd+0xde>
    0.00 :   6b582a: jmp    6b582d <ProcArrayAdd+0x10d>
         : 108    break;
    0.00 :   6b582c: nop
         : 110    }
         :
         : 112    movecount = arrayP->numProcs - index;
    0.00 :   6b582d: mov    -0x8(%rbp),%rax
    0.00 :   6b5831: mov    (%rax),%eax
    0.00 :   6b5833: sub    -0x1c(%rbp),%eax
    0.00 :   6b5836: mov    %eax,-0x10(%rbp)
         : 117    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b5839: mov    -0x10(%rbp),%eax
    0.00 :   6b583c: cltq
    0.00 :   6b583e: lea    0x0(,%rax,4),%rdx
         : 121    &arrayP->pgprocnos[index],
    0.00 :   6b5846: mov    -0x1c(%rbp),%eax
    0.00 :   6b5849: cltq
    0.00 :   6b584b: add    $0x8,%rax
    0.00 :   6b584f: lea    0x0(,%rax,4),%rcx
    0.00 :   6b5857: mov    -0x8(%rbp),%rax
    0.00 :   6b585b: add    %rcx,%rax
    0.00 :   6b585e: lea    0x4(%rax),%rcx
         : 129    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b5862: mov    -0x1c(%rbp),%eax
    0.00 :   6b5865: add    $0x1,%eax
    0.00 :   6b5868: cltq
    0.00 :   6b586a: add    $0x8,%rax
    0.00 :   6b586e: lea    0x0(,%rax,4),%rsi
    0.00 :   6b5876: mov    -0x8(%rbp),%rax
    0.00 :   6b587a: add    %rsi,%rax
    0.00 :   6b587d: add    $0x4,%rax
    0.00 :   6b5881: mov    %rcx,%rsi
    0.00 :   6b5884: mov    %rax,%rdi
    0.00 :   6b5887: call   ed240 <memmove@plt>
         : 141    movecount * sizeof(*arrayP->pgprocnos));
         : 142    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b588c: mov    -0x10(%rbp),%eax
    0.00 :   6b588f: cltq
    0.00 :   6b5891: lea    0x0(,%rax,4),%rdx
         : 146    &ProcGlobal->xids[index],
    0.00 :   6b5899: mov    0x6861b0(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58a0: mov    0x8(%rax),%rax
    0.00 :   6b58a4: mov    -0x1c(%rbp),%ecx
    0.00 :   6b58a7: movslq %ecx,%rcx
    0.00 :   6b58aa: shl    $0x2,%rcx
    0.00 :   6b58ae: add    %rax,%rcx
         : 153    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b58b1: mov    0x686198(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58b8: mov    0x8(%rax),%rax
    0.00 :   6b58bc: mov    -0x1c(%rbp),%esi
    0.00 :   6b58bf: add    $0x1,%esi
    0.00 :   6b58c2: movslq %esi,%rsi
    0.00 :   6b58c5: shl    $0x2,%rsi
    0.00 :   6b58c9: add    %rsi,%rax
    0.00 :   6b58cc: mov    %rcx,%rsi
    0.00 :   6b58cf: mov    %rax,%rdi
    0.00 :   6b58d2: call   ed240 <memmove@plt>
         : 164    movecount * sizeof(*ProcGlobal->xids));
         : 165    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b58d7: mov    -0x10(%rbp),%eax
    0.00 :   6b58da: cltq
    0.00 :   6b58dc: lea    (%rax,%rax,1),%rdx
         : 169    &ProcGlobal->subxidStates[index],
    0.00 :   6b58e0: mov    0x686169(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58e7: mov    0x10(%rax),%rax
    0.00 :   6b58eb: mov    -0x1c(%rbp),%ecx
    0.00 :   6b58ee: movslq %ecx,%rcx
    0.00 :   6b58f1: add    %rcx,%rcx
    0.00 :   6b58f4: add    %rax,%rcx
         : 176    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b58f7: mov    0x686152(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58fe: mov    0x10(%rax),%rax
    0.00 :   6b5902: mov    -0x1c(%rbp),%esi
    0.00 :   6b5905: add    $0x1,%esi
    0.00 :   6b5908: movslq %esi,%rsi
    0.00 :   6b590b: add    %rsi,%rsi
    0.00 :   6b590e: add    %rsi,%rax
    0.00 :   6b5911: mov    %rcx,%rsi
    0.00 :   6b5914: mov    %rax,%rdi
    0.00 :   6b5917: call   ed240 <memmove@plt>
         : 187    movecount * sizeof(*ProcGlobal->subxidStates));
         : 188    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b591c: mov    -0x10(%rbp),%eax
    0.00 :   6b591f: cltq
         : 191    &ProcGlobal->statusFlags[index],
    0.00 :   6b5921: mov    0x686128(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5928: mov    0x18(%rdx),%rcx
         : 194    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b592c: mov    -0x1c(%rbp),%edx
    0.00 :   6b592f: movslq %edx,%rdx
         : 197    &ProcGlobal->statusFlags[index],
    0.00 :   6b5932: lea    (%rcx,%rdx,1),%rsi
         : 199    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5936: mov    0x686113(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b593d: mov    0x18(%rdx),%rcx
    0.00 :   6b5941: mov    -0x1c(%rbp),%edx
    0.00 :   6b5944: add    $0x1,%edx
    0.00 :   6b5947: movslq %edx,%rdx
    0.00 :   6b594a: add    %rdx,%rcx
    0.00 :   6b594d: mov    %rax,%rdx
    0.00 :   6b5950: mov    %rcx,%rdi
    0.00 :   6b5953: call   ed240 <memmove@plt>
         : 209    movecount * sizeof(*ProcGlobal->statusFlags));
         :
         : 211    arrayP->pgprocnos[index] = GetNumberFromPGProc(proc);
    0.00 :   6b5958: mov    0x6860f1(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b595f: mov    (%rax),%rax
    0.00 :   6b5962: mov    -0x28(%rbp),%rdx
    0.00 :   6b5966: sub    %rax,%rdx
    0.00 :   6b5969: sar    $0x7,%rdx
    0.00 :   6b596d: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b5977: imul   %rdx,%rax
    0.00 :   6b597b: mov    %eax,%ecx
    0.00 :   6b597d: mov    -0x8(%rbp),%rax
    0.00 :   6b5981: mov    -0x1c(%rbp),%edx
    0.00 :   6b5984: movslq %edx,%rdx
    0.00 :   6b5987: add    $0x8,%rdx
    0.00 :   6b598b: mov    %ecx,0x4(%rax,%rdx,4)
         : 225    proc->pgxactoff = index;
    0.00 :   6b598f: mov    -0x28(%rbp),%rax
    0.00 :   6b5993: mov    -0x1c(%rbp),%edx
    0.00 :   6b5996: mov    %edx,0x2c(%rax)
         : 229    ProcGlobal->xids[index] = proc->xid;
    0.00 :   6b5999: mov    0x6860b0(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59a0: mov    0x8(%rax),%rax
    0.00 :   6b59a4: mov    -0x1c(%rbp),%edx
    0.00 :   6b59a7: movslq %edx,%rdx
    0.00 :   6b59aa: shl    $0x2,%rdx
    0.00 :   6b59ae: add    %rax,%rdx
    0.00 :   6b59b1: mov    -0x28(%rbp),%rax
    0.00 :   6b59b5: mov    0x3c(%rax),%eax
    0.00 :   6b59b8: mov    %eax,(%rdx)
         : 239    ProcGlobal->subxidStates[index] = proc->subxidStatus;
    0.00 :   6b59ba: mov    0x68608f(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59c1: mov    0x10(%rax),%rax
    0.00 :   6b59c5: mov    -0x1c(%rbp),%edx
    0.00 :   6b59c8: movslq %edx,%rdx
    0.00 :   6b59cb: add    %rdx,%rdx
    0.00 :   6b59ce: add    %rax,%rdx
    0.00 :   6b59d1: mov    -0x28(%rbp),%rax
    0.00 :   6b59d5: movzwl 0x44(%rax),%eax
    0.00 :   6b59d9: mov    %ax,(%rdx)
         : 249    ProcGlobal->statusFlags[index] = proc->statusFlags;
    0.00 :   6b59dc: mov    0x68606d(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b59e3: mov    0x18(%rax),%rdx
    0.00 :   6b59e7: mov    -0x1c(%rbp),%eax
    0.00 :   6b59ea: cltq
    0.00 :   6b59ec: add    %rax,%rdx
    0.00 :   6b59ef: mov    -0x28(%rbp),%rax
    0.00 :   6b59f3: movzbl 0x30(%rax),%eax
    0.00 :   6b59f7: mov    %al,(%rdx)
         :
         : 259    arrayP->numProcs++;
    0.00 :   6b59f9: mov    -0x8(%rbp),%rax
    0.00 :   6b59fd: mov    (%rax),%eax
    0.00 :   6b59ff: lea    0x1(%rax),%edx
    0.00 :   6b5a02: mov    -0x8(%rbp),%rax
    0.00 :   6b5a06: mov    %edx,(%rax)
         :
         : 266    /* adjust pgxactoff for all following PGPROCs */
         : 267    index++;
    0.00 :   6b5a08: addl   $0x1,-0x1c(%rbp)
         : 269    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5a0c: jmp    6b5a4c <ProcArrayAdd+0x32c>
         : 271    {
         : 272    int                     procno = arrayP->pgprocnos[index];
    0.00 :   6b5a0e: mov    -0x8(%rbp),%rax
    0.00 :   6b5a12: mov    -0x1c(%rbp),%edx
    0.00 :   6b5a15: movslq %edx,%rdx
    0.00 :   6b5a18: add    $0x8,%rdx
    0.00 :   6b5a1c: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5a20: mov    %eax,-0xc(%rbp)
         :
         : 280    Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 281    Assert(allProcs[procno].pgxactoff == index - 1);
         :
         : 283    allProcs[procno].pgxactoff = index;
    0.00 :   6b5a23: mov    0x683d7e(%rip),%rcx        # d397a8 <allProcs>
    0.00 :   6b5a2a: mov    -0xc(%rbp),%eax
    0.00 :   6b5a2d: movslq %eax,%rdx
    0.00 :   6b5a30: mov    %rdx,%rax
    0.00 :   6b5a33: shl    $0x3,%rax
    0.00 :   6b5a37: sub    %rdx,%rax
    0.00 :   6b5a3a: shl    $0x7,%rax
    0.00 :   6b5a3e: lea    (%rcx,%rax,1),%rdx
    0.00 :   6b5a42: mov    -0x1c(%rbp),%eax
   99.82 :   6b5a45: mov    %eax,0x2c(%rdx)
         : 294    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5a48: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b5a4c: mov    -0x8(%rbp),%rax
    0.00 :   6b5a50: mov    (%rax),%eax
    0.00 :   6b5a52: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5a55: jl     6b5a0e <ProcArrayAdd+0x2ee>
         :
         : 301    /*
         : 302    * Release in reversed acquisition order, to reduce frequency of having to
         : 303    * wait for XidGenLock while holding ProcArrayLock.
         : 304    */
         : 305    LWLockRelease(XidGenLock);
    0.00 :   6b5a57: mov    0x685202(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5a5e: add    $0x180,%rax
    0.00 :   6b5a64: mov    %rax,%rdi
    0.00 :   6b5a67: call   6d4da1 <LWLockRelease>
         : 310    LWLockRelease(ProcArrayLock);
    0.00 :   6b5a6c: mov    0x6851ed(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5a73: add    $0x200,%rax
    0.00 :   6b5a79: mov    %rax,%rdi
    0.00 :   6b5a7c: call   6d4da1 <LWLockRelease>
         : 315    }
    0.00 :   6b5a81: nop
    0.00 :   6b5a82: leave
    0.00 :   6b5a83: ret

  [text/plain] perf_with_patch-j6.txt (14.7K, ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/6-perf_with_patch-j6.txt)
  download | inline:

     0.13%     0.10%         11727  postgres         postgres                               [.] ProcArrayAdd


 Percent |	Source code & Disassembly of postgres for minor-faults (445 samples, percent: local period)
-----------------------------------------------------------------------------------------------------------
         :
         :
         :
         : 3      Disassembly of section .text:
         :
         : 5      00000000006b58ba <ProcArrayAdd>:
         : 6      /*
         : 7      * Add the specified PGPROC to the shared array.
         : 8      */
         : 9      void
         : 10     ProcArrayAdd(PGPROC *proc)
         : 11     {
    0.00 :   6b58ba: endbr64
    0.00 :   6b58be: push   %rbp
    0.00 :   6b58bf: mov    %rsp,%rbp
    0.00 :   6b58c2: sub    $0x30,%rsp
    0.00 :   6b58c6: mov    %rdi,-0x28(%rbp)
         : 17     int                     pgprocno = GetNumberFromPGProc(proc);
    0.00 :   6b58ca: mov    0x68617f(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b58d1: mov    (%rax),%rax
    0.00 :   6b58d4: mov    -0x28(%rbp),%rdx
    0.00 :   6b58d8: sub    %rax,%rdx
    0.00 :   6b58db: sar    $0x7,%rdx
    0.00 :   6b58df: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b58e9: imul   %rdx,%rax
    0.00 :   6b58ed: mov    %eax,-0x18(%rbp)
         : 26     ProcArrayStruct *arrayP = procArray;
    0.00 :   6b58f0: mov    0x683ea9(%rip),%rax        # d397a0 <procArray>
    0.00 :   6b58f7: mov    %rax,-0x8(%rbp)
         : 29     int                     index;
         : 30     int                     movecount;
         :
         : 32     /* See ProcGlobal comment explaining why both locks are held */
         : 33     LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
    0.00 :   6b58fb: mov    0x68535e(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5902: add    $0x200,%rax
    0.00 :   6b5908: mov    $0x0,%esi
    0.00 :   6b590d: mov    %rax,%rdi
    0.00 :   6b5910: call   6d48a7 <LWLockAcquire>
         : 39     LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    0.00 :   6b5915: mov    0x685344(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b591c: add    $0x180,%rax
    0.00 :   6b5922: mov    $0x0,%esi
    0.00 :   6b5927: mov    %rax,%rdi
    0.00 :   6b592a: call   6d48a7 <LWLockAcquire>
         :
         : 46     if (arrayP->numProcs >= arrayP->maxProcs)
    0.00 :   6b592f: mov    -0x8(%rbp),%rax
   65.30 :   6b5933: mov    (%rax),%edx
    0.00 :   6b5935: mov    -0x8(%rbp),%rax
    0.00 :   6b5939: mov    0x4(%rax),%eax
    0.00 :   6b593c: cmp    %eax,%edx
    0.00 :   6b593e: jl     6b598f <ProcArrayAdd+0xd5>
         : 53     /*
         : 54     * Oops, no room.  (This really shouldn't happen, since there is a
         : 55     * fixed supply of PGPROC structs too, and so we should have failed
         : 56     * earlier.)
         : 57     */
         : 58     ereport(FATAL,
    0.00 :   6b5940: mov    $0x0,%esi
    0.00 :   6b5945: mov    $0x16,%edi
    0.00 :   6b594a: call   8f9e02 <errstart_cold>
    0.00 :   6b594f: test   %al,%al
    0.00 :   6b5951: je     6b598f <ProcArrayAdd+0xd5>
    0.00 :   6b5953: mov    $0x30c5,%edi
    0.00 :   6b5958: call   8fa699 <errcode>
    0.00 :   6b595d: lea    0x449534(%rip),%rax        # afee98 <__func__.0+0x58>
    0.00 :   6b5964: mov    %rax,%rdi
    0.00 :   6b5967: mov    $0x0,%eax
    0.00 :   6b596c: call   8fa94c <errmsg>
    0.00 :   6b5971: lea    0x4499b0(%rip),%rax        # aff328 <__func__.19>
    0.00 :   6b5978: mov    %rax,%rdx
    0.00 :   6b597b: mov    $0x1e4,%esi
    0.00 :   6b5980: lea    0x449531(%rip),%rax        # afeeb8 <__func__.0+0x78>
    0.00 :   6b5987: mov    %rax,%rdi
    0.00 :   6b598a: call   8fa003 <errfinish>
         : 76     * PGPROC structure in the cache.
         : 77     *
         : 78     * Since the occurrence of adding/removing a proc is much lower than the
         : 79     * access to the ProcArray itself, the overhead should be marginal
         : 80     */
         : 81     for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b598f: movl   $0x0,-0x1c(%rbp)
    0.00 :   6b5996: jmp    6b59b9 <ProcArrayAdd+0xff>
         : 84     {
         : 85     int                     this_procno = arrayP->pgprocnos[index];
    0.00 :   6b5998: mov    -0x8(%rbp),%rax
    0.00 :   6b599c: mov    -0x1c(%rbp),%edx
    0.00 :   6b599f: movslq %edx,%rdx
    0.00 :   6b59a2: add    $0x8,%rdx
   34.70 :   6b59a6: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b59aa: mov    %eax,-0x14(%rbp)
         :
         : 93     Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 94     Assert(pgxactoffs[this_procno] == index);
         :
         : 96     /* If we have found our right position in the array, break */
         : 97     if (this_procno > pgprocno)
    0.00 :   6b59ad: mov    -0x14(%rbp),%eax
    0.00 :   6b59b0: cmp    -0x18(%rbp),%eax
    0.00 :   6b59b3: jg     6b59c6 <ProcArrayAdd+0x10c>
         : 101    for (index = 0; index < arrayP->numProcs; index++)
    0.00 :   6b59b5: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b59b9: mov    -0x8(%rbp),%rax
    0.00 :   6b59bd: mov    (%rax),%eax
    0.00 :   6b59bf: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b59c2: jl     6b5998 <ProcArrayAdd+0xde>
    0.00 :   6b59c4: jmp    6b59c7 <ProcArrayAdd+0x10d>
         : 108    break;
    0.00 :   6b59c6: nop
         : 110    }
         :
         : 112    movecount = arrayP->numProcs - index;
    0.00 :   6b59c7: mov    -0x8(%rbp),%rax
    0.00 :   6b59cb: mov    (%rax),%eax
    0.00 :   6b59cd: sub    -0x1c(%rbp),%eax
    0.00 :   6b59d0: mov    %eax,-0x10(%rbp)
         : 117    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b59d3: mov    -0x10(%rbp),%eax
    0.00 :   6b59d6: cltq
    0.00 :   6b59d8: lea    0x0(,%rax,4),%rdx
         : 121    &arrayP->pgprocnos[index],
    0.00 :   6b59e0: mov    -0x1c(%rbp),%eax
    0.00 :   6b59e3: cltq
    0.00 :   6b59e5: add    $0x8,%rax
    0.00 :   6b59e9: lea    0x0(,%rax,4),%rcx
    0.00 :   6b59f1: mov    -0x8(%rbp),%rax
    0.00 :   6b59f5: add    %rcx,%rax
    0.00 :   6b59f8: lea    0x4(%rax),%rcx
         : 129    memmove(&arrayP->pgprocnos[index + 1],
    0.00 :   6b59fc: mov    -0x1c(%rbp),%eax
    0.00 :   6b59ff: add    $0x1,%eax
    0.00 :   6b5a02: cltq
    0.00 :   6b5a04: add    $0x8,%rax
    0.00 :   6b5a08: lea    0x0(,%rax,4),%rsi
    0.00 :   6b5a10: mov    -0x8(%rbp),%rax
    0.00 :   6b5a14: add    %rsi,%rax
    0.00 :   6b5a17: add    $0x4,%rax
    0.00 :   6b5a1b: mov    %rcx,%rsi
    0.00 :   6b5a1e: mov    %rax,%rdi
    0.00 :   6b5a21: call   ed240 <memmove@plt>
         : 141    movecount * sizeof(*arrayP->pgprocnos));
         : 142    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b5a26: mov    -0x10(%rbp),%eax
    0.00 :   6b5a29: cltq
    0.00 :   6b5a2b: lea    0x0(,%rax,4),%rdx
         : 146    &ProcGlobal->xids[index],
    0.00 :   6b5a33: mov    0x686016(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a3a: mov    0x10(%rax),%rax
    0.00 :   6b5a3e: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5a41: movslq %ecx,%rcx
    0.00 :   6b5a44: shl    $0x2,%rcx
    0.00 :   6b5a48: add    %rax,%rcx
         : 153    memmove(&ProcGlobal->xids[index + 1],
    0.00 :   6b5a4b: mov    0x685ffe(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a52: mov    0x10(%rax),%rax
    0.00 :   6b5a56: mov    -0x1c(%rbp),%esi
    0.00 :   6b5a59: add    $0x1,%esi
    0.00 :   6b5a5c: movslq %esi,%rsi
    0.00 :   6b5a5f: shl    $0x2,%rsi
    0.00 :   6b5a63: add    %rsi,%rax
    0.00 :   6b5a66: mov    %rcx,%rsi
    0.00 :   6b5a69: mov    %rax,%rdi
    0.00 :   6b5a6c: call   ed240 <memmove@plt>
         : 164    movecount * sizeof(*ProcGlobal->xids));
         : 165    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b5a71: mov    -0x10(%rbp),%eax
    0.00 :   6b5a74: cltq
    0.00 :   6b5a76: lea    (%rax,%rax,1),%rdx
         : 169    &ProcGlobal->subxidStates[index],
    0.00 :   6b5a7a: mov    0x685fcf(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a81: mov    0x18(%rax),%rax
    0.00 :   6b5a85: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5a88: movslq %ecx,%rcx
    0.00 :   6b5a8b: add    %rcx,%rcx
    0.00 :   6b5a8e: add    %rax,%rcx
         : 176    memmove(&ProcGlobal->subxidStates[index + 1],
    0.00 :   6b5a91: mov    0x685fb8(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5a98: mov    0x18(%rax),%rax
    0.00 :   6b5a9c: mov    -0x1c(%rbp),%esi
    0.00 :   6b5a9f: add    $0x1,%esi
    0.00 :   6b5aa2: movslq %esi,%rsi
    0.00 :   6b5aa5: add    %rsi,%rsi
    0.00 :   6b5aa8: add    %rsi,%rax
    0.00 :   6b5aab: mov    %rcx,%rsi
    0.00 :   6b5aae: mov    %rax,%rdi
    0.00 :   6b5ab1: call   ed240 <memmove@plt>
         : 187    movecount * sizeof(*ProcGlobal->subxidStates));
         : 188    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ab6: mov    -0x10(%rbp),%eax
    0.00 :   6b5ab9: cltq
         : 191    &ProcGlobal->statusFlags[index],
    0.00 :   6b5abb: mov    0x685f8e(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5ac2: mov    0x20(%rdx),%rcx
         : 194    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ac6: mov    -0x1c(%rbp),%edx
    0.00 :   6b5ac9: movslq %edx,%rdx
         : 197    &ProcGlobal->statusFlags[index],
    0.00 :   6b5acc: lea    (%rcx,%rdx,1),%rsi
         : 199    memmove(&ProcGlobal->statusFlags[index + 1],
    0.00 :   6b5ad0: mov    0x685f79(%rip),%rdx        # d3ba50 <ProcGlobal>
    0.00 :   6b5ad7: mov    0x20(%rdx),%rcx
    0.00 :   6b5adb: mov    -0x1c(%rbp),%edx
    0.00 :   6b5ade: add    $0x1,%edx
    0.00 :   6b5ae1: movslq %edx,%rdx
    0.00 :   6b5ae4: add    %rdx,%rcx
    0.00 :   6b5ae7: mov    %rax,%rdx
    0.00 :   6b5aea: mov    %rcx,%rdi
    0.00 :   6b5aed: call   ed240 <memmove@plt>
         : 209    movecount * sizeof(*ProcGlobal->statusFlags));
         :
         : 211    arrayP->pgprocnos[index] = GetNumberFromPGProc(proc);
    0.00 :   6b5af2: mov    0x685f57(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5af9: mov    (%rax),%rax
    0.00 :   6b5afc: mov    -0x28(%rbp),%rdx
    0.00 :   6b5b00: sub    %rax,%rdx
    0.00 :   6b5b03: sar    $0x7,%rdx
    0.00 :   6b5b07: movabs $0x6db6db6db6db6db7,%rax
    0.00 :   6b5b11: imul   %rdx,%rax
    0.00 :   6b5b15: mov    %eax,%ecx
    0.00 :   6b5b17: mov    -0x8(%rbp),%rax
    0.00 :   6b5b1b: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b1e: movslq %edx,%rdx
    0.00 :   6b5b21: add    $0x8,%rdx
    0.00 :   6b5b25: mov    %ecx,0x4(%rax,%rdx,4)
         : 225    pgxactoffs[arrayP->pgprocnos[index]] = index;
    0.00 :   6b5b29: mov    0x683c80(%rip),%rdx        # d397b0 <pgxactoffs>
    0.00 :   6b5b30: mov    -0x8(%rbp),%rax
    0.00 :   6b5b34: mov    -0x1c(%rbp),%ecx
    0.00 :   6b5b37: movslq %ecx,%rcx
    0.00 :   6b5b3a: add    $0x8,%rcx
    0.00 :   6b5b3e: mov    0x4(%rax,%rcx,4),%eax
    0.00 :   6b5b42: cltq
    0.00 :   6b5b44: shl    $0x2,%rax
    0.00 :   6b5b48: add    %rax,%rdx
    0.00 :   6b5b4b: mov    -0x1c(%rbp),%eax
    0.00 :   6b5b4e: mov    %eax,(%rdx)
         : 237    ProcGlobal->xids[index] = proc->xid;
    0.00 :   6b5b50: mov    0x685ef9(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b57: mov    0x10(%rax),%rax
    0.00 :   6b5b5b: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b5e: movslq %edx,%rdx
    0.00 :   6b5b61: shl    $0x2,%rdx
    0.00 :   6b5b65: add    %rax,%rdx
    0.00 :   6b5b68: mov    -0x28(%rbp),%rax
    0.00 :   6b5b6c: mov    0x38(%rax),%eax
    0.00 :   6b5b6f: mov    %eax,(%rdx)
         : 247    ProcGlobal->subxidStates[index] = proc->subxidStatus;
    0.00 :   6b5b71: mov    0x685ed8(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b78: mov    0x18(%rax),%rax
    0.00 :   6b5b7c: mov    -0x1c(%rbp),%edx
    0.00 :   6b5b7f: movslq %edx,%rdx
    0.00 :   6b5b82: add    %rdx,%rdx
    0.00 :   6b5b85: add    %rax,%rdx
    0.00 :   6b5b88: mov    -0x28(%rbp),%rax
    0.00 :   6b5b8c: movzwl 0x40(%rax),%eax
    0.00 :   6b5b90: mov    %ax,(%rdx)
         : 257    ProcGlobal->statusFlags[index] = proc->statusFlags;
    0.00 :   6b5b93: mov    0x685eb6(%rip),%rax        # d3ba50 <ProcGlobal>
    0.00 :   6b5b9a: mov    0x20(%rax),%rdx
    0.00 :   6b5b9e: mov    -0x1c(%rbp),%eax
    0.00 :   6b5ba1: cltq
    0.00 :   6b5ba3: add    %rax,%rdx
    0.00 :   6b5ba6: mov    -0x28(%rbp),%rax
    0.00 :   6b5baa: movzbl 0x2c(%rax),%eax
    0.00 :   6b5bae: mov    %al,(%rdx)
         :
         : 267    arrayP->numProcs++;
    0.00 :   6b5bb0: mov    -0x8(%rbp),%rax
    0.00 :   6b5bb4: mov    (%rax),%eax
    0.00 :   6b5bb6: lea    0x1(%rax),%edx
    0.00 :   6b5bb9: mov    -0x8(%rbp),%rax
    0.00 :   6b5bbd: mov    %edx,(%rax)
         :
         : 274    /* adjust pgxactoff for all following PGPROCs */
         : 275    index++;
    0.00 :   6b5bbf: addl   $0x1,-0x1c(%rbp)
         : 277    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5bc3: jmp    6b5bf7 <ProcArrayAdd+0x33d>
         : 279    {
         : 280    int                     procno = arrayP->pgprocnos[index];
    0.00 :   6b5bc5: mov    -0x8(%rbp),%rax
    0.00 :   6b5bc9: mov    -0x1c(%rbp),%edx
    0.00 :   6b5bcc: movslq %edx,%rdx
    0.00 :   6b5bcf: add    $0x8,%rdx
    0.00 :   6b5bd3: mov    0x4(%rax,%rdx,4),%eax
    0.00 :   6b5bd7: mov    %eax,-0xc(%rbp)
         :
         : 288    Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
         : 289    Assert(pgxactoffs[procno] == index - 1);
         :
         : 291    pgxactoffs[procno] = index;
    0.00 :   6b5bda: mov    0x683bcf(%rip),%rax        # d397b0 <pgxactoffs>
    0.00 :   6b5be1: mov    -0xc(%rbp),%edx
    0.00 :   6b5be4: movslq %edx,%rdx
    0.00 :   6b5be7: shl    $0x2,%rdx
    0.00 :   6b5beb: add    %rax,%rdx
    0.00 :   6b5bee: mov    -0x1c(%rbp),%eax
    0.00 :   6b5bf1: mov    %eax,(%rdx)
         : 299    for (; index < arrayP->numProcs; index++)
    0.00 :   6b5bf3: addl   $0x1,-0x1c(%rbp)
    0.00 :   6b5bf7: mov    -0x8(%rbp),%rax
    0.00 :   6b5bfb: mov    (%rax),%eax
    0.00 :   6b5bfd: cmp    %eax,-0x1c(%rbp)
    0.00 :   6b5c00: jl     6b5bc5 <ProcArrayAdd+0x30b>
         :
         : 306    /*
         : 307    * Release in reversed acquisition order, to reduce frequency of having to
         : 308    * wait for XidGenLock while holding ProcArrayLock.
         : 309    */
         : 310    LWLockRelease(XidGenLock);
    0.00 :   6b5c02: mov    0x685057(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5c09: add    $0x180,%rax
    0.00 :   6b5c0f: mov    %rax,%rdi
    0.00 :   6b5c12: call   6d50fc <LWLockRelease>
         : 315    LWLockRelease(ProcArrayLock);
    0.00 :   6b5c17: mov    0x685042(%rip),%rax        # d3ac60 <MainLWLockArray>
    0.00 :   6b5c1e: add    $0x200,%rax
    0.00 :   6b5c24: mov    %rax,%rdi
    0.00 :   6b5c27: call   6d50fc <LWLockRelease>
         : 320    }
    0.00 :   6b5c2c: nop
    0.00 :   6b5c2d: leave
    0.00 :   6b5c2e: ret

  [text/x-patch] 0001-This-patch-reduce-connection-init-close-time.patch (14.0K, ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/7-0001-This-patch-reduce-connection-init-close-time.patch)
  download | inline diff:
From 437b48759126a4d8289fd10eb3a885392cf96a47 Mon Sep 17 00:00:00 2001
From: Maksim Melnikov <m.melnikov@postgrespro.ru>
Date: Tue, 18 Nov 2025 17:20:09 +0300
Subject: [PATCH] This patch reduce connection init/close time.

ProcArrayRemove/ProcArrayAdd are expensive in terms of accessing pgxactoff
field in PGPROC, because its are placed on different pages and it the
reason of page_faults occurence. Now one of the use case with pgxactoff
is iteration with gaps over PGPROCs and read/write pgxactoff, PGPROC
allocate ~1KB and it quite enough to have page_faults in case of such
accessing.

So we placed all pgxactoff in the separate array pgxactoffs to have adjacent
pages for them all. Indexes in allProcs aligned with pgxactoffs array, so
the Nth element in pgxactoffs refer to Nth PGPROC.

Exentually it helps to avoid extra page_faults and reduce connection
init/close time.

Tags: lwlock_scale
---
 src/backend/access/transam/varsup.c       | 10 +++---
 src/backend/commands/indexcmds.c          |  2 +-
 src/backend/commands/vacuum.c             |  2 +-
 src/backend/replication/logical/logical.c |  2 +-
 src/backend/replication/slot.c            |  2 +-
 src/backend/replication/walsender.c       |  2 +-
 src/backend/storage/ipc/procarray.c       | 38 ++++++++++++-----------
 src/backend/storage/lmgr/proc.c           |  8 +++--
 src/include/storage/proc.h                |  6 ++--
 9 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index dc5e32d86f3..6c941de5c99 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -85,7 +85,7 @@ GetNewTransactionId(bool isSubXact)
 	{
 		Assert(!isSubXact);
 		MyProc->xid = BootstrapTransactionId;
-		ProcGlobal->xids[MyProc->pgxactoff] = BootstrapTransactionId;
+		ProcGlobal->xids[GetMyXactOffPGProc()] = BootstrapTransactionId;
 		return FullTransactionIdFromEpochAndXid(0, BootstrapTransactionId);
 	}
 
@@ -244,18 +244,18 @@ GetNewTransactionId(bool isSubXact)
 	 */
 	if (!isSubXact)
 	{
-		Assert(ProcGlobal->subxidStates[MyProc->pgxactoff].count == 0);
-		Assert(!ProcGlobal->subxidStates[MyProc->pgxactoff].overflowed);
+		Assert(ProcGlobal->subxidStates[GetMyXactOffPGProc()].count == 0);
+		Assert(!ProcGlobal->subxidStates[GetMyXactOffPGProc()].overflowed);
 		Assert(MyProc->subxidStatus.count == 0);
 		Assert(!MyProc->subxidStatus.overflowed);
 
 		/* LWLockRelease acts as barrier */
 		MyProc->xid = xid;
-		ProcGlobal->xids[MyProc->pgxactoff] = xid;
+		ProcGlobal->xids[GetMyXactOffPGProc()] = xid;
 	}
 	else
 	{
-		XidCacheStatus *substat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
+		XidCacheStatus *substat = &ProcGlobal->subxidStates[GetMyXactOffPGProc()];
 		int			nxids = MyProc->subxidStatus.count;
 
 		Assert(substat->count == MyProc->subxidStatus.count);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 9ab74c8df0a..03721601070 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -4654,6 +4654,6 @@ set_indexsafe_procflags(void)
 
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 	MyProc->statusFlags |= PROC_IN_SAFE_IC;
-	ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+	ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 	LWLockRelease(ProcArrayLock);
 }
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 99d0db82ed7..10b712c8e78 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -2054,7 +2054,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 		MyProc->statusFlags |= PROC_IN_VACUUM;
 		if (params.is_wraparound)
 			MyProc->statusFlags |= PROC_VACUUM_FOR_WRAPAROUND;
-		ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+		ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 		LWLockRelease(ProcArrayLock);
 	}
 
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index a33a685dcc6..91d6d83a5d8 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -188,7 +188,7 @@ StartupDecodingContext(List *output_plugin_options,
 	{
 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 		MyProc->statusFlags |= PROC_IN_LOGICAL_DECODING;
-		ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+		ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 		LWLockRelease(ProcArrayLock);
 	}
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 83fcde74718..180cc800825 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -839,7 +839,7 @@ ReplicationSlotRelease(void)
 	/* might not have been set when we've been a plain slot */
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 	MyProc->statusFlags &= ~PROC_IN_LOGICAL_DECODING;
-	ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+	ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 	LWLockRelease(ProcArrayLock);
 
 	if (am_walsender)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 3d4ab929f91..38c935e09a0 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -351,7 +351,7 @@ InitWalSender(void)
 		Assert(MyProc->xmin == InvalidTransactionId);
 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 		MyProc->statusFlags |= PROC_AFFECTS_ALL_HORIZONS;
-		ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+		ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 		LWLockRelease(ProcArrayLock);
 	}
 
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9299bcebbda..35578e7222c 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -283,6 +283,7 @@ typedef enum KAXCompressReason
 } KAXCompressReason;
 
 static PGPROC *allProcs;
+static int *pgxactoffs;
 
 /*
  * Cache to reduce overhead of repeated calls to TransactionIdIsInProgress()
@@ -449,6 +450,7 @@ ProcArrayShmemInit(void *arg)
 	TransamVariables->xactCompletionCount = 1;
 
 	allProcs = ProcGlobal->allProcs;
+	pgxactoffs = ProcGlobal->pgxactoffs;
 }
 
 static void
@@ -498,7 +500,7 @@ ProcArrayAdd(PGPROC *proc)
 		int			this_procno = arrayP->pgprocnos[index];
 
 		Assert(this_procno >= 0 && this_procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[this_procno].pgxactoff == index);
+		Assert(pgxactoffs[this_procno] == index);
 
 		/* If we have found our right position in the array, break */
 		if (this_procno > pgprocno)
@@ -520,7 +522,7 @@ ProcArrayAdd(PGPROC *proc)
 			movecount * sizeof(*ProcGlobal->statusFlags));
 
 	arrayP->pgprocnos[index] = GetNumberFromPGProc(proc);
-	proc->pgxactoff = index;
+	pgxactoffs[arrayP->pgprocnos[index]] = index;
 	ProcGlobal->xids[index] = proc->xid;
 	ProcGlobal->subxidStates[index] = proc->subxidStatus;
 	ProcGlobal->statusFlags[index] = proc->statusFlags;
@@ -534,9 +536,9 @@ ProcArrayAdd(PGPROC *proc)
 		int			procno = arrayP->pgprocnos[index];
 
 		Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[procno].pgxactoff == index - 1);
+		Assert(pgxactoffs[procno] == index - 1);
 
-		allProcs[procno].pgxactoff = index;
+		pgxactoffs[procno] = index;
 	}
 
 	/*
@@ -574,10 +576,10 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 	LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
 
-	myoff = proc->pgxactoff;
+	myoff = GetXactOffPGProc(proc);
 
 	Assert(myoff >= 0 && myoff < arrayP->numProcs);
-	Assert(ProcGlobal->allProcs[arrayP->pgprocnos[myoff]].pgxactoff == myoff);
+	Assert(ProcGlobal->pgxactoffs[arrayP->pgprocnos[myoff]] == myoff);
 
 	if (TransactionIdIsValid(latestXid))
 	{
@@ -632,9 +634,9 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
 		int			procno = arrayP->pgprocnos[index];
 
 		Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
-		Assert(allProcs[procno].pgxactoff - 1 == index);
+		Assert(pgxactoffs[procno] - 1 == index);
 
-		allProcs[procno].pgxactoff = index;
+		pgxactoffs[procno] = index;
 	}
 
 	/*
@@ -708,9 +710,9 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
 		{
 			Assert(!LWLockHeldByMe(ProcArrayLock));
 			LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-			Assert(proc->statusFlags == ProcGlobal->statusFlags[proc->pgxactoff]);
+			Assert(proc->statusFlags == ProcGlobal->statusFlags[GetXactOffPGProc(proc)]);
 			proc->statusFlags &= ~PROC_VACUUM_STATE_MASK;
-			ProcGlobal->statusFlags[proc->pgxactoff] = proc->statusFlags;
+			ProcGlobal->statusFlags[GetXactOffPGProc(proc)] = proc->statusFlags;
 			LWLockRelease(ProcArrayLock);
 		}
 	}
@@ -724,7 +726,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
 static inline void
 ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
 {
-	int			pgxactoff = proc->pgxactoff;
+	int			pgxactoff = GetXactOffPGProc(proc);
 
 	/*
 	 * Note: we need exclusive lock here because we're going to change other
@@ -747,7 +749,7 @@ ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
 	if (proc->statusFlags & PROC_VACUUM_STATE_MASK)
 	{
 		proc->statusFlags &= ~PROC_VACUUM_STATE_MASK;
-		ProcGlobal->statusFlags[proc->pgxactoff] = proc->statusFlags;
+		ProcGlobal->statusFlags[GetXactOffPGProc(proc)] = proc->statusFlags;
 	}
 
 	/* Clear the subtransaction-XID cache too while holding the lock */
@@ -916,7 +918,7 @@ ProcArrayClearTransaction(PGPROC *proc)
 	 */
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
-	pgxactoff = proc->pgxactoff;
+	pgxactoff = GetXactOffPGProc(proc);
 
 	ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
 	proc->xid = InvalidTransactionId;
@@ -1475,7 +1477,7 @@ TransactionIdIsInProgress(TransactionId xid)
 	}
 
 	/* No shortcuts, gotta grovel through the array */
-	mypgxactoff = MyProc->pgxactoff;
+	mypgxactoff = GetMyXactOffPGProc();
 	numProcs = arrayP->numProcs;
 	for (int pgxactoff = 0; pgxactoff < numProcs; pgxactoff++)
 	{
@@ -2176,7 +2178,7 @@ GetSnapshotData(Snapshot snapshot)
 	}
 
 	latest_completed = TransamVariables->latestCompletedXid;
-	mypgxactoff = MyProc->pgxactoff;
+	mypgxactoff = GetMyXactOffPGProc();
 	myxid = other_xids[mypgxactoff];
 	Assert(myxid == MyProc->xid);
 
@@ -2215,7 +2217,7 @@ GetSnapshotData(Snapshot snapshot)
 			TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
 			uint8		statusFlags;
 
-			Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
+			Assert(pgxactoffs[arrayP->pgprocnos[pgxactoff]] == pgxactoff);
 
 			/*
 			 * If the transaction has no XID assigned, we can skip it; it
@@ -2583,7 +2585,7 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
 		MyProc->xmin = TransactionXmin = xmin;
 		MyProc->statusFlags = (MyProc->statusFlags & ~PROC_XMIN_FLAGS) |
 			(proc->statusFlags & PROC_XMIN_FLAGS);
-		ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
+		ProcGlobal->statusFlags[GetMyXactOffPGProc()] = MyProc->statusFlags;
 
 		result = true;
 	}
@@ -4032,7 +4034,7 @@ XidCacheRemoveRunningXids(TransactionId xid,
 	 */
 	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
-	mysubxidstat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
+	mysubxidstat = &ProcGlobal->subxidStates[GetMyXactOffPGProc()];
 
 	/*
 	 * Under normal circumstances xid and xids[] will be in increasing order,
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1ac25068d62..5ae4922128e 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -165,6 +165,7 @@ ProcGlobalShmemRequest(void *arg)
 	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
 	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->subxidStates)));
 	size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->statusFlags)));
+	size = add_size(size, mul_size(TotalProcs, sizeof(int)));
 	ProcGlobalAllProcsShmemSize = size;
 	ShmemRequestStruct(.name = "PGPROC structures",
 					   .size = ProcGlobalAllProcsShmemSize,
@@ -273,7 +274,10 @@ ProcGlobalShmemInit(void *arg)
 	ProcGlobal->statusFlags = (uint8 *) ptr;
 	ptr = ptr + (TotalProcs * sizeof(*ProcGlobal->statusFlags));
 
-	/* make sure we didn't overflow */
+	ProcGlobal->pgxactoffs = (int *) ptr;
+	ptr = (char *) ptr + TotalProcs * sizeof(int);
+
+	/* make sure wer didn't overflow */
 	Assert((ptr > (char *) procs) && (ptr <= (char *) procs + requestSize));
 
 	/*
@@ -1498,7 +1502,7 @@ ProcSleep(LOCALLOCK *locallock)
 			 * the lock held, which is much more undesirable.
 			 */
 			LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-			statusFlags = ProcGlobal->statusFlags[autovac->pgxactoff];
+			statusFlags = ProcGlobal->statusFlags[GetXactOffPGProc(autovac)];
 			lockmethod_copy = lock->tag.locktag_lockmethodid;
 			locktag_copy = lock->tag;
 			LWLockRelease(ProcArrayLock);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 3e1d1fad5f9..fee9deb8f3a 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -210,9 +210,6 @@ typedef struct PGPROC
 	Oid			tempNamespaceId;	/* OID of temp schema this backend is
 									 * using */
 
-	int			pgxactoff;		/* offset into various ProcGlobal->arrays with
-								 * data mirrored from this PGPROC */
-
 	uint8		statusFlags;	/* this backend's status flags, see PROC_*
 								 * above. mirrored in
 								 * ProcGlobal->statusFlags[pgxactoff] */
@@ -445,6 +442,7 @@ typedef struct PROC_HDR
 {
 	/* Array of PGPROC structures (not including dummies for prepared txns) */
 	PGPROC	   *allProcs;
+	int		   *pgxactoffs;
 
 	/* Array mirroring PGPROC.xid for each PGPROC currently in the procarray */
 	TransactionId *xids;
@@ -509,6 +507,8 @@ extern PGDLLIMPORT PGPROC *PreparedXactProcs;
  */
 #define GetPGProcByNumber(n) (&ProcGlobal->allProcs[(n)])
 #define GetNumberFromPGProc(proc) ((proc) - &ProcGlobal->allProcs[0])
+#define GetXactOffPGProc(proc) (ProcGlobal->pgxactoffs[(proc) - &ProcGlobal->allProcs[0]])
+#define GetMyXactOffPGProc() (GetXactOffPGProc(MyProc))
 
 /*
  * We set aside some extra PGPROC structures for "special worker" processes,
-- 
2.43.0



view thread (18+ messages)  latest in thread

Message-ID: <65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru>
Permalink:  ../65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru/
Also on:    postgresql.org/message-id/65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: m.melnikov@postgrespro.ru, a.potapov@postgrespro.ru, boekewurm+postgres@gmail.com
  Subject: Re: Init connection time grows quadratically
  In-Reply-To: <65d0e5b2-2a40-4b12-be04-0804912d2daf@postgrespro.ru>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox