mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-30 10:52:15 +00:00
feat(telemetry): compute tokens_per_joule in InstrumentedEngine
Computes completion_tokens / energy_joules in both generate() and stream() methods. Zero when energy or tokens are zero. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ac8d6b01c7
commit
4e5709d478
@@ -173,6 +173,12 @@ class InstrumentedEngine(InferenceEngine):
|
||||
if completion_tokens > 0 and decode_latency > 0 else 0.0
|
||||
)
|
||||
|
||||
# --- Tier 4: Per-inference efficiency ---
|
||||
tokens_per_joule = (
|
||||
completion_tokens / energy_joules
|
||||
if energy_joules > 0 and completion_tokens > 0 else 0.0
|
||||
)
|
||||
|
||||
engine_id = getattr(self._inner, "engine_id", "unknown")
|
||||
|
||||
record = TelemetryRecord(
|
||||
@@ -201,6 +207,7 @@ class InstrumentedEngine(InferenceEngine):
|
||||
cpu_energy_joules=cpu_energy_joules,
|
||||
gpu_energy_joules=gpu_energy_joules,
|
||||
dram_energy_joules=dram_energy_joules,
|
||||
tokens_per_joule=tokens_per_joule,
|
||||
)
|
||||
|
||||
event_data = {
|
||||
@@ -364,6 +371,12 @@ class InstrumentedEngine(InferenceEngine):
|
||||
prefill_energy = energy_joules * prefill_frac
|
||||
decode_energy = energy_joules * (1.0 - prefill_frac)
|
||||
|
||||
# Per-inference efficiency
|
||||
tokens_per_joule = (
|
||||
token_count / energy_joules
|
||||
if energy_joules > 0 and token_count > 0 else 0.0
|
||||
)
|
||||
|
||||
engine_id = getattr(self._inner, "engine_id", "unknown")
|
||||
|
||||
record = TelemetryRecord(
|
||||
@@ -397,6 +410,7 @@ class InstrumentedEngine(InferenceEngine):
|
||||
cpu_energy_joules=cpu_energy_joules,
|
||||
gpu_energy_joules=gpu_energy_joules,
|
||||
dram_energy_joules=dram_energy_joules,
|
||||
tokens_per_joule=tokens_per_joule,
|
||||
)
|
||||
|
||||
event_data = {
|
||||
|
||||
@@ -120,3 +120,45 @@ class TestInstrumentedEngine:
|
||||
def test_engine_id_attribute(self, mock_engine, bus):
|
||||
ie = InstrumentedEngine(mock_engine, bus)
|
||||
assert ie.engine_id == "instrumented"
|
||||
|
||||
|
||||
class TestTokensPerJoule:
|
||||
def test_tokens_per_joule_zero_without_energy(self, mock_engine, bus):
|
||||
"""tokens_per_joule is 0.0 when no energy monitor is available."""
|
||||
ie = InstrumentedEngine(mock_engine, bus)
|
||||
messages = [Message(role=Role.USER, content="Hi")]
|
||||
ie.generate(messages, model="test")
|
||||
|
||||
tel_events = [
|
||||
e for e in bus.history
|
||||
if e.event_type == EventType.TELEMETRY_RECORD
|
||||
]
|
||||
record = tel_events[0].data["record"]
|
||||
assert record.tokens_per_joule == 0.0
|
||||
|
||||
def test_tokens_per_joule_formula_via_record(self):
|
||||
"""Verify the formula: tokens_per_joule = completion_tokens / energy_joules."""
|
||||
from openjarvis.core.types import TelemetryRecord
|
||||
|
||||
# Direct construction — verifies the field accepts computed values
|
||||
rec = TelemetryRecord(
|
||||
timestamp=1.0,
|
||||
model_id="test",
|
||||
completion_tokens=50,
|
||||
energy_joules=2.5,
|
||||
tokens_per_joule=50.0 / 2.5, # = 20.0
|
||||
)
|
||||
assert rec.tokens_per_joule == pytest.approx(20.0)
|
||||
|
||||
def test_tokens_per_joule_zero_when_no_tokens(self):
|
||||
"""tokens_per_joule is 0.0 when completion_tokens is 0."""
|
||||
from openjarvis.core.types import TelemetryRecord
|
||||
|
||||
rec = TelemetryRecord(
|
||||
timestamp=1.0,
|
||||
model_id="test",
|
||||
completion_tokens=0,
|
||||
energy_joules=5.0,
|
||||
tokens_per_joule=0.0,
|
||||
)
|
||||
assert rec.tokens_per_joule == 0.0
|
||||
|
||||
Reference in New Issue
Block a user