Skip to content

Commit fc82ca2

Browse files
committed
fix: parse dmidecode memory capacity labels consistently across versions
1 parent 30af957 commit fc82ca2

2 files changed

Lines changed: 54 additions & 24 deletions

File tree

emhttp/plugins/dynamix/DashStats.page

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,34 +163,45 @@ $total = exec("awk '/^MemTotal/{print $2*1024}' /proc/meminfo");
163163
unset($ports); exec("ls --indicator-style=none /sys/class/net|grep -Po '^(bond|eth|wlan)\d+$'",$ports);
164164
$ports[] = 'lo';
165165

166-
$sizes = ['MB','GB','TB'];
166+
$memory_units = [
167+
// dmidecode reports memory capacities using binary math; treat both SI and IEC labels as base-1024.
168+
// This keeps parsing consistent across dmidecode versions that may print GB/TB or GiB/TiB.
169+
'kb' => 1/1024, 'kib' => 1/1024,
170+
'mb' => 1, 'mib' => 1,
171+
'gb' => 1024, 'gib' => 1024,
172+
'tb' => 1048576,'tib' => 1048576,
173+
'pb' => 1073741824, 'pib' => 1073741824
174+
];
175+
$parse_memory_to_mib = function($value) use ($memory_units) {
176+
if (!preg_match('/([0-9.]+)\s*([A-Za-z]+)/',$value ?? '',$match)) return 0;
177+
$size = (float)$match[1];
178+
$unit = strtolower($match[2]);
179+
return isset($memory_units[$unit]) ? (int)round($size*$memory_units[$unit]) : 0;
180+
};
167181
$memory_type = $ecc = '';
168182
$memory_installed = $memory_maximum = 0;
169183
$memory_devices = dmidecode('Memory Device','17');
170184
foreach ($memory_devices as $device) {
171-
if (!is_numeric($device['Size'][0])) continue;
172-
[$size, $unit] = my_explode(' ',$device['Size']??'');
173-
$base = array_search($unit,$sizes);
174-
if ($base!==false) $memory_installed += $size*pow(1024,$base);
185+
$memory_installed += $parse_memory_to_mib($device['Size'] ?? '');
175186
if (!$memory_type && isset($device['Type']) && $device['Type']!='Unknown') $memory_type = $device['Type'];
176187
}
177188
$memory_array = dmidecode('Physical Memory Array','16');
178189
foreach ($memory_array as $device) {
179-
[$size, $unit] = my_explode(' ',$device['Maximum Capacity']??'');
180-
$base = array_search($unit,$sizes);
181-
if ($base>=1) $memory_maximum += $size*pow(1024,$base);
190+
$memory_maximum += $parse_memory_to_mib($device['Maximum Capacity'] ?? '');
182191
if (!$ecc && isset($device['Error Correction Type']) && $device['Error Correction Type']!='None') $ecc = "{$device['Error Correction Type']} ";
183192
}
184193
if ($memory_installed >= 1048576) {
185194
$memory_installed = round($memory_installed/1048576);
186195
$memory_maximum = round($memory_maximum/1048576);
187-
$unit = 'TiB';
196+
$memory_unit = 'TiB';
188197
} else {
189198
if ($memory_installed >= 1024) {
190199
$memory_installed = round($memory_installed/1024);
191200
$memory_maximum = round($memory_maximum/1024);
192-
$unit = 'GiB';}
193-
else $unit = 'MiB'; }
201+
$memory_unit = 'GiB';}
202+
else $memory_unit = 'MiB'; }
203+
204+
$unit = $memory_unit;
194205

195206
// get system resources size
196207
exec("df --output=size /boot /var/log /var/lib/docker 2>/dev/null|awk '(NR>1){print $1*1024}'",$df);
@@ -458,7 +469,7 @@ switch ($themeHelper->getThemeName()) { // $themeHelper set in DefaultPageLayout
458469
<span class='flex flex-row flex-wrap items-center gap-4'>
459470
<span class="head_info">
460471
<span>
461-
<i class='ups fa fa-line-chart'></i>_(Memory)_: <?="$memory_installed $unit $memory_type $ecc"?>
472+
<i class='ups fa fa-line-chart'></i>_(Memory)_: <?="$memory_installed $memory_unit $memory_type $ecc"?>
462473
</span>
463474
</span>
464475
<span class="switch">
@@ -489,7 +500,7 @@ switch ($themeHelper->getThemeName()) { // $themeHelper set in DefaultPageLayout
489500
<div class="tile-system-memory-labels">
490501
<div>
491502
<i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br>
492-
<i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?>
503+
<i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $memory_unit"?><?=$low?'*':''?>
493504
</div>
494505
<div>
495506
<legend>_(Legend)_</legend>

emhttp/plugins/dynamix/scripts/system_information

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,38 +83,57 @@ if (!empty($iommu_groups)) {
8383
$iommu .= '</a>';
8484
}
8585

86+
$normalize_binary_unit = function($value) {
87+
return preg_replace_callback('/\b([KMGTPE]?)(?:i)?B\b/i',function($match) {
88+
$prefix = strtoupper($match[1] ?? '');
89+
return $prefix ? "{$prefix}iB" : 'B';
90+
},$value ?? '');
91+
};
92+
8693
$cache_installed = [];
8794
$cache_devices = dmidecode('Cache Information',7);
88-
foreach ($cache_devices as $device) $cache_installed[] = $device['Socket Designation'].": ".str_replace(['kB','B'],['KB','iB'],$device['Installed Size']);
95+
foreach ($cache_devices as $device) {
96+
$cache_installed[] = $device['Socket Designation'].": ".$normalize_binary_unit($device['Installed Size'] ?? '');
97+
}
8998

9099
/*
91100
Memory Device (16) will get us each ram chip. By matching on MB it'll filter out Flash/Bios chips
92-
Sum up all the Memory Devices to get the amount of system memory installed. Convert MB to GB
101+
Sum up all the Memory Devices to get the amount of system memory installed. Convert MiB to GiB
93102
Physical Memory Array (16) usually one of these for a desktop-class motherboard but higher-end xeon motherboards
94-
might have two or more of these. The trick is to filter out any Flash/Bios types by matching on GB
103+
might have two or more of these. The trick is to filter out any Flash/Bios types by matching on GiB
95104
Sum up all the Physical Memory Arrays to get the motherboard's total memory capacity
96105
Extract error correction type, if none, do not include additional information in the output
97106
If maximum < installed then roundup maximum to the next power of 2 size of installed. E.g. 6 -> 8 or 12 -> 16
98107
*/
99-
$sizes = ['MB','GB','TB'];
108+
$memory_units = [
109+
// dmidecode reports memory capacities using binary math; treat both SI and IEC labels as base-1024.
110+
// This keeps parsing consistent across dmidecode versions that may print GB/TB or GiB/TiB.
111+
'kb' => 1/1024, 'kib' => 1/1024,
112+
'mb' => 1, 'mib' => 1,
113+
'gb' => 1024, 'gib' => 1024,
114+
'tb' => 1048576,'tib' => 1048576,
115+
'pb' => 1073741824, 'pib' => 1073741824
116+
];
117+
$parse_memory_to_mib = function($value) use ($memory_units) {
118+
if (!preg_match('/([0-9.]+)\s*([A-Za-z]+)/',$value ?? '',$match)) return 0;
119+
$size = (float)$match[1];
120+
$unit = strtolower($match[2]);
121+
return isset($memory_units[$unit]) ? (int)round($size*$memory_units[$unit]) : 0;
122+
};
100123
$memory_type = $ecc = '';
101124
$memory_installed = $memory_maximum = 0;
102125
$memory_devices = dmidecode('Memory Device',17);
103126
$modules = 0;
104127
foreach ($memory_devices as $device) {
105128
if (empty($device['Type']) || $device['Type']=='Unknown') continue;
106-
[$size, $unit] = my_explode(' ',$device['Size']);
107-
$base = array_search($unit,$sizes);
108-
if ($base!==false) $memory_installed += $size*pow(1024,$base);
129+
$memory_installed += $parse_memory_to_mib($device['Size'] ?? '');
109130
if (!$memory_type) $memory_type = $device['Type'];
110131
$modules++;
111132
}
112133
$memory = $modules > 1 ? "<span class='link blue-text' onclick=\"$('tr.ram').toggle()\">"._('Memory').":</span>" : _('Memory').':';
113134
$memory_array = dmidecode('Physical Memory Array',16);
114135
foreach ($memory_array as $device) {
115-
[$size, $unit] = my_explode(' ',$device['Maximum Capacity']);
116-
$base = array_search($unit,$sizes);
117-
if ($base>=1) $memory_maximum += $size*pow(1024,$base);
136+
$memory_maximum += $parse_memory_to_mib($device['Maximum Capacity'] ?? '');
118137
if (!$ecc && isset($device['Error Correction Type']) && $device['Error Correction Type']!='None') $ecc = $device['Error Correction Type']." ";
119138
}
120139
if ($memory_installed >= 1048576) {
@@ -152,7 +171,7 @@ span.link{text-decoration:underline;cursor:pointer}
152171
<?
153172
foreach ($memory_devices as $device) {
154173
if (empty($device['Type']) || $device['Type']=='Unknown') continue;
155-
$size = preg_replace('/( .)B$/','$1iB',_var($device,'Size',0));
174+
$size = $normalize_binary_unit(_var($device,'Size',0));
156175
echo "<tr class='ram'><td></td><td>",$device['Locator'],": ",_var($device,'Manufacturer')," ",_var($device,'Part Number'),", $size ",_var($device,'Type')," @ ",_var($device,'Configured Memory Speed'),"</td></tr>";
157176
}
158177

0 commit comments

Comments
 (0)