Skip to content
Open
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 @@ -125,5 +125,29 @@ void bind_systeminformationRVC4(pybind11::module& m, void* pCallstack) {
.def_property(
"chipTemperature",
[](SystemInformationRVC4& i) -> ChipTemperatureRVC4& { return i.chipTemperature; },
[](SystemInformationRVC4& i, ChipTemperatureRVC4 val) { i.chipTemperature = val; });
[](SystemInformationRVC4& i, ChipTemperatureRVC4 val) { i.chipTemperature = val; })
.def_readwrite("gpuUtilizationPercent",
&SystemInformationRVC4::gpuUtilizationPercent,
"Whole-GPU utilization percentage from the vendor sampling window; -1 when unavailable.")
.def_readwrite("dspHvxActivityPercent",
&SystemInformationRVC4::dspHvxActivityPercent,
"DSP HVX activity percentage from the vendor sampling window; it is not awake residency or total NPU utilization; -1 when unavailable.")
.def_readwrite("dspHmxActivityPercent",
&SystemInformationRVC4::dspHmxActivityPercent,
"DSP HMX activity percentage from the vendor sampling window; it is not awake residency or total NPU utilization; -1 when unavailable.")
.def_readwrite("dspQ6LoadKcps",
&SystemInformationRVC4::dspQ6LoadKcps,
"DSP Q6 load in KCPS from the vendor sampling window; it is not awake residency or total NPU utilization; -1 when unavailable.")
.def_readwrite("powerSystemWatts",
&SystemInformationRVC4::powerSystemWatts,
"vdd_5v0 system rail in watts, converted from microwatts. Rails are independent readings, not additive; -1 when unavailable.")
.def_readwrite("powerProcessorWatts",
&SystemInformationRVC4::powerProcessorWatts,
"vdd_3v9 processor rail in watts, converted from microwatts. Rails are independent readings, not additive; -1 when unavailable.")
.def_readwrite("powerPoeWatts",
&SystemInformationRVC4::powerPoeWatts,
"PoE power rail in watts, converted from microwatts. Rails are independent readings, not additive; -1 when unavailable.")
.def_readwrite("powerTofWatts",
&SystemInformationRVC4::powerTofWatts,
"ToF power rail in watts, converted from microwatts. Rails are independent readings, not additive; -1 when unavailable.");
}
16 changes: 16 additions & 0 deletions bindings/python/tests/compiler_warning_bindings_roundtrip_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,29 @@ def test_system_information_rvc4_binding_roundtrip():
system_information.processCpuAvgUsage = expected_process_cpu_avg
system_information.cpuUsages = expected_cpu_usages
system_information.chipTemperature = expected_chip_temperature
system_information.gpuUtilizationPercent = 23.5
system_information.dspHvxActivityPercent = 10.25
system_information.dspHmxActivityPercent = 4.75
system_information.dspQ6LoadKcps = 321.0
system_information.powerSystemWatts = 2.1
system_information.powerProcessorWatts = 1.2
system_information.powerPoeWatts = 0.7
system_information.powerTofWatts = 0.3

assert normalize(system_information.ddrMemoryUsage) == normalize(expected_ddr)
assert system_information.processMemoryUsage == 123456789
assert normalize(system_information.cpuAvgUsage) == normalize(expected_cpu_avg)
assert normalize(system_information.processCpuAvgUsage) == normalize(expected_process_cpu_avg)
assert normalize(system_information.cpuUsages) == normalize(expected_cpu_usages)
assert normalize(system_information.chipTemperature) == normalize(expected_chip_temperature)
assert system_information.gpuUtilizationPercent == pytest.approx(23.5)
assert system_information.dspHvxActivityPercent == pytest.approx(10.25)
assert system_information.dspHmxActivityPercent == pytest.approx(4.75)
assert system_information.dspQ6LoadKcps == pytest.approx(321.0)
assert system_information.powerSystemWatts == pytest.approx(2.1)
assert system_information.powerProcessorWatts == pytest.approx(1.2)
assert system_information.powerPoeWatts == pytest.approx(0.7)
assert system_information.powerTofWatts == pytest.approx(0.3)


def test_tracked_features_binding_roundtrip():
Expand Down
2 changes: 1 addition & 1 deletion cmake/Depthai/DepthaiDeviceRVC4Config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
set(DEPTHAI_DEVICE_RVC4_MATURITY "snapshot")

# "version if applicable"
set(DEPTHAI_DEVICE_RVC4_VERSION "0.0.1+280e85c74c5f8bc7507d5e3d666fca3e58a8e1f7")
set(DEPTHAI_DEVICE_RVC4_VERSION "0.0.1+8105811b437b32ea14a4040e8d361652b9cbdd82")
13 changes: 13 additions & 0 deletions examples/cpp/Misc/SystemLogger/system_logger.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <atomic>
#include <csignal>
#include <iomanip>
#include <iostream>
#include <sstream>

#include "depthai/depthai.hpp"

Expand Down Expand Up @@ -36,6 +38,17 @@ void printSystemInformation(const dai::SystemInformationRVC4& info) {
const auto& t = info.chipTemperature;
std::cout << "Chip temperature - average: " << t.average << ", cpuss: " << t.cpuss << ", gpuss: " << t.gpuss << ", mdmss: " << t.mdmss
<< ", video: " << t.video << ", ddr: " << t.ddr << ", camera: " << t.camera << std::endl;
const auto formatMetric = [](double value, const char* unit) -> std::string {
if(value < 0) return "unavailable";
std::ostringstream text;
text << std::fixed << std::setprecision(2) << value << unit;
return text.str();
};
std::cout << "GPU utilization: " << formatMetric(info.gpuUtilizationPercent, "%") << '\n';
std::cout << "DSP - HVX: " << formatMetric(info.dspHvxActivityPercent, "%") << ", HMX: " << formatMetric(info.dspHmxActivityPercent, "%")
<< ", Q6: " << formatMetric(info.dspQ6LoadKcps, " KCPS") << '\n';
std::cout << "Power rails - System: " << formatMetric(info.powerSystemWatts, " W") << ", Processor: " << formatMetric(info.powerProcessorWatts, " W")
<< ", PoE: " << formatMetric(info.powerPoeWatts, " W") << ", ToF: " << formatMetric(info.powerTofWatts, " W") << '\n';
std::cout << "----------------------------------------" << std::endl;
}

Expand Down
11 changes: 11 additions & 0 deletions examples/python/Misc/SystemLogger/system_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ def printSystemInformationRVC4(info: dai.SystemInformationRVC4):

t = info.chipTemperature
print(f"Chip temperature - average: {t.average:.2f}, cpuss: {t.cpuss:.2f}, gpuss: {t.gpuss:.2f}, mdmss: {t.mdmss:.2f}, video: {t.video:.2f}, ddr: {t.ddr:.2f}, camera: {t.camera:.2f}")
def format_metric(value: float, unit: str) -> str:
return "unavailable" if value < 0 else f"{value:.2f}{unit}"

print(f"GPU utilization: {format_metric(info.gpuUtilizationPercent, '%')}")
print(f"DSP - HVX: {format_metric(info.dspHvxActivityPercent, '%')}, "
f"HMX: {format_metric(info.dspHmxActivityPercent, '%')}, "
f"Q6: {format_metric(info.dspQ6LoadKcps, ' KCPS')}")
print(f"Power rails - System: {format_metric(info.powerSystemWatts, ' W')}, "
f"Processor: {format_metric(info.powerProcessorWatts, ' W')}, "
f"PoE: {format_metric(info.powerPoeWatts, ' W')}, "
f"ToF: {format_metric(info.powerTofWatts, ' W')}")
print("----------------------------------------")

# Create pipeline
Expand Down
33 changes: 28 additions & 5 deletions include/depthai/pipeline/datatype/SystemInformationRVC4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
namespace dai {

/**
* SystemInformation message
* Carries memory usage, cpu usage and chip temperatures.
* SystemInformation message.
* Carries memory and CPU usage, chip temperatures, accelerator activity and power readings.
*/
class SystemInformationRVC4 : public Buffer {
public:
Expand All @@ -23,18 +23,41 @@ class SystemInformationRVC4 : public Buffer {
virtual ~SystemInformationRVC4();

MemoryInfo ddrMemoryUsage;
int64_t processMemoryUsage;
int64_t processMemoryUsage = 0;
CpuUsage cpuAvgUsage;
CpuUsage processCpuAvgUsage;
std::vector<CpuUsage> cpuUsages;
ChipTemperatureRVC4 chipTemperature;

double gpuUtilizationPercent = -1;
double dspHvxActivityPercent = -1;
double dspHmxActivityPercent = -1;
double dspQ6LoadKcps = -1;
double powerSystemWatts = -1;
double powerProcessorWatts = -1;
double powerPoeWatts = -1;
double powerTofWatts = -1;

void serialize(std::vector<std::uint8_t>& metadata, DatatypeEnum& datatype) const override;
DatatypeEnum getDatatype() const override {
return DatatypeEnum::SystemInformationRVC4;
}

DEPTHAI_SERIALIZE(SystemInformationRVC4, ddrMemoryUsage, processMemoryUsage, cpuAvgUsage, processCpuAvgUsage, cpuUsages, chipTemperature);
DEPTHAI_SERIALIZE(SystemInformationRVC4,
ddrMemoryUsage,
processMemoryUsage,
cpuAvgUsage,
processCpuAvgUsage,
cpuUsages,
chipTemperature,
gpuUtilizationPercent,
dspHvxActivityPercent,
dspHmxActivityPercent,
dspQ6LoadKcps,
powerSystemWatts,
powerProcessorWatts,
powerPoeWatts,
powerTofWatts);
};

} // namespace dai
} // namespace dai
1 change: 1 addition & 0 deletions include/depthai/utility/EventsManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <atomic>
#include <condition_variable>
#include <deque>
#include <future>
#include <memory>
#include <mutex>
Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ dai_set_test_labels(imgframe_test onhost ci)
dai_add_test(pointclouddata_test src/onhost_tests/pipeline/datatype/pointclouddata_test.cpp)
dai_set_test_labels(pointclouddata_test onhost ci)

# SystemInformationRVC4 serialization compatibility
dai_add_test(systeminformationrvc4_test src/onhost_tests/pipeline/datatype/systeminformationrvc4_test.cpp)
dai_set_test_labels(systeminformationrvc4_test onhost ci)

# PointCloud node tests
dai_add_test(point_cloud_test src/onhost_tests/point_cloud_test.cpp)
dai_set_test_labels(point_cloud_test onhost ci)
Expand Down
17 changes: 16 additions & 1 deletion tests/src/ondevice_tests/pipeline/node/system_logger_test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <catch2/catch_all.hpp>
#include <cmath>
#include <limits>

#include "depthai/depthai.hpp"
#include "depthai/pipeline/node/SystemLogger.hpp"
Expand Down Expand Up @@ -42,6 +44,9 @@ void testSystemLoggerNode(const dai::SystemInformation& info) {

void testSystemLoggerNode(const dai::SystemInformationRVC4& info) {
constexpr float kCpuUsageTolerance = 1e-4f;
const auto isUnavailableOrInRange = [](double value, double upperBound) {
return value == -1 || (std::isfinite(value) && value >= 0 && value <= upperBound);
};

// DDR memory
REQUIRE(info.ddrMemoryUsage.used > 0);
Expand Down Expand Up @@ -71,6 +76,16 @@ void testSystemLoggerNode(const dai::SystemInformationRVC4& info) {
float total = info.chipTemperature.cpuss + info.chipTemperature.gpuss + info.chipTemperature.mdmss + info.chipTemperature.video + info.chipTemperature.ddr
+ info.chipTemperature.camera;
REQUIRE(info.chipTemperature.average == Catch::Approx(total / 6.0f).epsilon(0.01));

// Vendor counters may be unavailable on a platform/firmware combination.
REQUIRE(isUnavailableOrInRange(info.gpuUtilizationPercent, 100));
REQUIRE(isUnavailableOrInRange(info.dspHvxActivityPercent, 100));
REQUIRE(isUnavailableOrInRange(info.dspHmxActivityPercent, 100));
REQUIRE(isUnavailableOrInRange(info.dspQ6LoadKcps, std::numeric_limits<double>::max()));
REQUIRE(isUnavailableOrInRange(info.powerSystemWatts, std::numeric_limits<double>::max()));
REQUIRE(isUnavailableOrInRange(info.powerProcessorWatts, std::numeric_limits<double>::max()));
REQUIRE(isUnavailableOrInRange(info.powerPoeWatts, std::numeric_limits<double>::max()));
REQUIRE(isUnavailableOrInRange(info.powerTofWatts, std::numeric_limits<double>::max()));
}

TEST_CASE("Test SystemLogger Node") {
Expand All @@ -91,4 +106,4 @@ TEST_CASE("Test SystemLogger Node") {
testSystemLoggerNode(*sysInfo);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "depthai/pipeline/datatype/SystemInformationRVC4.hpp"

#include <catch2/catch_all.hpp>
#include <stdexcept>

#include "depthai/utility/Serialization.hpp"

namespace {

// Wire schema shipped before accelerator and power fields were appended.
struct LegacySystemInformationRVC4 {
dai::MemoryInfo ddrMemoryUsage;
int64_t processMemoryUsage = 0;
dai::CpuUsage cpuAvgUsage;
dai::CpuUsage processCpuAvgUsage;
std::vector<dai::CpuUsage> cpuUsages;
dai::ChipTemperatureRVC4 chipTemperature;

DEPTHAI_SERIALIZE(LegacySystemInformationRVC4, ddrMemoryUsage, processMemoryUsage, cpuAvgUsage, processCpuAvgUsage, cpuUsages, chipTemperature);
};

} // namespace

TEST_CASE("SystemInformationRVC4 appended fields serialize and roundtrip") {
dai::SystemInformationRVC4 message;
REQUIRE(message.gpuUtilizationPercent == -1);
REQUIRE(message.dspHvxActivityPercent == -1);
REQUIRE(message.dspHmxActivityPercent == -1);
REQUIRE(message.dspQ6LoadKcps == -1);
REQUIRE(message.powerSystemWatts == -1);
REQUIRE(message.powerProcessorWatts == -1);
REQUIRE(message.powerPoeWatts == -1);
REQUIRE(message.powerTofWatts == -1);
message.gpuUtilizationPercent = 23.5;
message.dspHvxActivityPercent = 10.25;
message.dspHmxActivityPercent = 4.75;
message.dspQ6LoadKcps = 321.0;
message.powerSystemWatts = 2.1;
message.powerProcessorWatts = 1.2;
message.powerPoeWatts = 0.7;
message.powerTofWatts = 0.3;

const auto bytes = dai::utility::serialize(message);
dai::SystemInformationRVC4 restored;
REQUIRE(dai::utility::deserialize(bytes, restored));
REQUIRE(restored.gpuUtilizationPercent == Catch::Approx(23.5));
REQUIRE(restored.dspHvxActivityPercent == Catch::Approx(10.25));
REQUIRE(restored.dspHmxActivityPercent == Catch::Approx(4.75));
REQUIRE(restored.dspQ6LoadKcps == Catch::Approx(321.0));
REQUIRE(restored.powerSystemWatts == Catch::Approx(2.1));
REQUIRE(restored.powerProcessorWatts == Catch::Approx(1.2));
REQUIRE(restored.powerPoeWatts == Catch::Approx(0.7));
REQUIRE(restored.powerTofWatts == Catch::Approx(0.3));
}

TEST_CASE("SystemInformationRVC4 old wire payload is not compatible with the extended libnop schema") {
LegacySystemInformationRVC4 oldMessage;
oldMessage.processMemoryUsage = 12345;
oldMessage.cpuAvgUsage.average = 0.5f;

const auto oldBytes = dai::utility::serialize(oldMessage);
dai::SystemInformationRVC4 decoded;
bool decodedSuccessfully = false;
try {
decodedSuccessfully = dai::utility::deserialize(oldBytes, decoded);
} catch(const std::runtime_error&) {
// In exception-enabled builds libnop reports a truncated struct by throwing.
}
REQUIRE_FALSE(decodedSuccessfully);
}

TEST_CASE("SystemInformationRVC4 extended wire payload is not compatible with the old libnop schema") {
dai::SystemInformationRVC4 newMessage;
newMessage.processMemoryUsage = 12345;
newMessage.cpuAvgUsage.average = 0.5f;
newMessage.gpuUtilizationPercent = 50;

const auto newBytes = dai::utility::serialize(newMessage);
LegacySystemInformationRVC4 oldDecoder;
bool decodedSuccessfully = false;
try {
decodedSuccessfully = dai::utility::deserialize(newBytes, oldDecoder);
} catch(const std::runtime_error&) {
// In exception-enabled builds libnop reports a struct member-count mismatch by throwing.
}
REQUIRE_FALSE(decodedSuccessfully);
}