The run binary bracketed the inference with host_counter() reads: on macOS 27 the load-average estimator, so an in-process Metal decode and a llama.cpp subprocess were both estimated from host load, although this host reads both engines' own processes. The in-process engine (jouleclaw-runtime, Metal kernels) is now metered by ProcessSpanMeter(gpu_liveness_load) with SpanUses::CpuGpu: this process's CPU plus its GPU (an exact zero with no GPU time, the rail when it owned the GPU). The llama engine's subprocess runs behind a gate (sh waits, then execs "$0" "$@") and is read on its own process tree by TreeMeter, waited for with WNOWAIT before the reap (LlamaCompletionBackend::complete_metered). grade() is the one place the receipt's energy is decided, mesh ProcessMeter's rule: a reading that covers the whole inference keeps its grade; a partial one (GPU shared, or a child that exited in its window, or undeclared) is an Estimator, the reading plus the host counter's figure or the token estimate; no reading leaves that rest as it was. The receipt has no coverage field, so a partial reading is never sealed HwShunt. Tested against oracles sharing no code: this process's own ri_energy_nj read around a CPU burn (span 0.985 of it, GPU an exact zero, Whole, HwShunt), and a stand-in llama (this test binary) reporting its own count from inside (reading 0.998 of it, Estimator). The example workspace builds standalone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
41 lines
2.4 KiB
TOML
41 lines
2.4 KiB
TOML
# Standalone example (own workspace) — does NOT join joule-code-rs's workspace, so
|
|
# the standard's lib stays free of a JouleClaw dependency. This is a *consumer
|
|
# binding*: how to wire JouleClaw's L3 (Model) tier into the Joule Code cascade.
|
|
[workspace]
|
|
|
|
[package]
|
|
name = "l3-jouleclaw-binding"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
rust-version = "1.97"
|
|
license = "Apache-2.0"
|
|
description = "Example binding: JouleClaw's L3 model tier (jouleclaw-llm LlmBackend) as a Joule Code cascade FnStage. Verified model-free via EchoBackend; a real backend (vLLM, or jouleclaw-runtime GGUF) drops into the same slot."
|
|
publish = false
|
|
|
|
[dependencies]
|
|
joule-code-schema = { path = "../../joule-code-rs/crates/joule-code-schema" }
|
|
joule-code-cargo = { path = "../../joule-code-rs/crates/joule-code-cargo" }
|
|
joule-code-receipt = { path = "../../joule-code-rs/crates/joule-code-receipt" }
|
|
joule-code-cascade = { path = "../../joule-code-rs/crates/joule-code-cascade" }
|
|
jouleclaw-llm = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-llm" }
|
|
jouleclaw-energy = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-energy", features = ["ioreport"] }
|
|
# JouleClaw's own from-scratch GGUF tensor runtime (no llama.cpp, no FFI) —
|
|
# the in-process L3 backend.
|
|
jouleclaw-runtime = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-runtime" }
|
|
jouleclaw-loader-gguf = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf", features = ["rayon", "fabric"] }
|
|
# The grades (`Measured` / `Benchmarked` / `Estimated`) the fabric ledger prices
|
|
# a call from, which the L3 stage grades the call's projected energy by.
|
|
jouleclaw-fabric = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-fabric" }
|
|
# The GPU load the in-process meter's GPU-counter liveness probe runs
|
|
# (`gpu_liveness_load`): the `run` binary meters the in-process engine on this
|
|
# process's own CPU and GPU (`jouleclaw_energy::span::ProcessSpanMeter`).
|
|
jouleclaw-backend-apple = { path = "../../../jouleclaw/jouleclaw-rs/crates/jouleclaw-backend-apple" }
|
|
# The llama engine's subprocess, read on its own process tree where the host
|
|
# counts each process's CPU energy (macOS): `TreeMeter`.
|
|
sandbox-meter = { path = "../../../sandbox/sandbox-rs/crates/sandbox-meter" }
|
|
serde_json = "1"
|
|
|
|
# macOS: the llama engine's process is waited for without being reaped
|
|
# (`waitid` with `WNOWAIT`), so the tree meter reads its exited count.
|
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
libc = "0.2"
|