Skip to content

Commit

Permalink
Add NnxBuildFlow and fix cmake flow
Browse files Browse the repository at this point in the history
  • Loading branch information
lukamac committed Dec 13, 2024
1 parent 397a3e3 commit 8f67d15
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 51 deletions.
98 changes: 98 additions & 0 deletions test/NnxBuildFlow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import os
import subprocess
from abc import ABC, abstractmethod
from enum import Enum
from pathlib import Path
from typing import Dict, Type

from NnxMapping import NnxName


class NnxBuildFlow(ABC):

@abstractmethod
def __init__(self, nnxName: NnxName) -> None: ...

@abstractmethod
def build(self) -> None: ...

@abstractmethod
def run(self) -> str: ...

@abstractmethod
def __str__(self) -> str: ...

@staticmethod
def cmd_run(cmd: str, env=None) -> str:
proc = subprocess.run(
cmd.split(), check=True, capture_output=True, text=True, env=env
)
return proc.stdout


class MakeBuildFlow(NnxBuildFlow):
BUILD_CMD = "make -C app all platform=gvsoc"
RUN_CMD = "make -C app run platform=gvsoc"

def __init__(self, nnxName: NnxName) -> None:
self.nnxName = nnxName

def env(self) -> os._Environ:
_env = os.environ
_env["ACCELERATOR"] = str(self.nnxName)
return _env

def build(self) -> None:
Path("app/src/nnx_layer.c").touch()
_ = NnxBuildFlow.cmd_run(MakeBuildFlow.BUILD_CMD, self.env())

def run(self) -> str:
return NnxBuildFlow.cmd_run(MakeBuildFlow.RUN_CMD, self.env())

def __str__(self) -> str:
return "make"


class CmakeBuildFlow(NnxBuildFlow):
BINARY_NAME = "test-pulp-nnx"
TOOLCHAIN_FILE = "cmake/toolchain_llvm.cmake"
GVSOC_TARGET = "siracusa"

def __init__(self, nnxName: NnxName) -> None:
self.nnxName = nnxName
self.build_dir = os.path.abspath(f"app/build_{nnxName}")
self.gvsoc_workdir = os.path.join(self.build_dir, "gvsoc_workdir")
assert "GVSOC" in os.environ, "The GVSOC environment variable is not set."

def prepare(self) -> None:
os.makedirs(self.gvsoc_workdir, exist_ok=True)
subprocess.run(
f"cmake -Sapp -B{self.build_dir} -GNinja -DCMAKE_TOOLCHAIN_FILE={CmakeBuildFlow.TOOLCHAIN_FILE} -DACCELERATOR={self.nnxName}".split(),
check=True,
)

def build(self) -> None:
_ = NnxBuildFlow.cmd_run(f"cmake --build {self.build_dir}")

def run(self) -> str:
bin = os.path.join(self.build_dir, CmakeBuildFlow.BINARY_NAME)
gvsoc = os.environ["GVSOC"]
cmd = f"{gvsoc} --binary {bin} --work-dir {self.gvsoc_workdir} --target {CmakeBuildFlow.GVSOC_TARGET} image flash run"
return NnxBuildFlow.cmd_run(cmd)

def __str__(self) -> str:
return "cmake"


class NnxBuildFlowName(Enum):
make = "make"
cmake = "cmake"

def __str__(self) -> str:
return self.value


NnxBuildFlowClsMapping: Dict[NnxBuildFlowName, Type[NnxBuildFlow]] = {
NnxBuildFlowName.make: MakeBuildFlow,
NnxBuildFlowName.cmake: CmakeBuildFlow,
}
25 changes: 10 additions & 15 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import pydantic
import pytest

from NnxBuildFlow import CmakeBuildFlow, NnxBuildFlowName
from NnxMapping import NnxMapping, NnxName
from NnxTestClasses import NnxTest, NnxTestGenerator
from TestClasses import implies
Expand Down Expand Up @@ -68,9 +69,10 @@ def pytest_addoption(parser):
)
parser.addoption(
"--build-flow",
dest="build_flow",
choices=["make", "cmake"],
default="make",
dest="buildFlowName",
type=NnxBuildFlowName,
choices=list(NnxBuildFlowName),
default=NnxBuildFlowName.make,
help="Choose the build flow. Default: make",
)

Expand All @@ -85,10 +87,10 @@ def pytest_generate_tests(metafunc):
regenerate = metafunc.config.getoption("regenerate")
timeout = metafunc.config.getoption("timeout")
nnxName = metafunc.config.getoption("accelerator")
build_flow = metafunc.config.getoption("build_flow")
buildFlowName = metafunc.config.getoption("buildFlowName")

assert implies(
build_flow == "cmake", nnxName == "neureka_v2"
buildFlowName == NnxBuildFlowName.cmake, nnxName == NnxName.neureka_v2
), "The cmake build flow has been tested only with the neureka_v2 accelerator"

if recursive:
Expand Down Expand Up @@ -122,17 +124,10 @@ def pytest_generate_tests(metafunc):
)
)

if build_flow == "cmake":
build_dir = os.path.abspath(f"app/build_{nnxName}")
gvsoc_workdir = os.path.join(build_dir, "gvsoc_workdir")
os.makedirs(gvsoc_workdir, exist_ok=True)
assert "GVSOC" in os.environ, "The GVSOC environment variable is not set."
subprocess.run(
f"cmake -Sapp -B{build_dir} -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain_llvm.cmake -DACCELERATOR={nnxName}".split(),
check=True,
)
if buildFlowName == NnxBuildFlowName.cmake:
CmakeBuildFlow(nnxName).prepare()

metafunc.parametrize("nnxName", [nnxName])
metafunc.parametrize("build_flow", [build_flow])
metafunc.parametrize("buildFlowName", [buildFlowName])
metafunc.parametrize("nnxTestName", nnxTestNames)
metafunc.parametrize("timeout", [timeout])
41 changes: 5 additions & 36 deletions test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pathlib import Path
from typing import Dict, Literal, Optional, Tuple, Type, Union

from NnxBuildFlow import NnxBuildFlowClsMapping, NnxBuildFlowName
from NnxMapping import NnxMapping, NnxName
from NnxTestClasses import NnxTest, NnxTestConf, NnxTestHeaderGenerator, NnxWeight

Expand Down Expand Up @@ -107,42 +108,9 @@ def assert_message(msg: str, test_name: str, stdout: str, stderr: Optional[str]
return retval


def build(nnxName: NnxName, flow: Literal["make", "cmake"]) -> None:
env = os.environ

if flow == "make":
Path("app/src/nnx_layer.c").touch()
cmd = "make -C app all platform=gvsoc"
env["ACCELERATOR"] = str(nnxName)
elif flow == "cmake":
cmd = "cmake --build app/build"

subprocess.run(cmd.split(), check=True, capture_output=True, text=True, env=env)


def run(nnxName: NnxName, flow: Literal["make", "cmake"]) -> str:
env = os.environ

if flow == "make":
cmd = "make -C app run platform=gvsoc"
env["ACCELERATOR"] = str(nnxName)
elif flow == "cmake":
build_dir = os.path.abspath(f"app/build_{nnxName}")
bin = os.path.join(build_dir, "test-pulp-nnx")
gvsoc = env["GVSOC"]
gvsoc_workdir = os.path.join(build_dir, "gvsoc_workdir")
cmd = f"{gvsoc} --binary {bin} --work-dir {gvsoc_workdir} --target siracusa image flash run"

proc = subprocess.run(
cmd.split(), check=True, capture_output=True, text=True, env=env
)

return proc.stdout


def test(
nnxName: NnxName,
build_flow: Literal["cmake", "make"],
buildFlowName: NnxBuildFlowName,
nnxTestName: str,
timeout: int,
):
Expand All @@ -153,8 +121,9 @@ def test(

NnxTestHeaderGenerator(weightCls).generate(nnxTestName, nnxTest)

build(nnxName, build_flow)
stdout = run(nnxName, build_flow)
buildFlow = NnxBuildFlowClsMapping[buildFlowName](nnxName)
buildFlow.build()
stdout = buildFlow.run()

match_success = re.search(r"> Success! No errors found.", stdout)
match_fail = re.search(r"> Failure! Found (\d*)/(\d*) errors.", stdout)
Expand Down

0 comments on commit 8f67d15

Please sign in to comment.