Skip to content

Commit 3993d59

Browse files
committed
Updated memory readings
1 parent f1a9131 commit 3993d59

File tree

3 files changed

+108
-24
lines changed

3 files changed

+108
-24
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,31 +109,35 @@ GPU Info: [
109109
Memory Info: {
110110
size: 34249633792,
111111
utilization: {
112-
used: 22930456576,
113-
free: 11319177216,
114-
percentage: 0.669509540313861
112+
used: 22643089408,
113+
free: 11606544384,
114+
percentage: 0.6611191683249166
115115
},
116116
devices: [
117117
{
118118
manufacturer: 'Kingston',
119119
model: 'KF3200C16D4/16GX',
120+
bankName: 'BANK 0',
120121
size: 17179869184,
121122
busWidth: 64,
122123
maxClockSpeed: 2400,
123124
clockSpeed: 2400,
124125
voltage: 1.2,
126+
locator: 'Controller0-ChannelA-DIMM1',
125127
type: 'DDR4',
126128
transfersPerClockCycle: 2,
127129
bandwidth: 38400000000
128130
},
129131
{
130132
manufacturer: 'Kingston',
131133
model: 'KF3200C16D4/16GX',
134+
bankName: 'BANK 1',
132135
size: 17179869184,
133136
busWidth: 64,
134137
maxClockSpeed: 2400,
135138
clockSpeed: 2400,
136139
voltage: 1.2,
140+
locator: 'Controller0-ChannelB-DIMM1',
137141
type: 'DDR4',
138142
transfersPerClockCycle: 2,
139143
bandwidth: 38400000000

src/docker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export type DockerContainer = {
22

3-
};
3+
};

src/memory.ts

Lines changed: 100 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ export type MemoryDevice = {
2828
/** Memory type (e.g., DDR4, LPDDR4X). */
2929
type?: string;
3030

31+
/** Name assigned to slot by the firmware. */
32+
locator?: string;
33+
34+
/** Name of the slot based on motherboard layout (bank locator). */
35+
bankName?: string;
36+
3137
/** Configured clock speed in MHz. */
3238
clockSpeed?: number;
3339

@@ -82,11 +88,80 @@ export async function getMemoryInfo(): Promise<Memory> {
8288
percentage: (os.totalmem() - os.freemem()) / os.totalmem(),
8389
},
8490
};
91+
const interleavePositions = new Set<number>();
8592

8693
switch(process.platform){
8794

95+
case 'darwin':
8896
case 'linux': {
89-
// TODO
97+
const output = await execCommand(
98+
'dmidecode --type memory'
99+
).catch(() => '');
100+
const lines = output.split('\n');
101+
let currDevice: MemoryDevice | null = null;
102+
let ignoreBlock = true;
103+
for(let i=0; i < lines.length; i++){
104+
const [key, value] = lines[i].split(': ').map(s => s.trim());
105+
if(!key || !currDevice){ // empty line marks new device
106+
if(currDevice && Object.keys(currDevice).length > 0) {
107+
memoryInfo.devices = memoryInfo.devices || [];
108+
memoryInfo.devices.push(currDevice as any);
109+
}
110+
currDevice = {};
111+
ignoreBlock = true;
112+
continue;
113+
}
114+
if(!value){
115+
ignoreBlock = ignoreBlock || (key === 'Memory Device');
116+
continue; // skip lines without value
117+
}
118+
if(ignoreBlock) continue; // skip block if marked to ignore
119+
if(key === 'Total Width' || key === 'Data Width'){
120+
const busWidth = parseInt(value.split(' ')[0], 10); // strip unit 'bits'
121+
if(!Number.isNaN(busWidth)) currDevice.busWidth = busWidth;
122+
} else
123+
if(key === 'Size'){
124+
const size = parseInt(value.split(' ')[0], 10); // strip unit 'MB'
125+
if(!Number.isNaN(size)) currDevice.size = size * 1024 * 1024; // convert MB to bytes
126+
} else
127+
if(key === 'Locator' || key === 'Socket Designation'){
128+
currDevice.locator = value;
129+
} else
130+
if(key === 'Bank Locator'){
131+
currDevice.bankName = value;
132+
} else
133+
if(key === 'Type'){
134+
currDevice.type = value;
135+
} else
136+
if(key === 'Speed'){
137+
const mhz = parseInt(value.split(' ')[0], 10); // strip unit 'MHz'
138+
if(!Number.isNaN(mhz)){
139+
currDevice.clockSpeed = mhz;
140+
currDevice.maxClockSpeed = mhz; // use max speed as default clock speed
141+
}
142+
} else
143+
if(key === 'Configured Memory Speed' || key === 'Configured Clock Speed'){
144+
const mhz = parseInt(value.split(' ')[0], 10); // strip unit 'MHz'
145+
if(!Number.isNaN(mhz)){
146+
currDevice.clockSpeed = mhz;
147+
if(!currDevice.maxClockSpeed) currDevice.maxClockSpeed = mhz; // use configured speed as default max speed
148+
}
149+
} else
150+
if(key === 'Manufacturer'){
151+
currDevice.manufacturer = value;
152+
} else
153+
if(key === 'Part Number'){
154+
currDevice.model = currDevice.model || value; // use first available model
155+
} else
156+
if(key === 'Rank'){
157+
const rank = parseInt(value, 10);
158+
if(!Number.isNaN(rank)) interleavePositions.add(rank);
159+
} else
160+
if(key === 'Voltage' || key === 'Configured Voltage'){
161+
const voltage = parseFloat(value.split(' ')[0]); // strip unit 'V'
162+
if(!Number.isNaN(voltage)) currDevice.voltage = voltage; // keep in volts
163+
}
164+
}
90165
break;
91166
}
92167

@@ -95,7 +170,6 @@ export async function getMemoryInfo(): Promise<Memory> {
95170
'powershell -Command "Get-CimInstance -ClassName Win32_PhysicalMemory | Format-List"'
96171
).catch(() => '');
97172
const lines = output.split('\n');
98-
const interleavePositions = new Set<number>();
99173
let currDevice: MemoryDevice | null = null;
100174
for(let i=0; i < lines.length; i++){
101175
const [key, value] = lines[i].split(' : ').map(s => s.trim());
@@ -115,6 +189,9 @@ export async function getMemoryInfo(): Promise<Memory> {
115189
if(key === 'Model' || key === 'PartNumber'){
116190
currDevice.model = currDevice.model || value;
117191
} else
192+
if(key === 'BankLabel'){
193+
currDevice.bankName = value;
194+
} else
118195
if(key === 'Capacity'){
119196
const size = parseInt(value, 10);
120197
if(!Number.isNaN(size)) currDevice.size = size;
@@ -134,7 +211,7 @@ export async function getMemoryInfo(): Promise<Memory> {
134211
if(!currDevice.clockSpeed) currDevice.clockSpeed = mhz; // use max speed as default clock speed
135212
}
136213
} else
137-
if(key === 'ConfiguredClockSpeed'){ // higher priority than Speed
214+
if(key === 'ConfiguredClockSpeed' || key === 'ConfiguredMemorySpeed'){ // higher priority than Speed
138215
const mhz = parseInt(value, 10);
139216
if(!Number.isNaN(mhz)){
140217
currDevice.clockSpeed = mhz;
@@ -145,6 +222,9 @@ export async function getMemoryInfo(): Promise<Memory> {
145222
const voltage = parseFloat(value);
146223
if(!Number.isNaN(voltage)) currDevice.voltage = voltage / 1000; // convert from mV to V
147224
} else
225+
if(key === 'DeviceLocator'){
226+
currDevice.locator = value;
227+
} else
148228
if(key === 'SMBIOSMemoryType'){
149229
switch(value){
150230
case '0': currDevice.type = 'Unknown'; break;
@@ -185,26 +265,26 @@ export async function getMemoryInfo(): Promise<Memory> {
185265
}
186266
}
187267
}
268+
break;
269+
}
270+
}
188271

189-
// post-processing
190-
if(memoryInfo.devices){
191-
const parallelism = Math.max(1, interleavePositions.size);
192-
let clockSpeed: number | undefined;
193-
let busWidth: number | undefined;
194-
let transfersPerCycle: number | undefined;
195-
for(let device of memoryInfo.devices){
196-
if(device.size && device.busWidth && device.clockSpeed){
197-
clockSpeed = clockSpeed ? Math.min(clockSpeed, device.clockSpeed) : device.clockSpeed;
198-
busWidth = busWidth ? Math.min(busWidth, device.busWidth) : device.busWidth;
199-
transfersPerCycle = transfersPerCycle ? Math.min(transfersPerCycle, device.transfersPerClockCycle ?? 1) : device.transfersPerClockCycle;
200-
device.bandwidth = device.clockSpeed*1000*1000 * device.busWidth/8 * (transfersPerCycle ?? 1);
201-
}
202-
}
203-
if(clockSpeed && busWidth)
204-
memoryInfo.bandwidth = clockSpeed*1000*1000 * busWidth/8 * (transfersPerCycle ?? 1) * parallelism; // bytes per second
272+
// post-processing
273+
if(memoryInfo.devices){
274+
const parallelism = Math.max(1, interleavePositions.size);
275+
let clockSpeed: number | undefined;
276+
let busWidth: number | undefined;
277+
let transfersPerCycle: number | undefined;
278+
for(let device of memoryInfo.devices){
279+
if(device.size && device.busWidth && device.clockSpeed){
280+
clockSpeed = clockSpeed ? Math.min(clockSpeed, device.clockSpeed) : device.clockSpeed;
281+
busWidth = busWidth ? Math.min(busWidth, device.busWidth) : device.busWidth;
282+
transfersPerCycle = transfersPerCycle ? Math.min(transfersPerCycle, device.transfersPerClockCycle ?? 1) : device.transfersPerClockCycle;
283+
device.bandwidth = device.clockSpeed*1000*1000 * device.busWidth/8 * (transfersPerCycle ?? 1);
205284
}
206-
break;
207285
}
286+
if(clockSpeed && busWidth)
287+
memoryInfo.bandwidth = clockSpeed*1000*1000 * busWidth/8 * (transfersPerCycle ?? 1) * parallelism; // bytes per second
208288
}
209289

210290
return memoryInfo;

0 commit comments

Comments
 (0)