Skip to content

Commit b0c395c

Browse files
authored
[projmgr] MLOps: handle image-only target-set
1 parent af2c644 commit b0c395c

11 files changed

Lines changed: 202 additions & 32 deletions

tools/projmgr/include/ProjMgrMlops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class ProjMgrMlops {
135135
std::string BuildActive(const std::string& targetType, const std::string& targetSet) const;
136136
std::string GetCustomScalar(const CustomItem& custom, const std::string& key) const;
137137
std::string BuildVelaOptions(const MlopsNpuType& npu, const MlopsVelaItem& vela) const;
138-
void SetMlopsRunType(MlopsRunType& run, const std::string& targetType, const std::string& targetSet,
138+
bool SetMlopsRunType(MlopsRunType& run, const std::string& targetType, const TargetSetItem& targetSet,
139139
const std::vector<ContextItem>& contexts, const std::string& outBaseDir, const std::string& solutionName) const;
140140
};
141141

tools/projmgr/include/ProjMgrWorker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,8 @@ class ProjMgrWorker {
13971397
void ResolvePackRequirement(ContextItem& context, const PackItem& packEntry, bool ignoreCBuildPack);
13981398
void FormatResolvedPackIds();
13991399
void RetrieveToolchainConfigFiles();
1400+
bool PushImageOnlyTargetType(const std::string& targetType, const std::vector<ImageItem>& images, StrVec& imageOnlyTargetTypes);
1401+
14001402
};
14011403

14021404
#endif // PROJMGRWORKER_H

tools/projmgr/src/ProjMgrMlops.cpp

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,37 @@ string ProjMgrMlops::BuildVelaOptions(const MlopsNpuType& npu, const MlopsVelaIt
115115
return options;
116116
}
117117

118-
void ProjMgrMlops::SetMlopsRunType(MlopsRunType& run, const string& targetType, const string& targetSet,
118+
bool ProjMgrMlops::SetMlopsRunType(MlopsRunType& run, const string& targetType, const TargetSetItem& targetSet,
119119
const vector<ContextItem>& contexts, const string& outBaseDir, const string& solutionName) const {
120-
run.active = BuildActive(targetType, targetSet);
120+
run.active = BuildActive(targetType, targetSet.set);
121121
run.cbuildRun = outBaseDir + '/' + solutionName + '+' + targetType + ".cbuild-run.yml";
122-
for (const auto& context : contexts) {
122+
for (auto context : contexts) {
123123
if (context.outputTypes.elf.on) {
124124
MlopsOutputType output;
125125
output.file = context.directories.cprj + '/' + context.directories.outdir + '/' + context.outputTypes.elf.filename;
126126
output.type = RteConstants::OUTPUT_TYPE_ELF;
127127
run.output.push_back(output);
128128
}
129+
if (context.imageOnly) {
130+
for (auto item : targetSet.images) {
131+
if (!item.image.empty()) {
132+
if (!m_worker->ProcessSequenceRelative(context, item.image, context.csolution->directory, false)) {
133+
return false;
134+
}
135+
if (RteFsUtils::IsRelative(item.image)) {
136+
RteFsUtils::NormalizePath(item.image, context.directories.cprj);
137+
}
138+
if (ProjMgrUtils::FileTypeFromExtension(item.image) == RteConstants::OUTPUT_TYPE_ELF) {
139+
MlopsOutputType output;
140+
output.file = item.image;
141+
output.type = RteConstants::OUTPUT_TYPE_ELF;
142+
run.output.push_back(output);
143+
}
144+
}
145+
}
146+
}
129147
}
148+
return true;
130149
}
131150

132151
bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& mlops) {
@@ -157,22 +176,20 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
157176
{hardwareTargetSet, hardwareType, hardwareContexts}, {simulatorTargetSet, simulatorType, simulatorContexts}};
158177
for (auto& [targetSet, targetType, ref] : refs) {
159178
for (const auto& entry : targetSet.images) {
160-
if (!entry.context.empty()) {
161-
const string contextName = entry.context + "+" + targetType;
162-
if (contexts->find(contextName) != contexts->end()) {
163-
// process context precedences if needed
164-
auto& context = contexts->at(contextName);
165-
if (!context.precedences) {
166-
if (!m_worker->ParseContextLayers(context) || !m_worker->LoadPacks(context) ||
167-
!m_worker->ProcessPrecedences(context, BoardOrDevice::Both) ||
168-
!m_worker->SetTargetAttributes(context, context.targetAttributes)) {
169-
return false;
170-
}
171-
m_worker->CollectNpuInfo(context);
179+
const string contextName = (entry.context.empty() ? csolution.name : entry.context) + "+" + targetType;
180+
if (contexts->find(contextName) != contexts->end()) {
181+
// process context precedences if needed
182+
auto& context = contexts->at(contextName);
183+
if (!context.precedences) {
184+
if (!m_worker->ParseContextLayers(context) || !m_worker->LoadPacks(context) ||
185+
!m_worker->ProcessPrecedences(context, BoardOrDevice::Both) ||
186+
!m_worker->SetTargetAttributes(context, context.targetAttributes)) {
187+
return false;
172188
}
173-
ref.push_back(context);
174-
pnames.insert(context.deviceItem.pname);
189+
m_worker->CollectNpuInfo(context);
175190
}
191+
ref.push_back(context);
192+
pnames.insert(context.deviceItem.pname);
176193
}
177194
}
178195
}
@@ -185,7 +202,7 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
185202
for (const auto& [ref, t] : contextRefs) {
186203
if (!t.targetType.empty() && ref.empty()) {
187204
// print error if context for specified target type was not found
188-
ProjMgrLogger::Get().Error("mlops: no project-context specified for target '" +
205+
ProjMgrLogger::Get().Error("mlops: no image or project-context specified for target '" +
189206
t.targetType + (t.targetSet.empty() ? "" : '@' + t.targetSet) + "'");
190207
return false;
191208
}
@@ -198,8 +215,8 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
198215
ContextItem& hardwareContext = hardwareFound ? hardwareContexts.front() : emptyContext;
199216
ContextItem& simulatorContext = simulatorFound ? simulatorContexts.front() : emptyContext;
200217

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

204221
// mlops description
205222
mlops.description = solutionMlops.description;
@@ -289,13 +306,17 @@ bool ProjMgrMlops::CollectSettings(const CsolutionItem& csolution, MlopsType& ml
289306
if (hardwareFound) {
290307
// set hardware run types
291308
const string outBaseDir = hardwareContext.directories.cprj + "/" + hardwareContext.directories.outBaseDir;
292-
SetMlopsRunType(mlops.hardware, hardwareType, hardwareTargetSet.set, hardwareContexts, outBaseDir, csolution.name);
309+
if (!SetMlopsRunType(mlops.hardware, hardwareType, hardwareTargetSet, hardwareContexts, outBaseDir, csolution.name)) {
310+
return false;
311+
}
293312
}
294313

295314
if (simulatorFound) {
296315
// set simulator run types
297316
const string outBaseDir = simulatorContext.directories.cprj + "/" + simulatorContext.directories.outBaseDir;
298-
SetMlopsRunType(mlops.simulator, simulatorType, simulatorTargetSet.set, simulatorContexts, outBaseDir, csolution.name);
317+
if (!SetMlopsRunType(mlops.simulator, simulatorType, simulatorTargetSet, simulatorContexts, outBaseDir, csolution.name)) {
318+
return false;
319+
}
299320

300321
// get debugger model and config-file
301322
mlops.simulator.model = GetCustomScalar(simulatorTargetSet.debugger.custom, "model");

tools/projmgr/src/ProjMgrWorker.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,34 @@ ProjMgrWorker::~ProjMgrWorker(void) {
6464
}
6565
}
6666

67+
bool ProjMgrWorker::PushImageOnlyTargetType(const string& targetType, const vector<ImageItem>& images, StrVec& imageOnlyTargetTypes) {
68+
if (images.empty()) {
69+
return false;
70+
}
71+
for (const auto& item : images) {
72+
if (!item.context.empty()) {
73+
return false;
74+
}
75+
}
76+
CollectionUtils::PushBackUniquely(imageOnlyTargetTypes, targetType);
77+
return true;
78+
}
79+
6780
void ProjMgrWorker::AddImageOnlyContext() {
81+
StrVec imageOnlyTargetTypes;
82+
// add image-only context for active target-set
6883
if (!m_activeTargetSet.images.empty()) {
69-
for (const auto& item : m_activeTargetSet.images) {
70-
if (!item.context.empty()) {
71-
return;
84+
PushImageOnlyTargetType(m_activeTargetType, m_activeTargetSet.images, imageOnlyTargetTypes);
85+
}
86+
// add other image-only contexts (if any)
87+
for (const auto& [targetType, item] : m_parser->GetCsolution().targetTypes) {
88+
for (const auto& targetSet : item.targetSet) {
89+
if (PushImageOnlyTargetType(targetType, targetSet.images, imageOnlyTargetTypes)) {
90+
break;
7291
}
7392
}
93+
}
94+
for (const auto& targetType : imageOnlyTargetTypes) {
7495
ContextDesc descriptor;
7596
ContextItem context;
7697
context.imageOnly = true;
@@ -79,7 +100,7 @@ void ProjMgrWorker::AddImageOnlyContext() {
79100
context.cproject = &m_imageOnly;
80101
context.cproject->name = name;
81102
context.cproject->directory = context.csolution->directory;
82-
AddContext(descriptor, { "", m_activeTargetType }, context);
103+
AddContext(descriptor, { "", targetType }, context);
83104
}
84105
}
85106

tools/projmgr/test/data/MLOps/extended.csolution.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
solution:
44
compiler: AC6
55

6+
packs:
7+
- pack: ARM::RteTest_DFP
8+
69
mlops: # enable *.cbuild-mlops.yml
710
description: ML model with extended configuration
811
npu:
@@ -34,8 +37,6 @@ solution:
3437

3538
- type: Simulator
3639
device: RteTest_ARMCM0_Dual
37-
define:
38-
- SIMULATOR
3940
variables:
4041
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
4142
target-set:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json
2+
3+
solution:
4+
compiler: AC6
5+
6+
packs:
7+
- pack: ARM::RteTest_DFP
8+
9+
mlops:
10+
description: Image-only MLOps with malformed hardware image path
11+
12+
target-types:
13+
- type: Hardware
14+
device: RteTest_ARMCM0_Dual:cm0_core0
15+
target-set:
16+
- set:
17+
images:
18+
- image: $BadVar$/hardware.elf
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json
2+
3+
solution:
4+
compiler: AC6
5+
6+
packs:
7+
- pack: ARM::RteTest_DFP
8+
9+
mlops:
10+
description: Image-only MLOps with malformed simulator image path
11+
12+
target-types:
13+
- type: Simulator
14+
device: RteTest_ARMCM0_Dual:cm0_core0
15+
target-set:
16+
- set: FVP-Test
17+
debugger:
18+
name: Arm-FVP
19+
images:
20+
- image: $BadVar$/simulator.elf

tools/projmgr/test/data/MLOps/minimal.csolution.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
solution:
44
compiler: AC6
55

6+
packs:
7+
- pack: ARM::RteTest_DFP
8+
69
mlops:
710
description: ML model with minimal configuration
8-
model:
11+
model:
912
clayer: $AI-Layer$
10-
13+
1114
target-types:
1215
- type: Hardware
1316
device: RteTest_ARMCM0_Dual
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json
2+
3+
solution:
4+
compiler: AC6
5+
6+
packs:
7+
- pack: ARM::RteTest_DFP
8+
9+
mlops:
10+
description: ML model with minimal image-only configuration
11+
model:
12+
clayer: $AI-Layer$
13+
14+
target-types:
15+
- type: Hardware
16+
device: RteTest_ARMCM0_Dual:cm0_core0
17+
variables:
18+
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
19+
target-set:
20+
- set:
21+
images:
22+
- image: images/hardware.elf
23+
24+
- type: Simulator
25+
device: RteTest_ARMCM0_Dual:cm0_core0
26+
variables:
27+
- AI-Layer: $SolutionDir()$/ai_layer/ai_layer.clayer.yml
28+
target-set:
29+
- set: FVP-Test
30+
debugger:
31+
name: Arm-FVP
32+
model: FVP_Corstone_SSE-320
33+
config-file: fvp/fvp_config.txt
34+
images:
35+
- image: images/simulator.elf
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cbuild-mlops:
2+
description: ML model with minimal image-only configuration
3+
processor:
4+
type: Cortex-M0
5+
npu:
6+
type: Ethos-U55
7+
macs: 128
8+
vela:
9+
ini: .cmsis/vela_deviceLevel.ini
10+
options: --accelerator-config ethos-u55-128
11+
model:
12+
clayer: ai_layer/ai_layer.clayer.yml
13+
name: Algorithm
14+
hardware:
15+
active: Hardware
16+
cbuild-run: out/minimal_image_only+Hardware.cbuild-run.yml
17+
output:
18+
- file: images/hardware.elf
19+
type: elf
20+
simulator:
21+
active: Simulator@FVP-Test
22+
cbuild-run: out/minimal_image_only+Simulator.cbuild-run.yml
23+
output:
24+
- file: images/simulator.elf
25+
type: elf
26+
model: FVP_Corstone_SSE-320
27+
config-file: fvp/fvp_config.txt

0 commit comments

Comments
 (0)