mem() added reclaimable (Linux, macOS)

This commit is contained in:
Sebastian Hildebrandt 2025-05-24 06:52:52 +02:00
parent 5b79685f5e
commit 63b01c4418
8 changed files with 76 additions and 16 deletions

View File

@ -90,6 +90,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page.
| Version | Date | Comment |
| ------- | ---------- | --------------------------------------------------------------------------------------------------- |
| 5.27.0 | 2025-05-24 | `mem()` added reclaimable (Linux, macOS) |
| 5.26.2 | 2025-05-23 | `memLayout()` manufacturers reference updated |
| 5.26.1 | 2025-05-22 | `inetChecksite()` fix timeout |
| 5.26.0 | 2025-05-21 | `getStatic()` added audio, usb, bluetooth, printer |

View File

@ -31,9 +31,9 @@
## The Systeminformation Project
This is amazing. Started as a small project just for myself, it now has > 17,000
lines of code, > 650 versions published, up to 8 mio downloads per month, > 330
mio downloads overall. #1 NPM ranking for backend packages. Thank you to all who
contributed to this project!
lines of code, > 650 versions published, up to 8 mio downloads per month, > 350
mio downloads overall. Top 10 NPM ranking for backend packages. Thank you to all
who contributed to this project!
> **Upcoming Version 6** ⭐️⭐️⭐️
>
@ -163,6 +163,7 @@ si.cpu()
(last 7 major and minor version releases)
- Version 5.27.0: `mem()` added reclaimable memory
- Version 5.26.0: `getStatic()`, `getAll()` added usb, audio, bluetooth, printer
- Version 5.25.0: `versions()` added homebrew
- Version 5.24.0: `versions()` added bun and deno
@ -338,6 +339,7 @@ Full function reference with examples can be found at
| | buffers | X | | | | | used by buffers |
| | cached | X | | | | | used by cache |
| | slab | X | | | | | used by slab |
| | reclaimable | X | | X | | | reclaimable (SReclaimable) |
| | available | X | X | X | X | X | potentially available (total - active) |
| | swaptotal | X | X | X | X | X | |
| | swapused | X | X | X | X | X | |

View File

@ -57,6 +57,11 @@
</tr>
</thead>
<tbody>
<tr>
<th scope="row">5.27.0</th>
<td>2024-05-24</td>
<td><span class="code">mem()</span> added reclaimable (linux, macOS)</td>
</tr>
<tr>
<th scope="row">5.26.2</th>
<td>2024-05-23</td>

View File

@ -170,7 +170,7 @@
<img class="logo" src="assets/logo.png" alt="logo">
<div class="title">systeminformation</div>
<div class="subtitle"><span id="typed"></span>&nbsp;</div>
3<div class="version">New Version: <span id="version">5.26.2</span></div>
3<div class="version">New Version: <span id="version">5.27.0</span></div>
<button class="btn btn-light" onclick="location.href='https://github.com/sebhildebrandt/systeminformation'">View on Github <i class=" fab fa-github"></i></button>
</div>
<div class="down">

View File

@ -157,6 +157,16 @@
<td></td>
<td>used by slab</td>
</tr>
<tr>
<td></td>
<td>reclaimable</td>
<td>X</td>
<td></td>
<td>X</td>
<td></td>
<td></td>
<td>reclaimable</td>
</tr>
<tr>
<td></td>
<td>available</td>

View File

@ -575,7 +575,7 @@ function blockDevices(callback) {
if (_linux) {
// see https://wiki.ubuntuusers.de/lsblk/
// exec("lsblk -bo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,TRAN,SERIAL,LABEL,MODEL,OWNER,GROUP,MODE,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC,SCHED,RQ-SIZE,RA,WSAME", function (error, stdout) {
exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,TRAN,SERIAL,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procLsblk1 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,TRAN,SERIAL,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = blkStdoutToObject(stdout).split('\n');
data = parseBlk(lines);
@ -586,7 +586,7 @@ function blockDevices(callback) {
}
resolve(data);
} else {
exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procLsblk2 = exec('lsblk -bPo NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT,UUID,ROTA,RO,RM,LABEL,MODEL,OWNER 2>/dev/null', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = blkStdoutToObject(stdout).split('\n');
data = parseBlk(lines);
@ -597,11 +597,23 @@ function blockDevices(callback) {
}
resolve(data);
});
procLsblk2.on('error', function () {
if (callback) {
callback(data);
}
resolve(data);
});
}
});
procLsblk1.on('error', function () {
if (callback) {
callback(data);
}
resolve(data);
});
}
if (_darwin) {
exec('diskutil info -all', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procDskutil = exec('diskutil info -all', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
// parse lines into temp array of devices
@ -613,6 +625,12 @@ function blockDevices(callback) {
}
resolve(data);
});
procDskutil.on('error', function () {
if (callback) {
callback(data);
}
resolve(data);
});
}
if (_sunos) {
if (callback) { callback(data); }
@ -747,7 +765,7 @@ function fsStats(callback) {
if ((_fs_speed && !_fs_speed.ms) || (_fs_speed && _fs_speed.ms && Date.now() - _fs_speed.ms >= 500)) {
if (_linux) {
// exec("df -k | grep /dev/", function(error, stdout) {
exec('lsblk -r 2>/dev/null | grep /', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procLsblk = exec('lsblk -r 2>/dev/null | grep /', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
let fs_filter = [];
@ -759,7 +777,7 @@ function fsStats(callback) {
});
let output = fs_filter.join('|');
exec('cat /proc/diskstats | egrep "' + output + '"', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procCat = exec('cat /proc/diskstats | egrep "' + output + '"', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
@ -778,6 +796,12 @@ function fsStats(callback) {
}
resolve(result);
});
procCat.on('error', function () {
if (callback) {
callback(result);
}
resolve(result);
});
} else {
if (callback) {
callback(result);
@ -785,9 +809,16 @@ function fsStats(callback) {
resolve(result);
}
});
procLsblk.on('error', function () {
if (callback) {
callback(result);
}
resolve(result);
});
}
if (_darwin) {
exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
const procIoreg = exec('ioreg -c IOBlockStorageDriver -k Statistics -r -w0 | sed -n "/IOBlockStorageDriver/,/Statistics/p" | grep "Statistics" | tr -cd "01234567890,\n"', { maxBuffer: 1024 * 1024 }, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
@ -806,6 +837,12 @@ function fsStats(callback) {
}
resolve(result);
});
procIoreg.on('error', function () {
if (callback) {
callback(result);
}
resolve(result);
});
}
} else {
result.ms = _fs_speed.last_ms;

1
lib/index.d.ts vendored
View File

@ -123,6 +123,7 @@ export namespace Systeminformation {
buffers: number;
cached: number;
slab: number;
reclaimable: number;
swaptotal: number;
swapused: number;
swapfree: number;

View File

@ -31,13 +31,13 @@ const _sunos = (_platform === 'sunos');
const RAM_manufacturers = {
'00CE': 'Samsung Electronics Inc',
'014F': 'Transcend Information',
'017A': 'Apacer Technology Inc',
'014F': 'Transcend Information Inc.',
'017A': 'Apacer Technology Inc.',
'0198': 'HyperX',
'029E': 'Corsair',
'02FE': 'Elpida',
'04CB': 'A-DATA',
'04CD': 'G-Skill International Enterprise',
'04CD': 'G.Skill International Enterprise',
'059B': 'Crucial',
'1315': 'Crucial',
'2C00': 'Micron Technology Inc.',
@ -52,6 +52,7 @@ const RAM_manufacturers = {
'SAMSUNG': 'Samsung Electronics Inc.',
'HYNIX': 'Hynix Semiconductor Inc.',
'G-SKILL': 'G-Skill International Enterprise',
'G.SKILL': 'G-Skill International Enterprise',
'TRANSCEND': 'Transcend Information',
'APACER': 'Apacer Technology Inc',
'MICRON': 'Micron Technology Inc.',
@ -151,6 +152,7 @@ function mem(callback) {
cached: 0,
slab: 0,
buffcache: 0,
reclaimable: 0,
swaptotal: 0,
swapused: 0,
@ -191,6 +193,8 @@ function mem(callback) {
result.writeback = result.writeback ? result.writeback * 1024 : 0;
result.dirty = parseInt(util.getValue(lines, 'dirty'), 10);
result.dirty = result.dirty ? result.dirty * 1024 : 0;
result.reclaimable = parseInt(util.getValue(lines, 'sreclaimable'), 10);
result.reclaimable = result.reclaimable ? result.reclaimable * 1024 : 0;
}
if (callback) { callback(result); }
resolve(result);
@ -242,11 +246,11 @@ function mem(callback) {
util.noop();
}
try {
exec('vm_stat 2>/dev/null | grep "Pages active"', function (error, stdout) {
exec('vm_stat 2>/dev/null | egrep "Pages active|Pages inactive"', function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.active = parseInt(lines[0].split(':')[1], 10) * pageSize;
result.active = (parseInt(util.getValue(lines, 'Pages active'), 10) || 0) * pageSize;
result.reclaimable = (parseInt(util.getValue(lines, 'Pages inactive'), 10) || 0) * pageSize;
result.buffcache = result.used - result.active;
result.available = result.free + result.buffcache;
}