forked from zcalusic/sysinfo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemory.go
121 lines (106 loc) · 2.95 KB
/
memory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bytes"
"encoding/binary"
"io/ioutil"
"strconv"
)
// Memory information.
type Memory struct {
Type string `json:"type,omitempty"`
Speed uint `json:"speed,omitempty"` // RAM data rate in MT/s
Size uint `json:"size,omitempty"` // RAM size in MB
}
func word(data []byte, index int) uint16 {
return binary.LittleEndian.Uint16(data[index : index+2])
}
func dword(data []byte, index int) uint32 {
return binary.LittleEndian.Uint32(data[index : index+4])
}
func qword(data []byte, index int) uint64 {
return binary.LittleEndian.Uint64(data[index : index+8])
}
func (si *SysInfo) getMemoryInfo() {
dmi, err := ioutil.ReadFile("/sys/firmware/dmi/tables/DMI")
if err != nil {
// Xen hypervisor
if targetKB := slurpFile("/sys/devices/system/xen_memory/xen_memory0/target_kb"); targetKB != "" {
si.Memory.Type = "DRAM"
size, _ := strconv.ParseUint(targetKB, 10, 64)
si.Memory.Size = uint(size) / 1024
}
return
}
si.Memory.Size = 0
var memSizeAlt uint
loop:
for p := 0; p < len(dmi)-1; {
recType := dmi[p]
recLen := dmi[p+1]
switch recType {
case 4:
if si.CPU.Speed == 0 {
si.CPU.Speed = uint(word(dmi, p+0x16))
}
case 17:
size := uint(word(dmi, p+0x0c))
if size == 0 || size == 0xffff || size&0x8000 == 0x8000 {
break
}
if size == 0x7fff {
if recLen >= 0x20 {
size = uint(dword(dmi, p+0x1c))
} else {
break
}
}
si.Memory.Size += size
if si.Memory.Type == "" {
// SMBIOS Reference Specification Version 3.0.0, page 92
memTypes := [...]string{
"Other", "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "FLASH",
"EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM",
"DDR", "DDR2", "DDR2 FB-DIMM", "Reserved", "Reserved", "Reserved", "DDR3",
"FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4",
}
if index := int(dmi[p+0x12]); index >= 1 && index <= len(memTypes) {
si.Memory.Type = memTypes[index-1]
}
}
if si.Memory.Speed == 0 && recLen >= 0x17 {
if speed := uint(word(dmi, p+0x15)); speed != 0 {
si.Memory.Speed = speed
}
}
case 19:
start := uint(dword(dmi, p+0x04))
end := uint(dword(dmi, p+0x08))
if start == 0xffffffff && end == 0xffffffff {
if recLen >= 0x1f {
start64 := qword(dmi, p+0x0f)
end64 := qword(dmi, p+0x17)
memSizeAlt += uint((end64 - start64 + 1) / 1048576)
}
} else {
memSizeAlt += (end - start + 1) / 1024
}
case 127:
break loop
}
for p += int(recLen); p < len(dmi)-1; {
if bytes.Equal(dmi[p:p+2], []byte{0, 0}) {
p += 2
break
}
p++
}
}
// Sometimes DMI type 17 has no information, so we fall back to DMI type 19, to at least get the RAM size.
if si.Memory.Size == 0 && memSizeAlt > 0 {
si.Memory.Type = "DRAM"
si.Memory.Size = memSizeAlt
}
}