Skip to content

Commit 80db36a

Browse files
authored
Merge pull request #106 from cosmo-wander-ai/codex/rv1126b-npu-load-metrics
fix(rknn): parse RV1126B aggregate NPU load
2 parents 7f855c6 + 42c7e1f commit 80db36a

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

src/service/system/impl/AcceleratorMetricsProviderRknn.cc

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,30 @@ namespace {
5151
return std::nullopt;
5252
cores_by_id[*core_id] = static_cast<double>(*percent) / 100.0;
5353
}
54-
if (cores_by_id.empty())
54+
if (!cores_by_id.empty()) {
55+
NpuLoadSnapshot result;
56+
result.cores.reserve(cores_by_id.size());
57+
for (const auto& [core_id, load] : cores_by_id) {
58+
(void)core_id;
59+
result.cores.push_back(load);
60+
result.aggregate = std::max(result.aggregate, load);
61+
}
62+
return result;
63+
}
64+
65+
// Single-core Rockchip parts such as RV1126B expose only an aggregate
66+
// counter ("NPU load: 37%") instead of RK3576-style CoreN fields.
67+
static const std::regex aggregate_pattern(R"(NPU\s+load\s*:\s*([0-9]+)\s*%)", std::regex::icase);
68+
std::smatch aggregate_match;
69+
if (!std::regex_search(text, aggregate_match, aggregate_pattern))
70+
return std::nullopt;
71+
const auto percent = ParseUnsigned(aggregate_match[1]);
72+
if (!percent || *percent > 100)
5573
return std::nullopt;
5674

5775
NpuLoadSnapshot result;
58-
result.cores.reserve(cores_by_id.size());
59-
for (const auto& [core_id, load] : cores_by_id) {
60-
(void)core_id;
61-
result.cores.push_back(load);
62-
result.aggregate = std::max(result.aggregate, load);
63-
}
76+
result.aggregate = static_cast<double>(*percent) / 100.0;
77+
result.cores.push_back(result.aggregate);
6478
return result;
6579
}
6680

test/test_accelerator_metrics_provider.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ TEST_CASE("RKNN accelerator metrics provider reports per-core busy-time load", "
6767
CHECK(metrics.gpudevusage.front().gpuusage == Catch::Approx(0.42));
6868
}
6969

70+
TEST_CASE("RKNN accelerator metrics provider reports aggregate-only busy-time load",
71+
"[system][metrics][rknn]") {
72+
ScopedNpuLoadFixture fixture("NPU load: 37%\n");
73+
auto provider = cosmo::service::detail::CreateAcceleratorMetricsProvider();
74+
REQUIRE(provider != nullptr);
75+
76+
const auto metrics = provider->QueryUtilization();
77+
CHECK(metrics.gpuusageAvailable);
78+
CHECK(metrics.gpuusage == Catch::Approx(0.37));
79+
CHECK(metrics.utilizationMetric == "busy-time-load");
80+
REQUIRE(metrics.coreUtilizations.size() == 1);
81+
CHECK(metrics.coreUtilizations.front() == Catch::Approx(0.37));
82+
REQUIRE(metrics.gpudevusage.size() == 1);
83+
CHECK(metrics.gpudevusage.front().gpuusage == Catch::Approx(0.37));
84+
}
85+
7086
TEST_CASE("RKNN accelerator metrics provider rejects invalid load", "[system][metrics][rknn]") {
7187
ScopedNpuLoadFixture fixture("NPU load: Core0: 105%, Core1: 0%,\n");
7288
auto provider = cosmo::service::detail::CreateAcceleratorMetricsProvider();
@@ -77,4 +93,16 @@ TEST_CASE("RKNN accelerator metrics provider rejects invalid load", "[system][me
7793
CHECK(metrics.gpuusage == 0.0);
7894
CHECK(metrics.coreUtilizations.empty());
7995
}
96+
97+
TEST_CASE("RKNN accelerator metrics provider rejects invalid aggregate-only load",
98+
"[system][metrics][rknn]") {
99+
ScopedNpuLoadFixture fixture("NPU load: 101%\n");
100+
auto provider = cosmo::service::detail::CreateAcceleratorMetricsProvider();
101+
REQUIRE(provider != nullptr);
102+
103+
const auto metrics = provider->QueryUtilization();
104+
CHECK_FALSE(metrics.gpuusageAvailable);
105+
CHECK(metrics.gpuusage == 0.0);
106+
CHECK(metrics.coreUtilizations.empty());
107+
}
80108
#endif

0 commit comments

Comments
 (0)