mlonmcu 0.3.0.dev0__3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mlonmcu/__init__.py +26 -0
- mlonmcu/artifact.py +172 -0
- mlonmcu/cli/__init__.py +19 -0
- mlonmcu/cli/build.py +119 -0
- mlonmcu/cli/cleanup.py +75 -0
- mlonmcu/cli/common.py +227 -0
- mlonmcu/cli/compile.py +87 -0
- mlonmcu/cli/env.py +68 -0
- mlonmcu/cli/export.py +93 -0
- mlonmcu/cli/flow.py +67 -0
- mlonmcu/cli/helper/__init__.py +18 -0
- mlonmcu/cli/helper/filter.py +25 -0
- mlonmcu/cli/helper/parse.py +159 -0
- mlonmcu/cli/init.py +130 -0
- mlonmcu/cli/load.py +87 -0
- mlonmcu/cli/main.py +116 -0
- mlonmcu/cli/models.py +48 -0
- mlonmcu/cli/run.py +56 -0
- mlonmcu/cli/setup.py +136 -0
- mlonmcu/cli/tune.py +48 -0
- mlonmcu/config.py +219 -0
- mlonmcu/context/__init__.py +22 -0
- mlonmcu/context/context.py +545 -0
- mlonmcu/context/read_write_filelock.py +327 -0
- mlonmcu/environment/__init__.py +18 -0
- mlonmcu/environment/config.py +214 -0
- mlonmcu/environment/environment.py +501 -0
- mlonmcu/environment/init.py +191 -0
- mlonmcu/environment/list.py +81 -0
- mlonmcu/environment/loader.py +250 -0
- mlonmcu/environment/templates.py +69 -0
- mlonmcu/environment/writer.py +117 -0
- mlonmcu/feature/__init__.py +18 -0
- mlonmcu/feature/feature.py +230 -0
- mlonmcu/feature/features.py +1537 -0
- mlonmcu/feature/type.py +33 -0
- mlonmcu/flow/__init__.py +61 -0
- mlonmcu/flow/backend.py +234 -0
- mlonmcu/flow/framework.py +69 -0
- mlonmcu/flow/tflm/__init__.py +23 -0
- mlonmcu/flow/tflm/backend/__init__.py +23 -0
- mlonmcu/flow/tflm/backend/backend.py +47 -0
- mlonmcu/flow/tflm/backend/tflmc.py +129 -0
- mlonmcu/flow/tflm/backend/tflmi.py +385 -0
- mlonmcu/flow/tflm/framework.py +81 -0
- mlonmcu/flow/tvm/__init__.py +23 -0
- mlonmcu/flow/tvm/backend/__init__.py +26 -0
- mlonmcu/flow/tvm/backend/backend.py +282 -0
- mlonmcu/flow/tvm/backend/model_info.py +307 -0
- mlonmcu/flow/tvm/backend/python_utils.py +36 -0
- mlonmcu/flow/tvm/backend/tuner.py +41 -0
- mlonmcu/flow/tvm/backend/tvmaot.py +162 -0
- mlonmcu/flow/tvm/backend/tvmaotplus.py +51 -0
- mlonmcu/flow/tvm/backend/tvmc_utils.py +172 -0
- mlonmcu/flow/tvm/backend/tvmcg.py +102 -0
- mlonmcu/flow/tvm/backend/tvmllvm.py +106 -0
- mlonmcu/flow/tvm/backend/tvmrt.py +151 -0
- mlonmcu/flow/tvm/backend/wrapper.py +645 -0
- mlonmcu/flow/tvm/framework.py +96 -0
- mlonmcu/logging.py +79 -0
- mlonmcu/mlonmcu.py +19 -0
- mlonmcu/models/__init__.py +31 -0
- mlonmcu/models/convert_data.py +107 -0
- mlonmcu/models/frontend.py +571 -0
- mlonmcu/models/group.py +29 -0
- mlonmcu/models/lookup.py +345 -0
- mlonmcu/models/metadata.py +133 -0
- mlonmcu/models/model.py +104 -0
- mlonmcu/models/options.py +64 -0
- mlonmcu/models/utils.py +136 -0
- mlonmcu/platform/__init__.py +27 -0
- mlonmcu/platform/_platform.py +46 -0
- mlonmcu/platform/espidf/__init__.py +25 -0
- mlonmcu/platform/espidf/espidf.py +489 -0
- mlonmcu/platform/espidf/espidf_target.py +257 -0
- mlonmcu/platform/lookup.py +126 -0
- mlonmcu/platform/microtvm/__init__.py +25 -0
- mlonmcu/platform/microtvm/microtvm.py +580 -0
- mlonmcu/platform/microtvm/microtvm_arduino_target.py +68 -0
- mlonmcu/platform/microtvm/microtvm_backend.py +64 -0
- mlonmcu/platform/microtvm/microtvm_espidf_target.py +94 -0
- mlonmcu/platform/microtvm/microtvm_etissvp_target.py +98 -0
- mlonmcu/platform/microtvm/microtvm_host_target.py +46 -0
- mlonmcu/platform/microtvm/microtvm_spike_target.py +230 -0
- mlonmcu/platform/microtvm/microtvm_target.py +189 -0
- mlonmcu/platform/microtvm/microtvm_template_target.py +55 -0
- mlonmcu/platform/microtvm/microtvm_zephyr_target.py +91 -0
- mlonmcu/platform/mlif/__init__.py +25 -0
- mlonmcu/platform/mlif/mlif.py +300 -0
- mlonmcu/platform/mlif/mlif_target.py +86 -0
- mlonmcu/platform/platform.py +244 -0
- mlonmcu/platform/tvm/__init__.py +25 -0
- mlonmcu/platform/tvm/tvm.py +429 -0
- mlonmcu/platform/tvm/tvm_backend.py +57 -0
- mlonmcu/platform/tvm/tvm_target.py +165 -0
- mlonmcu/platform/zephyr/__init__.py +25 -0
- mlonmcu/platform/zephyr/zephyr.py +450 -0
- mlonmcu/platform/zephyr/zephyr_target.py +110 -0
- mlonmcu/plugins.py +26 -0
- mlonmcu/report.py +99 -0
- mlonmcu/session/__init__.py +18 -0
- mlonmcu/session/postprocess/__init__.py +43 -0
- mlonmcu/session/postprocess/postprocess.py +62 -0
- mlonmcu/session/postprocess/postprocesses.py +487 -0
- mlonmcu/session/run.py +1008 -0
- mlonmcu/session/session.py +373 -0
- mlonmcu/setup/__init__.py +18 -0
- mlonmcu/setup/cache.py +147 -0
- mlonmcu/setup/gen_requirements.py +619 -0
- mlonmcu/setup/setup.py +285 -0
- mlonmcu/setup/task.py +380 -0
- mlonmcu/setup/tasks/__init__.py +40 -0
- mlonmcu/setup/tasks/arm_gcc.py +58 -0
- mlonmcu/setup/tasks/cmsisnn.py +151 -0
- mlonmcu/setup/tasks/common.py +36 -0
- mlonmcu/setup/tasks/corstone300.py +64 -0
- mlonmcu/setup/tasks/espidf.py +87 -0
- mlonmcu/setup/tasks/etiss.py +147 -0
- mlonmcu/setup/tasks/llvm.py +67 -0
- mlonmcu/setup/tasks/mlif.py +49 -0
- mlonmcu/setup/tasks/muriscvnn.py +166 -0
- mlonmcu/setup/tasks/pulp.py +192 -0
- mlonmcu/setup/tasks/riscv_gcc.py +146 -0
- mlonmcu/setup/tasks/spike.py +190 -0
- mlonmcu/setup/tasks/tf.py +92 -0
- mlonmcu/setup/tasks/tflite.py +59 -0
- mlonmcu/setup/tasks/tflmc.py +141 -0
- mlonmcu/setup/tasks/tvm.py +172 -0
- mlonmcu/setup/tasks/utvmcg.py +96 -0
- mlonmcu/setup/tasks/zephyr.py +119 -0
- mlonmcu/setup/utils.py +374 -0
- mlonmcu/target/__init__.py +37 -0
- mlonmcu/target/_target.py +41 -0
- mlonmcu/target/arm/__init__.py +3 -0
- mlonmcu/target/arm/corstone300.py +235 -0
- mlonmcu/target/arm/util.py +109 -0
- mlonmcu/target/common.py +194 -0
- mlonmcu/target/elf.py +256 -0
- mlonmcu/target/host_x86.py +84 -0
- mlonmcu/target/metrics.py +75 -0
- mlonmcu/target/riscv/__init__.py +7 -0
- mlonmcu/target/riscv/etiss_pulpino.py +462 -0
- mlonmcu/target/riscv/gvsoc_pulp.py +215 -0
- mlonmcu/target/riscv/ovpsim.py +301 -0
- mlonmcu/target/riscv/riscv.py +185 -0
- mlonmcu/target/riscv/riscv_qemu.py +166 -0
- mlonmcu/target/riscv/spike.py +243 -0
- mlonmcu/target/riscv/util.py +134 -0
- mlonmcu/target/target.py +200 -0
- mlonmcu/utils.py +49 -0
- mlonmcu/version.py +21 -0
- mlonmcu-0.3.0.dev0.dist-info/LICENSE +202 -0
- mlonmcu-0.3.0.dev0.dist-info/METADATA +343 -0
- mlonmcu-0.3.0.dev0.dist-info/NOTICE +8 -0
- mlonmcu-0.3.0.dev0.dist-info/RECORD +376 -0
- mlonmcu-0.3.0.dev0.dist-info/WHEEL +5 -0
- mlonmcu-0.3.0.dev0.dist-info/entry_points.txt +3 -0
- mlonmcu-0.3.0.dev0.dist-info/top_level.txt +1 -0
- resources/frameworks/tvm/crt_config/README.md +7 -0
- resources/frameworks/tvm/crt_config/crt_config.h +53 -0
- resources/frameworks/tvm/tuning_records/riscv_cpu_v0.01.log.best +46 -0
- resources/patches/fix_esp32c3_march.patch +20 -0
- resources/patches/pulp_freertos_support.patch +55 -0
- resources/platforms/espidf/micro_speech_esp32devboard/CMakeLists.txt +29 -0
- resources/platforms/espidf/micro_speech_esp32devboard/README.md +70 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/CMakeLists.txt +78 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/Kconfig +76 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_data.c +26 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_model_support/process_input.c +35 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_model_support/process_output.c +45 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/exit.h +26 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/ml_interface.h +70 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/printing.h +31 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface.c +74 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface_tflm.cc +64 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface_tvm.c +53 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/tflite-lib/CMakeLists.txt +140 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/tflite-lib/Kconfig +8 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/tvm-lib/CMakeLists.txt +66 -0
- resources/platforms/espidf/micro_speech_esp32devboard/components/tvm-lib/Kconfig +7 -0
- resources/platforms/espidf/micro_speech_esp32devboard/example_test.py +38 -0
- resources/platforms/espidf/micro_speech_esp32devboard/info.txt +9 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/CMakeLists.txt +58 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/audio_provider.cc +193 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/audio_provider.h +49 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/command_responder.cc +53 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/command_responder.h +35 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.cc +132 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.cc.orig +145 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.h +55 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/COPYING +11 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/_kiss_fft_guts.h +168 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/kiss_fft.c +408 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/kiss_fft.h +124 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/tools/kiss_fftr.c +159 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/tools/kiss_fftr.h +46 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/main.cc +63 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/main_functions.cc +204 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/main_functions.h +37 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/micro_features_generator.cc +121 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/micro_features_generator.h +38 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/micro_model_settings.cc +23 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/micro_model_settings.h +43 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/bits.h +102 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft.cc +52 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft.h +50 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft_util.cc +69 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft_util.h +34 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank.c +134 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank.h +63 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank_util.c +220 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank_util.h +50 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend.c +72 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend.h +64 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend_util.c +85 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend_util.h +52 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_common.h +48 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_int16.cc +8 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_int16.h +34 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_lut.c +30 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_lut.h +40 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale.c +83 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale.h +39 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale_util.c +27 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale_util.h +45 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction.c +51 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction.h +46 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction_util.c +45 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction_util.h +50 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control.c +56 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control.h +47 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control_util.c +92 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control_util.h +57 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window.c +70 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window.h +49 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window_util.c +73 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window_util.h +45 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/pins.c +14 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/pins.h +30 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/recognize_commands.cc +150 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/recognize_commands.h +173 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/ringbuf.c +333 -0
- resources/platforms/espidf/micro_speech_esp32devboard/main/ringbuf.h +74 -0
- resources/platforms/espidf/micro_speech_esp32devboard/sdkconfig.defaults +36 -0
- resources/platforms/espidf/project/CMakeLists.txt +29 -0
- resources/platforms/espidf/project/README.md +70 -0
- resources/platforms/espidf/project/components/mlif/CMakeLists.txt +77 -0
- resources/platforms/espidf/project/components/mlif/Kconfig +76 -0
- resources/platforms/espidf/project/components/mlif/default_data.c +26 -0
- resources/platforms/espidf/project/components/mlif/default_model_support/process_input.c +35 -0
- resources/platforms/espidf/project/components/mlif/default_model_support/process_output.c +45 -0
- resources/platforms/espidf/project/components/mlif/include/exit.h +26 -0
- resources/platforms/espidf/project/components/mlif/include/ml_interface.h +60 -0
- resources/platforms/espidf/project/components/mlif/include/printing.h +31 -0
- resources/platforms/espidf/project/components/mlif/ml_interface.c +54 -0
- resources/platforms/espidf/project/components/mlif/ml_interface_tflm.cc +40 -0
- resources/platforms/espidf/project/components/mlif/ml_interface_tvm.c +40 -0
- resources/platforms/espidf/project/components/tflite-lib/CMakeLists.txt +142 -0
- resources/platforms/espidf/project/components/tflite-lib/Kconfig +8 -0
- resources/platforms/espidf/project/components/tvm-lib/CMakeLists.txt +66 -0
- resources/platforms/espidf/project/components/tvm-lib/Kconfig +7 -0
- resources/platforms/espidf/project/example_test.py +38 -0
- resources/platforms/espidf/project/main/CMakeLists.txt +25 -0
- resources/platforms/espidf/project/main/main.c +57 -0
- resources/platforms/espidf/project/sdkconfig.defaults +26 -0
- resources/platforms/zephyr/project/CMakeLists.txt +22 -0
- resources/platforms/zephyr/project/Kconfig +101 -0
- resources/platforms/zephyr/project/README.rst +33 -0
- resources/platforms/zephyr/project/cmake/AddAllSubdirs.cmake +21 -0
- resources/platforms/zephyr/project/cmake/ChooseTarget.cmake +22 -0
- resources/platforms/zephyr/project/cmake/LinkTFLite.cmake +223 -0
- resources/platforms/zephyr/project/cmake/LinkTVM.cmake +68 -0
- resources/platforms/zephyr/project/cmake/LookupClang.cmake +41 -0
- resources/platforms/zephyr/project/cmake/backends/tflmc.cmake +5 -0
- resources/platforms/zephyr/project/cmake/backends/tflmi.cmake +5 -0
- resources/platforms/zephyr/project/cmake/backends/tvmaot.cmake +10 -0
- resources/platforms/zephyr/project/cmake/backends/tvmaotplus.cmake +10 -0
- resources/platforms/zephyr/project/cmake/backends/tvmcg.cmake +10 -0
- resources/platforms/zephyr/project/cmake/backends/tvmllvm.cmake +8 -0
- resources/platforms/zephyr/project/cmake/backends/tvmrt.cmake +8 -0
- resources/platforms/zephyr/project/cmake/extras.cmake +9 -0
- resources/platforms/zephyr/project/cmake/features/auto_vectorize_gcc.cmake +65 -0
- resources/platforms/zephyr/project/cmake/features/auto_vectorize_llvm.cmake +20 -0
- resources/platforms/zephyr/project/cmake/features/cmsisnn.cmake +86 -0
- resources/platforms/zephyr/project/cmake/features/muriscvnn.cmake +87 -0
- resources/platforms/zephyr/project/cmake/frameworks/tflm.cmake +1 -0
- resources/platforms/zephyr/project/cmake/frameworks/tflm_mlif.cmake +8 -0
- resources/platforms/zephyr/project/cmake/frameworks/tvm.cmake +1 -0
- resources/platforms/zephyr/project/cmake/frameworks/tvm_mlif.cmake +37 -0
- resources/platforms/zephyr/project/lib/CMakeLists.txt +13 -0
- resources/platforms/zephyr/project/lib/drivers/fake_input.c +10 -0
- resources/platforms/zephyr/project/lib/drivers/fake_input.h +8 -0
- resources/platforms/zephyr/project/lib/ml_interface/CMakeLists.txt +31 -0
- resources/platforms/zephyr/project/lib/ml_interface/default_data.c +8 -0
- resources/platforms/zephyr/project/lib/ml_interface/default_model_support/CMakeLists.txt +2 -0
- resources/platforms/zephyr/project/lib/ml_interface/default_model_support/process_input.c +17 -0
- resources/platforms/zephyr/project/lib/ml_interface/default_model_support/process_output.c +27 -0
- resources/platforms/zephyr/project/lib/ml_interface/ml_interface.c +36 -0
- resources/platforms/zephyr/project/lib/ml_interface/ml_interface.h +47 -0
- resources/platforms/zephyr/project/lib/ml_interface/ml_interface_tflm.cc +22 -0
- resources/platforms/zephyr/project/lib/ml_interface/ml_interface_tvm.c +22 -0
- resources/platforms/zephyr/project/lib/support/CMakeLists.txt +2 -0
- resources/platforms/zephyr/project/lib/support/dummy.c +0 -0
- resources/platforms/zephyr/project/lib/support/exit.h +8 -0
- resources/platforms/zephyr/project/lib/support/printing.h +11 -0
- resources/platforms/zephyr/project/lib/support/quantize.h +23 -0
- resources/platforms/zephyr/project/lib/targets/corstone300.c +62 -0
- resources/platforms/zephyr/project/lib/targets/default.c +2 -0
- resources/platforms/zephyr/project/lib/targets/etiss_pulpino.c +112 -0
- resources/platforms/zephyr/project/lib/targets/generic_riscv.c +112 -0
- resources/platforms/zephyr/project/lib/targets/riscv_qemu.c +112 -0
- resources/platforms/zephyr/project/lib/targets/target.h +2 -0
- resources/platforms/zephyr/project/prj.conf +11 -0
- resources/platforms/zephyr/project/sample.yaml +19 -0
- resources/platforms/zephyr/project/src/main.c +71 -0
- resources/platforms/zephyr/project2/CMakeLists.txt +72 -0
- resources/platforms/zephyr/project2/Kconfig +101 -0
- resources/platforms/zephyr/project2/README.rst +33 -0
- resources/platforms/zephyr/project2/cmake/AddAllSubdirs.cmake +21 -0
- resources/platforms/zephyr/project2/cmake/ChooseTarget.cmake +22 -0
- resources/platforms/zephyr/project2/cmake/LinkTFLite.cmake +223 -0
- resources/platforms/zephyr/project2/cmake/LinkTVM.cmake +68 -0
- resources/platforms/zephyr/project2/cmake/LookupClang.cmake +41 -0
- resources/platforms/zephyr/project2/cmake/backends/tflmc.cmake +5 -0
- resources/platforms/zephyr/project2/cmake/backends/tflmi.cmake +5 -0
- resources/platforms/zephyr/project2/cmake/backends/tvmaot.cmake +10 -0
- resources/platforms/zephyr/project2/cmake/backends/tvmaotplus.cmake +10 -0
- resources/platforms/zephyr/project2/cmake/backends/tvmcg.cmake +10 -0
- resources/platforms/zephyr/project2/cmake/backends/tvmllvm.cmake +8 -0
- resources/platforms/zephyr/project2/cmake/backends/tvmrt.cmake +8 -0
- resources/platforms/zephyr/project2/cmake/extras.cmake +9 -0
- resources/platforms/zephyr/project2/cmake/features/auto_vectorize_gcc.cmake +65 -0
- resources/platforms/zephyr/project2/cmake/features/auto_vectorize_llvm.cmake +20 -0
- resources/platforms/zephyr/project2/cmake/features/cmsisnn.cmake +86 -0
- resources/platforms/zephyr/project2/cmake/features/muriscvnn.cmake +87 -0
- resources/platforms/zephyr/project2/cmake/frameworks/tflm.cmake +1 -0
- resources/platforms/zephyr/project2/cmake/frameworks/tflm_mlif.cmake +8 -0
- resources/platforms/zephyr/project2/cmake/frameworks/tvm.cmake +1 -0
- resources/platforms/zephyr/project2/cmake/frameworks/tvm_mlif.cmake +37 -0
- resources/platforms/zephyr/project2/default_data.c +8 -0
- resources/platforms/zephyr/project2/default_model_support/CMakeLists.txt +3 -0
- resources/platforms/zephyr/project2/default_model_support/process_input.c +17 -0
- resources/platforms/zephyr/project2/default_model_support/process_output.c +27 -0
- resources/platforms/zephyr/project2/lib/CMakeLists.txt +13 -0
- resources/platforms/zephyr/project2/lib/drivers/fake_input.c +10 -0
- resources/platforms/zephyr/project2/lib/drivers/fake_input.h +8 -0
- resources/platforms/zephyr/project2/lib/support/CMakeLists.txt +2 -0
- resources/platforms/zephyr/project2/lib/support/dummy.c +0 -0
- resources/platforms/zephyr/project2/lib/support/exit.h +8 -0
- resources/platforms/zephyr/project2/lib/support/printing.h +11 -0
- resources/platforms/zephyr/project2/lib/support/quantize.h +23 -0
- resources/platforms/zephyr/project2/lib/targets/corstone300.c +62 -0
- resources/platforms/zephyr/project2/lib/targets/default.c +2 -0
- resources/platforms/zephyr/project2/lib/targets/etiss_pulpino.c +112 -0
- resources/platforms/zephyr/project2/lib/targets/generic_riscv.c +112 -0
- resources/platforms/zephyr/project2/lib/targets/riscv_qemu.c +112 -0
- resources/platforms/zephyr/project2/lib/targets/target.h +2 -0
- resources/platforms/zephyr/project2/ml_interface.c +36 -0
- resources/platforms/zephyr/project2/ml_interface.h +47 -0
- resources/platforms/zephyr/project2/ml_interface_tflm.cc +22 -0
- resources/platforms/zephyr/project2/ml_interface_tvm.c +22 -0
- resources/platforms/zephyr/project2/prj.conf +13 -0
- resources/platforms/zephyr/project2/sample.yaml +19 -0
- resources/platforms/zephyr/project2/settings.json +6 -0
- resources/platforms/zephyr/project2/src/main.c +35 -0
- resources/pycharm/.run/README.md +73 -0
- resources/pycharm/.run/step1_ init env.run.xml +24 -0
- resources/pycharm/.run/step2_ setup.run.xml +25 -0
- resources/pycharm/.run/step3_ run resnet on pulpxpulpissimo.run.xml +25 -0
- resources/templates/default.yml.j2 +258 -0
- resources/templates/dev.yml.j2 +212 -0
- resources/templates/minimal.yml.j2 +234 -0
- resources/templates/phi.yml.j2 +282 -0
- resources/templates/pulp.yml.j2 +267 -0
- resources/templates/research.yml.j2 +237 -0
- resources/templates/tumeda.yml.j2 +239 -0
mlonmcu/session/run.py
ADDED
|
@@ -0,0 +1,1008 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2022 TUM Department of Electrical and Computer Engineering.
|
|
3
|
+
#
|
|
4
|
+
# This file is part of MLonMCU.
|
|
5
|
+
# See https://github.com/tum-ei-eda/mlonmcu.git for further info.
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
"""Definition of a MLonMCU Run which represents a single benchmark instance for a given set of options."""
|
|
20
|
+
import itertools
|
|
21
|
+
import os
|
|
22
|
+
import copy
|
|
23
|
+
import tempfile
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from enum import IntEnum
|
|
26
|
+
|
|
27
|
+
from mlonmcu.logging import get_logger
|
|
28
|
+
from mlonmcu.artifact import ArtifactFormat, lookup_artifacts
|
|
29
|
+
from mlonmcu.config import str2bool
|
|
30
|
+
from mlonmcu.platform.platform import CompilePlatform, TargetPlatform, BuildPlatform, TunePlatform
|
|
31
|
+
from mlonmcu.report import Report # TODO: move to mlonmcu.session.report
|
|
32
|
+
from mlonmcu.config import resolve_required_config, filter_config
|
|
33
|
+
from mlonmcu.models.lookup import lookup_models
|
|
34
|
+
from mlonmcu.feature.type import FeatureType
|
|
35
|
+
from mlonmcu.feature.features import get_matching_features, get_available_features
|
|
36
|
+
from mlonmcu.target.metrics import Metrics
|
|
37
|
+
from mlonmcu.models import SUPPORTED_FRONTENDS
|
|
38
|
+
from mlonmcu.platform import get_platforms
|
|
39
|
+
from mlonmcu.flow import SUPPORTED_FRAMEWORKS, SUPPORTED_BACKENDS
|
|
40
|
+
|
|
41
|
+
from .postprocess import SUPPORTED_POSTPROCESSES
|
|
42
|
+
from .postprocess.postprocess import RunPostprocess
|
|
43
|
+
|
|
44
|
+
logger = get_logger()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class RunStage(IntEnum):
|
|
48
|
+
"""Type describing the stages a run can have."""
|
|
49
|
+
|
|
50
|
+
NOP = 0
|
|
51
|
+
LOAD = 1 # unimplemented
|
|
52
|
+
TUNE = 2
|
|
53
|
+
BUILD = 3
|
|
54
|
+
COMPILE = 4
|
|
55
|
+
RUN = 5
|
|
56
|
+
POSTPROCESS = 6
|
|
57
|
+
DONE = 7
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Run:
|
|
61
|
+
"""A run is single model/backend/framework/target combination with a given set of features and configs."""
|
|
62
|
+
|
|
63
|
+
FEATURES = ["autotune", "target_optimized"]
|
|
64
|
+
|
|
65
|
+
DEFAULTS = {
|
|
66
|
+
"export_optional": False,
|
|
67
|
+
"tune_enabled": False,
|
|
68
|
+
"target_to_backend": False,
|
|
69
|
+
"stage_subdirs": False,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
REQUIRED = []
|
|
73
|
+
OPTIONAL = []
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_file(cls, path):
|
|
77
|
+
"""Restore a run object which was written to the disk."""
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
idx=None,
|
|
83
|
+
model=None,
|
|
84
|
+
framework=None,
|
|
85
|
+
frontends=None,
|
|
86
|
+
backend=None,
|
|
87
|
+
target=None,
|
|
88
|
+
platforms=None, # TODO: rename
|
|
89
|
+
features=None, # TODO: All features combined or explicit run-features -> postprocesses?
|
|
90
|
+
config=None, # TODO: All config combined or explicit run-config?
|
|
91
|
+
postprocesses=None,
|
|
92
|
+
archived=False,
|
|
93
|
+
session=None,
|
|
94
|
+
comment="",
|
|
95
|
+
):
|
|
96
|
+
self.idx = idx
|
|
97
|
+
self.model = model # Model name, not object?
|
|
98
|
+
self.frontends = frontends if frontends is not None else []
|
|
99
|
+
self.framework = framework # ???
|
|
100
|
+
self.backend = backend
|
|
101
|
+
self.platforms = platforms if platforms is not None else []
|
|
102
|
+
self.artifacts_per_stage = {}
|
|
103
|
+
self.archived = archived
|
|
104
|
+
self.session = session
|
|
105
|
+
self.postprocesses = postprocesses if postprocesses else []
|
|
106
|
+
self.comment = comment
|
|
107
|
+
# self.stage = RunStage.NOP # max executed stage
|
|
108
|
+
self.completed = {stage: stage == RunStage.NOP for stage in RunStage}
|
|
109
|
+
|
|
110
|
+
self.init_directory()
|
|
111
|
+
self.target = target
|
|
112
|
+
self.cache_hints = []
|
|
113
|
+
self.config = config if config else {}
|
|
114
|
+
self.features = features if features else []
|
|
115
|
+
self.run_config = {}
|
|
116
|
+
self.run_features = self.process_features(features)
|
|
117
|
+
self.run_config = filter_config(self.config, "run", self.DEFAULTS, self.OPTIONAL, self.REQUIRED)
|
|
118
|
+
self.sub_names = []
|
|
119
|
+
self.result = None
|
|
120
|
+
self.failing = False # -> RunStatus
|
|
121
|
+
# self.lock = threading.Lock() # FIXME: use mutex instead of boolean
|
|
122
|
+
self.locked = False
|
|
123
|
+
self.report = None
|
|
124
|
+
|
|
125
|
+
def process_features(self, features):
|
|
126
|
+
"""Utility which handles postprocess_features."""
|
|
127
|
+
if features is None:
|
|
128
|
+
return []
|
|
129
|
+
features = get_matching_features(features, FeatureType.RUN)
|
|
130
|
+
for feature in features:
|
|
131
|
+
assert feature.name in self.FEATURES, f"Incompatible feature: {feature.name}"
|
|
132
|
+
tmp_run_config = {f"run.{key}": value for key, value in self.run_config.items()}
|
|
133
|
+
feature.add_run_config(tmp_run_config)
|
|
134
|
+
self.run_config = filter_config(tmp_run_config, "run", self.DEFAULTS, self.OPTIONAL, self.REQUIRED)
|
|
135
|
+
return features
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def tune_enabled(self):
|
|
139
|
+
"""Get tune_enabled property."""
|
|
140
|
+
value = self.run_config["tune_enabled"]
|
|
141
|
+
return str2bool(value) if not isinstance(value, (bool, int)) else value
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def target_to_backend(self):
|
|
145
|
+
"""Get target_to_backend property."""
|
|
146
|
+
value = self.run_config["target_to_backend"]
|
|
147
|
+
return str2bool(value) if not isinstance(value, (bool, int)) else value
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def export_optional(self):
|
|
151
|
+
"""Get export_optional property."""
|
|
152
|
+
value = self.run_config["export_optional"]
|
|
153
|
+
return str2bool(value) if not isinstance(value, (bool, int)) else value
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def stage_subdirs(self):
|
|
157
|
+
value = self.run_config["stage_subdirs"]
|
|
158
|
+
return str2bool(value) if not isinstance(value, (bool, int)) else value
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def build_platform(self):
|
|
162
|
+
"""Get platform for build stage."""
|
|
163
|
+
if self.backend is not None and (
|
|
164
|
+
hasattr(self.backend, "platform") and isinstance(self.backend.platform, BuildPlatform)
|
|
165
|
+
):
|
|
166
|
+
return self.backend.platform
|
|
167
|
+
for platform in self.platforms:
|
|
168
|
+
if isinstance(platform, BuildPlatform):
|
|
169
|
+
return platform
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def tune_platform(self):
|
|
174
|
+
"""Get platform for tune stage."""
|
|
175
|
+
if self.backend is not None and (
|
|
176
|
+
hasattr(self.backend, "platform") and isinstance(self.backend.platform, TunePlatform)
|
|
177
|
+
):
|
|
178
|
+
return self.backend.platform
|
|
179
|
+
for platform in self.platforms:
|
|
180
|
+
if isinstance(platform, TunePlatform):
|
|
181
|
+
return platform
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def compile_platform(self):
|
|
186
|
+
"""Get platform for compile stage."""
|
|
187
|
+
if self.target is not None and isinstance(self.target.platform, CompilePlatform):
|
|
188
|
+
return self.target.platform
|
|
189
|
+
for platform in self.platforms:
|
|
190
|
+
if isinstance(platform, CompilePlatform):
|
|
191
|
+
return platform
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def target_platform(self): # TODO: rename to run_stage?
|
|
196
|
+
"""Get platform for run stage."""
|
|
197
|
+
if self.target:
|
|
198
|
+
assert isinstance(self.target.platform, TargetPlatform)
|
|
199
|
+
return self.target.platform
|
|
200
|
+
for platform in self.platforms:
|
|
201
|
+
if isinstance(platform, TargetPlatform):
|
|
202
|
+
return platform
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
def has_stage(self, stage):
|
|
206
|
+
"""Returns true if the given stage is available for this run."""
|
|
207
|
+
if stage == RunStage.NOP:
|
|
208
|
+
return True
|
|
209
|
+
if stage == RunStage.LOAD:
|
|
210
|
+
return self.model is not None and len(self.frontends) > 0
|
|
211
|
+
if stage == RunStage.TUNE:
|
|
212
|
+
return self.tune_enabled and self.backend is not None
|
|
213
|
+
if stage == RunStage.BUILD:
|
|
214
|
+
return self.backend is not None and self.framework is not None
|
|
215
|
+
if stage == RunStage.COMPILE:
|
|
216
|
+
return self.target is not None and len(self.platforms) > 0 and self.compile_platform is not None
|
|
217
|
+
if stage == RunStage.RUN:
|
|
218
|
+
return self.target is not None and len(self.platforms) > 0 and self.target_platform is not None
|
|
219
|
+
if stage == RunStage.POSTPROCESS:
|
|
220
|
+
return len(self.postprocesses) > 0
|
|
221
|
+
if stage == RunStage.DONE:
|
|
222
|
+
return False
|
|
223
|
+
return False # TODO: Throw error instead?
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def next_stage(self):
|
|
227
|
+
"""Determines the next not yet completed stage. Returns RunStage.DONE if already completed."""
|
|
228
|
+
for stage in RunStage:
|
|
229
|
+
if not self.completed[stage.value] and self.has_stage(stage):
|
|
230
|
+
return stage
|
|
231
|
+
return RunStage.DONE
|
|
232
|
+
|
|
233
|
+
def lock(self):
|
|
234
|
+
"""Aquire a mutex to lock the current run."""
|
|
235
|
+
# ret = self.lock.acquire(timeout=0)
|
|
236
|
+
ret = not self.locked
|
|
237
|
+
self.locked = True
|
|
238
|
+
if not ret:
|
|
239
|
+
raise RuntimeError("Parallel processing of the same run is not allowed")
|
|
240
|
+
|
|
241
|
+
def unlock(self):
|
|
242
|
+
"""Release a mutex to unlock the current run."""
|
|
243
|
+
# self.lock.release()
|
|
244
|
+
self.locked = False
|
|
245
|
+
|
|
246
|
+
def init_directory(self):
|
|
247
|
+
"""Initialize the temporary directory for this run."""
|
|
248
|
+
if self.session is None:
|
|
249
|
+
assert not self.archived
|
|
250
|
+
self.tempdir = tempfile.TemporaryDirectory()
|
|
251
|
+
self.dir = Path(self.tempdir.name)
|
|
252
|
+
else:
|
|
253
|
+
self.tempdir = None
|
|
254
|
+
self.dir = self.session.runs_dir / str(self.idx)
|
|
255
|
+
if not self.dir.is_dir():
|
|
256
|
+
os.mkdir(self.dir)
|
|
257
|
+
# This is not a good idea, but else we would need a mutex/lock on the shared build_dir
|
|
258
|
+
# A solution would be to split up the framework runtime libs from the mlif...
|
|
259
|
+
for platform in self.platforms: # TODO: only do this if needed! (not for every platform)
|
|
260
|
+
# The stage_subdirs setting is ignored here because platforms can be multi-stage!
|
|
261
|
+
platform.init_directory(path=Path(self.dir) / platform.name)
|
|
262
|
+
|
|
263
|
+
def copy(self):
|
|
264
|
+
"""Create a new run based on this instance."""
|
|
265
|
+
new = copy.deepcopy(self)
|
|
266
|
+
if self.session:
|
|
267
|
+
new_idx = self.session.request_run_idx()
|
|
268
|
+
new.idx = new_idx
|
|
269
|
+
self.init_directory()
|
|
270
|
+
return new
|
|
271
|
+
|
|
272
|
+
def init_component(self, component_cls, context=None):
|
|
273
|
+
"""Helper function to create and configure a MLonMCU component instance for this run."""
|
|
274
|
+
required_keys = component_cls.REQUIRED
|
|
275
|
+
optional_keys = component_cls.OPTIONAL
|
|
276
|
+
self.config.update(
|
|
277
|
+
resolve_required_config(
|
|
278
|
+
required_keys,
|
|
279
|
+
optional=optional_keys,
|
|
280
|
+
features=self.features,
|
|
281
|
+
config=self.config,
|
|
282
|
+
cache=context.cache if context else None,
|
|
283
|
+
default_flags=context.environment.flags if context else None,
|
|
284
|
+
hints=self.cache_hints,
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
component_config = self.config.copy() # TODOL get rid of this
|
|
288
|
+
return component_cls(features=self.features, config=component_config)
|
|
289
|
+
|
|
290
|
+
def add_model(self, model):
|
|
291
|
+
"""Setter for the model instance."""
|
|
292
|
+
self.model = model
|
|
293
|
+
|
|
294
|
+
def add_frontend(self, frontend):
|
|
295
|
+
"""Setter for the frontend instance."""
|
|
296
|
+
self.frontends = [frontend]
|
|
297
|
+
|
|
298
|
+
def add_frontends(self, frontends):
|
|
299
|
+
"""Setter for the list of frontends."""
|
|
300
|
+
self.frontends = frontends
|
|
301
|
+
|
|
302
|
+
def add_backend(self, backend):
|
|
303
|
+
"""Setter for the backend instance."""
|
|
304
|
+
self.backend = backend
|
|
305
|
+
# assert len(self.platforms) > 0, "Add at least a platform before adding a backend."
|
|
306
|
+
if self.model is not None:
|
|
307
|
+
assert self.backend.supports_model(self.model), (
|
|
308
|
+
"The added backend does not support the chosen model. "
|
|
309
|
+
"Add the backend before adding a model to find a suitable frontend."
|
|
310
|
+
)
|
|
311
|
+
for platform in self.platforms:
|
|
312
|
+
self.backend.add_platform_defs(platform.name, platform.definitions)
|
|
313
|
+
|
|
314
|
+
def add_framework(self, framework):
|
|
315
|
+
"""Setter for the framework instance."""
|
|
316
|
+
self.framework = framework
|
|
317
|
+
# assert len(self.platforms) > 0, "Add at least a platform before adding a framework."
|
|
318
|
+
for platform in self.platforms:
|
|
319
|
+
self.framework.add_platform_defs(platform.name, platform.definitions)
|
|
320
|
+
|
|
321
|
+
def add_target(self, target):
|
|
322
|
+
"""Setter for the target instance."""
|
|
323
|
+
self.target = target
|
|
324
|
+
assert self.platforms is not None, "Add at least a platform before adding a target."
|
|
325
|
+
for platform in self.platforms:
|
|
326
|
+
self.target.add_platform_defs(platform.name, platform.definitions)
|
|
327
|
+
self.cache_hints = [self.target.get_arch()]
|
|
328
|
+
# self.resolve_chache_refs()
|
|
329
|
+
|
|
330
|
+
def add_platform(self, platform):
|
|
331
|
+
"""Setter for the platform instance."""
|
|
332
|
+
self.platforms = [platform]
|
|
333
|
+
if self.backend:
|
|
334
|
+
self.backend.add_platform_defs(platform.name, platform.definitions)
|
|
335
|
+
if self.framework:
|
|
336
|
+
self.framework.add_platform_defs(platform.name, platform.definitions)
|
|
337
|
+
|
|
338
|
+
def add_platforms(self, platforms):
|
|
339
|
+
"""Setter for the list of platforms."""
|
|
340
|
+
self.platforms = platforms
|
|
341
|
+
for platform in platforms:
|
|
342
|
+
if self.backend:
|
|
343
|
+
self.backend.add_platform_defs(platform.name, platform.definitions)
|
|
344
|
+
if self.framework:
|
|
345
|
+
self.framework.add_platform_defs(platform.name, platform.definitions)
|
|
346
|
+
|
|
347
|
+
def add_postprocess(self, postprocess, append=False):
|
|
348
|
+
"""Setter for a postprocess instance."""
|
|
349
|
+
if append:
|
|
350
|
+
self.postprocesses.append(postprocess)
|
|
351
|
+
else:
|
|
352
|
+
self.postprocesses = [postprocess]
|
|
353
|
+
|
|
354
|
+
def add_postprocesses(self, postprocesses, append=False):
|
|
355
|
+
"""Setter for the list of postprocesses."""
|
|
356
|
+
if append:
|
|
357
|
+
self.postprocesses.extend(postprocesses)
|
|
358
|
+
else:
|
|
359
|
+
self.postprocesses = postprocesses
|
|
360
|
+
|
|
361
|
+
def add_feature(self, feature):
|
|
362
|
+
"""Setter for a feature instance."""
|
|
363
|
+
self.features = [feature]
|
|
364
|
+
self.run_features = self.process_features(self.features)
|
|
365
|
+
|
|
366
|
+
def add_features(self, features, append=False):
|
|
367
|
+
"""Setter for the list of features."""
|
|
368
|
+
self.features = features if not append else self.features + features
|
|
369
|
+
self.run_features = self.process_features(self.features)
|
|
370
|
+
|
|
371
|
+
def pick_model_frontend(self, model_hints, backend=None):
|
|
372
|
+
assert len(model_hints) > 0
|
|
373
|
+
if backend is None:
|
|
374
|
+
self.frontends = [
|
|
375
|
+
frontend for frontend in self.frontends if model_hints[0].formats[0] in frontend.input_formats
|
|
376
|
+
]
|
|
377
|
+
assert len(self.frontends) > 0
|
|
378
|
+
return model_hints[0]
|
|
379
|
+
for model_hint in model_hints:
|
|
380
|
+
if backend.supports_model(model_hint):
|
|
381
|
+
self.frontends = [
|
|
382
|
+
frontend for frontend in self.frontends if model_hint.formats[0] in frontend.input_formats
|
|
383
|
+
]
|
|
384
|
+
return model_hint
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
def add_model_by_name(self, model_name, context=None):
|
|
388
|
+
"""Helper function to initialize and configure a model by its name."""
|
|
389
|
+
assert context is not None, "Please supply a context"
|
|
390
|
+
assert len(self.frontends) > 0, "Add a frontend to the run before adding a model"
|
|
391
|
+
model_hints = lookup_models([model_name], frontends=self.frontends, context=context)
|
|
392
|
+
assert len(model_hints) > 0, f"Model with name '{model_name}' not found"
|
|
393
|
+
model_hint = self.pick_model_frontend(model_hints, backend=self.backend)
|
|
394
|
+
assert model_hint is not None, "Unable to pick a suitable model"
|
|
395
|
+
self.add_model(model_hint)
|
|
396
|
+
|
|
397
|
+
def add_frontend_by_name(self, frontend_name, context=None):
|
|
398
|
+
"""Helper function to initialize and configure a frontend by its name."""
|
|
399
|
+
self.add_frontends_by_name([frontend_name], context=context)
|
|
400
|
+
|
|
401
|
+
def add_frontends_by_name(self, frontend_names, context=None):
|
|
402
|
+
"""Helper function to initialize and configure frontends by their names."""
|
|
403
|
+
frontends = []
|
|
404
|
+
for name in frontend_names:
|
|
405
|
+
try:
|
|
406
|
+
assert context is not None and context.environment.has_frontend(
|
|
407
|
+
name
|
|
408
|
+
), f"The frontend '{name}' is not enabled for this environment"
|
|
409
|
+
frontends.append(self.init_component(SUPPORTED_FRONTENDS[name], context=context))
|
|
410
|
+
except Exception:
|
|
411
|
+
continue
|
|
412
|
+
assert len(frontends) > 0, "No compatible frontend was found"
|
|
413
|
+
self.add_frontends(frontends)
|
|
414
|
+
|
|
415
|
+
def add_backend_by_name(self, backend_name, context=None):
|
|
416
|
+
"""Helper function to initialize and configure a backend by its name."""
|
|
417
|
+
assert context is not None and context.environment.has_backend(
|
|
418
|
+
backend_name
|
|
419
|
+
), f"The backend '{backend_name}' is not enabled for this environment"
|
|
420
|
+
if self.build_platform:
|
|
421
|
+
self.add_backend(self.init_component(self.build_platform.create_backend(backend_name), context=context))
|
|
422
|
+
else:
|
|
423
|
+
self.add_backend(self.init_component(SUPPORTED_BACKENDS[backend_name], context=context))
|
|
424
|
+
framework_name = self.backend.framework # TODO: does this work?
|
|
425
|
+
assert context.environment.has_framework(
|
|
426
|
+
framework_name
|
|
427
|
+
), f"The framework '{framework_name}' is not enabled for this environment"
|
|
428
|
+
self.add_framework(self.init_component(SUPPORTED_FRAMEWORKS[framework_name], context=context))
|
|
429
|
+
|
|
430
|
+
def add_target_by_name(self, target_name, context=None):
|
|
431
|
+
"""Helper function to initialize and configure a target by its name."""
|
|
432
|
+
# We can not use the following code snipped are platform targets may be resolved dynamically
|
|
433
|
+
# assert context is not None and context.environment.has_target(
|
|
434
|
+
# target_name
|
|
435
|
+
# ), f"The target '{target_name}' is not enabled for this environment"
|
|
436
|
+
assert len(self.platforms) > 0, "Please add a platform to the run before adding the target"
|
|
437
|
+
self.add_target(self.init_component(self.target_platform.create_target(target_name), context=context))
|
|
438
|
+
|
|
439
|
+
def add_platform_by_name(self, platform_name, context=None):
|
|
440
|
+
"""Helper function to initialize and configure a platform by its name."""
|
|
441
|
+
self.add_platforms_by_name([platform_name], context=context)
|
|
442
|
+
|
|
443
|
+
def add_platforms_by_name(self, platform_names, context=None):
|
|
444
|
+
"""Helper function to initialize and configure platforms by their names."""
|
|
445
|
+
platforms = []
|
|
446
|
+
for name in platform_names:
|
|
447
|
+
assert context is not None and context.environment.has_platform(
|
|
448
|
+
name
|
|
449
|
+
), f"The platform '{name}' is not enabled for this environment"
|
|
450
|
+
platforms.append(self.init_component(get_platforms()[name], context=context))
|
|
451
|
+
self.add_platforms(platforms)
|
|
452
|
+
|
|
453
|
+
def add_postprocess_by_name(self, postprocess_name, append=True, context=None):
|
|
454
|
+
"""Helper function to initialize and configure a postprocesses by its name."""
|
|
455
|
+
self.add_postprocesses_by_name([postprocess_name], append=append, context=context)
|
|
456
|
+
|
|
457
|
+
def add_postprocesses_by_name(self, postprocess_names, append=False, context=None):
|
|
458
|
+
"""Helper function to initialize and configure postprocesses by their names."""
|
|
459
|
+
postprocesses = []
|
|
460
|
+
for name in postprocess_names:
|
|
461
|
+
# TODO: ?
|
|
462
|
+
# assert context is not None and context.environment.has_postprocess(
|
|
463
|
+
# postprocess_name
|
|
464
|
+
# ), f"The postprocess '{postprocess_name}' is not enabled for this environment"
|
|
465
|
+
postprocesses.append(self.init_component(SUPPORTED_POSTPROCESSES[name], context=context))
|
|
466
|
+
self.add_postprocesses(postprocesses, append=append)
|
|
467
|
+
|
|
468
|
+
def add_feature_by_name(self, feature_name, append=True, context=None):
|
|
469
|
+
"""Helper function to initialize and configure a feature by its name."""
|
|
470
|
+
self.add_features_by_name([feature_name], context=context, append=append)
|
|
471
|
+
|
|
472
|
+
def add_features_by_name(self, feature_names, append=False, context=None):
|
|
473
|
+
"""Helper function to initialize and configure features by their names."""
|
|
474
|
+
features = []
|
|
475
|
+
for feature_name in feature_names:
|
|
476
|
+
available_features = get_available_features(feature_name=feature_name)
|
|
477
|
+
for feature_cls in available_features:
|
|
478
|
+
features.append(self.init_component(feature_cls, context=context))
|
|
479
|
+
self.add_features(features, append=append)
|
|
480
|
+
|
|
481
|
+
def __repr__(self):
|
|
482
|
+
probs = []
|
|
483
|
+
if self.model:
|
|
484
|
+
probs.append(str(self.model))
|
|
485
|
+
if len(self.platforms) > 0:
|
|
486
|
+
probs.append(str(self.platforms[0] if len(self.platforms) == 1 else self.platforms))
|
|
487
|
+
if len(self.frontends) > 0:
|
|
488
|
+
probs.append(str(self.frontends[0] if len(self.frontends) == 1 else self.frontends))
|
|
489
|
+
if self.backend:
|
|
490
|
+
probs.append(str(self.backend))
|
|
491
|
+
if self.target:
|
|
492
|
+
probs.append(str(self.target))
|
|
493
|
+
if self.features and len(self.features) > 0:
|
|
494
|
+
probs.append(str(self.features))
|
|
495
|
+
if self.config and len(self.config) > 0:
|
|
496
|
+
probs.append(str(self.config))
|
|
497
|
+
return "Run(" + ",".join(probs) + ")"
|
|
498
|
+
|
|
499
|
+
@property
|
|
500
|
+
def frontend(self):
|
|
501
|
+
assert len(self.frontends) > 0, "Not frontend is available for this run."
|
|
502
|
+
return self.frontends[0]
|
|
503
|
+
|
|
504
|
+
@property
|
|
505
|
+
def artifacts(self):
|
|
506
|
+
return list(
|
|
507
|
+
itertools.chain([subs[subs.keys[0]] for stage, subs in self.artifacts_per_stage.items()])
|
|
508
|
+
) # TODO: fix default only
|
|
509
|
+
|
|
510
|
+
def toDict(self):
|
|
511
|
+
"""Utility not implemented yet. (TODO: remove?)"""
|
|
512
|
+
raise NotImplementedError
|
|
513
|
+
|
|
514
|
+
def export_stage(self, stage, optional=False):
|
|
515
|
+
"""Export stage artifacts of this run to its directory."""
|
|
516
|
+
# TODO: per stage subdirs?
|
|
517
|
+
subdir = self.stage_subdirs
|
|
518
|
+
if stage in self.artifacts_per_stage:
|
|
519
|
+
for name in self.artifacts_per_stage[stage]:
|
|
520
|
+
artifacts = self.artifacts_per_stage[stage][name]
|
|
521
|
+
for artifact in artifacts:
|
|
522
|
+
if not artifact.optional or optional:
|
|
523
|
+
dest = self.dir
|
|
524
|
+
if subdir:
|
|
525
|
+
stage_idx = int(stage)
|
|
526
|
+
dest = dest / "stages" / str(stage_idx)
|
|
527
|
+
# TODO: stages.txt for mapping between stage idx and name
|
|
528
|
+
if name not in ["", "default"]:
|
|
529
|
+
dest = dest / "sub" / name
|
|
530
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
531
|
+
extract = artifact.fmt == ArtifactFormat.MLF
|
|
532
|
+
# extract = artifact.fmt == ArtifactFormat.MLF
|
|
533
|
+
# and not isinstance(self.platform, MicroTvmPlatform)
|
|
534
|
+
artifact.export(dest)
|
|
535
|
+
# Keep the tar as well as the extracted files
|
|
536
|
+
if extract:
|
|
537
|
+
artifact.export(dest, extract=True)
|
|
538
|
+
|
|
539
|
+
def postprocess(self):
|
|
540
|
+
"""Postprocess the 'run'."""
|
|
541
|
+
logger.debug("%s Processing stage POSTPROCESS", self.prefix)
|
|
542
|
+
self.lock()
|
|
543
|
+
# assert self.completed[RunStage.RUN] # Alternative: allow to trigger previous stages recursively as a fallback
|
|
544
|
+
|
|
545
|
+
self.artifacts_per_stage[RunStage.POSTPROCESS] = []
|
|
546
|
+
temp_report = self.get_report()
|
|
547
|
+
for postprocess in self.postprocesses:
|
|
548
|
+
if isinstance(postprocess, RunPostprocess):
|
|
549
|
+
artifacts = postprocess.post_run(temp_report, self.artifacts)
|
|
550
|
+
if artifacts is not None:
|
|
551
|
+
self.artifacts_per_stage[RunStage.POSTPROCESS].extend(artifacts) # TODO: subs?
|
|
552
|
+
self.report = temp_report
|
|
553
|
+
|
|
554
|
+
self.completed[RunStage.POSTPROCESS] = True
|
|
555
|
+
self.unlock()
|
|
556
|
+
|
|
557
|
+
def run(self):
|
|
558
|
+
"""Run the 'run' using the defined target."""
|
|
559
|
+
logger.debug("%s Processing stage RUN", self.prefix)
|
|
560
|
+
self.lock()
|
|
561
|
+
# Alternative: drop artifacts of higher stages when re-triggering a lower one?
|
|
562
|
+
self.artifacts_per_stage[RunStage.RUN] = {}
|
|
563
|
+
if self.has_stage(RunStage.COMPILE):
|
|
564
|
+
assert self.completed[RunStage.COMPILE]
|
|
565
|
+
self.export_stage(RunStage.COMPILE, optional=self.export_optional)
|
|
566
|
+
for name in self.artifacts_per_stage[RunStage.COMPILE]:
|
|
567
|
+
elf_artifact = self.artifacts_per_stage[RunStage.COMPILE][name][0]
|
|
568
|
+
self.target.generate_metrics(elf_artifact.path)
|
|
569
|
+
artifacts = self.target.artifacts
|
|
570
|
+
if isinstance(artifacts, dict):
|
|
571
|
+
self.artifacts_per_stage[RunStage.RUN].update(
|
|
572
|
+
{key if name in ["", "default"] else f"{name}_{key}": value for key, value in artifacts.items()}
|
|
573
|
+
)
|
|
574
|
+
else:
|
|
575
|
+
self.artifacts_per_stage[RunStage.RUN].update(
|
|
576
|
+
{name if name in ["", "default"] else f"{name}": artifacts}
|
|
577
|
+
)
|
|
578
|
+
else:
|
|
579
|
+
assert self.completed[RunStage.BUILD] # Used for tvm platform
|
|
580
|
+
self.export_stage(RunStage.BUILD, optional=self.export_optional)
|
|
581
|
+
for name in self.artifacts_per_stage[RunStage.BUILD]:
|
|
582
|
+
shared_object_artifact = self.artifacts_per_stage[RunStage.BUILD][name][0]
|
|
583
|
+
self.target.generate_metrics(shared_object_artifact.path)
|
|
584
|
+
artifacts = self.target.artifacts
|
|
585
|
+
if isinstance(artifacts, dict):
|
|
586
|
+
self.artifacts_per_stage[RunStage.RUN].update(
|
|
587
|
+
{key if name in ["", "default"] else f"{name}_{key}": value for key, value in artifacts.items()}
|
|
588
|
+
)
|
|
589
|
+
else:
|
|
590
|
+
self.artifacts_per_stage[RunStage.RUN].update(
|
|
591
|
+
{name if name in ["", "default"] else f"{name}": artifacts}
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
self.completed[RunStage.RUN] = True
|
|
595
|
+
self.unlock()
|
|
596
|
+
|
|
597
|
+
def compile(self):
|
|
598
|
+
"""Compile the target software for the run."""
|
|
599
|
+
logger.debug("%s Processing stage COMPILE", self.prefix)
|
|
600
|
+
self.lock()
|
|
601
|
+
assert self.completed[RunStage.BUILD]
|
|
602
|
+
|
|
603
|
+
self.export_stage(RunStage.BUILD, optional=self.export_optional)
|
|
604
|
+
self.artifacts_per_stage[RunStage.COMPILE] = {}
|
|
605
|
+
for name in self.artifacts_per_stage[RunStage.BUILD]:
|
|
606
|
+
codegen_dir = self.dir if not self.stage_subdirs else (self.dir / "stages" / str(int(RunStage.BUILD)))
|
|
607
|
+
if name not in ["", "default"]:
|
|
608
|
+
codegen_dir = codegen_dir / "sub" / name
|
|
609
|
+
# TODO!
|
|
610
|
+
self.compile_platform.generate_elf(codegen_dir, self.target) # TODO: has to go into different dirs
|
|
611
|
+
artifacts = self.compile_platform.artifacts
|
|
612
|
+
if isinstance(artifacts, dict):
|
|
613
|
+
self.artifacts_per_stage[RunStage.COMPILE].update(
|
|
614
|
+
{key if name in ["", "default"] else f"{name}_{key}": value for key, value in artifacts.items()}
|
|
615
|
+
)
|
|
616
|
+
else:
|
|
617
|
+
self.artifacts_per_stage[RunStage.COMPILE].update(
|
|
618
|
+
{name if name in ["", "default"] else f"{name}": artifacts}
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
self.completed[RunStage.COMPILE] = True
|
|
622
|
+
self.unlock()
|
|
623
|
+
|
|
624
|
+
def build(self):
|
|
625
|
+
"""Process the run using the choosen backend."""
|
|
626
|
+
logger.debug("%s Processing stage BUILD", self.prefix)
|
|
627
|
+
self.lock()
|
|
628
|
+
assert (not self.has_stage(RunStage.TUNE)) or self.completed[RunStage.TUNE]
|
|
629
|
+
|
|
630
|
+
if self.target_to_backend:
|
|
631
|
+
assert self.target is not None, "Config target_to_backend can only be used if a target was provided"
|
|
632
|
+
cfg = self.target.get_backend_config(self.backend.name) # Do not expect a backend prefix here
|
|
633
|
+
if len(cfg) > 0:
|
|
634
|
+
logger.debug("Updating backend config based on given target.")
|
|
635
|
+
self.backend.config.update(cfg)
|
|
636
|
+
|
|
637
|
+
self.export_stage(RunStage.LOAD, optional=self.export_optional) # Not required anymore?
|
|
638
|
+
self.artifacts_per_stage[RunStage.BUILD] = {}
|
|
639
|
+
for name in self.artifacts_per_stage[RunStage.LOAD]:
|
|
640
|
+
model_artifact = self.artifacts_per_stage[RunStage.LOAD][name][0]
|
|
641
|
+
if not model_artifact.exported:
|
|
642
|
+
model_artifact.export(self.dir)
|
|
643
|
+
self.backend.load_model(model=model_artifact.path)
|
|
644
|
+
if self.has_stage(RunStage.TUNE):
|
|
645
|
+
self.export_stage(RunStage.TUNE, optional=self.export_optional)
|
|
646
|
+
if len(self.artifacts_per_stage[RunStage.TUNE][name]) > 0: # TODO: inaccurate!
|
|
647
|
+
tuning_artifact = self.artifacts_per_stage[RunStage.TUNE][name][0]
|
|
648
|
+
if not tuning_artifact.exported:
|
|
649
|
+
tuning_artifact.export(self.dir)
|
|
650
|
+
self.backend.tuning_records = tuning_artifact.path
|
|
651
|
+
|
|
652
|
+
# TODO: allow raw data as well as filepath in backends
|
|
653
|
+
self.backend.generate_code()
|
|
654
|
+
artifacts = self.backend.artifacts
|
|
655
|
+
if isinstance(artifacts, dict):
|
|
656
|
+
self.artifacts_per_stage[RunStage.BUILD].update(
|
|
657
|
+
{key if name in ["", "default"] else f"{name}_{key}": value for key, value in artifacts.items()}
|
|
658
|
+
)
|
|
659
|
+
else:
|
|
660
|
+
self.artifacts_per_stage[RunStage.BUILD].update(
|
|
661
|
+
{name if name in ["", "default"] else f"{name}": artifacts}
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
self.completed[RunStage.BUILD] = True
|
|
665
|
+
self.unlock()
|
|
666
|
+
|
|
667
|
+
def tune(self):
|
|
668
|
+
"""Tune the run using the choosen backend (if supported)."""
|
|
669
|
+
logger.debug("%s Processing stage TUNE", self.prefix)
|
|
670
|
+
self.lock()
|
|
671
|
+
assert self.completed[RunStage.LOAD]
|
|
672
|
+
|
|
673
|
+
if self.target_to_backend:
|
|
674
|
+
assert self.target is not None, "Config target_to_backend can only be used if a target was provided"
|
|
675
|
+
cfg = self.target.get_backend_config(self.backend.name) # Do not expect a backend prefix here
|
|
676
|
+
if len(cfg) > 0:
|
|
677
|
+
logger.debug("Updating backend config based on given target.")
|
|
678
|
+
self.backend.config.update(cfg)
|
|
679
|
+
|
|
680
|
+
self.export_stage(RunStage.LOAD, optional=self.export_optional)
|
|
681
|
+
self.artifacts_per_stage[RunStage.TUNE] = {}
|
|
682
|
+
for name in self.artifacts_per_stage[RunStage.LOAD]:
|
|
683
|
+
model_artifact = self.artifacts_per_stage[RunStage.LOAD][name][0]
|
|
684
|
+
# if not model_artifact.exported:
|
|
685
|
+
# model_artifact.export(self.dir)
|
|
686
|
+
|
|
687
|
+
# TODO: allow raw data as well as filepath in backends
|
|
688
|
+
assert self.tune_platform, "Autotuning requires a TunePlatform"
|
|
689
|
+
res = self.tune_platform.tune_model(model_artifact.path, self.backend, self.target)
|
|
690
|
+
if res:
|
|
691
|
+
if isinstance(res, dict):
|
|
692
|
+
self.artifacts_per_stage[RunStage.TUNE].update(
|
|
693
|
+
{key if name in ["", "default"] else f"{name}_{key}": value for key, value in res.items()}
|
|
694
|
+
)
|
|
695
|
+
else:
|
|
696
|
+
self.artifacts_per_stage[RunStage.TUNE].update(
|
|
697
|
+
{name if name in ["", "default"] else f"{name}": res}
|
|
698
|
+
)
|
|
699
|
+
else:
|
|
700
|
+
self.artifacts_per_stage[RunStage.TUNE][name] = []
|
|
701
|
+
|
|
702
|
+
self.completed[RunStage.TUNE] = True
|
|
703
|
+
self.unlock()
|
|
704
|
+
|
|
705
|
+
def load(self):
|
|
706
|
+
"""Load the model using the given frontend."""
|
|
707
|
+
logger.debug("%s Processing stage LOAD", self.prefix)
|
|
708
|
+
self.lock()
|
|
709
|
+
# assert self.completed[RunStage.NOP]
|
|
710
|
+
|
|
711
|
+
self.frontend.generate_models(self.model)
|
|
712
|
+
# The following is very very dirty but required to update arena sizes via model metadata...
|
|
713
|
+
cfg_new = {}
|
|
714
|
+
self.frontend.process_metadata(self.model, cfg=cfg_new)
|
|
715
|
+
if len(cfg_new) > 0:
|
|
716
|
+
for key, value in cfg_new.items():
|
|
717
|
+
component, name = key.split(".")[:2]
|
|
718
|
+
if self.backend is not None and component == self.backend.name:
|
|
719
|
+
self.backend.config[name] = value
|
|
720
|
+
else:
|
|
721
|
+
for platform in self.platforms:
|
|
722
|
+
if platform is not None and component == platform.name:
|
|
723
|
+
platform.config[name] = value
|
|
724
|
+
self.config[key] = value
|
|
725
|
+
artifacts = self.frontend.artifacts
|
|
726
|
+
if isinstance(artifacts, dict):
|
|
727
|
+
self.artifacts_per_stage[RunStage.LOAD] = artifacts
|
|
728
|
+
else:
|
|
729
|
+
self.artifacts_per_stage[RunStage.LOAD] = {"default": artifacts}
|
|
730
|
+
|
|
731
|
+
self.completed[RunStage.LOAD] = True
|
|
732
|
+
self.unlock()
|
|
733
|
+
|
|
734
|
+
def process(self, until=RunStage.RUN, skip=None, export=False):
|
|
735
|
+
"""Process the run until a given stage."""
|
|
736
|
+
skip = skip if skip is not None else []
|
|
737
|
+
if until == RunStage.DONE:
|
|
738
|
+
until = RunStage.DONE - 1
|
|
739
|
+
start = self.next_stage # self.stage hold the max finished stage
|
|
740
|
+
if until < start:
|
|
741
|
+
logger.debug("%s Nothing to do", self.prefix)
|
|
742
|
+
return self.get_report()
|
|
743
|
+
|
|
744
|
+
if start > RunStage.NOP:
|
|
745
|
+
logger.debug(
|
|
746
|
+
# self.prefix + "Processing run until stage %s: %s",
|
|
747
|
+
"%s Continuing run from stage %s until stage %s",
|
|
748
|
+
self.prefix,
|
|
749
|
+
str(RunStage(start).name),
|
|
750
|
+
str(RunStage(until).name),
|
|
751
|
+
# str(self),
|
|
752
|
+
)
|
|
753
|
+
else:
|
|
754
|
+
logger.debug(
|
|
755
|
+
# self.prefix + "Processing run until stage %s: %s",
|
|
756
|
+
"%s Processing run until stage %s",
|
|
757
|
+
self.prefix,
|
|
758
|
+
str(RunStage(until).name),
|
|
759
|
+
# str(self),
|
|
760
|
+
)
|
|
761
|
+
for stage in range(start, until + 1):
|
|
762
|
+
if not self.has_stage(stage):
|
|
763
|
+
continue
|
|
764
|
+
if stage in skip:
|
|
765
|
+
logger.debug("%s Skipping stage %s", self.prefix, str(RunStage(stage).name))
|
|
766
|
+
continue
|
|
767
|
+
if stage < RunStage.POSTPROCESS:
|
|
768
|
+
self.report = None # Regenerate report if earlier stages are executed
|
|
769
|
+
stage_funcs = {
|
|
770
|
+
RunStage.NOP: lambda *args, **kwargs: None, # stage already done
|
|
771
|
+
RunStage.LOAD: self.load,
|
|
772
|
+
RunStage.TUNE: self.tune,
|
|
773
|
+
RunStage.BUILD: self.build,
|
|
774
|
+
RunStage.COMPILE: self.compile,
|
|
775
|
+
RunStage.RUN: self.run,
|
|
776
|
+
RunStage.POSTPROCESS: self.postprocess,
|
|
777
|
+
}
|
|
778
|
+
func = stage_funcs[stage]
|
|
779
|
+
if func:
|
|
780
|
+
self.failing = False
|
|
781
|
+
try:
|
|
782
|
+
func()
|
|
783
|
+
except Exception as e:
|
|
784
|
+
self.failing = True
|
|
785
|
+
if self.locked:
|
|
786
|
+
self.unlock()
|
|
787
|
+
logger.exception(e)
|
|
788
|
+
run_stage = RunStage(stage).name
|
|
789
|
+
logger.error("%s Run failed at stage '%s', aborting...", self.prefix, run_stage)
|
|
790
|
+
break
|
|
791
|
+
# self.stage = stage # FIXME: The stage_func should update the stage intead?
|
|
792
|
+
report = self.get_report()
|
|
793
|
+
if export:
|
|
794
|
+
self.export(optional=self.export_optional) # TODO: set to flase?
|
|
795
|
+
report_file = Path(self.dir) / "report.csv"
|
|
796
|
+
report.export(report_file)
|
|
797
|
+
return report
|
|
798
|
+
|
|
799
|
+
def write_run_file(self):
|
|
800
|
+
"""Create a run.txt file which contains information used to reconstruct the run based
|
|
801
|
+
on its properties at a later point in time."""
|
|
802
|
+
logger.debug("%s Writing run file", self.prefix)
|
|
803
|
+
filename = self.dir / "run.txt"
|
|
804
|
+
with open(filename, "w", encoding="utf-8") as handle:
|
|
805
|
+
handle.write(str(self))
|
|
806
|
+
|
|
807
|
+
@property
|
|
808
|
+
def prefix(self):
|
|
809
|
+
"""Get prefix property."""
|
|
810
|
+
return (
|
|
811
|
+
(f"[session-{self.session.idx}] [run-{self.idx}]" if self.session else f"[run-{self.idx}]")
|
|
812
|
+
if self.idx is not None
|
|
813
|
+
else ""
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
def get_all_feature_names(self):
|
|
817
|
+
"""Return list of feature names for this run."""
|
|
818
|
+
return [feature.name for feature in self.features]
|
|
819
|
+
|
|
820
|
+
def get_all_postprocess_names(self):
|
|
821
|
+
"""Return list of postprocess names for this run."""
|
|
822
|
+
return [postprocess.name for postprocess in self.postprocesses]
|
|
823
|
+
|
|
824
|
+
def get_frontend_name(self):
|
|
825
|
+
"""Return frontend name(s) for this run."""
|
|
826
|
+
ret = [frontend.name for frontend in self.frontends]
|
|
827
|
+
return ret[0] if len(ret) == 1 else ret
|
|
828
|
+
|
|
829
|
+
def get_platform_name(self):
|
|
830
|
+
"""Return platform name(s) for this run."""
|
|
831
|
+
used = list(set([self.tune_platform, self.build_platform, self.compile_platform, self.target_platform]))
|
|
832
|
+
ret = [platform.name for platform in used if platform is not None]
|
|
833
|
+
return ret[0] if len(ret) == 1 else ret
|
|
834
|
+
|
|
835
|
+
def get_all_configs(self, omit_paths=False, omit_defaults=False, omit_globals=False):
|
|
836
|
+
"""Return dict with component-specific and global configuration for this run."""
|
|
837
|
+
|
|
838
|
+
def has_prefix(key):
|
|
839
|
+
"""Returns true if the configuration key does not have global scope."""
|
|
840
|
+
return "." in key
|
|
841
|
+
|
|
842
|
+
def config_helper(obj, prefix=None):
|
|
843
|
+
"""Helper to access the configuration of a given component object."""
|
|
844
|
+
if prefix:
|
|
845
|
+
name = prefix
|
|
846
|
+
else:
|
|
847
|
+
assert hasattr(obj, "name")
|
|
848
|
+
name = obj.name
|
|
849
|
+
omit_list = []
|
|
850
|
+
defaults = obj.DEFAULTS
|
|
851
|
+
for key, value in obj.config.items():
|
|
852
|
+
if omit_defaults and key in defaults and defaults[key] == value:
|
|
853
|
+
omit_list.append(key)
|
|
854
|
+
ret = {
|
|
855
|
+
key if has_prefix(key) else f"{name}.{key}": value
|
|
856
|
+
for key, value in obj.config.items()
|
|
857
|
+
if key not in omit_list
|
|
858
|
+
}
|
|
859
|
+
if omit_paths:
|
|
860
|
+
ret = {
|
|
861
|
+
key: value
|
|
862
|
+
for key, value in ret.items()
|
|
863
|
+
if not (isinstance(value, Path) or (isinstance(value, str) and Path(value).exists()))
|
|
864
|
+
}
|
|
865
|
+
return ret
|
|
866
|
+
|
|
867
|
+
ret = {}
|
|
868
|
+
if not omit_globals:
|
|
869
|
+
ret.update(
|
|
870
|
+
{key: value for key, value in self.config.items() if not has_prefix(key)}
|
|
871
|
+
) # Only config without a prefix!
|
|
872
|
+
for frontend in self.frontends:
|
|
873
|
+
ret.update(config_helper(frontend))
|
|
874
|
+
if self.backend:
|
|
875
|
+
ret.update(config_helper(self.backend))
|
|
876
|
+
if self.framework:
|
|
877
|
+
ret.update(config_helper(self.framework))
|
|
878
|
+
if self.target:
|
|
879
|
+
ret.update(config_helper(self.target))
|
|
880
|
+
for platform in self.platforms:
|
|
881
|
+
ret.update(config_helper(platform))
|
|
882
|
+
for feature in self.features:
|
|
883
|
+
ret.update(config_helper(feature))
|
|
884
|
+
for postprocess in self.postprocesses:
|
|
885
|
+
ret.update(config_helper(postprocess))
|
|
886
|
+
return ret
|
|
887
|
+
|
|
888
|
+
def get_report(self):
|
|
889
|
+
"""Returns teh complete report of this run."""
|
|
890
|
+
if self.completed[RunStage.POSTPROCESS]:
|
|
891
|
+
if self.report is not None:
|
|
892
|
+
return (
|
|
893
|
+
self.report
|
|
894
|
+
) # Use postprocessed report instead of generating a new one (TODO: find a better approach)
|
|
895
|
+
# TODO: config or args for stuff like (session id) and run id as well as detailed features and configs
|
|
896
|
+
report = Report()
|
|
897
|
+
pre = {}
|
|
898
|
+
if self.session is not None:
|
|
899
|
+
pre["Session"] = self.session.idx
|
|
900
|
+
if self.idx is not None:
|
|
901
|
+
pre["Run"] = self.idx
|
|
902
|
+
if self.model:
|
|
903
|
+
pre["Model"] = self.model.name
|
|
904
|
+
if len(self.frontends) > 0:
|
|
905
|
+
pre["Frontend"] = self.get_frontend_name()
|
|
906
|
+
if self.framework:
|
|
907
|
+
pre["Framework"] = self.framework.name
|
|
908
|
+
if self.backend:
|
|
909
|
+
pre["Backend"] = self.backend.name
|
|
910
|
+
if len(self.platforms) > 0:
|
|
911
|
+
pre["Platform"] = self.get_platform_name()
|
|
912
|
+
if self.target:
|
|
913
|
+
pre["Target"] = self.target.name
|
|
914
|
+
post = {}
|
|
915
|
+
post["Features"] = self.get_all_feature_names()
|
|
916
|
+
# post["Config"] = self.get_all_configs(omit_paths=True, omit_defaults=True, omit_globals=True)
|
|
917
|
+
post["Config"] = self.get_all_configs(omit_paths=True, omit_defaults=False, omit_globals=True)
|
|
918
|
+
post["Postprocesses"] = self.get_all_postprocess_names()
|
|
919
|
+
post["Comment"] = self.comment if len(self.comment) > 0 else "-"
|
|
920
|
+
if self.failing:
|
|
921
|
+
post["Failing"] = True
|
|
922
|
+
|
|
923
|
+
self.export_stage(RunStage.RUN, optional=self.export_optional)
|
|
924
|
+
|
|
925
|
+
subs = []
|
|
926
|
+
if RunStage.LOAD in self.artifacts_per_stage:
|
|
927
|
+
names = self.artifacts_per_stage[RunStage.LOAD].keys()
|
|
928
|
+
subs = names
|
|
929
|
+
if RunStage.TUNE in self.artifacts_per_stage:
|
|
930
|
+
names = self.artifacts_per_stage[RunStage.TUNE].keys()
|
|
931
|
+
subs = names
|
|
932
|
+
if RunStage.BUILD in self.artifacts_per_stage:
|
|
933
|
+
names = self.artifacts_per_stage[RunStage.BUILD].keys()
|
|
934
|
+
subs = names
|
|
935
|
+
# metrics = Metrics()
|
|
936
|
+
metrics_by_sub = {}
|
|
937
|
+
if RunStage.COMPILE in self.artifacts_per_stage:
|
|
938
|
+
names = self.artifacts_per_stage[RunStage.COMPILE].keys()
|
|
939
|
+
subs = names
|
|
940
|
+
for name in self.artifacts_per_stage[RunStage.COMPILE]:
|
|
941
|
+
metrics_by_sub[name] = Metrics()
|
|
942
|
+
if (
|
|
943
|
+
len(self.artifacts_per_stage[RunStage.COMPILE][name]) > 1
|
|
944
|
+
): # TODO: look for artifact of type metrics instead
|
|
945
|
+
compile_metrics_artifact = lookup_artifacts(
|
|
946
|
+
self.artifacts_per_stage[RunStage.COMPILE][name], name="metrics.csv"
|
|
947
|
+
)[0]
|
|
948
|
+
compile_metrics = Metrics.from_csv(compile_metrics_artifact.content)
|
|
949
|
+
metrics_by_sub[name] = compile_metrics
|
|
950
|
+
|
|
951
|
+
if RunStage.RUN in self.artifacts_per_stage:
|
|
952
|
+
names = self.artifacts_per_stage[RunStage.RUN].keys()
|
|
953
|
+
if (
|
|
954
|
+
RunStage.COMPILE in self.artifacts_per_stage
|
|
955
|
+
and len(self.artifacts_per_stage[RunStage.COMPILE][name]) > 1
|
|
956
|
+
):
|
|
957
|
+
if not self.failing:
|
|
958
|
+
assert len(names) == len(subs), "Run and Compile Stage should have the same number of subs" # TODO: fix
|
|
959
|
+
if not self.failing:
|
|
960
|
+
subs = names
|
|
961
|
+
for name in self.artifacts_per_stage[RunStage.RUN]:
|
|
962
|
+
run_metrics_artifact = lookup_artifacts(
|
|
963
|
+
self.artifacts_per_stage[RunStage.RUN][name], name="metrics.csv"
|
|
964
|
+
)[0]
|
|
965
|
+
run_metrics = Metrics.from_csv(run_metrics_artifact.content)
|
|
966
|
+
# Combine with compile metrics
|
|
967
|
+
if name in metrics_by_sub:
|
|
968
|
+
metrics_data = metrics_by_sub[name].get_data()
|
|
969
|
+
else:
|
|
970
|
+
metrics_data = {}
|
|
971
|
+
run_metrics_data = run_metrics.get_data()
|
|
972
|
+
for key, value in metrics_data.items():
|
|
973
|
+
if key not in run_metrics_data:
|
|
974
|
+
run_metrics.add(key, value)
|
|
975
|
+
metrics_by_sub[name] = run_metrics
|
|
976
|
+
|
|
977
|
+
pres = []
|
|
978
|
+
mains = []
|
|
979
|
+
posts = []
|
|
980
|
+
for sub in subs:
|
|
981
|
+
if sub not in ["", "default"]:
|
|
982
|
+
pres.append({**pre, "Sub": sub})
|
|
983
|
+
else:
|
|
984
|
+
pres.append(pre)
|
|
985
|
+
if sub in metrics_by_sub:
|
|
986
|
+
main = metrics_by_sub[sub].get_data(include_optional=self.export_optional)
|
|
987
|
+
else:
|
|
988
|
+
main = {}
|
|
989
|
+
mains.append(main if len(main) > 0 else {"Incomplete": [True]})
|
|
990
|
+
posts.append(post) # TODO: omit for subs?
|
|
991
|
+
report.set(pre=pres, main=mains, post=posts)
|
|
992
|
+
return report
|
|
993
|
+
|
|
994
|
+
def export(self, path=None, optional=False):
|
|
995
|
+
"""Write a run configuration to a disk."""
|
|
996
|
+
logger.debug("%s Exporting run to disk", self.prefix)
|
|
997
|
+
if path is not None:
|
|
998
|
+
raise NotImplementedError
|
|
999
|
+
assert not self.locked
|
|
1000
|
+
for stage in range(self.next_stage):
|
|
1001
|
+
if not self.has_stage(stage):
|
|
1002
|
+
continue
|
|
1003
|
+
self.export_stage(stage, optional=optional)
|
|
1004
|
+
|
|
1005
|
+
self.write_run_file()
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
# TODO: implement close()? and use closing contextlib?
|