Skip to content

Commit f6cc4e2

Browse files
authored
util: implement GetTotalMemory for mac and windows (#6272)
1 parent 3a0cd6e commit f6cc4e2

File tree

5 files changed

+133
-16
lines changed

5 files changed

+133
-16
lines changed

util/util.go

+2-14
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package util
2121

2222
import (
2323
"fmt"
24-
"runtime"
2524
"syscall"
2625
)
2726

@@ -74,18 +73,7 @@ func GetCurrentProcessTimes() (utime int64, stime int64, err error) {
7473
return
7574
}
7675

77-
// GetTotalMemory gets total system memory on Linux systems
76+
// GetTotalMemory gets total system memory
7877
func GetTotalMemory() uint64 {
79-
switch runtime.GOOS {
80-
case "linux":
81-
// Use sysinfo on Linux
82-
var si syscall.Sysinfo_t
83-
err := syscall.Sysinfo(&si)
84-
if err != nil {
85-
return 0
86-
}
87-
return si.Totalram
88-
default:
89-
return 0
90-
}
78+
return getTotalMemory()
9179
}

util/util_darwin.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (C) 2019-2025 Algorand, Inc.
2+
// This file is part of go-algorand
3+
//
4+
// go-algorand is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// go-algorand is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package util
18+
19+
import (
20+
"syscall"
21+
"unsafe"
22+
)
23+
24+
func getTotalMemory() uint64 {
25+
out, err := syscall.Sysctl("hw.memsize")
26+
if err != nil {
27+
return 0
28+
}
29+
b := []byte(out)
30+
if len(b) < 8 {
31+
b = append(b, 0)
32+
}
33+
return *(*uint64)(unsafe.Pointer(&b[0]))
34+
}

util/util_linux.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (C) 2019-2025 Algorand, Inc.
2+
// This file is part of go-algorand
3+
//
4+
// go-algorand is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// go-algorand is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package util
18+
19+
import (
20+
"syscall"
21+
)
22+
23+
func getTotalMemory() uint64 {
24+
var si syscall.Sysinfo_t
25+
err := syscall.Sysinfo(&si)
26+
if err != nil {
27+
return 0
28+
}
29+
// support 32-bit systems where Totalram is uint32
30+
return uint64(si.Totalram) * uint64(si.Unit)
31+
}

util/util_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2019-2025 Algorand, Inc.
2+
// This file is part of go-algorand
3+
//
4+
// go-algorand is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// go-algorand is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package util
18+
19+
import (
20+
"testing"
21+
22+
"github.com/algorand/go-algorand/test/partitiontest"
23+
"github.com/stretchr/testify/require"
24+
)
25+
26+
func TestGetTotalMemory(t *testing.T) {
27+
partitiontest.PartitionTest(t)
28+
t.Parallel()
29+
30+
mem := GetTotalMemory()
31+
require.Greater(t, mem, uint64(0))
32+
}

util/util_windows.go

+34-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"math"
2222
"syscall"
2323
"time"
24+
"unsafe"
2425
)
2526

2627
/* misc */
@@ -70,7 +71,38 @@ func filetimeToDuration(ft *syscall.Filetime) time.Duration {
7071
return time.Duration(n * 100)
7172
}
7273

73-
// GetTotalMemory gets total system memory, returns 0 on Windows
74+
// GetTotalMemory gets total system memory on Windows
7475
func GetTotalMemory() uint64 {
75-
return 0
76+
var memoryStatusEx MemoryStatusEx
77+
memoryStatusEx.dwLength = uint32(unsafe.Sizeof(memoryStatusEx))
78+
79+
if err := globalMemoryStatusEx(&memoryStatusEx); err != nil {
80+
return 0
81+
}
82+
return memoryStatusEx.ullTotalPhys
83+
}
84+
85+
type MemoryStatusEx struct {
86+
dwLength uint32
87+
dwMemoryLoad uint32
88+
ullTotalPhys uint64
89+
ullAvailPhys uint64
90+
ullTotalPageFile uint64
91+
ullAvailPageFile uint64
92+
ullTotalVirtual uint64
93+
ullAvailVirtual uint64
94+
ullAvailExtendedVirtual uint64
95+
}
96+
97+
var (
98+
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
99+
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
100+
)
101+
102+
func globalMemoryStatusEx(memoryStatusEx *MemoryStatusEx) error {
103+
ret, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(memoryStatusEx)))
104+
if ret == 0 {
105+
return syscall.GetLastError()
106+
}
107+
return nil
76108
}

0 commit comments

Comments
 (0)