Skip to content

Commit 40fcc7c

Browse files
Dequinomarchioa
authored andcommitted
First MAGIA workflow
1 parent 62e5f1a commit 40fcc7c

11 files changed

Lines changed: 301 additions & 36 deletions

File tree

Deeploy/Targets/Magia/Deployer.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from typing import Callable, Dict, List, Type
6+
7+
import numpy as np
8+
import onnx_graphsurgeon as gs
9+
10+
from Deeploy.AbstractDataTypes import Pointer
11+
from Deeploy.CommonExtensions.NetworkDeployers.SignPropDeployer import SignPropDeployer
12+
from Deeploy.DeeployTypes import ConstantBuffer, DeploymentPlatform, NodeTemplate, TopologyOptimizer, VariableBuffer
13+
14+
class MagiaDeployer(SignPropDeployer):
15+
16+
def __init__(self,
17+
graph: gs.Graph,
18+
deploymentPlatform: DeploymentPlatform,
19+
inputTypes: Dict[str, Type[Pointer]],
20+
loweringOptimizer: TopologyOptimizer,
21+
scheduler: Callable = lambda x: x,
22+
name: str = 'DeeployNetwork',
23+
default_channels_first = False,
24+
deeployStateDir: str = "DeeployStateDir",
25+
inputOffsets: Dict[str, int] = {}):
26+
27+
super().__init__(graph,
28+
deploymentPlatform,
29+
inputTypes,
30+
loweringOptimizer,
31+
scheduler,
32+
name,
33+
default_channels_first = default_channels_first,
34+
deeployStateDir = deeployStateDir,
35+
inputOffsets = inputOffsets)
36+
37+
self.loweringOptimizer.passes += [
38+
# Extra optimizer passes on the lowering optimization pass. It seems to be different than the "normal" optimization passes defined on the Platform.
39+
]

Deeploy/Targets/Magia/Platform.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import numpy as np
6+
import onnx_graphsurgeon as gs
7+
8+
from Deeploy.DeeployTypes import ConstantBuffer, DeploymentEngine, DeploymentPlatform, NetworkContext, NodeMapper, \
9+
NodeTemplate, StructBuffer, TopologyOptimizer, TransientBuffer, VariableBuffer
10+
11+
from Deeploy.Targets.Generic.Templates import AllocateTemplate as BasicAllocateTemplate
12+
from Deeploy.Targets.Generic.Bindings import BasicAddBindings
13+
from Deeploy.Targets.Generic.Parsers import AddParser
14+
from Deeploy.Targets.Generic.Layers import AddLayer
15+
16+
from Deeploy.Targets.Magia.Templates import AllocateTemplate, FreeTemplate
17+
18+
AddMapper = NodeMapper(AddParser(), BasicAddBindings)
19+
20+
MagiaMapping = {
21+
'Add': AddLayer([AddMapper])
22+
}
23+
24+
class MagiaVariableBuffer(VariableBuffer):
25+
26+
initTemplate = AllocateTemplate.magiaInitTemplate
27+
allocTemplate = AllocateTemplate.magiaAllocateTemplate
28+
deallocTemplate = FreeTemplate.magiaFreeTemplate
29+
30+
def _bufferRepresentation(self):
31+
32+
if hasattr(self, "_memoryLevel"):
33+
memoryLevel = self._memoryLevel
34+
else:
35+
memoryLevel = None
36+
37+
return {
38+
"type": self._instance,
39+
"name": self.name,
40+
"size": int(np.prod(self.shape)),
41+
"_memoryLevel": memoryLevel
42+
}
43+
44+
class MagiaTransientBuffer(TransientBuffer):
45+
46+
initTemplate = AllocateTemplate.magiaInitTemplate
47+
allocTemplate = AllocateTemplate.magiaAllocateTemplate
48+
deallocTemplate = FreeTemplate.magiaFreeTemplate
49+
50+
def _bufferRepresentation(self):
51+
52+
if hasattr(self, "_memoryLevel"):
53+
memoryLevel = self._memoryLevel
54+
else:
55+
memoryLevel = None
56+
57+
return {"type": self._type,
58+
"name": self.name,
59+
"size": self.size,
60+
"_memoryLevel": memoryLevel
61+
}
62+
63+
class MagiaConstantBuffer(ConstantBuffer):
64+
65+
initTemplate = AllocateTemplate.magiaGlobalInitTemplate
66+
allocTemplate = AllocateTemplate.magiaGlobalAllocateTemplate
67+
deallocTemplate = FreeTemplate.magiaGlobalTemplate
68+
69+
def _bufferRepresentation(self):
70+
operatorRepresentation = super()._bufferRepresentation()
71+
72+
if hasattr(self, "_memoryLevel"):
73+
memoryLevel = self._memoryLevel
74+
else:
75+
memoryLevel = None
76+
77+
operatorRepresentation["_memoryLevel"] = memoryLevel
78+
79+
return operatorRepresentation
80+
81+
class MagiaStructBuffer(StructBuffer):
82+
83+
initTemplate = BasicAllocateTemplate.referenceStructInitTemplate
84+
allocTemplate = BasicAllocateTemplate.referenceStructAllocateTemplate
85+
deallocTemplate = NodeTemplate("")
86+
87+
88+
MagiaOptimizer = TopologyOptimizer(
89+
[
90+
# Insert here the ONNX optimization passes.
91+
],
92+
name = "MagiaOptimizer")
93+
94+
95+
_includeList = [
96+
"tile.h", "idma.h", "redmule.h", "eventunit.h"
97+
]
98+
99+
100+
class MagiaMeshEngine(DeploymentEngine):
101+
102+
def __init__(self,
103+
name: str,
104+
Mapping = MagiaMapping,
105+
initCode = "",
106+
includeList = _includeList,
107+
n_tiles: int = 4) -> None:
108+
super().__init__(name, Mapping, initCode, includeList)
109+
self.n_tiles = n_tiles
110+
111+
class MagiaPlatform(DeploymentPlatform):
112+
113+
def __init__(self,
114+
engines = [MagiaMeshEngine("MagiaMesh")],
115+
variableBuffer = MagiaVariableBuffer,
116+
constantBuffer = MagiaConstantBuffer,
117+
structBuffer = MagiaStructBuffer,
118+
transientBuffer = MagiaTransientBuffer) -> None:
119+
super().__init__(engines, variableBuffer, constantBuffer, structBuffer, transientBuffer)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-FileCopyrightText: 2021 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from Deeploy.DeeployTypes import NodeTemplate
6+
7+
magiaInitTemplate = NodeTemplate("${type.typeName} ${name};\n")
8+
9+
magiaAllocateTemplate = NodeTemplate("""
10+
% if _memoryLevel == "L1":
11+
${name} = (${type.typeName}) magia_l1_malloc(sizeof(${type.referencedType.typeName}) * ${size});\n
12+
% elif _memoryLevel == "L2" or _memoryLevel is None:
13+
${name} = (${type.typeName}) magia_l2_malloc(sizeof(${type.referencedType.typeName}) * ${size});\n
14+
% endif
15+
""")
16+
17+
magiaGlobalInitTemplate = NodeTemplate("""
18+
% if _memoryLevel == "L1":
19+
static ${type.referencedType.typeName} ${name}[${size}] = {${values}};\n
20+
% elif _memoryLevel == "L2" or _memoryLevel is None:
21+
extern ${type.referencedType.typeName} ${name}[${size}] = {${values}};\n
22+
% endif
23+
""")
24+
25+
magiaGlobalAllocateTemplate = NodeTemplate("")
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-FileCopyrightText: 2023 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from Deeploy.DeeployTypes import NodeTemplate
6+
7+
magiaFreeTemplate = NodeTemplate("""
8+
% if _memoryLevel == "L1":
9+
magia_l1_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});
10+
% elif _memoryLevel == "L2" or _memoryLevel is None:
11+
magia_l2_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});
12+
% endif
13+
""")
14+
15+
magiaGlobalTemplate = NodeTemplate("magia_l2_free(${name}, sizeof(${type.referencedType.typeName}) * ${size});")

DeeployTest/Platforms/Magia/CMakeLists.txt

Whitespace-only changes.

DeeployTest/Platforms/Magia/main.c

Whitespace-only changes.

DeeployTest/generateNetwork.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from Deeploy.Logging import DEFAULT_LOGGER as log
2222
from Deeploy.Targets.CortexM.Platform import CMSISPlatform
2323
from Deeploy.Targets.PULPOpen.Platform import PULPClusterEngine, PULPPlatform
24+
from Deeploy.Targets.Magia.Platform import MagiaMeshEngine, MagiaPlatform
2425

2526

2627
def generateNetwork(args):
@@ -87,6 +88,10 @@ def generateNetwork(args):
8788
clusters = [engine for engine in platform.engines if isinstance(engine, PULPClusterEngine)]
8889
for cluster in clusters:
8990
cluster.n_cores = args.cores
91+
92+
meshes = [engine for engine in platform.engines if isinstance(engine, MagiaMeshEngine)]
93+
for mesh in meshes:
94+
mesh.n_tiles = args.tiles
9095

9196
inputTypes = {}
9297
inputOffsets = {}
@@ -166,34 +171,36 @@ def generateNetwork(args):
166171
dest = 'debug',
167172
action = 'store_true',
168173
default = False,
169-
help = 'Enable debugging mode\n')
174+
help = 'Enable debugging mode.\n')
170175
parser.add_argument('--profileUntiled',
171176
action = 'store_true',
172177
dest = 'profileUntiled',
173178
default = False,
174-
help = 'Profile Untiled for L2\n')
179+
help = 'Profile Untiled for L2.\n')
175180
parser.add_argument('--input-type-map',
176181
nargs = '*',
177182
default = [],
178183
type = str,
179184
help = '(Optional) mapping of input names to data types. '
180-
'If not specified, types are inferred from the input data. '
181-
'Example: --input-type-map input_0=int8_t input_1=float32_t ...')
185+
'If not specified, types are inferred from the input data.'
186+
'Example: --input-type-map input_0=int8_t input_1=float32_t ...\n')
182187
parser.add_argument('--input-offset-map',
183188
nargs = '*',
184189
default = [],
185190
type = str,
186191
help = '(Optional) mapping of input names to offsets. '
187192
'If not specified, offsets are set to 0. '
188-
'Example: --input-offset-map input_0=0 input_1=128 ...')
193+
'Example: --input-offset-map input_0=0 input_1=128 ...\n')
189194
parser.add_argument('--shouldFail', action = 'store_true')
190-
parser.add_argument(
191-
"--cores",
192-
type = int,
193-
default = 1,
194-
help =
195-
"Number of cores on which the network is run. Currently, required for im2col buffer sizing on Siracusa. Default: 1.",
196-
)
195+
parser.add_argument("--cores",
196+
type = int,
197+
default = 1,
198+
help = 'Number of cores on which the network is run.'
199+
'Currently, required for im2col buffer sizing on Siracusa. Default: 1.\n')
200+
parser.add_argument("--tiles",
201+
type = int,
202+
default = 1,
203+
help = 'Number of tiles on which the network is run (mesh based architectures only).\n')
197204
parser.set_defaults(shouldFail = False)
198205

199206
args = parser.parse_args()

DeeployTest/testRunner_magia.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-FileCopyrightText: 2023 ETH Zurich and University of Bologna
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from testUtils.testRunner import TestRunner, TestRunnerArgumentParser
6+
7+
if __name__ == "__main__":
8+
9+
parser = TestRunnerArgumentParser(
10+
tiling_arguments = False,
11+
description = "Deeploy Code Generation Utility for the Magia Platform (no Tiling).")
12+
13+
parser.add_argument('--tiles',
14+
metavar = '<tiles>',
15+
dest = 'tiles',
16+
type = int,
17+
default = 4,
18+
help = 'Set number of mesh tiles')
19+
20+
args = parser.parse_args()
21+
22+
testRunner = TestRunner(platform = "Magia", simulator = "none", tiling = False, argument_parser = parser)
23+
24+
testRunner.run()

DeeployTest/testUtils/codeGenerate.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from Deeploy.DeeployTypes import CodeGenVerbosity, ConstantBuffer, NetworkDeployer, VariableBuffer
1111
from Deeploy.Targets.MemPool.Platform import MemPoolPlatform
1212
from Deeploy.Targets.PULPOpen.Platform import MemoryPULPPlatform, MemoryPULPPlatformWrapper, PULPPlatform
13+
from Deeploy.Targets.Magia.Platform import MagiaPlatform
1314

1415
_TEXT_ALIGN = 30
1516

@@ -119,12 +120,17 @@ def generateTestNetworkHeader(deployer: NetworkDeployer) -> str:
119120
retStr += """
120121
#ifndef __DEEPLOY_HEADER__
121122
#define __DEEPLOY_HEADER__
122-
#include <stdio.h>
123123
#include <stdint.h>
124-
#include <stdlib.h>
125124
"""
125+
126+
if not isinstance(deployer.Platform, MagiaPlatform):
127+
retStr += """
128+
#include <stdio.h>
129+
#include <stdlib.h>
130+
"""
131+
126132
retStr += deployer.generateIncludeString()
127-
if isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper)):
133+
if isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper, MagiaPlatform)):
128134
retStr += """
129135
void RunNetwork();
130136
void InitNetwork();
@@ -148,15 +154,15 @@ def generateTestNetworkHeader(deployer: NetworkDeployer) -> str:
148154
def generateTestNetworkImplementation(deployer: NetworkDeployer, verbosityCfg: CodeGenVerbosity) -> str:
149155
retStr = ""
150156

151-
retStr += """#include <stdio.h>
152-
#include <stdlib.h>
153-
#include <math.h>
154-
"""
155-
retStr += deployer.generateIncludeString()
157+
if not isinstance(deployer.Platform, MagiaPlatform):
158+
retStr += """#include <stdio.h>
159+
#include <stdlib.h>
160+
#include <math.h>
161+
"""
162+
retStr += deployer.generateIncludeString()
163+
156164
retStr += """
157-
158165
#include "Network.h"
159-
160166
"""
161167

162168
retStr += deployer.generateBufferInitializationCode()
@@ -168,7 +174,7 @@ def generateTestNetworkImplementation(deployer: NetworkDeployer, verbosityCfg: C
168174
retStr += """
169175
void RunNetwork(__attribute__((unused)) uint32_t core_id, __attribute__((unused)) uint32_t numThreads){
170176
"""
171-
elif isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper)):
177+
elif isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper, MagiaPlatform)):
172178
retStr += """
173179
void RunNetwork(){
174180
"""
@@ -180,7 +186,7 @@ def generateTestNetworkImplementation(deployer: NetworkDeployer, verbosityCfg: C
180186
retStr += deployer.generateInferenceInitializationCode()
181187

182188
retStr += deployer.generateFunction(verbosityCfg)
183-
if isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper)):
189+
if isinstance(deployer.Platform, (PULPPlatform, MemoryPULPPlatform, MemoryPULPPlatformWrapper, MagiaPlatform)):
184190
retStr += """
185191
}
186192

0 commit comments

Comments
 (0)