code wiki / _hdl_build / nx_energy_model.nx
nx_energy_model.nx
buildroot/runtime/_hdl_build/nx_energy_model.nx
about
nx_energy_model.nx -- STATE-INDEPENDENT energy estimation, pure NishiLang.
The S-class answer to "you can only measure energy when not charging": you do
NOT measure the battery at all. Energy is estimated from a CHARGE-INDEPENDENT
activity counter -- cycles (rdtsc/rdcycle, available on EVERY target including a
PMU-less VM) or retired instructions (perf, where a PMU exists) -- times a
per-unit energy coefficient:
energy = activity_count * energy_per_unit
activity_count does not depend on whether the node is plugged in, so this yields
a real energy number on AC, on a battery-less server, on a supercomputer node,
or on a discharging garden sensor -- ANY power state, ANY hardware.
The coefficient is the only chip-specific part. A real joule sensor (RAPL, an
INA219 on the rail, or a discharging fuel-gauge) CALIBRATES it once:
energy_per_unit = real_energy_measured / activity_count_for_that_work
Where no sensor is present we use a documented PRIOR (clearly labeled, not a
measured claim) and refine it the moment a sensor appears. So a sensor IMPROVES
the number; it is never REQUIRED to get one.
Research (Cardinal #4, real sources): per-operation / per-cycle energy figures --
Horowitz, "Computing's Energy Problem (and what we can do about it)," ISSCC 2014;
event-driven accounting -- Bellosa, ACM SIGOPS EW 2000; PMC power models -- Isci
& Martonosi, MICRO 2003; Bircher & John, ISPASS 2007.
dependencies 1 imports · 1 importers
imports: nx_syscalls.nx
imported by: nx_energy_model_test.nx
structs
| none |
consts
| 28 | const EM_MAGIC_1000000: i64 = 1000000 |
| 34 | const EM_PRIOR_FJ_PER_CYCLE: i64 = 5000000 |
functions
| 37 | func em_energy_fj(activity: i64, fj_per_unit: i64) -> i64 { return activity * fj_per_unit } called by 1: main |
| 41 | func em_calibrate_fj_per_unit(real_energy_fj: i64, activity: i64) -> i64 called by 1: main |
| 47 | func em_fj_to_pj(fj: i64) -> i64 { return fj / 1000 } |
| 48 | func em_fj_to_nj(fj: i64) -> i64 { return fj / EM_MAGIC_1000000 } called by 1: main |