Add SNMP extend script for AMD GPU power and clock - #627
Conversation
|
Reworked the output format after finding that the consumer side had to rebuild the card blocks by counting lines. Each card now emits an identifier line naming the metrics it carries, followed by those metrics in that order: The names live on the identifier line because the value lines cannot hold them — LibreNMS reads a sensor OID straight into a numeric value, so a label beside the number is parsed as part of it. The metric list is built from the same variable the loop reads, so a metric added to the script appears in both places or in neither. The consumer side is librenms/librenms#20258; the two go together. |
The net-snmp lmSensors module maps only the temperature, fan and voltage features of libsensors, so GPU power and clock are given no index and never reach SNMP. This script reads them from sysfs and serves them as a table under the LibreNMS enterprise tree, for discovery as power and frequency sensors. The table is indexed by the PCI address of the card, so an OID carries the card it belongs to. A card added, removed or unbound from the driver leaves the readings of the others where they are, and two identical cards in one host stay apart. A reading the card does not publish has no cell at all - that OID answers noSuchInstance - rather than a placeholder that has to mean something. On APUs power1_average is not always readable, since the SMU may decline it while idle, so a card reporting only power1_input is ordinary. Cards are walked through /sys/bus/pci/drivers/amdgpu rather than through hwmonN, since hwmon numbering is not stable across reboots while PCI slot addressing is. Product names are looked up in the libdrm ids table by device id and revision, falling back to the PCI address when the table is absent or does not list the card. The rows are materialised once per collection, already in the order a walk traverses them, so getnext is the first entry ordering after the requested OID rather than arithmetic over columns and rows. A sparse table, a host with no cards, and a request past the end of the tree are then the same case rather than three. Requires the companion MIB and discovery modules in librenms/librenms#20258; the OID space is unusable without them.
The net-snmp lmSensors module maps only the temperature, fan and voltage features of libsensors, so GPU power and clock are given no index at all and lmMiscSensorsTable stays empty. They cannot reach LM-SENSORS-MIB regardless of configuration. GPU temperature and voltages are unaffected and keep arriving as before. This discovers them from the companion pass_persist script in librenms-agent, which serves them as a table under LIBRENMS-AMDGPU-MIB. Each card is one row and a sensor group of its own, identified by PCI address and, where libdrm knows the card, by product name. The table is indexed by the PCI address, so the OID of a sensor carries the card it reads. That removes a failure the earlier extend-based approach had to warn about: cards changing no longer shifts the readings of the others onto their neighbours. The sensor index is the address together with the MIB object, so it stays valid if the script ever reorders what it reports. A reading the card does not publish has no cell in the table, and the OID answers noSuchInstance - there is no placeholder value to filter here. No thresholds are set. The frequency class guesses the reading +/-5%, which is not meaningful for a GPU core clock that moves between idle and boost by design, and a ceiling cannot be inferred from the sensor alone - the same driver serves parts whose boost differs by a factor of ten. This is stated in the docs so users adjust the limits themselves. Placed in unix.inc.php rather than linux.inc.php: the group covers Proxmox and the other unix os entries as well, and frequency/linux.inc.php already serves the Raspberry Pi. The two files repeat the walk deliberately - the query cache keys on oids plus options, so the identical chains resolve to a single walk for both classes, while a single file serving both would be included before the discovery_submodules.sensors filter and would produce power sensors for users who disabled that class. The MIB takes .1.3.6.1.4.1.60652.101, the next free arc under the LibreNMS enterprise number after .100 (XCP-NG-VMINFO-MIB); say if another is preferred. Test data covers both paths: a card libdrm knows, and a second one identified by address alone with a reading it does not publish. The development host has a single GPU, so the multi-card path is covered there rather than by hardware. Requires librenms/librenms-agent#627; the two go together.
|
Rewritten as Details and the reasoning are on the LibreNMS side: librenms/librenms#20258. The two go together — this OID space is not usable without the MIB that ships there. |
Adds an SNMP extend script exposing AMD GPU power and clock.
These cannot reach SNMP on their own. The net-snmp
lmSensorsmodule maps onlythe temperature, fan and voltage features of libsensors, so watts and hertz are
given no index at all and
lmMiscSensorsTablestays empty — no configurationchanges that. GPU temperature and voltages are unaffected and keep arriving
through
LM-SENSORS-MIBas before; this only adds what is missing.The companion discovery side is librenms/librenms#20258.
Output
One block of exactly four lines per card:
The three metric lines carry a bare number, because LibreNMS reads a sensor OID
straight into a numeric value — a label on the same line would be parsed as part
of the number and silently yield 0.
Notes on the design
Fixed block length. An attribute that cannot be read is emitted as
U, notomitted. On APUs
power1_averageis not always available — the SMU may declineit while idle — so a card publishing only some of the three is the ordinary
case. Omitting the line would shift every following value onto the wrong sensor;
Uleaves a placeholder that discovery ignores. This followsups-nut.sh, whichuses
Unknownthe same way.Cards found through the PCI driver directory, not through
hwmonN: hwmonnumbering is not stable across reboots, PCI slot addressing is. The glob expands
alphabetically, so block order is deterministic.
Product names come from the libdrm ids table, matched on device id and
revision — the revision matters, since e.g.
15BFrevisionC4is a Radeon 780Mwhile
C5is a 740M. A card the table does not list falls back to its PCIaddress alone.
Testing
Verified on a Ryzen 8845HS host (Radeon 780M, Proxmox), run both as root and as
the snmpd user through sudo. Also exercised against a synthetic sysfs tree with
three cards — complete, missing an attribute, and with no hwmon node — to confirm
the block length holds and a card without hwmon emits nothing rather than
shifting the others.
shellcheckclean at all severities;sh -nanddash -nclean.