Skip to content

Commit 207e88f

Browse files
committed
feat: Add SMBIOS GetSystemFirmwareTable P/Invoke for Windows memory details
1 parent bab81cb commit 207e88f

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

‎src/BenchmarkDotNet/Environments/PhysicalMemoryInfo.cs‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ private static (long? FrequencyMHz, string? MemoryType) GetLinuxOrWindowsMemoryD
130130
{
131131
try
132132
{
133+
if (OsDetector.IsWindows7OrLater())
134+
{
135+
return GetWindowsSmbiosMemoryDetails();
136+
}
137+
133138
// Try reading /sys/devices/system/edac/mc/ on Linux
134139
if (Directory.Exists("/sys/devices/system/edac/mc"))
135140
{
@@ -156,6 +161,97 @@ private static (long? FrequencyMHz, string? MemoryType) GetLinuxOrWindowsMemoryD
156161
return (null, null);
157162
}
158163

164+
[SupportedOSPlatform("windows5.1.2600")]
165+
private static (long? FrequencyMHz, string? MemoryType) GetWindowsSmbiosMemoryDetails()
166+
{
167+
try
168+
{
169+
const uint rsMb = 0x52534D42; // 'RSMB'
170+
uint bufferSize = NativeMethods.GetSystemFirmwareTable(rsMb, 0, IntPtr.Zero, 0);
171+
if (bufferSize == 0)
172+
return (null, null);
173+
174+
byte[] buffer = new byte[bufferSize];
175+
if (NativeMethods.GetSystemFirmwareTable(rsMb, 0, buffer, bufferSize) == 0)
176+
return (null, null);
177+
178+
// SMBIOS table header: Data at offset 8
179+
int offset = 8;
180+
long? maxSpeed = null;
181+
string? detectedType = null;
182+
183+
while (offset + 4 <= buffer.Length)
184+
{
185+
byte type = buffer[offset];
186+
byte length = buffer[offset + 1];
187+
188+
if (length < 4 || offset + length > buffer.Length)
189+
break;
190+
191+
// Type 17: Memory Device
192+
if (type == 17 && length >= 0x15)
193+
{
194+
// Memory Type at offset 0x12
195+
byte rawMemoryType = buffer[offset + 0x12];
196+
string? memTypeStr = MapSmbiosMemoryType(rawMemoryType);
197+
if (memTypeStr != null && detectedType == null)
198+
{
199+
detectedType = memTypeStr;
200+
}
201+
202+
// Speed in MHz at offset 0x15 (WORD)
203+
if (length >= 0x17)
204+
{
205+
ushort speed = (ushort)(buffer[offset + 0x15] | (buffer[offset + 0x16] << 8));
206+
if (speed > 0 && speed < 0xFFFF)
207+
{
208+
if (maxSpeed == null || speed > maxSpeed.Value)
209+
{
210+
maxSpeed = speed;
211+
}
212+
}
213+
}
214+
}
215+
216+
// Move past formatted area
217+
offset += length;
218+
219+
// Skip unformatted string section (double null-terminated)
220+
while (offset < buffer.Length - 1 && !(buffer[offset] == 0 && buffer[offset + 1] == 0))
221+
{
222+
offset++;
223+
}
224+
offset += 2;
225+
}
226+
227+
return (maxSpeed, detectedType);
228+
}
229+
catch
230+
{
231+
return (null, null);
232+
}
233+
}
234+
235+
private static class NativeMethods
236+
{
237+
[DllImport("kernel32.dll", SetLastError = true)]
238+
public static extern uint GetSystemFirmwareTable(uint firmwareTableProviderSignature, uint firmwareTableID, byte[] pFirmwareTableBuffer, uint bufferSize);
239+
240+
[DllImport("kernel32.dll", SetLastError = true)]
241+
public static extern uint GetSystemFirmwareTable(uint firmwareTableProviderSignature, uint firmwareTableID, IntPtr pFirmwareTableBuffer, uint bufferSize);
242+
}
243+
244+
private static string? MapSmbiosMemoryType(byte type) => type switch
245+
{
246+
0x1A => "DDR3",
247+
0x1A + 1 => "DDR4",
248+
0x1A + 2 => "LPDDR3",
249+
0x1A + 3 => "LPDDR4",
250+
0x22 => "DDR5",
251+
0x23 => "LPDDR5",
252+
_ => null
253+
};
254+
159255
private static PhysicalMemoryInfo? GetMacMemory()
160256
{
161257
long total = 0;

0 commit comments

Comments
 (0)