Joular Core :zap:

Joular Core is a Rust library for measuring power and energy across 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 allows applications, telemetry services, benchmarks, and custom developer tools to monitor CPU, GPU, and total system power, as well as attribute energy usage to specific process IDs (PIDs) or multi-process applications. It 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/.
The crate exposes reusable monitoring, output, IPC, and API building blocks that can be embedded in command-line tools, graphical applications, telemetry services, benchmarks, or custom developer tools.
Currently, the library is used in these two multi-OS applications:
- Joular Core CLI: a command-line program, working on all OSes.
- Joular Core GUI: a graphical program written in Rust, and working on all OSes.
Joular Core is under active development and currently in beta quality. Expect rough edges and features still being worked on and polished.
:satellite: Supported platforms
- 💻 Supported Systems: 🐧 Linux, 🪟 Windows, 🍎 macOS, 🍓 Raspberry Pi, 💽 Virtual Machines.
- ⚙️ Supported Architectures: x86_64 (amd64), x86/i686, aarch64, arm, armv7, GPUs (Nvidia, Apple, AMD).
🌍 Universal Compatibility:
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.
:rocket: Features
- 📊 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
📦 Installation & Setup
Add joularcore to your Rust project's Cargo.toml:
[]
= "0.1.0"
Or via the command line:
⚙️ Cargo Features
You can customize the features compiled into joularcore to minimize binary size and dependencies depending on your deployment target:
| 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. |
sbc |
off | Single-board computer support with SBC-specific power models. On Linux, this selects the SBC backend instead of the RAPL-based desktop/server backend. |
Feature Examples in Cargo.toml:
# Minimal core library (no VM file reading, no API server)
= { = "0.1.0", = false }
# Core library with VM support only
= { = "0.1.0", = false, = ["vm"] }
# SBC build for Raspberry Pi target
= { = "0.1.0", = false, = ["sbc"] }
💡 Quickstart & Code Examples
1. Simple System Power Sampling
use ;
use Duration;
2. Monitoring a Specific Process ID (PID)
use ;
use Duration;
3. Writing Output to CSV, Shared Memory, or API
use ;
use RingBufferWriter;
:bulb: Configuration
On most platforms, no configuration is needed. Joular Core detects the platform, finds the right power interface, and starts measuring.
Platform requirements
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. Library callers can pass true to platform::current(true) to allow GUI-style elevation with an askpass prompt, or false for normal sudo authentication. 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.
Virtual Machines
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).
Single-Board Computers (SBC)
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.
🛠️ Low-Level IPC Interfaces
Shared memory ring buffer
When RingBufferWriter is enabled, joularcore streams real-time readings into a zero-copy shared memory buffer accessible by separate native binaries:
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.
HTTP and WebSockets API
When built with feature = "api", Joular Core hosts an embedded web server:
Endpoints:
| Endpoint | Protocol | Description |
|---|---|---|
/data |
HTTP GET | Returns the latest power reading as JSON |
/ws |
WebSocket | Streams each new JSON reading published by the monitor loop |
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), pass extra origins to common::spawn_api_server or, when using Args, set api_allowed_origins. Passing * allows any origin.
📜 License
Joular Core is licensed under the GNU Lesser General Public License 3 license only (LGPL-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 Lesser General Public License v3.0 (LGPL-3.0-only) which accompanies this distribution.
Author: Prof. Adel Noureddine