LingSys
↓ 0 downloadsYour machine's memory, GPU, motherboard and network, drawn and played in the Ling design system: LingSys, a small build for USB liquid-cooler displays, LingNet for IPv4/IPv6, DNS and packets, and a LingOS edition. 64-bit and 32-bit Windows builds included.
Keywords system-monitor, visualization, network, ipv6, gpu, lcd, lingos, ling
lingfu install LingSysCode / Files (48)
sampler.ps1
# HatchMEM sampler: writes a small text snapshot of Windows memory counters for hatchmem.ling.
#
# Ling has no builtin that reads operating-system memory, so this script is the only bridge.
# It never touches process memory: it reads the same performance counters Task Manager shows.
# Output (mem.snap, replaced atomically each tick), one record per line, fields split by '|':
# t|<unix seconds>
# g|total|avail|free|standby|modified|nonpaged|paged|compressed|committed|commit_limit|cache (MB)
# r|faults|reads|writes|pages_in|pages_out|demand_zero|cache_faults|copy_writes (per second)
# p|name|pid|working_set|private|io_read|io_write|faults (MB, MB, KB/s, KB/s, /s)
param(
[string]$Out = (Join-Path $PSScriptRoot 'mem.snap'),
[double]$Interval = 0.5,
[int]$Top = 28,
[switch]$Once,
[int]$ParentPid = 0 # exit when this process is gone (the exe starts the samplers and passes its own id)
)
$ErrorActionPreference = 'Stop'
$MB = 1MB
$total = [double](Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory
$inv = [Globalization.CultureInfo]::InvariantCulture
function F($v) { ([double]$v).ToString('0.##', $inv) }
do {
if ($ParentPid -gt 0 -and -not (Get-Process -Id $ParentPid -ErrorAction SilentlyContinue)) { break }
$t0 = Get-Date
$m = Get-CimInstance Win32_PerfFormattedData_PerfOS_Memory
$procs = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
Where-Object { $_.Name -ne '_Total' -and $_.Name -ne 'Idle' }
$zip = ($procs | Where-Object { $_.Name -eq 'Memory Compression' } | Select-Object -First 1).WorkingSetPrivate
$standby = [double]$m.StandbyCacheCoreBytes + $m.StandbyCacheNormalPriorityBytes + $m.StandbyCacheReserveBytes
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add('t|' + [DateTimeOffset]::UtcNow.ToUnixTimeSeconds())
$lines.Add('g|' + (@($total, $m.AvailableBytes, $m.FreeAndZeroPageListBytes, $standby, $m.ModifiedPageListBytes,
$m.PoolNonpagedBytes, $m.PoolPagedBytes, $zip, $m.CommittedBytes, $m.CommitLimit, $m.CacheBytes |
ForEach-Object { F ($_ / $MB) }) -join '|'))
$lines.Add('r|' + (@($m.PageFaultsPersec, $m.PageReadsPersec, $m.PageWritesPersec, $m.PagesInputPersec,
$m.PagesOutputPersec, $m.DemandZeroFaultsPersec, $m.CacheFaultsPersec, $m.WriteCopiesPersec |
ForEach-Object { F $_ }) -join '|'))
# Private bytes of everything (for the DATA slice), then the biggest few for the process views.
$privAll = ($procs | Measure-Object WorkingSetPrivate -Sum).Sum
$lines.Add('s|' + (F ($privAll / $MB)) + '|' + $procs.Count)
foreach ($p in ($procs | Sort-Object WorkingSet -Descending | Select-Object -First $Top)) {
$name = ($p.Name -replace '[|#\r\n]', '_')
$lines.Add('p|' + $name + '|' + $p.IDProcess + '|' + (F ($p.WorkingSet / $MB)) + '|' +
(F ($p.WorkingSetPrivate / $MB)) + '|' + (F ($p.IOReadBytesPersec / 1KB)) + '|' +
(F ($p.IOWriteBytesPersec / 1KB)) + '|' + (F $p.PageFaultsPersec))
}
$tmp = "$Out.tmp"
[IO.File]::WriteAllText($tmp, ($lines -join "`n") + "`n")
Move-Item -Force $tmp $Out
if ($Once) { break }
$left = $Interval - ((Get-Date) - $t0).TotalSeconds
if ($left -gt 0) { Start-Sleep -Milliseconds ([int]($left * 1000)) }
} while ($true)