Skip to content
Merged
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
2 changes: 1 addition & 1 deletion tools/projmgr/include/ProjMgrMlops.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class ProjMgrMlops {
std::string BuildActive(const std::string& targetType, const std::string& targetSet) const;
std::string GetCustomScalar(const CustomItem& custom, const std::string& key) const;
std::string BuildVelaOptions(const MlopsNpuType& npu, const MlopsVelaItem& vela) const;
void SetMlopsRunType(MlopsRunType& run, const std::string& targetType, const std::string& targetSet,
bool SetMlopsRunType(MlopsRunType& run, const std::string& targetType, const TargetSetItem& targetSet,
const std::vector<ContextItem>& contexts, const std::string& outBaseDir, const std::string& solutionName) const;
};

Expand Down
2 changes: 2 additions & 0 deletions tools/projmgr/include/ProjMgrWorker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,8 @@ class ProjMgrWorker {
void ResolvePackRequirement(ContextItem& context, const PackItem& packEntry, bool ignoreCBuildPack);
void FormatResolvedPackIds();
void RetrieveToolchainConfigFiles();
bool PushImageOnlyTargetType(const std::string& targetType, const std::vector<ImageItem>& images, StrVec& imageOnlyTargetTypes);

};

#endif // PROJMGRWORKER_H
65 changes: 43 additions & 22 deletions tools/projmgr/src/ProjMgrMlops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,37 @@ string ProjMgrMlops::BuildVelaOptions(const MlopsNpuType& npu, const MlopsVelaIt
return options;
}

void ProjMgrMlops::SetMlopsRunType(MlopsRunType& run, const string& targetType, const string& targetSet,
bool ProjMgrMlops::SetMlopsRunType(MlopsRunType& run, const string& targetType, const TargetSetItem& targetSet,
const vector<ContextItem>& contexts, const string& outBaseDir, const string& solutionName) const {
run.active = BuildActive(targetType, targetSet);
run.active = BuildActive(targetType, targetSet.set);
run.cbuildRun = outBaseDir + '/' + solutionName + '+' + targetType + ".cbuild-run.yml";
for (const auto& context : contexts) {
for (auto context : contexts) {
if (context.outputTypes.elf.on) {
MlopsOutputType output;
output.file = context.directories.cprj + '/' + context.directories.outdir + '/' + context.outputTypes.elf.filename;
output.type = RteConstants::OUTPUT_TYPE_ELF;
run.output.push_back(output);
}
if (context.imageOnly) {
for (auto item : targetSet.images) {
if (!item.image.empty()) {
if (!m_worker->ProcessSequenceRelative(context, item.image, context.csolution->directory, false)) {
return false;
}
if (RteFsUtils::IsRelative(item.image)) {
RteFsUtils::NormalizePath(item.image, context.directories.cprj);
}
if (ProjMgrUtils::FileTypeFromExtension(item.image) == RteConstants::OUTPUT_TYPE_ELF) {
MlopsOutputType output;
output.file = item.image;
output.type = RteConstants::OUTPUT_TYPE_ELF;
run.output.push_back(output);
}
}
Comment thread
brondani marked this conversation as resolved.
}
}
}
return true;
}

bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& mlops) {
Expand Down Expand Up @@ -157,22 +176,20 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
{hardwareTargetSet, hardwareType, hardwareContexts}, {simulatorTargetSet, simulatorType, simulatorContexts}};
for (auto& [targetSet, targetType, ref] : refs) {
for (const auto& entry : targetSet.images) {
if (!entry.context.empty()) {
const string contextName = entry.context + "+" + targetType;
if (contexts->find(contextName) != contexts->end()) {
// process context precedences if needed
auto& context = contexts->at(contextName);
if (!context.precedences) {
if (!m_worker->ParseContextLayers(context) || !m_worker->LoadPacks(context) ||
!m_worker->ProcessPrecedences(context, BoardOrDevice::Both) ||
!m_worker->SetTargetAttributes(context, context.targetAttributes)) {
return false;
}
m_worker->CollectNpuInfo(context);
const string contextName = (entry.context.empty() ? csolution.name : entry.context) + "+" + targetType;
if (contexts->find(contextName) != contexts->end()) {
// process context precedences if needed
auto& context = contexts->at(contextName);
if (!context.precedences) {
if (!m_worker->ParseContextLayers(context) || !m_worker->LoadPacks(context) ||
!m_worker->ProcessPrecedences(context, BoardOrDevice::Both) ||
!m_worker->SetTargetAttributes(context, context.targetAttributes)) {
return false;
}
ref.push_back(context);
pnames.insert(context.deviceItem.pname);
m_worker->CollectNpuInfo(context);
}
ref.push_back(context);
pnames.insert(context.deviceItem.pname);
}
}
}
Expand All @@ -185,7 +202,7 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
for (const auto& [ref, t] : contextRefs) {
if (!t.targetType.empty() && ref.empty()) {
// print error if context for specified target type was not found
ProjMgrLogger::Get().Error("mlops: no project-context specified for target '" +
ProjMgrLogger::Get().Error("mlops: no image or project-context specified for target '" +
t.targetType + (t.targetSet.empty() ? "" : '@' + t.targetSet) + "'");
return false;
}
Expand All @@ -198,8 +215,8 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
ContextItem& hardwareContext = hardwareFound ? hardwareContexts.front() : emptyContext;
ContextItem& simulatorContext = simulatorFound ? simulatorContexts.front() : emptyContext;

// if hardware is not determined use first default context for processor type and access sequences
ContextItem& context = hardwareFound ? hardwareContext : contexts->begin()->second;
// if hardware is not determined use first selected context for processor type and access sequences
ContextItem& context = hardwareFound ? hardwareContext : contexts->at(m_worker->GetSelectedContexts().front());

// mlops description
mlops.description = solutionMlops.description;
Expand Down Expand Up @@ -289,13 +306,17 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
if (hardwareFound) {
// set hardware run types
const string outBaseDir = hardwareContext.directories.cprj + "/" + hardwareContext.directories.outBaseDir;
SetMlopsRunType(mlops.hardware, hardwareType, hardwareTargetSet.set, hardwareContexts, outBaseDir, csolution.name);
if (!SetMlopsRunType(mlops.hardware, hardwareType, hardwareTargetSet, hardwareContexts, outBaseDir, csolution.name)) {
return false;
}
}

if (simulatorFound) {
// set simulator run types
const string outBaseDir = simulatorContext.directories.cprj + "/" + simulatorContext.directories.outBaseDir;
SetMlopsRunType(mlops.simulator, simulatorType, simulatorTargetSet.set, simulatorContexts, outBaseDir, csolution.name);
if (!SetMlopsRunType(mlops.simulator, simulatorType, simulatorTargetSet, simulatorContexts, outBaseDir, csolution.name)) {
return false;
}

// get debugger model and config-file
mlops.simulator.model = GetCustomScalar(simulatorTargetSet.debugger.custom, "model");
Expand Down
29 changes: 25 additions & 4 deletions tools/projmgr/src/ProjMgrWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,34 @@ ProjMgrWorker::~ProjMgrWorker(void) {
}
}

bool ProjMgrWorker::PushImageOnlyTargetType(const string& targetType, const vector<ImageItem>& images, StrVec& imageOnlyTargetTypes) {
if (images.empty()) {
return false;
}
for (const auto& item : images) {
if (!item.context.empty()) {
return false;
}
}
CollectionUtils::PushBackUniquely(imageOnlyTargetTypes, targetType);
return true;
Comment thread
brondani marked this conversation as resolved.
}

void ProjMgrWorker::AddImageOnlyContext() {
StrVec imageOnlyTargetTypes;
// add image-only context for active target-set
if (!m_activeTargetSet.images.empty()) {
for (const auto& item : m_activeTargetSet.images) {
if (!item.context.empty()) {
return;
PushImageOnlyTargetType(m_activeTargetType, m_activeTargetSet.images, imageOnlyTargetTypes);
}
// add other image-only contexts (if any)
for (const auto& [targetType, item] : m_parser->GetCsolution().targetTypes) {
for (const auto& targetSet : item.targetSet) {
if (PushImageOnlyTargetType(targetType, targetSet.images, imageOnlyTargetTypes)) {
break;
}
}
}
for (const auto& targetType : imageOnlyTargetTypes) {
ContextDesc descriptor;
ContextItem context;
context.imageOnly = true;
Expand All @@ -79,7 +100,7 @@ void ProjMgrWorker::AddImageOnlyContext() {
context.cproject = &m_imageOnly;
context.cproject->name = name;
context.cproject->directory = context.csolution->directory;
AddContext(descriptor, { "", m_activeTargetType }, context);
AddContext(descriptor, { "", targetType }, context);
}
}

Expand Down
5 changes: 3 additions & 2 deletions tools/projmgr/test/data/MLOps/extended.csolution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
solution:
compiler: AC6

packs:
- pack: ARM::RteTest_DFP

mlops: # enable *.cbuild-mlops.yml
description: ML model with extended configuration
npu:
Expand Down Expand Up @@ -34,8 +37,6 @@ solution:

- type: Simulator
device: RteTest_ARMCM0_Dual
define:
- SIMULATOR
variables:
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
target-set:
Expand Down
18 changes: 18 additions & 0 deletions tools/projmgr/test/data/MLOps/failure_image_only_hw.csolution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json

solution:
compiler: AC6

packs:
- pack: ARM::RteTest_DFP

mlops:
description: Image-only MLOps with malformed hardware image path

target-types:
- type: Hardware
device: RteTest_ARMCM0_Dual:cm0_core0
target-set:
- set:
images:
- image: $BadVar$/hardware.elf
20 changes: 20 additions & 0 deletions tools/projmgr/test/data/MLOps/failure_image_only_sim.csolution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json

solution:
compiler: AC6

packs:
- pack: ARM::RteTest_DFP

mlops:
description: Image-only MLOps with malformed simulator image path

target-types:
- type: Simulator
device: RteTest_ARMCM0_Dual:cm0_core0
target-set:
- set: FVP-Test
debugger:
name: Arm-FVP
images:
- image: $BadVar$/simulator.elf
7 changes: 5 additions & 2 deletions tools/projmgr/test/data/MLOps/minimal.csolution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
solution:
compiler: AC6

packs:
- pack: ARM::RteTest_DFP

mlops:
description: ML model with minimal configuration
model:
model:
clayer: $AI-Layer$

target-types:
- type: Hardware
device: RteTest_ARMCM0_Dual
Expand Down
35 changes: 35 additions & 0 deletions tools/projmgr/test/data/MLOps/minimal_image_only.csolution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json

solution:
compiler: AC6

packs:
- pack: ARM::RteTest_DFP

mlops:
description: ML model with minimal image-only configuration
model:
clayer: $AI-Layer$

target-types:
- type: Hardware
device: RteTest_ARMCM0_Dual:cm0_core0
variables:
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
target-set:
- set:
images:
- image: images/hardware.elf

- type: Simulator
device: RteTest_ARMCM0_Dual:cm0_core0
variables:
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
target-set:
- set: FVP-Test
debugger:
name: Arm-FVP
model: FVP_Corstone_SSE-320
config-file: fvp/fvp_config.txt
images:
- image: images/simulator.elf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cbuild-mlops:
description: ML model with minimal image-only configuration
processor:
type: Cortex-M0
npu:
type: Ethos-U55
macs: 128
vela:
ini: .cmsis/vela_deviceLevel.ini
options: --accelerator-config ethos-u55-128
model:
clayer: ai_layer/ai_layer.clayer.yml
name: Algorithm
hardware:
active: Hardware
cbuild-run: out/minimal_image_only+Hardware.cbuild-run.yml
output:
- file: images/hardware.elf
type: elf
simulator:
active: Simulator@FVP-Test
cbuild-run: out/minimal_image_only+Simulator.cbuild-run.yml
output:
- file: images/simulator.elf
type: elf
model: FVP_Corstone_SSE-320
config-file: fvp/fvp_config.txt
24 changes: 23 additions & 1 deletion tools/projmgr/test/src/ProjMgrUnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7769,7 +7769,7 @@ TEST_F(ProjMgrUnitTests, GenerateMLOps) {
const vector<pair<string, string>> failureCases = {
{ "failure1", "mlops: target type 'OtherHardware' not found" },
{ "failure2", "mlops: target set 'Simulator@OtherSet' not found" },
{ "failure3", "mlops: no project-context specified for target 'Simulator@FVP-Test'" },
{ "failure3", "mlops: no image or project-context specified for target 'Simulator@FVP-Test'" },
};
for (const auto& [name, expectedError] : failureCases) {
csolution = testinput_folder + "/MLOps/" + name + ".csolution.yml";
Expand All @@ -7791,3 +7791,25 @@ TEST_F(ProjMgrUnitTests, GenerateMLOps) {
cbuildIdx["build-idx"]["cbuilds"][0]["messages"]["errors"][0].as<string>());
RteFsUtils::RemoveDir(mlopsOutput);
}

TEST_F(ProjMgrUnitTests, GenerateMLOps_ImageOnly) {
char* argv[5];
string csolution = testinput_folder + "/MLOps/minimal_image_only.csolution.yml";
argv[1] = (char*)"convert";
argv[2] = (char*)csolution.c_str();
argv[3] = (char*)"--active";
argv[4] = (char*)"";
EXPECT_EQ(0, RunProjMgr(5, argv, m_envp));
ProjMgrTestEnv::CompareFile(testinput_folder + "/MLOps/minimal_image_only.cbuild-mlops.yml",
testinput_folder + "/MLOps/ref/minimal_image_only.cbuild-mlops.yml");

// SetMlopsRunType failure for hardware: malformed access sequence in hardware image path
csolution = testinput_folder + "/MLOps/failure_image_only_hw.csolution.yml";
argv[2] = (char*)csolution.c_str();
EXPECT_EQ(1, RunProjMgr(5, argv, m_envp));

// SetMlopsRunType failure for simulator: malformed access sequence in simulator image path
csolution = testinput_folder + "/MLOps/failure_image_only_sim.csolution.yml";
argv[2] = (char*)csolution.c_str();
EXPECT_EQ(1, RunProjMgr(5, argv, m_envp));
}
Loading