Joular Core is a platform to measure power and energy across all systems and devices.
It measures CPU and GPU power consumption in real time, and can break that down to individual processes or applications. Joular Core runs on Linux, Windows, macOS, Raspberry Pi, and inside virtual machines.
It is written in Rust and compiles to a native binary with minimal overhead. It ships with both a command-line interface and a graphical user interface, and can export data to CSV files, a shared-memory ring buffer, and an HTTP/WebSocket API.
Full documentation (user and reference guides) are available at: https://joular.github.io/joularcore/.
Joular Core is under active development and currently in beta quality. Expect rough edges and features still being worked on and polished.
- π» Supported Systems: π§ Linux, πͺ Windows, π MacOS, π Raspberry Pi, π½ Virtual Machines.
- βοΈ Supported Architectures: x86_64 (amd64), x86/i686, aarch64, arm, armv7, GPUs (Nvidia, Apple, AMD).
CPU:
| OS / Architecture | x86_64 | i686 | Apple Silicon | arm | armv7 | aarch64 |
|---|---|---|---|---|---|---|
| Linux | β | β | ||||
| Windows | β | β | ||||
| macOS | β | β | ||||
| SBC (Raspberry Pi) | β | β | β | |||
| Virtual Machines | β | β | β | β | β | β |
GPU:
| OS / Architecture | Nvidia | AMD | Apple GPU |
|---|---|---|---|
| Linux | β | β | |
| Windows | β | β | |
| macOS | β | ||
| SBC (Raspberry Pi) | |||
| Virtual Machines | β | β | β |
Supported SBC platforms: Raspberry Pi (models: Zero W, 1 B, 1 B+, 2 B, 3 B, 3 B+, 4 B, 400, 5 B), Asus Tinker Board S.
- π Real-time CPU and GPU power monitoring on PCs, servers, and single-board computers
- π Monitor power from inside virtual machines using data from the hypervisor or an external meter
- π Per-process power monitoring: track the energy consumption of a specific PID
- π Per-application power monitoring: track a named application across all its processes, with variable refresh interval
- π Export power data to CSV files (append or overwrite mode)
- π Write power data to a shared-memory ring buffer for low-latency IPC with other programs
- π Expose power data over HTTP (GET
/data) and WebSocket (/ws) endpoints - βοΈ Filter output to only show CPU power, GPU power, or both
- βοΈ CPU idle baseline calibration: automatically or manually subtract idle CPU power before attributing it to a process or application
- βοΈ Linux systemd service for running as a daemon
- β¨οΈ Command-line interface (CLI) with colored, human-readable output or a stripped numeric-only mode
- π¨ Graphical user interface (GUI) built with egui, with live power graphs and 60-second history
Joular Core is written in Rust and uses Cargo for compilation.
cargo build --releaseProduces the joularcore CLI binary and the joularcoregui GUI binary, with virtual machine support, HTTP/WebSocket API, and GUI all enabled.
cargo build --release --features sbcAdds support for single-board computers. This replaces RAPL-based CPU monitoring with our regression models specific to each supported SBC platform.
You can build Joular Core with or without virtual machine support or the GUI. For instance, this is useful when you don't need the GUI (i.e., in server environments) and want to build a smaller binary.
Use --no-default-features to start from a minimal build and add only what you need:
# Minimal: CLI only, no VM support, no API, no GUI
cargo build --release --no-default-features
# CLI with VM support but no GUI or API
cargo build --release --no-default-features --features vm
# CLI with VM and API but no GUI
cargo build --release --no-default-features --features vm,api
# SBC with GUI but no VM or API
cargo build --release --no-default-features --features gui,sbcβοΈ Available Features:
| Feature | Default | Description |
|---|---|---|
vm |
on | Monitor power inside virtual machines using files written by the hypervisor or an external meter |
api |
on | HTTP and WebSocket API server. CSV and ring buffer export work regardless of this feature. |
gui |
on | Graphical user interface |
sbc |
off | Single-board computer support with SBC-specific power models. This disables RAPL-based monitoring for our SBC-specific regression models |
Use cargo-make with the targets defined in Makefile.toml. For example, to build for all supported Raspberry Pi architectures (aarch64, arm, armv7):
cargo make build-sbcOn most platforms, no configuration is needed. Joular Core detects the platform, finds the right power interface, and starts measuring.
Linux (PC / servers)
Reads CPU power via the Intel RAPL package interface (/sys/class/powercap/intel-rapl/). These files are typically readable only by root, so either run Joular Core with sudo or grant read access to the RAPL files. See this issue for details. If RAPL is unavailable or unreadable, Joular Core warns and continues with CPU power reported as 0 W.
GPU power is read via nvidia-smi (Nvidia) or amd-smi / rocm-smi (AMD) if installed.
Windows
CPU power requires Hubblo's RAPL driver, used through the Scaphandre driver interface. The easiest way to install a signed version is through the Scaphandre installer. Once the driver is installed, Joular Core runs without administrator rights.
GPU power is read via nvidia-smi and amd-smi.
macOS
No additional dependencies. Uses powermetrics, which is installed by default on macOS, but requires elevated access to read power data. The CLI should be run with sudo; the GUI can ask for elevation. Apple Silicon GPU power is read through the same interface.
Raspberry Pi / SBC
No dependencies and no sudo required when built with the sbc feature. CPU power is calculated using regression models tuned for each supported board. Unsupported boards report 0 W. GPU is not supported on SBC platforms.
Set environment variables to point Joular Core at a file written by the hypervisor or an external power meter:
| Variable | Description |
|---|---|
VM_CPU_POWER_FILE |
Path to the CPU power data file |
VM_CPU_POWER_FORMAT |
Format of that file: joularcore, powerjoular, or watts (default: watts) |
VM_GPU_POWER_FILE |
Path to the GPU power data file |
VM_GPU_POWER_FORMAT |
Format of that file: joularcore, powerjoular, or watts (default: watts) |
Formats:
watts: a plain text file containing a single numeric value (watts).powerjoular: CSV with three columns; power is in the third column. This is the default output of PowerJoular.joularcore: CSV with a header row matching Joular Core CSV output. Joular Core reads the last data row. For CPU power it prefersApp Power (W), thenProcess Power (W), thenCPU Power (W); for GPU power it readsGPU Power (W).
By default, Joular Core ships with our built-in regression models for all supported Raspberry Pi boards. If you want to use your own model, set:
SBC_POWER_MODEL_JSON=/path/to/model.json
The JSON file format must match the one used in the Joular Power Models Database.
Run joularcore --help for a complete list. The main options are:
| Option | Description |
|---|---|
-p, --pid <PID> |
Monitor a specific process by PID |
-a, --app <APP> |
Monitor an application by name (covers all its processes) |
-f, --file <FILE> |
Write output to a file. CSV is used by default; with -i, the file receives numeric-only values. |
-o, --overwrite |
With -f, truncate before each write so only the latest data row/value is kept |
-c, --component <cpu|gpu> |
Show only CPU or only GPU power |
-i, --numeric |
Output only the numeric value, no formatting or labels |
-s, --silent |
Suppress terminal output (file, ring buffer, and API still work) |
-g, --gui |
Start the graphical user interface |
-r, --ringbuffer |
Write power data to the shared-memory ring buffer |
--api-port <PORT> |
Start the HTTP and WebSocket API server on this port |
--api-allowed-origin <ORIGIN> |
Allow an extra CORS origin for the API (repeatable). Localhost is always allowed. |
--app-refresh-interval <SECONDS> |
How often to rescan for new PIDs belonging to an application (default: 3s; set to 0 to rescan every second) |
--cpu-idle-baseline <WATTS> |
Subtract a fixed idle CPU baseline before attributing power to a PID or application |
--calibrate-cpu-idle-baseline |
Measure idle CPU power automatically (5 samples, 1 second each) and use that as the baseline |
Notes:
--pidand--appare mutually exclusive.--cpu-idle-baselineand--calibrate-cpu-idle-baselineare mutually exclusive.-oonly has effect when used with-f.- In the CLI,
-g/--guiconflicts with--pid,--app,--file,--overwrite,--silent, and--numeric. - When
-fis used, the live terminal display is replaced by file output.
# Monitor system power
joularcore
# Monitor a specific process
joularcore -p 1234
# Monitor an application by name, write to CSV
joularcore -a firefox -f power.csv
# Run silently, write to CSV, expose via API
joularcore -s -f power.csv --api-port 8080
# Only show CPU power, numeric output
joularcore -c cpu -i
# Launch the GUI (configure everything from inside the GUI)
joularcore -g
# Subtract idle CPU baseline when attributing process power
joularcore -p 1234 --calibrate-cpu-idle-baselineJoular Core is also available with a graphical user interface (GUI), written in Rust (egui library), and which works seamlessly and in a coherent way across all platforms and operating systems.
The GUI can be started in two ways:
- Pass
-gor--guito the CLI:joularcore --guiorjoularcore -g - Launch the GUI binary directly:
joularcoregui(orjoularcoregui.exeon Windows)
The GUI shows real-time CPU power, GPU power, total power, and CPU usage, along with a 60-second rolling history graph. From the options screen you can select which process or application to monitor, choose which component to display (CPU, GPU, or both), enable CSV export, configure the API port and ring buffer, and calibrate the CPU idle baseline β no terminal required.
When --gui is used from the CLI, monitoring target, CSV export, component filtering, and pause/start behavior are configured in the GUI. The --gui flag conflicts with terminal/file-oriented options (--pid, --app, --file, --overwrite, --silent, and --numeric), but startup options such as --ringbuffer, --api-port, --api-allowed-origin, --app-refresh-interval, and the CPU idle baseline flags can still preconfigure the GUI session.
When run with -r or --ringbuffer, Joular Core writes power data to a shared-memory region that other programs can read directly β no file I/O or network overhead.
Default paths:
| OS | Path |
|---|---|
| Linux | /dev/shm/joularcorering |
| macOS | /tmp/joularcorering |
| Windows | Local\\JoularCoreRing |
The shared memory region starts with an 8-byte native-endian u64 head counter, followed by 5 slots. Each slot is a C-compatible RingBufferStruct containing timestamp (u64, Unix seconds), CPU power (f64, watts), GPU power (f64, watts), Total power (f64, watts), CPU usage (f64, percent), and PID or app power (f64, watts). Fields that are not applicable to the current monitoring mode (for example, per-process power when not monitoring a process) are set to 0. Consumers can compare timestamp against the current time to detect stale or paused samples.
When built with the api feature (on by default), Joular Core can expose power data over a local HTTP and WebSocket server.
joularcore --api-port 8080Endpoints:
| Endpoint | Protocol | Description |
|---|---|---|
/data |
HTTP GET | Returns the latest power reading as JSON |
/ws |
WebSocket | Streams a new JSON reading every second |
JSON fields:
| Field | Type | Description |
|---|---|---|
timestamp |
integer | Unix timestamp (seconds) |
cpu_power |
float | CPU power in watts |
gpu_power |
float | GPU power in watts |
total_power |
float | Total (CPU + GPU) power in watts |
cpu_usage |
float | System CPU usage as a percentage |
pid_or_app_power |
float | Power for the monitored PID or application in watts (0 if not set) |
The server binds to 127.0.0.1 only. CORS is locked down to http://127.0.0.1:<port> and http://localhost:<port> by default, so no other website can read your power data through the browser. To allow an additional origin (for example, a self-hosted dashboard), use --api-allowed-origin β the flag is repeatable. Passing * allows any origin.
joularcore --api-port 8080 --api-allowed-origin https://my-dashboard.example.comA ready-to-use systemd unit file is included in the systemd/ directory. It runs Joular Core as a daemon that continuously overwrites /tmp/joularcore-service.csv with the latest power reading. Because overwrite mode truncates before each write, the default service file contains only the latest data row, without a CSV header.
sudo cp systemd/joularcore.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable joularcore
sudo systemctl start joularcoreTo use a different output path or add options, edit the ExecStart line in the service file before copying it.
Joular Core is licensed under the GNU GPL 3 license only (GPL-3.0-only).
Copyright Β© 2025-2026, Adel Noureddine. All rights reserved. This program and the accompanying materials are made available under the terms of the GNU General Public License v3.0 (GPL-3.0-only) which accompanies this distribution.
Author: Prof. Adel Noureddine


















