Skip to content

Commit 7e1b61c

Browse files
committed
runtime: mark pages we return to kernel as NOHUGEPAGE
We return memory to the kernel with madvise(..., DONTNEED). Also mark returned memory with NOHUGEPAGE to keep the kernel from merging this memory into a huge page, effectively reallocating it. Only known to be a problem on linux/{386,amd64,amd64p32} at the moment. It may come up on other os/arch combinations in the future. Fixes #8832 Change-Id: Ifffc6627a0296926e3f189a8a9b6e4bdb54c79eb Reviewed-on: https://go-review.googlesource.com/5660 Reviewed-by: Dmitry Vyukov <[email protected]>
1 parent 6d1ebeb commit 7e1b61c

12 files changed

+50
-12
lines changed

src/runtime/arch1_386.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl
1313
_PCQuantum = 1
1414
_Int64Align = 4
15+
hugePageSize = 1 << 21
1516
)

src/runtime/arch1_amd64.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = 4096
1313
_PCQuantum = 1
1414
_Int64Align = 8
15+
hugePageSize = 1 << 21
1516
)

src/runtime/arch1_amd64p32.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl)
1313
_PCQuantum = 1
1414
_Int64Align = 8
15+
hugePageSize = 1 << 21
1516
)

src/runtime/arch1_arm.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl)
1313
_PCQuantum = 4
1414
_Int64Align = 4
15+
hugePageSize = 0
1516
)

src/runtime/arch1_ppc64.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = 65536
1313
_PCQuantum = 4
1414
_Int64Align = 8
15+
hugePageSize = 0
1516
)

src/runtime/arch1_ppc64le.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ const (
1212
_PhysPageSize = 65536
1313
_PCQuantum = 4
1414
_Int64Align = 8
15+
hugePageSize = 0
1516
)

src/runtime/defs_linux_386.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ const (
1717
_MAP_PRIVATE = 0x2
1818
_MAP_FIXED = 0x10
1919

20-
_MADV_DONTNEED = 0x4
20+
_MADV_DONTNEED = 0x4
21+
_MADV_HUGEPAGE = 0xe
22+
_MADV_NOHUGEPAGE = 0xf
2123

2224
_SA_RESTART = 0x10000000
2325
_SA_ONSTACK = 0x8000000

src/runtime/defs_linux_amd64.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ const (
1717
_MAP_PRIVATE = 0x2
1818
_MAP_FIXED = 0x10
1919

20-
_MADV_DONTNEED = 0x4
20+
_MADV_DONTNEED = 0x4
21+
_MADV_HUGEPAGE = 0xe
22+
_MADV_NOHUGEPAGE = 0xf
2123

2224
_SA_RESTART = 0x10000000
2325
_SA_ONSTACK = 0x8000000

src/runtime/defs_linux_arm.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@ const (
66
_ENOMEM = 0xc
77
_EAGAIN = 0xb
88

9-
_PROT_NONE = 0
10-
_PROT_READ = 0x1
11-
_PROT_WRITE = 0x2
12-
_PROT_EXEC = 0x4
13-
_MAP_ANON = 0x20
14-
_MAP_PRIVATE = 0x2
15-
_MAP_FIXED = 0x10
16-
_MADV_DONTNEED = 0x4
9+
_PROT_NONE = 0
10+
_PROT_READ = 0x1
11+
_PROT_WRITE = 0x2
12+
_PROT_EXEC = 0x4
13+
14+
_MAP_ANON = 0x20
15+
_MAP_PRIVATE = 0x2
16+
_MAP_FIXED = 0x10
17+
18+
_MADV_DONTNEED = 0x4
19+
_MADV_HUGEPAGE = 0xe
20+
_MADV_NOHUGEPAGE = 0xf
21+
1722
_SA_RESTART = 0x10000000
1823
_SA_ONSTACK = 0x8000000
1924
_SA_RESTORER = 0 // unused on ARM

src/runtime/defs_linux_ppc64.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ const (
1717
_MAP_PRIVATE = 0x2
1818
_MAP_FIXED = 0x10
1919

20-
_MADV_DONTNEED = 0x4
20+
_MADV_DONTNEED = 0x4
21+
_MADV_HUGEPAGE = 0xe
22+
_MADV_NOHUGEPAGE = 0xf
2123

2224
_SA_RESTART = 0x10000000
2325
_SA_ONSTACK = 0x8000000

src/runtime/defs_linux_ppc64le.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ const (
1717
_MAP_PRIVATE = 0x2
1818
_MAP_FIXED = 0x10
1919

20-
_MADV_DONTNEED = 0x4
20+
_MADV_DONTNEED = 0x4
21+
_MADV_HUGEPAGE = 0xe
22+
_MADV_NOHUGEPAGE = 0xf
2123

2224
_SA_RESTART = 0x10000000
2325
_SA_ONSTACK = 0x8000000

src/runtime/mem_linux.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,29 @@ func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
6767
}
6868

6969
func sysUnused(v unsafe.Pointer, n uintptr) {
70+
if hugePageSize != 0 && (uintptr(v)%hugePageSize != 0 || n%hugePageSize != 0) {
71+
// See issue 8832
72+
// Linux kernel bug: https://bugzilla.kernel.org/show_bug.cgi?id=93111
73+
// Mark the region as NOHUGEPAGE so the kernel's khugepaged
74+
// doesn't undo our DONTNEED request. khugepaged likes to migrate
75+
// regions which are only partially mapped to huge pages, including
76+
// regions with some DONTNEED marks. That needlessly allocates physical
77+
// memory for our DONTNEED regions.
78+
madvise(v, n, _MADV_NOHUGEPAGE)
79+
}
7080
madvise(v, n, _MADV_DONTNEED)
7181
}
7282

7383
func sysUsed(v unsafe.Pointer, n uintptr) {
84+
if hugePageSize != 0 {
85+
// Undo the NOHUGEPAGE marks from sysUnused. There is no alignment check
86+
// around this call as spans may have been merged in the interim.
87+
// Note that this might enable huge pages for regions which were
88+
// previously disabled. Unfortunately there is no easy way to detect
89+
// what the previous state was, and in any case we probably want huge
90+
// pages to back our heap if the kernel can arrange that.
91+
madvise(v, n, _MADV_HUGEPAGE)
92+
}
7493
}
7594

7695
func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {

0 commit comments

Comments
 (0)