Skip to content

feat: add metrics publisher for NT #1791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
package org.photonvision.common.dataflow.networktables;

import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.cscore.CameraServerJNI;
import edu.wpi.first.networktables.LogMessage;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEvent;
import edu.wpi.first.networktables.NetworkTableEvent.Kind;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.ProtobufPublisher;
import edu.wpi.first.networktables.StringSubscriber;
import java.io.IOException;
import java.util.EnumSet;
Expand All @@ -34,6 +36,7 @@
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
import org.photonvision.common.dataflow.websocket.UIPhotonConfiguration;
import org.photonvision.common.hardware.HardwareManager;
import org.photonvision.common.hardware.metrics.DeviceMetrics;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.LogLevel;
import org.photonvision.common.logging.Logger;
Expand All @@ -56,6 +59,12 @@ public class NetworkTablesManager {
private StringSubscriber m_fieldLayoutSubscriber =
kRootTable.getStringTopic(kFieldLayoutName).subscribe("");

ProtobufPublisher<DeviceMetrics> metricPublisher =
kRootTable
.getSubTable(".metrics")
.getProtobufTopic(CameraServerJNI.getHostname(), DeviceMetrics.proto)
.publish();

private final TimeSyncManager m_timeSync = new TimeSyncManager(kRootTable);

private NetworkTablesManager() {
Expand Down Expand Up @@ -201,6 +210,10 @@ private void broadcastVersion() {
kRootTable.getEntry("buildDate").setString(PhotonVersion.buildDate);
}

private void broadcastMetrics() {
metricPublisher.set(HardwareManager.getInstance().getMetrics());
}

public void setConfig(NetworkConfig config) {
if (config.runNTServer) {
setServerMode();
Expand Down Expand Up @@ -242,9 +255,9 @@ private void setServerMode() {

// So it seems like if Photon starts before the robot NT server does, and both aren't static IP,
// it'll never connect. This hack works around it by restarting the client/server while the nt
// instance
// isn't connected, same as clicking the save button in the settings menu (or restarting the
// service)
// instance isn't connected, same as clicking the save button in the settings menu
// (or restarting the service)
// It's also used to update the metrics every tick
private void ntTick() {
if (!ntInstance.isConnected()
&& !ConfigManager.getInstance().getConfig().getNetworkConfig().runNTServer) {
Expand All @@ -256,6 +269,8 @@ private void ntTick() {
logger.error(
"[NetworkTablesManager] Could not connect to the robot! Will retry in the background...");
}

broadcastMetrics();
}

public long getTimeSinceLastPong() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.hardware.GPIO.CustomGPIO;
import org.photonvision.common.hardware.GPIO.pi.PigpioSocket;
import org.photonvision.common.hardware.metrics.DeviceMetrics;
import org.photonvision.common.hardware.metrics.MetricsManager;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
Expand Down Expand Up @@ -229,4 +230,8 @@ public HardwareConfig getConfig() {
public void publishMetrics() {
metricsManager.publishMetrics();
}

public DeviceMetrics getMetrics() {
return metricsManager.getMetrics();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.common.hardware.metrics;

import org.photonvision.common.hardware.metrics.proto.DeviceMetricsProto;

public record DeviceMetrics(
String cpuTemp,
String cpuUtil,
String cpuMem,
String cpuThr,
String cpuUptime,
String gpuMem,
String ramUtil,
String gpuMemUtil,
String diskUtilPct,
String npuUsage,
String ipAddress) {
public static final DeviceMetricsProto proto = new DeviceMetricsProto();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.configuration.HardwareConfig;
import org.photonvision.common.dataflow.DataChangeService;
Expand Down Expand Up @@ -129,21 +128,24 @@ public String getIpAddress() {
return addr;
}

public DeviceMetrics getMetrics() {
return new DeviceMetrics(
this.getTemp(),
this.getUtilization(),
this.getMemory(),
this.getThrottleReason(),
this.getUptime(),
this.getGPUMemorySplit(),
this.getUsedRam(),
this.getMallocedMemory(),
this.getUsedDiskPct(),
this.getNpuUsage(),
this.getIpAddress());
}

public void publishMetrics() {
logger.debug("Publishing Metrics...");
final var metrics = new HashMap<String, String>();

metrics.put("cpuTemp", this.getTemp());
metrics.put("cpuUtil", this.getUtilization());
metrics.put("cpuMem", this.getMemory());
metrics.put("cpuThr", this.getThrottleReason());
metrics.put("cpuUptime", this.getUptime());
metrics.put("gpuMem", this.getGPUMemorySplit());
metrics.put("ramUtil", this.getUsedRam());
metrics.put("gpuMemUtil", this.getMallocedMemory());
metrics.put("diskUtilPct", this.getUsedDiskPct());
metrics.put("npuUsage", this.getNpuUsage());
metrics.put("ipAddress", this.getIpAddress());
var metrics = getMetrics();

DataChangeService.getInstance().publishEvent(OutgoingUIEvent.wrappedOf("metrics", metrics));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.common.hardware.metrics.proto;

import edu.wpi.first.util.protobuf.Protobuf;
import org.photonvision.common.hardware.metrics.DeviceMetrics;
import org.photonvision.proto.Photon.ProtobufDeviceMetrics;
import us.hebi.quickbuf.Descriptors.Descriptor;

public class DeviceMetricsProto implements Protobuf<DeviceMetrics, ProtobufDeviceMetrics> {
@Override
public Class<DeviceMetrics> getTypeClass() {
return DeviceMetrics.class;
}

@Override
public Descriptor getDescriptor() {
return ProtobufDeviceMetrics.getDescriptor();
}

@Override
public ProtobufDeviceMetrics createMessage() {
return ProtobufDeviceMetrics.newInstance();
}

@Override
public DeviceMetrics unpack(ProtobufDeviceMetrics msg) {
return new DeviceMetrics(
msg.getCpuTemp(),
msg.getCpuUtil(),
msg.getCpuMem(),
msg.getCpuThr(),
msg.getCpuUptime(),
msg.getGpuMem(),
msg.getRamUtil(),
msg.getGpuMemUtil(),
msg.getDiskUtilPct(),
msg.getNpuUsage(),
msg.getIpAddress());
}

@Override
public void pack(ProtobufDeviceMetrics msg, DeviceMetrics value) {
msg.setCpuTemp(value.cpuTemp());
msg.setCpuUtil(value.cpuUtil());
msg.setCpuMem(value.cpuMem());
msg.setCpuThr(value.cpuThr());
msg.setCpuUptime(value.cpuUptime());
msg.setGpuMem(value.gpuMem());
msg.setRamUtil(value.ramUtil());
msg.setGpuMemUtil(value.gpuMemUtil());
msg.setDiskUtilPct(value.diskUtilPct());
msg.setNpuUsage(value.npuUsage());
msg.setIpAddress(value.ipAddress());
}
}
14 changes: 14 additions & 0 deletions photon-targeting/src/main/proto/photon.proto
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,17 @@ message ProtobufPhotonPipelineResult {
int64 nt_publish_timestamp_micros = 6;
int64 time_since_last_pong_micros = 7;
}

message ProtobufDeviceMetrics {
string cpu_temp = 1;
string cpu_util = 2;
string cpu_mem = 3;
string cpu_thr = 4;
string cpu_uptime = 5;
string gpu_mem = 6;
string ram_util = 7;
string gpu_mem_util = 8;
string disk_util_pct = 9;
string npu_usage = 10;
string ip_address = 11;
}
2 changes: 1 addition & 1 deletion photon-targeting/src/test/java/jni/FileLoggerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package wpiutil_extras;
package jni;

import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
Expand Down
Loading