Skip to content

Commit 57ea7e1

Browse files
macdicehackorum
authored andcommitted
Support huge_pages and huge_page_size on FreeBSD.
FreeBSD often uses huge (super) pages due to automatic promotion, but it may be useful to be able to request that explicitly, and to be able to experiment with different page sizes by explicit request. Discussion: https://postgr.es/m/3043b674-46d6-a8e9-3811-5a3007c8dceb%40ww-it.cn
1 parent db0c984 commit 57ea7e1

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

doc/src/sgml/config.sgml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,9 +1850,9 @@ include_dir 'conf.d'
18501850
</para>
18511851

18521852
<para>
1853-
At present, this setting is supported only on Linux and Windows. The
1853+
At present, this setting is supported only on Linux, FreeBSD and Windows. The
18541854
setting is ignored on other systems when set to
1855-
<literal>try</literal>. On Linux, it is only supported when
1855+
<literal>try</literal>. On Linux and FreeBSD, it is only supported when
18561856
<varname>shared_memory_type</varname> is set to <literal>mmap</literal>
18571857
(the default).
18581858
</para>
@@ -1914,7 +1914,7 @@ include_dir 'conf.d'
19141914
about usage and support, see <xref linkend="linux-huge-pages"/>.
19151915
</para>
19161916
<para>
1917-
Non-default settings are currently supported only on Linux.
1917+
Non-default settings are currently supported only on Linux and FreeBSD.
19181918
</para>
19191919
</listitem>
19201920
</varlistentry>

src/backend/port/sysv_shmem.c

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,9 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
578578
bool
579579
check_huge_page_size(int *newval, void **extra, GucSource source)
580580
{
581-
#if !(defined(MAP_HUGE_MASK) && defined(MAP_HUGE_SHIFT))
582-
/* Recent enough Linux only, for now. See GetHugePageSize(). */
581+
#if !(defined(MAP_HUGE_MASK) && defined(MAP_HUGE_SHIFT)) && \
582+
!defined(SHM_LARGEPAGE_ALLOC_DEFAULT)
583+
/* Recent enough Linux and FreeBSD only, for now. */
583584
if (*newval != 0)
584585
{
585586
GUC_check_errdetail("\"huge_page_size\" must be 0 on this platform.");
@@ -604,12 +605,9 @@ CreateAnonymousSegment(Size *size)
604605
int mmap_errno = 0;
605606
int mmap_flags = MAP_SHARED | MAP_ANONYMOUS | MAP_HASSEMAPHORE;
606607

607-
#ifndef MAP_HUGETLB
608-
/* PGSharedMemoryCreate should have dealt with this case */
609-
Assert(huge_pages != HUGE_PAGES_ON);
610-
#else
611608
if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY)
612609
{
610+
#ifdef MAP_HUGETLB
613611
/*
614612
* Round up the request size to a suitable large value.
615613
*/
@@ -627,8 +625,52 @@ CreateAnonymousSegment(Size *size)
627625
if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED)
628626
elog(DEBUG1, "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m",
629627
allocsize);
630-
}
631628
#endif
629+
#ifdef SHM_LARGEPAGE_ALLOC_DEFAULT
630+
int nsizes;
631+
size_t *page_sizes;
632+
size_t page_size;
633+
int page_size_index = -1;
634+
635+
/*
636+
* Find the matching page size index, or if huge_page_size wasn't set,
637+
* then skip the smallest size and take the next one after that.
638+
*/
639+
nsizes = getpagesizes(NULL, 0);
640+
page_sizes = palloc(nsizes * sizeof(*page_sizes));
641+
getpagesizes(page_sizes, nsizes);
642+
for (int i = 0; i < nsizes; ++i)
643+
{
644+
if (huge_page_size * 1024 == page_sizes[i] ||
645+
(huge_page_size == 0 && i > 0))
646+
{
647+
page_size = page_sizes[i];
648+
page_size_index = i;
649+
if (allocsize % page_size != 0)
650+
allocsize += page_size - (allocsize % page_size);
651+
break;
652+
}
653+
}
654+
pfree(page_sizes);
655+
if (index >= 0)
656+
{
657+
int fd;
658+
659+
fd = shm_create_largepage(SHM_ANON, O_RDWR, page_size_index,
660+
SHM_LARGEPAGE_ALLOC_DEFAULT, 0);
661+
if (fd >= 0)
662+
{
663+
if (ftruncate(fd, allocsize) == 0)
664+
{
665+
ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
666+
MAP_SHARED, fd, 0);
667+
mmap_errno = errno;
668+
}
669+
close(fd);
670+
}
671+
}
672+
#endif
673+
}
632674

633675
/*
634676
* Report whether huge pages are in use. This needs to be tracked before
@@ -720,7 +762,7 @@ PGSharedMemoryCreate(Size size,
720762
DataDir)));
721763

722764
/* Complain if hugepages demanded but we can't possibly support them */
723-
#if !defined(MAP_HUGETLB)
765+
#if !defined(MAP_HUGETLB) && !defined(SHM_LARGEPAGE_ALLOC_DEFAULT)
724766
if (huge_pages == HUGE_PAGES_ON)
725767
ereport(ERROR,
726768
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

0 commit comments

Comments
 (0)