Skip to content

Heat from compute

A GPU turns nearly every watt it draws into heat. When the machine sits in a building's heating loop - a compute heater, or a liquid-cooled unit feeding a heat pump - that heat is the second product of the same kilowatt-hour. SilentSwarm does two things for such a fleet:

  • It meters the energy each machine's GPUs drew, per machine, per pool and in total, so you know how much heat each unit delivered.
  • It listens to the building's heat demand. The owner of a machine (or a heat pump controller acting for them) records how much heat the building wants, and the scheduler prefers those machines for training work.

The business page SilentSwarm for compute heat pumps describes the idea for manufacturers; this page is how it works.

Energy metering

Every fellow reports its GPUs' board power with its heartbeat (NVML, or nvidia-smi as a fallback). Once a minute the leader's metrics roll-up takes the power of every online machine and adds power x tick length to:

  • the machine's own total (kept in the leader's state DB, never reset),
  • the community total that the public numbers show (heat.energy_kwh in /api/v1/public/stats),
  • the pool's stored power_w series, so the power history can be charted like any other pool metric (pools_metrics with metric=power_w, kept 7 days at minute resolution and 90 days hourly).

What the number is - and is not

It is GPU board power, sampled once per roll-up tick. CPU, memory, fans and power-supply losses also end up as heat and are not counted, so a machine's real heat output is somewhat higher. It is not a calibrated heat meter either; use a certified heat meter where a figure has to be billed.

A machine that reports no power (no NVIDIA driver, or one that refuses the query) adds nothing and shows -, never 0 W.

The pool page

Pool members see a Heat output card on the pool's overview once a machine has reported power: power right now, the energy delivered since metering began, how many machines ask for heat, and per machine its power, hottest GPU, delivered energy and heat demand. Set on a row (shown to the machine's owner and the pool's owner) records a demand by hand.

The heat demand

A demand is a number from 0 to 100 % - how much of the heat the machine can give the building wants right now - with an expiry. It expires so a controller that goes offline does not steer work forever: after ttl_s seconds (default one hour, at most seven days) it reads as no signal. A controller re-sends it to keep it alive.

Who may set it: the machine's owner (the member whose token joined it), the pool's owner, or an admin. Starting and stopping a demand is recorded in the pool's timeline and the audit log; a controller refreshing the same demand is not, so the timeline stays readable.

What the scheduler does with it

When a training job has more qualifying machines than it needs, the placer picks the machines asking for the most heat first, then the usual order (most free GPU memory). It never places work on a machine that would not qualify anyway, and serving ignores the demand - a chat model has to answer whether or not the building is cold.

The demand does not cap a GPU's power: that needs root on the fellow, which runs rootless. A building that needs less heat has to say so with a lower demand, or take the machine out of the schedule (node role standby).

From a heat pump controller

Create an API token with the operate scope for the account that owns the machine (Profile → API tokens), then:

# The building wants 80 % for the next 15 minutes
curl -X PUT "$LEADER/api/v1/pools/$POOL_ID/nodes/$FELLOW_ID/heat-demand" \
  -H "Authorization: Bearer $SWARM_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"demand_pct": 80, "ttl_s": 900, "source": "heat pump controller"}'

# Read power, energy and demand for the whole pool
curl "$LEADER/api/v1/pools/$POOL_ID/heat" -H "Authorization: Bearer $SWARM_API_TOKEN"

# Withdraw the demand
curl -X DELETE "$LEADER/api/v1/pools/$POOL_ID/nodes/$FELLOW_ID/heat-demand" \
  -H "Authorization: Bearer $SWARM_API_TOKEN"

The same actions are MCP tools: pools_heat, pools_set_heat_demand and pools_clear_heat_demand (see the tool reference).

API summary

Method Path Who What
GET /api/v1/pools/{pool_id}/heat pool members Power now, energy per machine and in total, active demands, can_set per machine, and method
PUT /api/v1/pools/{pool_id}/nodes/{fellow_id}/heat-demand machine owner, pool owner, admin Body {"demand_pct": 0-100, "ttl_s": 60-604800, "source": "..."}
DELETE /api/v1/pools/{pool_id}/nodes/{fellow_id}/heat-demand machine owner, pool owner, admin Withdraw the demand
GET /api/v1/public/stats anyone heat.power_kw and heat.energy_kwh for the whole leader, withheld below the privacy floor like every machine number