Skip to content
| Marketplace
Sign in
Visual Studio Code>Visualization>System Monitor Status BarNew to Visual Studio Code? Get it now.
System Monitor Status Bar

System Monitor Status Bar

Leterme Florent

|
38 installs
| (0) | Free
CPU, GPU, disk, memory, swap, power draw and battery in the status bar, as coloured progress bars with live values.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

System Monitor Status Bar

Is it your build, or is it your machine? CPU, GPU, disk, system memory, swap, power draw and battery as real coloured progress bars in the VS Code status bar, on whichever side you want them.

CPU, GPU, disk and memory in the VS Code status bar

The problem

Something is slow, and you have no idea which resource ran out. Alt-tabbing to Task Manager tells you three seconds later, about a moment that has already passed, in a window that now has focus and is itself skewing the reading. Meanwhile the monitors that do live in the editor tend to cost more than what they measure: one of them shells out to PowerShell on every refresh and burns nearly three seconds of wall time per tick to tell you your CPU is busy.

What you get

CPU, GPU, memory, swap, power draw, battery and one group per disk, always visible, updating on their own:

CPU ▓▓░░░ 34%   GPU ░░░░░ 12%   C: ▓▓░░░ 43%   D: ░░░░░ 8%   RAM ▓▓░░░ 12.35 / 31.74 GB   SWAP ▓░░░░ 1.20 / 8.00 GB   PWR ▓░░░░ 40 W   BAT ▓▓▓▓░ 81%

The last two only appear where they can be measured: PWR on Linux, BAT on a machine that has a battery.

Every disk gets its own group, labelled with its own name: volume letters on Windows, the device name on Linux (sda, nvme0n1). Which ones appear is up to you, through System Monitor: Choose the disks shown or the diskDevices setting.

CPU and GPU work the same way. By default each is a single group, the average of every logical core and the sum of every graphics adapter. System Monitor: Choose the CPU cores shown and System Monitor: Choose the GPUs shown add one group per core (C0, C1...) or per adapter (GPU0, GPU1 on Windows and with nvidia-smi, card0 on Linux), with or without the global group next to them. On Windows a laptop often reports a second, virtual adapter that stays at zero: that is why the default keeps the sum.

Bars are drawn with an embedded icon font, sharing the exact glyphs and fill algorithm of Claude Rate Limit Status Bar so both extensions read as one band. Colour lives on the bar alone: green below 50 %, yellow below 75 %, orange below 90 %, red at 90 % and above. Labels and readings follow statusBar.foreground, which keeps them legible on light and dark themes alike.

One setting moves every group from left to right and back, with no window reload. Memory is shown in GB to two decimals, used against total, because "78 %" does not tell you whether the 4 GB you are about to allocate will fit. Values are padded to a fixed width with figure spaces, trailing, so each reading sits the same distance from its bar and going from 9 % to 100 % does not slide the whole band along.

Hovering gives the processor model, core count, used, free and total memory and swap, and the age of the last GPU sample. Each disk group carries its full instance name, which the label shortens, and a link to pick which disks are shown.

Where the numbers come from

CPU and memory come from Node's own os module, so no process is spawned and the cost is not measurable. This part is identical on Windows, Linux and macOS. CPU is the average across every logical core, computed by differencing cumulative counters between two refreshes, which is why the first tick shows --: a rate needs two samples.

GPU and disk are platform-specific, each with its own source.

On Windows, both come from performance counters read through a single long-lived typeperf process. GPU is 3D engine utilisation; disk is queried per physical device (0 C:, 1 D:, and so on) plus the _Total instance Windows already aggregates.

typeperf only accepts localised counter names, so \PhysicalDisk(_Total)\% Disk Time is rejected outright on a French Windows. It does however accept a list in which only some counters resolve, as long as one of them does. Every known spelling is passed at once and the columns are resolved from the CSV header it returns, which keeps it to one process and one code path across locales.

On Linux, disk comes from /proc/diskstats: field 13 is the milliseconds spent doing I/O on that device, the same counter iostat derives %util from. Reading it needs no process at all, just a file read, cheaper than the Windows path. Every whole disk is read individually, partitions and virtual devices such as loop0 or dm-0 excluded.

GPU on Linux is auto-detected once at startup, in this order: /sys/class/drm/card*/device/gpu_busy_percent if the kernel exposes it, which covers AMD's amdgpu driver and some newer Intel setups, otherwise nvidia-smi if it resolves on PATH. Unlike the Windows probe, nvidia-smi is invoked once per refresh rather than streamed, because its own startup cost is a few tens of milliseconds, negligible next to the nearly three seconds a spawned PowerShell process costs, which is exactly what streaming was built to avoid on Windows. If neither source is available, the group greys out with --, the same degraded state as a missing typeperf.

On macOS, GPU comes from ioreg, reading the PerformanceStatistics dictionary of the graphics accelerator. Both AGXAccelerator (Apple Silicon) and IOAccelerator (Intel and AMD) are tried, and the first one that answers is kept. Disk is deliberately left unmeasured and shows n/a: macOS exposes no occupancy percentage without privileges, since iostat reports throughput rather than busy time and fs_usage needs root. Turning a throughput into a percentage would produce a number that looks right and means nothing.

Memory and swap

On Windows and macOS, free memory is what Node's os.freemem() reports. On Linux the extension reads MemAvailable from /proc/meminfo instead, because os.freemem() returns MemFree, which leaves out the page cache the kernel hands back on demand and makes a healthy machine look nearly full.

Swap comes from /proc/meminfo on Linux and from sysctl -n vm.swapusage on macOS. On Windows the usage percentage is one more counter in the typeperf process already running, \Paging File(_Total)\% Usage, and the allocated size is read once from Win32_PageFileUsage when the extension starts. On a French Windows typeperf only accepts the counter as \Fichier d’échange(_Total)\Pourcentage d’utilisation, typographic apostrophes included, so both spellings are passed. A machine with no paging file or no swap shows the group greyed out with aucune or off.

Power and battery

PWR adds up what the processor and the graphics card draw, in watts. It is not the whole machine at the wall: screen, motherboard, disks and fans have no sensor a program can read, and the tooltip says so. The processor figure comes from the RAPL energy counter under /sys/class/powercap, a running total in microjoules, so like CPU it needs two ticks before showing a number. AMD and Intel graphics cards report their draw directly through hwmon (power1_average). The bar is full at sysmon.powerMaxWatts, 270 W by default, which is a 182 W graphics card plus a desktop processor at its peak; the power supply rating is a fair value to put there instead. Windows and macOS expose no such counter without administrator rights or a kernel driver, so the group stays hidden there, as it does on a Linux box where neither sensor exists. An NVIDIA card is not counted yet.

BAT shows the remaining charge with an icon for the direction of the current: a bolt while charging, a down arrow on battery, a plug when it sits full on the charger. Its colour runs the other way from the other groups, red when the charge is low. Linux reads /sys/class/power_supply, skipping the batteries of mice and headsets; macOS asks pmset -g batt every 30 seconds; Windows asks Win32_Battery once a minute, through the same kind of short PowerShell call the paging file size uses, since a battery moves slowly. A desktop has no battery and never shows the group.

Why the Windows GPU probe streams instead of querying per tick

Three approaches were measured on the reference machine, an AMD Radeon integrated GPU with no nvidia-smi:

Approach Resident memory CPU burned Latency per tick
typeperf streaming 12.1 MB 0.42 s over 6 s, startup included none, pushed
PowerShell Get-Counter daemon 76 to 91 MB 2.05 s over 12 s none, pushed
Get-Counter spawned per tick none ~2.8 s wall per tick 2.8 s

A monitor that costs more than what it measures is worse than no monitor, which rules out the third row, and the second one wants 90 MB to report on your memory.

The catch: typeperf freezes its counter instance set at startup, so a program that starts using the GPU afterwards would never appear. The probe is recycled every five minutes to pick those up, and sysmon.probeRestartSeconds tunes that.

What it costs to run

The display only writes to the status bar when something actually changed. Labels never change and a bar only moves when it crosses a fill step, so most ticks push nothing at all across the bridge to the UI process.

Tooltips are rebuilt on their own schedule, five seconds by default, rather than once per tick. VS Code does not refresh a tooltip while it is being hovered, so rebuilding four of them every two seconds served nobody.

Only one window measures. The others read what it published, through a lease file in the temp directory, so three open windows cost one probe instead of three while all three keep showing live values. If the window holding the lease closes, another takes over; if it is killed outright, the lease expires after eight seconds. Set shareProbe to false to give every window its own probe.

Languages

Commands, settings and tooltips are in English, and in French when VS Code runs in French. Group labels (CPU, GPU, RAM, SWAP, disk names) stay the same in every language so the band keeps its width.

Every status bar item has a name, shown when you right-click the status bar to hide it, and a screen reader description such as "CPU: 34 percent".

Privacy

No telemetry, no analytics, no network access of any kind. The extension reads two Node built-ins and, depending on platform, a Windows performance counter, a Linux sysfs or proc file, or the macOS registry through ioreg, all locally. Nothing leaves the machine.

Settings

Setting Default Description
sysmon.alignment "left" Which side of the status bar to use, left or right. Applied without a reload
sysmon.refreshSeconds 2 Display refresh interval, in seconds (clamped to 1-60)
sysmon.barWidth 5 Bar width, in cells (clamped to 4-20)
sysmon.showCpu true Show the CPU group
sysmon.showGpu true Show the GPU group
sysmon.showDisk true Show the disk groups, one per physical device
sysmon.showRam true Show the RAM group
sysmon.showSwap true Show the SWAP group: paging file on Windows, swap on Linux and macOS
sysmon.showPower true Show the PWR group, processor and graphics card power in watts. Linux only, hidden when no sensor is found
sysmon.showBattery true Show the BAT group, remaining charge with a charging or discharging icon. Hidden without a battery
sysmon.powerMaxWatts 270 Power that fills the PWR bar, in watts (clamped to 10-5000)
sysmon.ramValue "used" What the RAM group shows: used for used against total, free for free memory alone (19.39 GB free)
sysmon.diskDevices [] Disks to display, by name ("0 C:" on Windows, "sda" on Linux). Empty means every disk seen, so one plugged in later still shows up. Easiest to set through the System Monitor: Choose the disks shown command rather than typed by hand
sysmon.cpuDevices [] CPU groups to display: "all" for the average, then logical core numbers ("0", "1"). Empty means the average alone
sysmon.gpuDevices [] GPU groups to display: "all" for the sum of every adapter, then adapter ids ("0" on Windows, "card0" on Linux). Empty means the sum alone. Windows numbers adapters by LUID order, which is usually stable across reboots but not guaranteed
sysmon.showLabels true Show the CPU / GPU / DISK / RAM / SWAP label of each group
sysmon.showBars true Show the progress bar of each group
sysmon.showValues true Show the numeric value of each group
sysmon.probeRestartSeconds 300 Probe recycle interval, in seconds (minimum 60)
sysmon.tooltipSeconds 5 How often tooltips are rebuilt, in seconds
sysmon.shareProbe true Share a single probe across every VS Code window
sysmon.pauseWhenUnfocused false Stop the probe while the window has no focus. VS Code cannot tell a hidden window from a visible inactive one, so this greys out windows on a second screen
sysmon.unfocusedMultiplier 1 Refresh interval multiplier while the window has no focus

Turning off both showGpu and showDisk stops the probe entirely, so on Windows no typeperf process is spawned, and on Linux with an NVIDIA card no nvidia-smi invocation happens. Turning off both showBars and showValues hides every group, label included, since a lone label says nothing.

Some combinations worth knowing:

everything on              CPU ▓▓░░░ 34%   GPU ░░░░░ 12%   RAM ▓▓░░░ 12.35 / 31.74 GB
showLabels false           ▓▓░░░ 34%   ░░░░░ 12%   ▓▓░░░ 12.35 / 31.74 GB
showBars false             CPU 34%   GPU 12%   RAM 12.35 / 31.74 GB
showValues false           CPU ▓▓░░░   GPU ░░░░░   RAM ▓▓░░░
showCpu/showGpu false      DISK ▓░░░░ 11%   RAM ▓▓░░░ 12.35 / 31.74 GB

Commands

Command What it does
System Monitor: Restart the GPU/disk probe Restarts the probe immediately, from the command palette
System Monitor: Choose the disks shown Checklist of every disk seen so far. Leave everything checked for the default, where every disk counts, or uncheck some to only count the ones left. Also reachable from the DISK hover
System Monitor: Choose the CPU cores shown Checklist of the global average and every logical core. Also reachable from the CPU hover
System Monitor: Choose the GPUs shown Checklist of the global sum and every adapter seen by the probe. Also reachable from the GPU hover

Troubleshooting

If the bars render as empty boxes, restart VS Code. The icon font is loaded at startup, and a freshly installed extension does not get it until then.

If GPU or DISK shows -- in grey and stays there: on Windows, typeperf could not start or neither spelling of the counter resolved. Check it by hand with typeperf "\GPU Engine(*engtype_3D)\Utilization Percentage" -si 2 -sc 2, and on builds where the performance counters have been disabled or corrupted, lodctr /R rebuilds them. On Linux, GPU stays -- when neither gpu_busy_percent nor nvidia-smi was found at startup; run System Monitor: Restart the GPU/disk probe after installing drivers to re-detect without restarting the window. /proc/diskstats is present on every real Linux kernel, so DISK staying -- there points at something else, most likely a container or an unusually locked-down /proc.

On macOS, DISK showing n/a is expected and permanent, since the platform exposes no occupancy percentage without privileges. GPU showing n/a means neither accelerator class answered; ioreg -r -d 1 -w 0 -c AGXAccelerator | grep Utilization tells you whether the counter exists on your hardware.

A group greyed out with a stale number means no sample has arrived for thirty seconds. Run System Monitor: Restart the GPU/disk probe from the command palette.

CPU sitting at -- is only expected on the very first tick. If it persists, the refresh timer is not firing: check that sysmon.refreshSeconds is a number and not a string.

Each VS Code window runs its own extension host, but since 0.7.0 they share one probe through a lease file, so only one of them actually measures. Turning off both sysmon.showGpu and sysmon.showDisk spawns no process at all.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft