Skip to content

Commit 7ae2610

Browse files
aclementstmm1
authored andcommitted
runtime: fetch physical page size from the OS
Currently the physical page size assumed by the runtime is hard-coded. On Linux the runtime at least fetches the OS page size during init and sanity checks against the hard-coded value, but they may still differ. On other OSes we wouldn't even notice. Add support on all OSes to fetch the actual OS physical page size during runtime init and lift the sanity check of PhysPageSize from the Linux init code to general malloc init. Currently this is the only use of the retrieved page size, but we'll add more shortly. Updates golang#12480 and golang#10180. Change-Id: I065f2834bc97c71d3208edc17fd990ec9058b6da Reviewed-on: https://go-review.googlesource.com/25050 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rick Hudson <[email protected]>
1 parent 31e614a commit 7ae2610

14 files changed

+205
-22
lines changed

src/runtime/defs1_solaris_amd64.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const (
7878
_ITIMER_VIRTUAL = 0x1
7979
_ITIMER_PROF = 0x2
8080

81+
__SC_PAGESIZE = 0xb
8182
__SC_NPROCESSORS_ONLN = 0xf
8283

8384
_PTHREAD_CREATE_DETACHED = 0x40

src/runtime/export_mmap_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@
99
package runtime
1010

1111
var Mmap = mmap
12+
var Munmap = munmap
1213

1314
const ENOMEM = _ENOMEM
1415
const MAP_ANON = _MAP_ANON
1516
const MAP_PRIVATE = _MAP_PRIVATE
17+
const MAP_FIXED = _MAP_FIXED
18+
19+
func GetPhysPageSize() uintptr {
20+
return physPageSize
21+
}

src/runtime/malloc.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ const (
172172

173173
const _MaxArena32 = 1<<32 - 1
174174

175+
// physPageSize is the size in bytes of the OS's physical pages.
176+
// Mapping and unmapping operations must be done at multiples of
177+
// physPageSize.
178+
//
179+
// This must be set by the OS init code (typically in osinit) before
180+
// mallocinit.
181+
var physPageSize uintptr
182+
175183
// OS-defined helpers:
176184
//
177185
// sysAlloc obtains a large chunk of zeroed memory from the
@@ -217,6 +225,20 @@ func mallocinit() {
217225
throw("bad TinySizeClass")
218226
}
219227

228+
// Check physPageSize.
229+
if physPageSize == 0 {
230+
// The OS init code failed to fetch the physical page size.
231+
throw("failed to get system page size")
232+
}
233+
if sys.PhysPageSize < physPageSize {
234+
print("runtime: kernel page size (", physPageSize, ") is larger than runtime page size (", sys.PhysPageSize, ")\n")
235+
throw("bad kernel page size")
236+
}
237+
if sys.PhysPageSize%physPageSize != 0 {
238+
print("runtime: runtime page size (", sys.PhysPageSize, ") is not a multiple of kernel page size (", physPageSize, ")\n")
239+
throw("bad kernel page size")
240+
}
241+
220242
var p, bitmapSize, spansSize, pSize, limit uintptr
221243
var reserved bool
222244

src/runtime/os3_solaris.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,17 @@ func getncpu() int32 {
127127
return n
128128
}
129129

130+
func getPageSize() uintptr {
131+
n := int32(sysconf(__SC_PAGESIZE))
132+
if n <= 0 {
133+
return 0
134+
}
135+
return uintptr(n)
136+
}
137+
130138
func osinit() {
131139
ncpu = getncpu()
140+
physPageSize = getPageSize()
132141
}
133142

134143
func tstart_sysvicall()

src/runtime/os_darwin.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,19 @@ func osinit() {
5050
// can look at the environment first.
5151

5252
ncpu = getncpu()
53+
54+
physPageSize = getPageSize()
5355
}
5456

57+
const (
58+
_CTL_HW = 6
59+
_HW_NCPU = 3
60+
_HW_PAGESIZE = 7
61+
)
62+
5563
func getncpu() int32 {
5664
// Use sysctl to fetch hw.ncpu.
57-
mib := [2]uint32{6, 3}
65+
mib := [2]uint32{_CTL_HW, _HW_NCPU}
5866
out := uint32(0)
5967
nout := unsafe.Sizeof(out)
6068
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
@@ -64,6 +72,18 @@ func getncpu() int32 {
6472
return 1
6573
}
6674

75+
func getPageSize() uintptr {
76+
// Use sysctl to fetch hw.pagesize.
77+
mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
78+
out := uint32(0)
79+
nout := unsafe.Sizeof(out)
80+
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
81+
if ret >= 0 && int32(out) > 0 {
82+
return uintptr(out)
83+
}
84+
return 0
85+
}
86+
6787
var urandom_dev = []byte("/dev/urandom\x00")
6888

6989
//go:nosplit

src/runtime/os_dragonfly.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ const stackSystem = 0
5454

5555
// From DragonFly's <sys/sysctl.h>
5656
const (
57-
_CTL_HW = 6
58-
_HW_NCPU = 3
57+
_CTL_HW = 6
58+
_HW_NCPU = 3
59+
_HW_PAGESIZE = 7
5960
)
6061

6162
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
@@ -71,6 +72,17 @@ func getncpu() int32 {
7172
return 1
7273
}
7374

75+
func getPageSize() uintptr {
76+
mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
77+
out := uint32(0)
78+
nout := unsafe.Sizeof(out)
79+
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
80+
if ret >= 0 {
81+
return uintptr(out)
82+
}
83+
return 0
84+
}
85+
7486
//go:nosplit
7587
func futexsleep(addr *uint32, val uint32, ns int64) {
7688
systemstack(func() {
@@ -141,6 +153,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
141153

142154
func osinit() {
143155
ncpu = getncpu()
156+
physPageSize = getPageSize()
144157
}
145158

146159
var urandom_dev = []byte("/dev/urandom\x00")

src/runtime/os_freebsd.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ func osyield()
4141

4242
// From FreeBSD's <sys/sysctl.h>
4343
const (
44-
_CTL_HW = 6
45-
_HW_NCPU = 3
44+
_CTL_HW = 6
45+
_HW_NCPU = 3
46+
_HW_PAGESIZE = 7
4647
)
4748

4849
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
@@ -58,6 +59,17 @@ func getncpu() int32 {
5859
return 1
5960
}
6061

62+
func getPageSize() uintptr {
63+
mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
64+
out := uint32(0)
65+
nout := unsafe.Sizeof(out)
66+
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
67+
if ret >= 0 {
68+
return uintptr(out)
69+
}
70+
return 0
71+
}
72+
6173
// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
6274
// thus the code is largely similar. See Linux implementation
6375
// and lock_futex.go for comments.
@@ -128,6 +140,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
128140

129141
func osinit() {
130142
ncpu = getncpu()
143+
physPageSize = getPageSize()
131144
}
132145

133146
var urandom_dev = []byte("/dev/urandom\x00")

src/runtime/os_linux.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -207,17 +207,7 @@ func sysargs(argc int32, argv **byte) {
207207
startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:]
208208

209209
case _AT_PAGESZ:
210-
// Check that the true physical page size is
211-
// compatible with the runtime's assumed
212-
// physical page size.
213-
if sys.PhysPageSize < val {
214-
print("runtime: kernel page size (", val, ") is larger than runtime page size (", sys.PhysPageSize, ")\n")
215-
exit(1)
216-
}
217-
if sys.PhysPageSize%val != 0 {
218-
print("runtime: runtime page size (", sys.PhysPageSize, ") is not a multiple of kernel page size (", val, ")\n")
219-
exit(1)
220-
}
210+
physPageSize = val
221211
}
222212

223213
archauxv(tag, val)

src/runtime/os_nacl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ func osinit() {
116116
ncpu = 1
117117
getg().m.procid = 2
118118
//nacl_exception_handler(funcPC(sigtramp), nil);
119+
physPageSize = 65536
119120
}
120121

121122
func signame(sig uint32) string {

src/runtime/os_netbsd.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)
7979

8080
// From NetBSD's <sys/sysctl.h>
8181
const (
82-
_CTL_HW = 6
83-
_HW_NCPU = 3
82+
_CTL_HW = 6
83+
_HW_NCPU = 3
84+
_HW_PAGESIZE = 7
8485
)
8586

8687
func getncpu() int32 {
@@ -94,6 +95,17 @@ func getncpu() int32 {
9495
return 1
9596
}
9697

98+
func getPageSize() uintptr {
99+
mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
100+
out := uint32(0)
101+
nout := unsafe.Sizeof(out)
102+
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
103+
if ret >= 0 {
104+
return uintptr(out)
105+
}
106+
return 0
107+
}
108+
97109
//go:nosplit
98110
func semacreate(mp *m) {
99111
}
@@ -186,6 +198,7 @@ func netbsdMstart() {
186198

187199
func osinit() {
188200
ncpu = getncpu()
201+
physPageSize = getPageSize()
189202
}
190203

191204
var urandom_dev = []byte("/dev/urandom\x00")

src/runtime/os_openbsd.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ const (
6464

6565
// From OpenBSD's <sys/sysctl.h>
6666
const (
67-
_CTL_HW = 6
68-
_HW_NCPU = 3
67+
_CTL_HW = 6
68+
_HW_NCPU = 3
69+
_HW_PAGESIZE = 7
6970
)
7071

7172
func getncpu() int32 {
@@ -81,6 +82,17 @@ func getncpu() int32 {
8182
return 1
8283
}
8384

85+
func getPageSize() uintptr {
86+
mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
87+
out := uint32(0)
88+
nout := unsafe.Sizeof(out)
89+
ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
90+
if ret >= 0 {
91+
return uintptr(out)
92+
}
93+
return 0
94+
}
95+
8496
//go:nosplit
8597
func semacreate(mp *m) {
8698
}
@@ -163,6 +175,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
163175

164176
func osinit() {
165177
ncpu = getncpu()
178+
physPageSize = getPageSize()
166179
}
167180

168181
var urandom_dev = []byte("/dev/urandom\x00")

src/runtime/os_plan9.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,55 @@ func getproccount() int32 {
217217
return ncpu
218218
}
219219

220+
var devswap = []byte("/dev/swap\x00")
221+
var pagesize = []byte(" pagesize\n")
222+
223+
func getPageSize() uintptr {
224+
var buf [2048]byte
225+
var pos int
226+
fd := open(&devswap[0], _OREAD, 0)
227+
if fd < 0 {
228+
// There's not much we can do if /dev/swap doesn't
229+
// exist. However, nothing in the memory manager uses
230+
// this on Plan 9, so it also doesn't really matter.
231+
return minPhysPageSize
232+
}
233+
for pos < len(buf) {
234+
n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos))
235+
if n <= 0 {
236+
break
237+
}
238+
pos += int(n)
239+
}
240+
closefd(fd)
241+
text := buf[:pos]
242+
// Find "<n> pagesize" line.
243+
bol := 0
244+
for i, c := range text {
245+
if c == '\n' {
246+
bol = i + 1
247+
}
248+
if bytesHasPrefix(text[i:], pagesize) {
249+
// Parse number at the beginning of this line.
250+
return uintptr(_atoi(text[bol:]))
251+
}
252+
}
253+
// Again, the page size doesn't really matter, so use a fallback.
254+
return minPhysPageSize
255+
}
256+
257+
func bytesHasPrefix(s, prefix []byte) bool {
258+
if len(s) < len(prefix) {
259+
return false
260+
}
261+
for i, p := range prefix {
262+
if s[i] != p {
263+
return false
264+
}
265+
}
266+
return true
267+
}
268+
220269
var pid = []byte("#c/pid\x00")
221270

222271
func getpid() uint64 {
@@ -236,6 +285,7 @@ func getpid() uint64 {
236285
func osinit() {
237286
initBloc()
238287
ncpu = getproccount()
288+
physPageSize = getPageSize()
239289
getg().m.procid = getpid()
240290
notify(unsafe.Pointer(funcPC(sigtramp)))
241291
}

src/runtime/os_windows.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,12 @@ func getproccount() int32 {
205205
return int32(info.dwnumberofprocessors)
206206
}
207207

208+
func getPageSize() uintptr {
209+
var info systeminfo
210+
stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
211+
return uintptr(info.dwpagesize)
212+
}
213+
208214
const (
209215
currentProcess = ^uintptr(0) // -1 = current process
210216
currentThread = ^uintptr(1) // -2 = current thread
@@ -256,6 +262,8 @@ func osinit() {
256262

257263
ncpu = getproccount()
258264

265+
physPageSize = getPageSize()
266+
259267
// Windows dynamic priority boosting assumes that a process has different types
260268
// of dedicated threads -- GUI, IO, computational, etc. Go processes use
261269
// equivalent threads that all do a mix of GUI, IO, computations, etc.

0 commit comments

Comments
 (0)