An owned host's hour cost
What an owned host's hour cost: stado cost host
$ stado cost host gpu-host --since-hours 24
gpu-host at 0.21 EUR/kWh (supplier invoice, residential tariff), since 2026-01-01T09:00:00Z
2026-01-01T09:00:00Z cpu busy 12%; GPU-1a… busy 100% 0.410 kWh, 0.380 above idle 30.000 W; GPU-2b… busy 0% 0.031 kWh, 0.000 above idle 31.000 W; 0.0926 EUR, 0.0798 EUR above idle
total 0.0926 EUR, 0.0798 EUR above idle, over 1 hour(s)
Every host that publishes its beacon on a period (stado serve --health-interval-seconds) samples each board's utilization.gpu and
power.draw and its processor's busy share once per period, and keeps each
hour of the last day in the beacon's hours block: per board UUID the samples,
the busy samples and the watt-seconds drawn (each draw times the seconds since
the board's previous sample), and the processor's busy samples. stado cost host TARGET [--since-hours N] [--json] reads that block from the host's
newest beacon and prices each hour's energy at the tariff the registry declares
for the host:
"power_tariff": {"price_per_kwh": 0.21, "currency": "EUR", "source": "supplier invoice, residential tariff",
"usd_rate": {"usd_per_unit": 1.08, "as_of": "2026-01-01", "source": "central bank reference rate"}}
set with stado registry set --path targets.<host>.power_tariff --value '…'.
The registry refuses a tariff with no source (must name where the price was read …), a negative or missing price_per_kwh, an empty currency and any
other field. Marketplaces state income in US dollars and the cost report is
in US dollars, so a tariff in another currency carries usd_rate: the dollars
one unit was worth, the date of that rate and the published table it was read
from; the registry refuses a rate that is not above zero or lacks as_of or
source. Without it the hour is priced in the tariff's own currency only, and
every US-dollar figure (the cost report, stado market earnings, cost host's
in USD line) says the tariff is in <code> and declares no usd_rate …
instead of converting at a rate nobody stated.
A tariff that charges by the hour of day declares its bands and the time zone its hours are read in:
"power_tariff": {"price_per_kwh": 0.21, "currency": "EUR", "source": "supplier invoice, two-rate tariff",
"timezone": "Europe/Warsaw",
"bands": [{"from_hour": 22, "to_hour": 6, "price_per_kwh": 0.11},
{"from_hour": 13, "to_hour": 15, "price_per_kwh": 0.11}]}
A band runs from from_hour (inclusive) to to_hour (exclusive) of the local
day, past midnight when to_hour is not above from_hour; an hour no band
covers costs price_per_kwh. Every measured hour (cost host, stado market earnings, the cost report and placement) is priced at the band covering it,
and cost host prints each hour's price_per_kwh. The registry refuses bands
without an IANA timezone, a timezone without bands, an empty list, an hour
outside 0 to 23, a band whose two hours are equal, a negative price, two bands
covering the same hour, and any other band field.
The hardware's purchase is a cost of every hour too:
"hardware": {"purchase_price": 9000, "currency": "USD", "service_years": 4, "source": "purchase invoice"}
cost host prints the share of that price one hour carries (the price over
the service years of 365 days of 24 hours), the wear over the window, and
wear: not counted: <host> declares no hardware … for a host without it. The
registry refuses a price or service life that is not above zero, an empty
currency or source, and any other field.
A board turns the electricity it draws into heat in the room the host stands in. Where that heat replaces heating, the registry declares what one kWh of heat from the replaced heating costs (its fuel or electricity price over its efficiency) and, optionally, the months it heats:
"heat_use": {"price_per_kwh": 0.12, "currency": "USD", "source": "gas bill and boiler efficiency", "months": [1, 2, 3, 10, 11, 12]}
cost host then prints the boards' heat over the window in kWh, the part of it
given off in the declared months (every month when months is absent), and
its saving at that price. A host with no heat_use prints nothing about heat.
The registry refuses a price not above zero, an empty currency or source, a
months that is empty or names anything but 1 to 12, and any other field.
Each row prints the processor's busy share, each board's busy
share and kWh, and the cost; an hour no board was sampled in is unpriced: no board was sampled, and an hour one of whose boards reported no energy is
unpriced: board(s) <id> reported no watt_seconds this hour, never priced on
the other boards' draw alone; a busy share whose samples were not counted is
unread, never zero. Every reading an hour could not take is
printed as unread: <cause> (boards: nvidia-smi exited …, processor: …).
A Mac's CPU, GPU and Neural Engine share one power domain, so on macOS the
one board an hour prices is the package, macos-package: its draw is
powermetrics' processor.combined_power and it is busy when the graphics
sampler's gpu.idle_ratio is below one. powermetrics reads power only as
root, so the host declares the privileged helper that prints one sample,
host.power_helper (or STADO_HOST_POWER_HELPER), as command words, for
example a sudoers-allowed ["sudo", "-n", "/usr/bin/powermetrics", "--samplers", "cpu_power,gpu_power", "-n", "1", "-i", "1000", "-f", "plist"]. Without it every hour of the Mac is unread: boards: host.power_helper (STADO_HOST_POWER_HELPER) is not declared … and unpriced;
a helper that cannot run, exits non-zero, prints no plist or a sample without
processor.combined_power or gpu.idle_ratio is named the same way.
A board draws power when nothing runs on it, so the whole draw overstates what
a job or a rental cost. The beacon also keeps, per board and hour, the energy
and seconds of its zero-utilization samples; cost host takes each board's
idle draw in watts over the beacon's window, prints it, and prints the energy
and cost above it — what work on the board added. A board whose idle draw was
never measured in the window, or a beacon from before these fields, prints
above idle unread: a board's idle draw was never measured instead of
charging the whole draw as work.
--json prints stado.cost-host.v1 with the tariff, each hour (with
kwh_above_idle, cost_above_idle, kwh_unread and each board's idle_watts),
total_cost, total_cost_above_idle, hardware, wear, heat (use,
kwh, kwh_replacing_heating, saving, or null) and unpriced_hours. Refusals: a host
with no tariff (<host> declares no power_tariff, so its hours have no price; declare one with …), a host with no beacon, and a beacon with no hours
block (its Stado predates host-hour measurement, or its beacon is published
once).
Source: this website