diff --git a/tools/projmgr/src/ProjMgrMlops.cpp b/tools/projmgr/src/ProjMgrMlops.cpp index 2ec569de0..96094ec96 100644 --- a/tools/projmgr/src/ProjMgrMlops.cpp +++ b/tools/projmgr/src/ProjMgrMlops.cpp @@ -10,6 +10,8 @@ #include "ProjMgrParser.h" #include "ProjMgrUtils.h" +#include + using namespace std; ProjMgrMlops::ProjMgrMlops(ProjMgrWorker* worker) : m_worker(worker) { @@ -56,31 +58,34 @@ bool ProjMgrMlops::GetTargetSetItemRef(const TargetType& targetType, optional& npus, const string& filter) { if (!LoadPacks(context)) { return false; } + if (!selectedContext.empty()) { + if (!ProcessPrecedences(context, BoardOrDevice::Both)) { + return false; + } + if (!SetTargetAttributes(context, context.targetAttributes)) { + return false; + } + } CollectNpuInfo(context); for (const auto& npuInfoItem : context.npuInfoItems) { string npuString = npuInfoItem.type + " (" + npuInfoItem.macs + "):"; @@ -6460,6 +6468,9 @@ void ProjMgrWorker::CollectNpuInfo(ContextItem& context) { } // collect NPU features for each processor for (const auto& [pname, processor] : device->GetProcessors()) { + if (!context.deviceItem.pname.empty() && context.deviceItem.pname != pname) { + continue; + } const auto& features = device->GetEffectiveProperties("feature", pname); for (const auto& feature : features) { if (feature->GetAttribute("type") != "NPU") { diff --git a/tools/projmgr/test/data/MLOps/npu_mismatch.csolution.yml b/tools/projmgr/test/data/MLOps/npu_mismatch.csolution.yml new file mode 100644 index 000000000..e843837e8 --- /dev/null +++ b/tools/projmgr/test/data/MLOps/npu_mismatch.csolution.yml @@ -0,0 +1,33 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json + +solution: + compiler: AC6 + + mlops: + description: explicit npu configuration does not match DFP device information + npu: + type: Ethos-U85 + macs: 128 + + target-types: + - type: Hardware + device: RteTest_ARMCM0_Dual + target-set: + - set: + images: + - project-context: core0 + - project-context: core1 + + - type: Simulator + device: RteTest_ARMCM0_Dual + target-set: + - set: FVP-Test + debugger: + name: Arm-FVP + images: + - project-context: core0 + - project-context: core1 + + projects: + - project: core0/core0.cproject.yml + - project: core1/core1.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 229a5a0d4..f03e78d29 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -618,6 +618,21 @@ Ethos-U55 \\(128MACs\\):\n\ EXPECT_TRUE(regex_search(outStr, regex("\ Ethos-U55 \\(128MACs\\):\n\ ARM::RteTest_ARMCM0_Single, \\[cm0_core1\\] Cortex-M0\n"))); + + // verify NPU listing is restricted to the device and processor selected by a context + streamRedirect.ClearStringStreams(); + const string& csolution = testinput_folder + "/MLOps/minimal.csolution.yml"; + argv[3] = (char*)"--solution"; + argv[4] = (char*)csolution.c_str(); + argv[5] = (char*)"-c"; + argv[6] = (char*)"core0+Hardware"; + EXPECT_EQ(0, RunProjMgr(7, argv, 0)); + outStr = streamRedirect.GetOutString(); + EXPECT_NE(string::npos, outStr.find("ARM::RteTest_ARMCM0_Dual")); + EXPECT_NE(string::npos, outStr.find("[cm0_core0]")); + EXPECT_EQ(string::npos, outStr.find("ARM::RteTest_ARMCM0_Single")); + EXPECT_EQ(string::npos, outStr.find("[cm0_core1]")); + EXPECT_EQ(string::npos, outStr.find("Ethos-U55 (256MACs)")); } TEST_F(ProjMgrUnitTests, RunProjMgr_ListComponents) { @@ -7869,6 +7884,7 @@ TEST_F(ProjMgrUnitTests, ParseCommandLine_MutualExclusionOptions) { } TEST_F(ProjMgrUnitTests, GenerateMLOps) { + StdStreamRedirect streamRedirect; char* argv[5]; string csolution = testinput_folder + "/MLOps/minimal.csolution.yml"; argv[1] = (char*)"convert"; @@ -7908,6 +7924,18 @@ TEST_F(ProjMgrUnitTests, GenerateMLOps) { EXPECT_EQ("Ethos-U55", mlopsMacsOnly["cbuild-mlops"]["npu"]["type"].as()); EXPECT_EQ("128", mlopsMacsOnly["cbuild-mlops"]["npu"]["macs"].as()); + // Ethos-U85 and 128 MACs both exist in the DFP, but not as the same NPU capability + // verify that the type matches while the incompatible MAC count produces a warning + streamRedirect.ClearStringStreams(); + csolution = testinput_folder + "/MLOps/npu_mismatch.csolution.yml"; + argv[2] = (char*)csolution.c_str(); + EXPECT_EQ(0, RunProjMgr(5, argv, m_envp)); + const string warningStr = streamRedirect.GetErrorString(); + EXPECT_EQ(string::npos, warningStr.find("npu_mismatch.csolution.yml - warning csolution: " + "mlops.npu.type value does not match DFP device information")); + EXPECT_NE(string::npos, warningStr.find("npu_mismatch.csolution.yml - warning csolution: " + "mlops.npu.macs value does not match DFP device information")); + // hardware target is not present csolution = testinput_folder + "/MLOps/no_hardware.csolution.yml"; argv[2] = (char*)csolution.c_str();