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.
Files changed (376) hide show
  1. mlonmcu/__init__.py +26 -0
  2. mlonmcu/artifact.py +172 -0
  3. mlonmcu/cli/__init__.py +19 -0
  4. mlonmcu/cli/build.py +119 -0
  5. mlonmcu/cli/cleanup.py +75 -0
  6. mlonmcu/cli/common.py +227 -0
  7. mlonmcu/cli/compile.py +87 -0
  8. mlonmcu/cli/env.py +68 -0
  9. mlonmcu/cli/export.py +93 -0
  10. mlonmcu/cli/flow.py +67 -0
  11. mlonmcu/cli/helper/__init__.py +18 -0
  12. mlonmcu/cli/helper/filter.py +25 -0
  13. mlonmcu/cli/helper/parse.py +159 -0
  14. mlonmcu/cli/init.py +130 -0
  15. mlonmcu/cli/load.py +87 -0
  16. mlonmcu/cli/main.py +116 -0
  17. mlonmcu/cli/models.py +48 -0
  18. mlonmcu/cli/run.py +56 -0
  19. mlonmcu/cli/setup.py +136 -0
  20. mlonmcu/cli/tune.py +48 -0
  21. mlonmcu/config.py +219 -0
  22. mlonmcu/context/__init__.py +22 -0
  23. mlonmcu/context/context.py +545 -0
  24. mlonmcu/context/read_write_filelock.py +327 -0
  25. mlonmcu/environment/__init__.py +18 -0
  26. mlonmcu/environment/config.py +214 -0
  27. mlonmcu/environment/environment.py +501 -0
  28. mlonmcu/environment/init.py +191 -0
  29. mlonmcu/environment/list.py +81 -0
  30. mlonmcu/environment/loader.py +250 -0
  31. mlonmcu/environment/templates.py +69 -0
  32. mlonmcu/environment/writer.py +117 -0
  33. mlonmcu/feature/__init__.py +18 -0
  34. mlonmcu/feature/feature.py +230 -0
  35. mlonmcu/feature/features.py +1537 -0
  36. mlonmcu/feature/type.py +33 -0
  37. mlonmcu/flow/__init__.py +61 -0
  38. mlonmcu/flow/backend.py +234 -0
  39. mlonmcu/flow/framework.py +69 -0
  40. mlonmcu/flow/tflm/__init__.py +23 -0
  41. mlonmcu/flow/tflm/backend/__init__.py +23 -0
  42. mlonmcu/flow/tflm/backend/backend.py +47 -0
  43. mlonmcu/flow/tflm/backend/tflmc.py +129 -0
  44. mlonmcu/flow/tflm/backend/tflmi.py +385 -0
  45. mlonmcu/flow/tflm/framework.py +81 -0
  46. mlonmcu/flow/tvm/__init__.py +23 -0
  47. mlonmcu/flow/tvm/backend/__init__.py +26 -0
  48. mlonmcu/flow/tvm/backend/backend.py +282 -0
  49. mlonmcu/flow/tvm/backend/model_info.py +307 -0
  50. mlonmcu/flow/tvm/backend/python_utils.py +36 -0
  51. mlonmcu/flow/tvm/backend/tuner.py +41 -0
  52. mlonmcu/flow/tvm/backend/tvmaot.py +162 -0
  53. mlonmcu/flow/tvm/backend/tvmaotplus.py +51 -0
  54. mlonmcu/flow/tvm/backend/tvmc_utils.py +172 -0
  55. mlonmcu/flow/tvm/backend/tvmcg.py +102 -0
  56. mlonmcu/flow/tvm/backend/tvmllvm.py +106 -0
  57. mlonmcu/flow/tvm/backend/tvmrt.py +151 -0
  58. mlonmcu/flow/tvm/backend/wrapper.py +645 -0
  59. mlonmcu/flow/tvm/framework.py +96 -0
  60. mlonmcu/logging.py +79 -0
  61. mlonmcu/mlonmcu.py +19 -0
  62. mlonmcu/models/__init__.py +31 -0
  63. mlonmcu/models/convert_data.py +107 -0
  64. mlonmcu/models/frontend.py +571 -0
  65. mlonmcu/models/group.py +29 -0
  66. mlonmcu/models/lookup.py +345 -0
  67. mlonmcu/models/metadata.py +133 -0
  68. mlonmcu/models/model.py +104 -0
  69. mlonmcu/models/options.py +64 -0
  70. mlonmcu/models/utils.py +136 -0
  71. mlonmcu/platform/__init__.py +27 -0
  72. mlonmcu/platform/_platform.py +46 -0
  73. mlonmcu/platform/espidf/__init__.py +25 -0
  74. mlonmcu/platform/espidf/espidf.py +489 -0
  75. mlonmcu/platform/espidf/espidf_target.py +257 -0
  76. mlonmcu/platform/lookup.py +126 -0
  77. mlonmcu/platform/microtvm/__init__.py +25 -0
  78. mlonmcu/platform/microtvm/microtvm.py +580 -0
  79. mlonmcu/platform/microtvm/microtvm_arduino_target.py +68 -0
  80. mlonmcu/platform/microtvm/microtvm_backend.py +64 -0
  81. mlonmcu/platform/microtvm/microtvm_espidf_target.py +94 -0
  82. mlonmcu/platform/microtvm/microtvm_etissvp_target.py +98 -0
  83. mlonmcu/platform/microtvm/microtvm_host_target.py +46 -0
  84. mlonmcu/platform/microtvm/microtvm_spike_target.py +230 -0
  85. mlonmcu/platform/microtvm/microtvm_target.py +189 -0
  86. mlonmcu/platform/microtvm/microtvm_template_target.py +55 -0
  87. mlonmcu/platform/microtvm/microtvm_zephyr_target.py +91 -0
  88. mlonmcu/platform/mlif/__init__.py +25 -0
  89. mlonmcu/platform/mlif/mlif.py +300 -0
  90. mlonmcu/platform/mlif/mlif_target.py +86 -0
  91. mlonmcu/platform/platform.py +244 -0
  92. mlonmcu/platform/tvm/__init__.py +25 -0
  93. mlonmcu/platform/tvm/tvm.py +429 -0
  94. mlonmcu/platform/tvm/tvm_backend.py +57 -0
  95. mlonmcu/platform/tvm/tvm_target.py +165 -0
  96. mlonmcu/platform/zephyr/__init__.py +25 -0
  97. mlonmcu/platform/zephyr/zephyr.py +450 -0
  98. mlonmcu/platform/zephyr/zephyr_target.py +110 -0
  99. mlonmcu/plugins.py +26 -0
  100. mlonmcu/report.py +99 -0
  101. mlonmcu/session/__init__.py +18 -0
  102. mlonmcu/session/postprocess/__init__.py +43 -0
  103. mlonmcu/session/postprocess/postprocess.py +62 -0
  104. mlonmcu/session/postprocess/postprocesses.py +487 -0
  105. mlonmcu/session/run.py +1008 -0
  106. mlonmcu/session/session.py +373 -0
  107. mlonmcu/setup/__init__.py +18 -0
  108. mlonmcu/setup/cache.py +147 -0
  109. mlonmcu/setup/gen_requirements.py +619 -0
  110. mlonmcu/setup/setup.py +285 -0
  111. mlonmcu/setup/task.py +380 -0
  112. mlonmcu/setup/tasks/__init__.py +40 -0
  113. mlonmcu/setup/tasks/arm_gcc.py +58 -0
  114. mlonmcu/setup/tasks/cmsisnn.py +151 -0
  115. mlonmcu/setup/tasks/common.py +36 -0
  116. mlonmcu/setup/tasks/corstone300.py +64 -0
  117. mlonmcu/setup/tasks/espidf.py +87 -0
  118. mlonmcu/setup/tasks/etiss.py +147 -0
  119. mlonmcu/setup/tasks/llvm.py +67 -0
  120. mlonmcu/setup/tasks/mlif.py +49 -0
  121. mlonmcu/setup/tasks/muriscvnn.py +166 -0
  122. mlonmcu/setup/tasks/pulp.py +192 -0
  123. mlonmcu/setup/tasks/riscv_gcc.py +146 -0
  124. mlonmcu/setup/tasks/spike.py +190 -0
  125. mlonmcu/setup/tasks/tf.py +92 -0
  126. mlonmcu/setup/tasks/tflite.py +59 -0
  127. mlonmcu/setup/tasks/tflmc.py +141 -0
  128. mlonmcu/setup/tasks/tvm.py +172 -0
  129. mlonmcu/setup/tasks/utvmcg.py +96 -0
  130. mlonmcu/setup/tasks/zephyr.py +119 -0
  131. mlonmcu/setup/utils.py +374 -0
  132. mlonmcu/target/__init__.py +37 -0
  133. mlonmcu/target/_target.py +41 -0
  134. mlonmcu/target/arm/__init__.py +3 -0
  135. mlonmcu/target/arm/corstone300.py +235 -0
  136. mlonmcu/target/arm/util.py +109 -0
  137. mlonmcu/target/common.py +194 -0
  138. mlonmcu/target/elf.py +256 -0
  139. mlonmcu/target/host_x86.py +84 -0
  140. mlonmcu/target/metrics.py +75 -0
  141. mlonmcu/target/riscv/__init__.py +7 -0
  142. mlonmcu/target/riscv/etiss_pulpino.py +462 -0
  143. mlonmcu/target/riscv/gvsoc_pulp.py +215 -0
  144. mlonmcu/target/riscv/ovpsim.py +301 -0
  145. mlonmcu/target/riscv/riscv.py +185 -0
  146. mlonmcu/target/riscv/riscv_qemu.py +166 -0
  147. mlonmcu/target/riscv/spike.py +243 -0
  148. mlonmcu/target/riscv/util.py +134 -0
  149. mlonmcu/target/target.py +200 -0
  150. mlonmcu/utils.py +49 -0
  151. mlonmcu/version.py +21 -0
  152. mlonmcu-0.3.0.dev0.dist-info/LICENSE +202 -0
  153. mlonmcu-0.3.0.dev0.dist-info/METADATA +343 -0
  154. mlonmcu-0.3.0.dev0.dist-info/NOTICE +8 -0
  155. mlonmcu-0.3.0.dev0.dist-info/RECORD +376 -0
  156. mlonmcu-0.3.0.dev0.dist-info/WHEEL +5 -0
  157. mlonmcu-0.3.0.dev0.dist-info/entry_points.txt +3 -0
  158. mlonmcu-0.3.0.dev0.dist-info/top_level.txt +1 -0
  159. resources/frameworks/tvm/crt_config/README.md +7 -0
  160. resources/frameworks/tvm/crt_config/crt_config.h +53 -0
  161. resources/frameworks/tvm/tuning_records/riscv_cpu_v0.01.log.best +46 -0
  162. resources/patches/fix_esp32c3_march.patch +20 -0
  163. resources/patches/pulp_freertos_support.patch +55 -0
  164. resources/platforms/espidf/micro_speech_esp32devboard/CMakeLists.txt +29 -0
  165. resources/platforms/espidf/micro_speech_esp32devboard/README.md +70 -0
  166. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/CMakeLists.txt +78 -0
  167. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/Kconfig +76 -0
  168. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_data.c +26 -0
  169. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_model_support/process_input.c +35 -0
  170. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/default_model_support/process_output.c +45 -0
  171. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/exit.h +26 -0
  172. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/ml_interface.h +70 -0
  173. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/include/printing.h +31 -0
  174. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface.c +74 -0
  175. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface_tflm.cc +64 -0
  176. resources/platforms/espidf/micro_speech_esp32devboard/components/mlif2/ml_interface_tvm.c +53 -0
  177. resources/platforms/espidf/micro_speech_esp32devboard/components/tflite-lib/CMakeLists.txt +140 -0
  178. resources/platforms/espidf/micro_speech_esp32devboard/components/tflite-lib/Kconfig +8 -0
  179. resources/platforms/espidf/micro_speech_esp32devboard/components/tvm-lib/CMakeLists.txt +66 -0
  180. resources/platforms/espidf/micro_speech_esp32devboard/components/tvm-lib/Kconfig +7 -0
  181. resources/platforms/espidf/micro_speech_esp32devboard/example_test.py +38 -0
  182. resources/platforms/espidf/micro_speech_esp32devboard/info.txt +9 -0
  183. resources/platforms/espidf/micro_speech_esp32devboard/main/CMakeLists.txt +58 -0
  184. resources/platforms/espidf/micro_speech_esp32devboard/main/audio_provider.cc +193 -0
  185. resources/platforms/espidf/micro_speech_esp32devboard/main/audio_provider.h +49 -0
  186. resources/platforms/espidf/micro_speech_esp32devboard/main/command_responder.cc +53 -0
  187. resources/platforms/espidf/micro_speech_esp32devboard/main/command_responder.h +35 -0
  188. resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.cc +132 -0
  189. resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.cc.orig +145 -0
  190. resources/platforms/espidf/micro_speech_esp32devboard/main/feature_provider.h +55 -0
  191. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/COPYING +11 -0
  192. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/_kiss_fft_guts.h +168 -0
  193. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/kiss_fft.c +408 -0
  194. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/kiss_fft.h +124 -0
  195. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/tools/kiss_fftr.c +159 -0
  196. resources/platforms/espidf/micro_speech_esp32devboard/main/kissfft/tools/kiss_fftr.h +46 -0
  197. resources/platforms/espidf/micro_speech_esp32devboard/main/main.cc +63 -0
  198. resources/platforms/espidf/micro_speech_esp32devboard/main/main_functions.cc +204 -0
  199. resources/platforms/espidf/micro_speech_esp32devboard/main/main_functions.h +37 -0
  200. resources/platforms/espidf/micro_speech_esp32devboard/main/micro_features_generator.cc +121 -0
  201. resources/platforms/espidf/micro_speech_esp32devboard/main/micro_features_generator.h +38 -0
  202. resources/platforms/espidf/micro_speech_esp32devboard/main/micro_model_settings.cc +23 -0
  203. resources/platforms/espidf/micro_speech_esp32devboard/main/micro_model_settings.h +43 -0
  204. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/bits.h +102 -0
  205. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft.cc +52 -0
  206. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft.h +50 -0
  207. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft_util.cc +69 -0
  208. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/fft_util.h +34 -0
  209. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank.c +134 -0
  210. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank.h +63 -0
  211. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank_util.c +220 -0
  212. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/filterbank_util.h +50 -0
  213. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend.c +72 -0
  214. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend.h +64 -0
  215. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend_util.c +85 -0
  216. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/frontend_util.h +52 -0
  217. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_common.h +48 -0
  218. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_int16.cc +8 -0
  219. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/kiss_fft_int16.h +34 -0
  220. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_lut.c +30 -0
  221. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_lut.h +40 -0
  222. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale.c +83 -0
  223. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale.h +39 -0
  224. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale_util.c +27 -0
  225. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/log_scale_util.h +45 -0
  226. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction.c +51 -0
  227. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction.h +46 -0
  228. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction_util.c +45 -0
  229. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/noise_reduction_util.h +50 -0
  230. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control.c +56 -0
  231. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control.h +47 -0
  232. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control_util.c +92 -0
  233. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/pcan_gain_control_util.h +57 -0
  234. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window.c +70 -0
  235. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window.h +49 -0
  236. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window_util.c +73 -0
  237. resources/platforms/espidf/micro_speech_esp32devboard/main/microfrontend/lib/window_util.h +45 -0
  238. resources/platforms/espidf/micro_speech_esp32devboard/main/pins.c +14 -0
  239. resources/platforms/espidf/micro_speech_esp32devboard/main/pins.h +30 -0
  240. resources/platforms/espidf/micro_speech_esp32devboard/main/recognize_commands.cc +150 -0
  241. resources/platforms/espidf/micro_speech_esp32devboard/main/recognize_commands.h +173 -0
  242. resources/platforms/espidf/micro_speech_esp32devboard/main/ringbuf.c +333 -0
  243. resources/platforms/espidf/micro_speech_esp32devboard/main/ringbuf.h +74 -0
  244. resources/platforms/espidf/micro_speech_esp32devboard/sdkconfig.defaults +36 -0
  245. resources/platforms/espidf/project/CMakeLists.txt +29 -0
  246. resources/platforms/espidf/project/README.md +70 -0
  247. resources/platforms/espidf/project/components/mlif/CMakeLists.txt +77 -0
  248. resources/platforms/espidf/project/components/mlif/Kconfig +76 -0
  249. resources/platforms/espidf/project/components/mlif/default_data.c +26 -0
  250. resources/platforms/espidf/project/components/mlif/default_model_support/process_input.c +35 -0
  251. resources/platforms/espidf/project/components/mlif/default_model_support/process_output.c +45 -0
  252. resources/platforms/espidf/project/components/mlif/include/exit.h +26 -0
  253. resources/platforms/espidf/project/components/mlif/include/ml_interface.h +60 -0
  254. resources/platforms/espidf/project/components/mlif/include/printing.h +31 -0
  255. resources/platforms/espidf/project/components/mlif/ml_interface.c +54 -0
  256. resources/platforms/espidf/project/components/mlif/ml_interface_tflm.cc +40 -0
  257. resources/platforms/espidf/project/components/mlif/ml_interface_tvm.c +40 -0
  258. resources/platforms/espidf/project/components/tflite-lib/CMakeLists.txt +142 -0
  259. resources/platforms/espidf/project/components/tflite-lib/Kconfig +8 -0
  260. resources/platforms/espidf/project/components/tvm-lib/CMakeLists.txt +66 -0
  261. resources/platforms/espidf/project/components/tvm-lib/Kconfig +7 -0
  262. resources/platforms/espidf/project/example_test.py +38 -0
  263. resources/platforms/espidf/project/main/CMakeLists.txt +25 -0
  264. resources/platforms/espidf/project/main/main.c +57 -0
  265. resources/platforms/espidf/project/sdkconfig.defaults +26 -0
  266. resources/platforms/zephyr/project/CMakeLists.txt +22 -0
  267. resources/platforms/zephyr/project/Kconfig +101 -0
  268. resources/platforms/zephyr/project/README.rst +33 -0
  269. resources/platforms/zephyr/project/cmake/AddAllSubdirs.cmake +21 -0
  270. resources/platforms/zephyr/project/cmake/ChooseTarget.cmake +22 -0
  271. resources/platforms/zephyr/project/cmake/LinkTFLite.cmake +223 -0
  272. resources/platforms/zephyr/project/cmake/LinkTVM.cmake +68 -0
  273. resources/platforms/zephyr/project/cmake/LookupClang.cmake +41 -0
  274. resources/platforms/zephyr/project/cmake/backends/tflmc.cmake +5 -0
  275. resources/platforms/zephyr/project/cmake/backends/tflmi.cmake +5 -0
  276. resources/platforms/zephyr/project/cmake/backends/tvmaot.cmake +10 -0
  277. resources/platforms/zephyr/project/cmake/backends/tvmaotplus.cmake +10 -0
  278. resources/platforms/zephyr/project/cmake/backends/tvmcg.cmake +10 -0
  279. resources/platforms/zephyr/project/cmake/backends/tvmllvm.cmake +8 -0
  280. resources/platforms/zephyr/project/cmake/backends/tvmrt.cmake +8 -0
  281. resources/platforms/zephyr/project/cmake/extras.cmake +9 -0
  282. resources/platforms/zephyr/project/cmake/features/auto_vectorize_gcc.cmake +65 -0
  283. resources/platforms/zephyr/project/cmake/features/auto_vectorize_llvm.cmake +20 -0
  284. resources/platforms/zephyr/project/cmake/features/cmsisnn.cmake +86 -0
  285. resources/platforms/zephyr/project/cmake/features/muriscvnn.cmake +87 -0
  286. resources/platforms/zephyr/project/cmake/frameworks/tflm.cmake +1 -0
  287. resources/platforms/zephyr/project/cmake/frameworks/tflm_mlif.cmake +8 -0
  288. resources/platforms/zephyr/project/cmake/frameworks/tvm.cmake +1 -0
  289. resources/platforms/zephyr/project/cmake/frameworks/tvm_mlif.cmake +37 -0
  290. resources/platforms/zephyr/project/lib/CMakeLists.txt +13 -0
  291. resources/platforms/zephyr/project/lib/drivers/fake_input.c +10 -0
  292. resources/platforms/zephyr/project/lib/drivers/fake_input.h +8 -0
  293. resources/platforms/zephyr/project/lib/ml_interface/CMakeLists.txt +31 -0
  294. resources/platforms/zephyr/project/lib/ml_interface/default_data.c +8 -0
  295. resources/platforms/zephyr/project/lib/ml_interface/default_model_support/CMakeLists.txt +2 -0
  296. resources/platforms/zephyr/project/lib/ml_interface/default_model_support/process_input.c +17 -0
  297. resources/platforms/zephyr/project/lib/ml_interface/default_model_support/process_output.c +27 -0
  298. resources/platforms/zephyr/project/lib/ml_interface/ml_interface.c +36 -0
  299. resources/platforms/zephyr/project/lib/ml_interface/ml_interface.h +47 -0
  300. resources/platforms/zephyr/project/lib/ml_interface/ml_interface_tflm.cc +22 -0
  301. resources/platforms/zephyr/project/lib/ml_interface/ml_interface_tvm.c +22 -0
  302. resources/platforms/zephyr/project/lib/support/CMakeLists.txt +2 -0
  303. resources/platforms/zephyr/project/lib/support/dummy.c +0 -0
  304. resources/platforms/zephyr/project/lib/support/exit.h +8 -0
  305. resources/platforms/zephyr/project/lib/support/printing.h +11 -0
  306. resources/platforms/zephyr/project/lib/support/quantize.h +23 -0
  307. resources/platforms/zephyr/project/lib/targets/corstone300.c +62 -0
  308. resources/platforms/zephyr/project/lib/targets/default.c +2 -0
  309. resources/platforms/zephyr/project/lib/targets/etiss_pulpino.c +112 -0
  310. resources/platforms/zephyr/project/lib/targets/generic_riscv.c +112 -0
  311. resources/platforms/zephyr/project/lib/targets/riscv_qemu.c +112 -0
  312. resources/platforms/zephyr/project/lib/targets/target.h +2 -0
  313. resources/platforms/zephyr/project/prj.conf +11 -0
  314. resources/platforms/zephyr/project/sample.yaml +19 -0
  315. resources/platforms/zephyr/project/src/main.c +71 -0
  316. resources/platforms/zephyr/project2/CMakeLists.txt +72 -0
  317. resources/platforms/zephyr/project2/Kconfig +101 -0
  318. resources/platforms/zephyr/project2/README.rst +33 -0
  319. resources/platforms/zephyr/project2/cmake/AddAllSubdirs.cmake +21 -0
  320. resources/platforms/zephyr/project2/cmake/ChooseTarget.cmake +22 -0
  321. resources/platforms/zephyr/project2/cmake/LinkTFLite.cmake +223 -0
  322. resources/platforms/zephyr/project2/cmake/LinkTVM.cmake +68 -0
  323. resources/platforms/zephyr/project2/cmake/LookupClang.cmake +41 -0
  324. resources/platforms/zephyr/project2/cmake/backends/tflmc.cmake +5 -0
  325. resources/platforms/zephyr/project2/cmake/backends/tflmi.cmake +5 -0
  326. resources/platforms/zephyr/project2/cmake/backends/tvmaot.cmake +10 -0
  327. resources/platforms/zephyr/project2/cmake/backends/tvmaotplus.cmake +10 -0
  328. resources/platforms/zephyr/project2/cmake/backends/tvmcg.cmake +10 -0
  329. resources/platforms/zephyr/project2/cmake/backends/tvmllvm.cmake +8 -0
  330. resources/platforms/zephyr/project2/cmake/backends/tvmrt.cmake +8 -0
  331. resources/platforms/zephyr/project2/cmake/extras.cmake +9 -0
  332. resources/platforms/zephyr/project2/cmake/features/auto_vectorize_gcc.cmake +65 -0
  333. resources/platforms/zephyr/project2/cmake/features/auto_vectorize_llvm.cmake +20 -0
  334. resources/platforms/zephyr/project2/cmake/features/cmsisnn.cmake +86 -0
  335. resources/platforms/zephyr/project2/cmake/features/muriscvnn.cmake +87 -0
  336. resources/platforms/zephyr/project2/cmake/frameworks/tflm.cmake +1 -0
  337. resources/platforms/zephyr/project2/cmake/frameworks/tflm_mlif.cmake +8 -0
  338. resources/platforms/zephyr/project2/cmake/frameworks/tvm.cmake +1 -0
  339. resources/platforms/zephyr/project2/cmake/frameworks/tvm_mlif.cmake +37 -0
  340. resources/platforms/zephyr/project2/default_data.c +8 -0
  341. resources/platforms/zephyr/project2/default_model_support/CMakeLists.txt +3 -0
  342. resources/platforms/zephyr/project2/default_model_support/process_input.c +17 -0
  343. resources/platforms/zephyr/project2/default_model_support/process_output.c +27 -0
  344. resources/platforms/zephyr/project2/lib/CMakeLists.txt +13 -0
  345. resources/platforms/zephyr/project2/lib/drivers/fake_input.c +10 -0
  346. resources/platforms/zephyr/project2/lib/drivers/fake_input.h +8 -0
  347. resources/platforms/zephyr/project2/lib/support/CMakeLists.txt +2 -0
  348. resources/platforms/zephyr/project2/lib/support/dummy.c +0 -0
  349. resources/platforms/zephyr/project2/lib/support/exit.h +8 -0
  350. resources/platforms/zephyr/project2/lib/support/printing.h +11 -0
  351. resources/platforms/zephyr/project2/lib/support/quantize.h +23 -0
  352. resources/platforms/zephyr/project2/lib/targets/corstone300.c +62 -0
  353. resources/platforms/zephyr/project2/lib/targets/default.c +2 -0
  354. resources/platforms/zephyr/project2/lib/targets/etiss_pulpino.c +112 -0
  355. resources/platforms/zephyr/project2/lib/targets/generic_riscv.c +112 -0
  356. resources/platforms/zephyr/project2/lib/targets/riscv_qemu.c +112 -0
  357. resources/platforms/zephyr/project2/lib/targets/target.h +2 -0
  358. resources/platforms/zephyr/project2/ml_interface.c +36 -0
  359. resources/platforms/zephyr/project2/ml_interface.h +47 -0
  360. resources/platforms/zephyr/project2/ml_interface_tflm.cc +22 -0
  361. resources/platforms/zephyr/project2/ml_interface_tvm.c +22 -0
  362. resources/platforms/zephyr/project2/prj.conf +13 -0
  363. resources/platforms/zephyr/project2/sample.yaml +19 -0
  364. resources/platforms/zephyr/project2/settings.json +6 -0
  365. resources/platforms/zephyr/project2/src/main.c +35 -0
  366. resources/pycharm/.run/README.md +73 -0
  367. resources/pycharm/.run/step1_ init env.run.xml +24 -0
  368. resources/pycharm/.run/step2_ setup.run.xml +25 -0
  369. resources/pycharm/.run/step3_ run resnet on pulpxpulpissimo.run.xml +25 -0
  370. resources/templates/default.yml.j2 +258 -0
  371. resources/templates/dev.yml.j2 +212 -0
  372. resources/templates/minimal.yml.j2 +234 -0
  373. resources/templates/phi.yml.j2 +282 -0
  374. resources/templates/pulp.yml.j2 +267 -0
  375. resources/templates/research.yml.j2 +237 -0
  376. resources/templates/tumeda.yml.j2 +239 -0
@@ -0,0 +1,1537 @@
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 MLonMCU features and the feature registry."""
20
+
21
+ import re
22
+ import pandas as pd
23
+ from typing import Union
24
+
25
+ from mlonmcu.utils import is_power_of_two
26
+ from mlonmcu.config import str2bool
27
+ from mlonmcu.artifact import Artifact, ArtifactFormat
28
+ from .feature import (
29
+ BackendFeature,
30
+ FrameworkFeature,
31
+ PlatformFeature,
32
+ FrontendFeature,
33
+ TargetFeature,
34
+ SetupFeature,
35
+ RunFeature,
36
+ FeatureBase,
37
+ )
38
+
39
+ # from mlonmcu.flow import SUPPORTED_TVM_BACKENDS
40
+ SUPPORTED_TVM_BACKENDS = [
41
+ "tvmaot",
42
+ "tvmaotplus",
43
+ "tvmrt",
44
+ "tvmcg",
45
+ "tvmllvm",
46
+ ] # Workaround for cirvular import until we have a backend registry
47
+
48
+
49
+ def filter_none(data):
50
+ """Helper function which drop dict items with a None value."""
51
+ assert isinstance(data, dict), "Dict only"
52
+ out = {key: value for key, value in data.items() if value is not None}
53
+ return out
54
+
55
+
56
+ REGISTERED_FEATURES = {}
57
+
58
+
59
+ def register_feature(name):
60
+ """Decorator for adding a feature to the global registry."""
61
+
62
+ def real_decorator(obj):
63
+ REGISTERED_FEATURES[name] = obj
64
+
65
+ return real_decorator
66
+
67
+
68
+ def get_available_feature_names(feature_type=None):
69
+ """Utility for getting feature names."""
70
+ ret = []
71
+ if feature_type is None:
72
+ return REGISTERED_FEATURES.keys()
73
+
74
+ for name, feature in REGISTERED_FEATURES.items():
75
+ if feature_type in list(feature.types()):
76
+ ret.append(name)
77
+ return ret
78
+
79
+
80
+ def get_available_features(feature_type=None, feature_name=None):
81
+ """Utility for looking up features."""
82
+ names = get_available_feature_names(feature_type=feature_type)
83
+ return [REGISTERED_FEATURES[name] for name in names if feature_name is None or name == feature_name]
84
+
85
+
86
+ def get_matching_features(features, feature_type):
87
+ return [feature for feature in features if feature_type in feature.types()]
88
+
89
+
90
+ @register_feature("debug_arena")
91
+ class DebugArena(BackendFeature):
92
+ """Enable verbose printing of arena usage for debugging."""
93
+
94
+ def __init__(self, features=None, config=None):
95
+ super().__init__("debug_arena", features=features, config=config)
96
+
97
+ def get_backend_config(self, backend):
98
+ assert backend in [
99
+ "tvmaot",
100
+ "tvmaotplus",
101
+ "tvmrt",
102
+ "tflmi",
103
+ ], f"Unsupported feature '{self.name}' for backend '{backend}'"
104
+ return {f"{backend}.debug_arena": self.enabled}
105
+
106
+
107
+ @register_feature("validate")
108
+ class Validate(FrontendFeature, PlatformFeature):
109
+ """Enable validaton of inout and output tensors."""
110
+
111
+ DEFAULTS = {
112
+ **FeatureBase.DEFAULTS,
113
+ "allow_missing": True,
114
+ "fail_on_error": None,
115
+ }
116
+
117
+ def __init__(self, features=None, config=None):
118
+ super().__init__("validate", features=features, config=config)
119
+
120
+ @property
121
+ def allow_missing(self):
122
+ value = self.config["allow_missing"]
123
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
124
+
125
+ @property
126
+ def fail_on_error(self):
127
+ return self.config["fail_on_error"]
128
+
129
+ def get_frontend_config(self, frontend):
130
+ if not self.allow_missing:
131
+ raise NotImplementedError
132
+ return {f"{frontend}.use_inout_data": True}
133
+
134
+ def get_platform_config(self, platform):
135
+ assert platform == "mlif", f"Unsupported feature '{self.name}' for platform '{platform}'"
136
+ return filter_none(
137
+ {
138
+ f"{platform}.ignore_data": False,
139
+ f"{platform}.fail_on_error": self.fail_on_error,
140
+ }
141
+ )
142
+
143
+
144
+ @register_feature("muriscvnn")
145
+ class Muriscvnn(SetupFeature, FrameworkFeature, PlatformFeature):
146
+ """muRISCV-V NN wrappers for TFLite Micro"""
147
+
148
+ REQUIRED = ["muriscvnn.src_dir"]
149
+
150
+ def __init__(self, features=None, config=None):
151
+ super().__init__("muriscvnn", features=features, config=config)
152
+
153
+ @property
154
+ def muriscvnn_dir(self):
155
+ return str(self.config["muriscvnn.src_dir"])
156
+
157
+ def add_framework_config(self, framework, config):
158
+ assert framework == "tflm", f"Unsupported feature '{self.name}' for framework '{framework}'"
159
+ if f"{framework}.optimized_kernel" in config and config[f"{framework}.optimized_kernel"] not in [
160
+ None,
161
+ "cmsis_nn",
162
+ ]:
163
+ RuntimeError(f"There is already a optimized_kernel selected for framework '{framework}'")
164
+ else:
165
+ config[f"{framework}.optimized_kernel"] = "cmsis_nn"
166
+
167
+ def get_platform_defs(self, platform):
168
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
169
+ return {
170
+ "MURISCVNN": self.enabled,
171
+ "MURISCVNN_DIR": self.muriscvnn_dir,
172
+ }
173
+
174
+ def get_required_cache_flags(self):
175
+ ret = {}
176
+
177
+ ret["tflmc.exe"] = ["muriscvnn"]
178
+ return ret
179
+
180
+
181
+ @register_feature("cmsisnn")
182
+ class Cmsisnn(SetupFeature, FrameworkFeature, PlatformFeature):
183
+ """CMSIS-NN kernels for TFLite Micro"""
184
+
185
+ DEFAULTS = {
186
+ **FeatureBase.DEFAULTS,
187
+ }
188
+
189
+ REQUIRED = ["cmsisnn.dir"]
190
+
191
+ def __init__(self, features=None, config=None):
192
+ super().__init__("cmsisnn", features=features, config=config)
193
+
194
+ @property
195
+ def cmsisnn_dir(self):
196
+ return str(self.config["cmsisnn.dir"])
197
+
198
+ def add_framework_config(self, framework, config):
199
+ assert framework == "tflm", f"Unsupported feature '{self.name}' for framework '{framework}'"
200
+ if f"{framework}.optimized_kernel" in config and config[f"{framework}.optimized_kernel"] not in [
201
+ None,
202
+ "cmsis_nn",
203
+ ]:
204
+ RuntimeError(f"There is already a optimized_kernel selected for framework '{framework}'")
205
+ else:
206
+ config[f"{framework}.optimized_kernel"] = "cmsis_nn"
207
+
208
+ def get_platform_defs(self, platform):
209
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
210
+ return {
211
+ "CMSISNN": self.enabled,
212
+ "CMSISNN_DIR": self.cmsisnn_dir,
213
+ }
214
+
215
+ def get_required_cache_flags(self):
216
+ ret = {}
217
+ ret["tflmc.exe"] = ["cmsisnn"]
218
+ return ret
219
+
220
+
221
+ @register_feature("cmsisnnbyoc")
222
+ class CmsisnnByoc(SetupFeature, BackendFeature, PlatformFeature):
223
+ """CMSIS-NN kernels for TVM using BYOC wrappers."""
224
+
225
+ DEFAULTS = {
226
+ **FeatureBase.DEFAULTS,
227
+ "mcpu": None, # mve: cortex-m55, dsp: cortex-m4, cortex-m7, cortex-m33, cortex-m35p
228
+ }
229
+
230
+ REQUIRED = ["cmsisnn.dir"]
231
+
232
+ def __init__(self, features=None, config=None):
233
+ super().__init__("cmsisnnbyoc", features=features, config=config)
234
+
235
+ @property
236
+ def cmsisnn_dir(self):
237
+ return str(self.config["cmsisnn.dir"])
238
+
239
+ @property
240
+ def mcpu(self):
241
+ return self.config["mcpu"]
242
+
243
+ def add_backend_config(self, backend, config):
244
+ assert backend in SUPPORTED_TVM_BACKENDS, f"Unsupported feature '{self.name}' for backend '{backend}'"
245
+ extras = config.get(f"{backend}.extra_target", [])
246
+ if "cmsis-nn" not in extras:
247
+ if isinstance(extras, str):
248
+ extras = [extras]
249
+ extras.append("cmsis-nn")
250
+ config[f"{backend}.extra_target"] = extras
251
+ if self.mcpu:
252
+ # Ideally cmsisnnbyoc would have a mvei/dsp feature which could be used to set this automatically
253
+ config[f"{backend}.extra_target_mcpu"] = self.mcpu
254
+
255
+ def get_platform_defs(self, platform):
256
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
257
+ return {
258
+ "CMSISNN": self.enabled,
259
+ "CMSISNN_DIR": self.cmsisnn_dir,
260
+ }
261
+
262
+ def get_required_cache_flags(self):
263
+ ret = {}
264
+ ret["tvm.build_dir"] = ["cmsisnn"]
265
+ return ret
266
+
267
+
268
+ @register_feature("muriscvnnbyoc")
269
+ class MuriscvnnByoc(SetupFeature, BackendFeature, PlatformFeature):
270
+ """MuRiscvNN kernels for TVM using BYOC wrappers."""
271
+
272
+ DEFAULTS = {
273
+ **FeatureBase.DEFAULTS,
274
+ "mcpu": None, # mve: cortex-m55, dsp: cortex-m4, cortex-m7, cortex-m33, cortex-m35p
275
+ }
276
+
277
+ REQUIRED = ["muriscvnn.src_dir"]
278
+
279
+ def __init__(self, features=None, config=None):
280
+ super().__init__("muriscvnnbyoc", features=features, config=config)
281
+
282
+ @property
283
+ def muriscvnn_dir(self):
284
+ return str(self.config["muriscvnn.src_dir"])
285
+
286
+ @property
287
+ def mcpu(self):
288
+ return self.config["mcpu"]
289
+
290
+ def add_backend_config(self, backend, config):
291
+ assert backend in SUPPORTED_TVM_BACKENDS, f"Unsupported feature '{self.name}' for backend '{backend}'"
292
+ extras = config.get(f"{backend}.extra_target", [])
293
+ if "cmsis-nn" not in extras:
294
+ if isinstance(extras, str):
295
+ extras = [extras]
296
+ extras.append("cmsis-nn")
297
+ config[f"{backend}.extra_target"] = extras
298
+ if self.mcpu:
299
+ # Ideally muriscvnnbyoc would have a vext/pext feature which could be used to set this automatically
300
+ config[f"{backend}.extra_target_mcpu"] = self.mcpu
301
+
302
+ def get_platform_defs(self, platform):
303
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
304
+ return {
305
+ "MURISCVNN": self.enabled,
306
+ "MURISCVNN_DIR": self.muriscvnn_dir,
307
+ }
308
+
309
+ def get_required_cache_flags(self):
310
+ ret = {}
311
+ ret["tvm.build_dir"] = ["cmsisnn"]
312
+ return ret
313
+
314
+
315
+ # @before_feature("muriscvnn") # TODO: implement something like this
316
+ @register_feature("vext")
317
+ class Vext(SetupFeature, TargetFeature, PlatformFeature):
318
+ """Enable vector extension for supported RISC-V targets"""
319
+
320
+ DEFAULTS = {
321
+ **FeatureBase.DEFAULTS,
322
+ "vlen": 64, # TODO; define reasonable default? (Or put defaults in target and overwrite of not None)
323
+ "elen": 32,
324
+ # use target-side settings by default
325
+ "spec": None,
326
+ "embedded": None,
327
+ }
328
+
329
+ REQUIRED = []
330
+
331
+ def __init__(self, features=None, config=None):
332
+ super().__init__("vext", features=features, config=config)
333
+
334
+ @property
335
+ def vlen(self):
336
+ return int(self.config["vlen"])
337
+
338
+ @property
339
+ def elen(self):
340
+ return int(self.config["elen"])
341
+
342
+ @property
343
+ def spec(self):
344
+ return self.config["spec"]
345
+
346
+ @property
347
+ def embedded(self):
348
+ return self.config["embedded"]
349
+
350
+ def get_target_config(self, target):
351
+ # TODO: enforce llvm toolchain using add_compile_config and CompileFeature?
352
+ assert is_power_of_two(self.vlen)
353
+ return filter_none(
354
+ {
355
+ f"{target}.enable_vext": True,
356
+ f"{target}.vlen": self.vlen,
357
+ f"{target}.elen": self.elen,
358
+ f"{target}.vext_spec": self.spec,
359
+ f"{target}.embedded_vext": self.embedded,
360
+ }
361
+ )
362
+
363
+ # It would be great if we could enforce an llvm toolchain here
364
+ # def add_compile_config(self, config):
365
+ # # TODO: enforce llvm toolchain using add_compile_config and CompileFeature?
366
+ # if "mlif.toolchain" in config:
367
+ # assert "mlif.toolchain" == "llvm", "Vext requires LLVM target sw"
368
+ # else:
369
+ # config["mlif.toolchain"] = "llvm"
370
+
371
+ def get_platform_defs(self, platform):
372
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
373
+ return {"RISCV_VEXT": self.enabled}
374
+
375
+ def get_required_cache_flags(self):
376
+ return {
377
+ "muriscvnn.lib": ["vext"],
378
+ "tflmc.exe": ["vext"],
379
+ "riscv_gcc.install_dir": ["vext"],
380
+ "riscv_gcc.name": ["vext"],
381
+ }
382
+
383
+
384
+ @register_feature("pext")
385
+ class Pext(SetupFeature, TargetFeature, PlatformFeature):
386
+ """Enable packed SIMD extension for supported RISC-V targets"""
387
+
388
+ DEFAULTS = {
389
+ **FeatureBase.DEFAULTS,
390
+ # use target-side settings by default
391
+ "spec": None,
392
+ }
393
+
394
+ REQUIRED = []
395
+
396
+ def __init__(self, features=None, config=None):
397
+ super().__init__("pext", features=features, config=config)
398
+
399
+ @property
400
+ def spec(self):
401
+ return self.config["spec"]
402
+
403
+ def get_target_config(self, target):
404
+ return filter_none(
405
+ {
406
+ f"{target}.enable_pext": True, # Handle via arch characters in the future
407
+ f"{target}.pext_spec": self.spec,
408
+ }
409
+ )
410
+
411
+ def get_platform_defs(self, platform):
412
+ assert platform in ["mlif"], f"Unsupported feature '{self.name}' for platform '{platform}'"
413
+ return {"RISCV_PEXT": self.enabled}
414
+
415
+ def get_required_cache_flags(self):
416
+ # These will be merged automatically with existing ones
417
+ return {
418
+ "muriscvnn.lib": ["pext"],
419
+ "tflmc.exe": ["pext"],
420
+ "riscv_gcc.install_dir": ["pext"],
421
+ "riscv_gcc.name": ["pext"],
422
+ }
423
+
424
+
425
+ @register_feature("debug")
426
+ class Debug(SetupFeature, PlatformFeature):
427
+ """Enable debugging ability of target software."""
428
+
429
+ def __init__(self, features=None, config=None):
430
+ super().__init__("debug", features=features, config=config)
431
+
432
+ def get_required_cache_flags(self):
433
+ return {} if self.enabled else {} # TODO: remove?
434
+
435
+ def get_platform_config(self, platform):
436
+ return {f"{platform}.debug": self.enabled}
437
+
438
+
439
+ @register_feature("gdbserver")
440
+ class GdbServer(TargetFeature):
441
+ """Start debugging session for target software using gdbserver."""
442
+
443
+ DEFAULTS = {
444
+ **FeatureBase.DEFAULTS,
445
+ "attach": None,
446
+ "port": None,
447
+ }
448
+
449
+ def __init__(self, features=None, config=None):
450
+ super().__init__("gdbserver", features=features, config=config)
451
+
452
+ @property
453
+ def attach(self):
454
+ value = self.config["attach"]
455
+ return str2bool(value, allow_none=True) if not isinstance(value, (bool, int)) else value
456
+
457
+ @property
458
+ def port(self):
459
+ return int(self.config["port"]) if self.config["port"] is not None else None
460
+
461
+ def get_target_config(self, target):
462
+ assert target in ["host_x86", "etiss_pulpino", "ovpsim"]
463
+ return filter_none(
464
+ {
465
+ f"{target}.gdbserver_enable": self.enabled,
466
+ f"{target}.gdbserver_attach": self.attach,
467
+ f"{target}.gdbserver_port": self.port,
468
+ }
469
+ )
470
+
471
+
472
+ @register_feature("etissdbg")
473
+ class ETISSDebug(SetupFeature, TargetFeature):
474
+ """Debug ETISS internals."""
475
+
476
+ def __init__(self, features=None, config=None):
477
+ super().__init__("etissdbg", features=features, config=config)
478
+
479
+ def get_required_cache_flags(self):
480
+ return {"etiss.install_dir": ["dbg"], "etissvp.script": ["dbg"]} if self.enabled else {}
481
+
482
+ def get_target_config(self, target):
483
+ assert target in ["etiss_pulpino"]
484
+ return {"etiss_pulpino.debug_etiss": self.enabled}
485
+
486
+
487
+ @register_feature("trace")
488
+ class Trace(TargetFeature):
489
+ """Enable tracing of all memory accesses in ETISS."""
490
+
491
+ # TODO: support ovpsim --trace --tracemem SA
492
+
493
+ def __init__(self, features=None, config=None):
494
+ super().__init__("trace", features=features, config=config)
495
+
496
+ def get_target_config(self, target):
497
+ assert target in ["etiss_pulpino"]
498
+ return {"etiss_pulpino.trace_memory": self.enabled}
499
+
500
+
501
+ @register_feature("unpacked_api")
502
+ class UnpackedApi(BackendFeature): # TODO: should this be a feature or config only?
503
+ """Use unpacked interface api for TVMAOT backend to reduce stack usage."""
504
+
505
+ def __init__(self, features=None, config=None):
506
+ super().__init__("unpacked_api", features=features, config=config)
507
+
508
+ def get_backend_config(self, backend):
509
+ assert backend in ["tvmaot"], f"Unsupported feature '{self.name}' for backend '{backend}'"
510
+ return {f"{backend}.unpacked_api": self.enabled}
511
+
512
+
513
+ @register_feature("packed")
514
+ class Packed(FrameworkFeature, FrontendFeature, BackendFeature, SetupFeature):
515
+ """Sub-8-bit and sparsity feature for TFLite Micro kernels."""
516
+
517
+ def __init__(self, features=None, config=None):
518
+ super().__init__("packed", features=features, config=config)
519
+
520
+ def get_framework_config(self, framework):
521
+ raise NotImplementedError
522
+
523
+ def get_frontend_config(self, frontend):
524
+ assert frontend in ["tflm"], f"Unsupported feature '{self.name} for frontend '{frontend}''"
525
+ return {f"{frontend}.use_packed_weights": self.enabled}
526
+
527
+ def get_backend_config(self, backend):
528
+ raise NotImplementedError
529
+
530
+ def get_required_cache_flags(self):
531
+ return {"tflmc.exe": ["packed"]}
532
+
533
+
534
+ @register_feature("packing")
535
+ class Packing(FrontendFeature):
536
+ """Sub-8-bit and sparse weight packing for TFLite Frontend."""
537
+
538
+ def __init__(self, features=None, config=None):
539
+ super().__init__("packing", features=features, config=config)
540
+
541
+ def get_frontend_config(self, frontend):
542
+ assert frontend in ["tflm"], f"Unsupported feature '{self.name} for frontend '{frontend}''"
543
+ raise NotImplementedError
544
+ return {f"{frontend}.pack_weights": self.enabled}
545
+
546
+
547
+ @register_feature("usmp")
548
+ class Usmp(BackendFeature):
549
+ """Unified Static Memory Planning algorithm integrated in TVM"""
550
+
551
+ DEFAULTS = {
552
+ **FeatureBase.DEFAULTS,
553
+ "algorithm": "greedy_by_conflicts", # options: greedy_by_conflicts, greedy_by_size, hill_climb
554
+ }
555
+
556
+ def __init__(self, features=None, config=None):
557
+ super().__init__("usmp", features=features, config=config)
558
+
559
+ @property
560
+ def algorithm(self):
561
+ return str(self.config["algorithm"])
562
+
563
+ def add_backend_config(self, backend, config):
564
+ assert backend in ["tvmaot"], f"Unsupported feature '{self.name}' for backend '{backend}'"
565
+ if f"{backend}.extra_pass_config" in config:
566
+ tmp = config[f"{backend}.extra_pass_config"]
567
+ elif "extra_pass_config" in config:
568
+ tmp = config["extra_pass_config"]
569
+ else:
570
+ tmp = {}
571
+ if isinstance(tmp, str):
572
+ import ast
573
+
574
+ tmp = ast.literal_eval(tmp)
575
+ assert isinstance(tmp, dict)
576
+ tmp["tir.usmp.enable"] = self.enabled
577
+ if self.algorithm in ["greedy_by_size", "greedy_by_conflicts", "hill_climb"]:
578
+ tmp["tir.usmp.algorithm"] = self.algorithm
579
+ else:
580
+ tmp["tir.usmp.custom_algorithm"] = self.algorithm
581
+ config.update(
582
+ {f"{backend}.extra_pass_config": tmp, f"{backend}.arena_size": 0}
583
+ ) # In recent TVM versions USMP will have it's own arena.
584
+
585
+ # -> enable this via backend
586
+
587
+
588
+ @register_feature("moiopt")
589
+ class MOIOPT(BackendFeature):
590
+ """Memory-Optimizing, Inter-Operator Tiling - currently only supported with custom TVM"""
591
+
592
+ DEFAULTS = {
593
+ **FeatureBase.DEFAULTS,
594
+ "noftp": False,
595
+ "onlyftp": False,
596
+ "norecurse": False,
597
+ "maxpartitions": 0,
598
+ }
599
+
600
+ def __init__(self, features=None, config=None):
601
+ super().__init__("moiopt", features=features, config=config)
602
+
603
+ def add_backend_config(self, backend, config):
604
+ assert backend in ["tvmaot", "tvmrt"], f"Unsupported feature '{self.name}' for backend '{backend}'"
605
+ if f"{backend}.extra_pass_config" in config:
606
+ tmp = config[f"{backend}.extra_pass_config"]
607
+ elif "extra_pass_config" in config:
608
+ tmp = config["extra_pass_config"]
609
+ else:
610
+ tmp = {}
611
+ tmp["relay.moiopt.enable"] = self.enabled
612
+ tmp["relay.moiopt.noftp"] = self.config["noftp"]
613
+ tmp["relay.moiopt.onlyftp"] = self.config["onlyftp"]
614
+ tmp["relay.moiopt.norecurse"] = self.config["norecurse"]
615
+ tmp["relay.moiopt.maxpartitions"] = self.config["maxpartitions"]
616
+ config.update({f"{backend}.extra_pass_config": tmp})
617
+
618
+ # -> enable this via backend
619
+
620
+
621
+ @register_feature("visualize")
622
+ class Visualize(FrontendFeature):
623
+ """Visualize TFLite models."""
624
+
625
+ DEFAULTS = {
626
+ **FeatureBase.DEFAULTS,
627
+ }
628
+
629
+ REQUIRED = ["tflite_visualize.exe"]
630
+
631
+ def __init__(self, features=None, config=None):
632
+ super().__init__("visualize", features=features, config=config)
633
+
634
+ @property
635
+ def tflite_visualize_exe(self):
636
+ return self.config["tflite_visualize.exe"]
637
+
638
+ def get_frontend_config(self, frontend):
639
+ assert frontend in ["tflite"], f"Unsupported feature '{self.name}' for frontend '{frontend}'"
640
+ return filter_none(
641
+ {
642
+ f"{frontend}.visualize_enable": self.enabled,
643
+ f"{frontend}.visualize_script": self.tflite_visualize_exe,
644
+ }
645
+ )
646
+
647
+ def update_formats(self, frontend, input_formats, output_formats):
648
+ assert frontend in ["tflite"], f"Unsupported feature '{self.name}' for frontend '{frontend}'"
649
+ if self.enabled:
650
+ output_formats.append(ArtifactFormat.TEXT)
651
+
652
+
653
+ @register_feature("relayviz")
654
+ class Relayviz(FrontendFeature):
655
+ """Visualize TVM relay models."""
656
+
657
+ DEFAULTS = {
658
+ **FeatureBase.DEFAULTS,
659
+ "plotter": "term", # Alternative: dot
660
+ }
661
+
662
+ def __init__(self, features=None, config=None):
663
+ super().__init__("relayviz", features=features, config=config)
664
+
665
+ @property
666
+ def plotter(self):
667
+ return self.config.get("plotter", None)
668
+
669
+ def get_frontend_config(self, frontend):
670
+ assert frontend in ["relay"], f"Unsupported feature '{self.name}' for frontend '{frontend}'"
671
+ return filter_none(
672
+ {
673
+ f"{frontend}.visualize_graph": self.enabled,
674
+ f"{frontend}.relayviz_plotter": self.plotter,
675
+ }
676
+ )
677
+
678
+ def update_formats(self, frontend, input_formats, output_formats):
679
+ assert frontend in ["relay"], f"Unsupported feature '{self.name}' for frontend '{frontend}'"
680
+ if self.enabled:
681
+ output_formats.append(ArtifactFormat.TEXT)
682
+
683
+
684
+ @register_feature("autotuned")
685
+ class Autotuned(BackendFeature):
686
+ """Use existing TVM autotuning logs in backend."""
687
+
688
+ # TODO: FronendFeature to collect tuning logs or will we store them somewhere else?
689
+
690
+ DEFAULTS = {
691
+ **FeatureBase.DEFAULTS,
692
+ "results_file": None,
693
+ }
694
+
695
+ def __init__(self, features=None, config=None):
696
+ super().__init__("autotuned", features=features, config=config)
697
+
698
+ @property
699
+ def results_file(self):
700
+ return self.config["results_file"] if "results_file" in self.config else None
701
+
702
+ def get_backend_config(self, backend):
703
+ assert backend in SUPPORTED_TVM_BACKENDS
704
+ # TODO: error handling her eor on backend?
705
+ return filter_none(
706
+ {
707
+ f"{backend}.use_tuning_results": self.enabled,
708
+ f"{backend}.autotuning_results_file": self.results_file,
709
+ }
710
+ )
711
+
712
+
713
+ @register_feature("autotune")
714
+ class Autotune(PlatformFeature, RunFeature):
715
+ """Use the TVM autotuner inside the backend to generate tuning logs."""
716
+
717
+ DEFAULTS = {
718
+ **FeatureBase.DEFAULTS,
719
+ "results_file": None,
720
+ "append": None,
721
+ "tuner": None,
722
+ "trials": None,
723
+ "early_stopping": None,
724
+ "num_workers": None,
725
+ "max_parallel": None,
726
+ "use_rpc": None,
727
+ "timeout": None,
728
+ "mode": None,
729
+ "visualize": None,
730
+ "tasks": None,
731
+ # All None to use the defaults defined in the backend instead
732
+ }
733
+
734
+ def __init__(self, features=None, config=None):
735
+ super().__init__("autotune", features=features, config=config)
736
+
737
+ @property
738
+ def results_file(self):
739
+ return self.config["results_file"] if "results_file" in self.config else None
740
+
741
+ @property
742
+ def append(self):
743
+ return self.config["append"] if "append" in self.config else None
744
+
745
+ @property
746
+ def tuner(self):
747
+ return self.config["tuner"] if "tuner" in self.config else None
748
+
749
+ @property
750
+ def trials(self):
751
+ return self.config["trials"] if "trials" in self.config else None
752
+
753
+ @property
754
+ def early_stopping(self):
755
+ return self.config["early_stopping"] if "early_stopping" in self.config else None
756
+
757
+ @property
758
+ def num_workers(self):
759
+ return self.config["num_workers"] if "num_workers" in self.config else None
760
+
761
+ @property
762
+ def max_parallel(self):
763
+ return self.config["max_parallel"] if "max_parallel" in self.config else None
764
+
765
+ @property
766
+ def use_rpc(self):
767
+ return self.config["use_rpc"] if "use_rpc" in self.config else None
768
+
769
+ @property
770
+ def timeout(self):
771
+ return self.config["timeout"] if "timeout" in self.config else None
772
+
773
+ @property
774
+ def mode(self):
775
+ return self.config["mode"]
776
+
777
+ @property
778
+ def visualize(self):
779
+ return self.config["visualize"]
780
+
781
+ @property
782
+ def tasks(self):
783
+ return self.config["tasks"]
784
+
785
+ def get_platform_config(self, platform):
786
+ assert platform in ["tvm", "microtvm"]
787
+ # TODO: figure out a default path automatically
788
+ return filter_none(
789
+ {
790
+ f"{platform}.autotuning_enable": self.enabled,
791
+ f"{platform}.autotuning_results_file": self.results_file,
792
+ f"{platform}.autotuning_append": self.append,
793
+ f"{platform}.autotuning_tuner": self.tuner,
794
+ f"{platform}.autotuning_trials": self.trials,
795
+ f"{platform}.autotuning_early_stopping": self.early_stopping,
796
+ f"{platform}.autotuning_num_workers": self.num_workers,
797
+ f"{platform}.autotuning_max_parallel": self.max_parallel,
798
+ f"{platform}.autotuning_timeout": self.timeout,
799
+ f"{platform}.autotuning_mode": self.mode,
800
+ f"{platform}.autotuning_visualize": self.visualize,
801
+ f"{platform}.autotuning_tasks": self.tasks,
802
+ }
803
+ )
804
+
805
+ def get_run_config(self):
806
+ return {"run.tune_enabled": self.enabled}
807
+
808
+
809
+ @register_feature("disable_legalize")
810
+ class DisableLegalize(BackendFeature, SetupFeature):
811
+ """Enable transformation to reduces sizes of intermediate buffers by skipping legalization passes."""
812
+
813
+ REQUIRED = ["tvm_extensions.wrapper"]
814
+
815
+ def __init__(self, features=None, config=None):
816
+ super().__init__("disable_legalize", features=features, config=config)
817
+
818
+ @property
819
+ def tvm_extensions_wrapper(self):
820
+ return self.config["tvm_extensions.wrapper"]
821
+
822
+ def add_backend_config(self, backend, config):
823
+ assert backend in SUPPORTED_TVM_BACKENDS, f"Unsupported feature '{self.name}' for backend '{backend}'"
824
+ if f"{backend}.tvmc_extra_args" in config:
825
+ config[f"{backend}.tvmc_extra_args"].append("--disable-legalize")
826
+ else:
827
+ config[f"{backend}.tvmc_extra_args"] = ["--disable-legalize"]
828
+ if f"{backend}.tvmc_custom_script" in config:
829
+ assert config[f"{backend}.tvmc_custom_script"] is None or str(
830
+ config[f"{backend}.tvmc_custom_script"]
831
+ ) == str(
832
+ self.tvm_extensions_wrapper
833
+ ), f"{backend}.tvmc_custom_script is already set. Can't enable feature: {self.name}"
834
+ config[f"{backend}.tvmc_custom_script"] = self.tvm_extensions_wrapper
835
+
836
+ def get_required_cache_flags(self):
837
+ ret = {}
838
+
839
+ ret["tvm.pythonpath"] = ["patch"]
840
+ return ret
841
+
842
+
843
+ @register_feature("demo")
844
+ class Demo(PlatformFeature):
845
+ """Run demo application instead of benchmarking code."""
846
+
847
+ DEFAULTS = {
848
+ **FeatureBase.DEFAULTS,
849
+ "board": None,
850
+ "print_stats": False,
851
+ "print_interval_ms": 5000,
852
+ }
853
+
854
+ REQUIRED = []
855
+
856
+ def __init__(self, features=None, config=None):
857
+ super().__init__("demo", features=features, config=config)
858
+
859
+ @property
860
+ def board(self):
861
+ return self.config["board"]
862
+
863
+ @property
864
+ def print_stats(self):
865
+ return self.config["print_stats"]
866
+
867
+ @property
868
+ def print_interval_ms(self):
869
+ return self.config["print_interval_ms"]
870
+
871
+ def get_platform_defs(self, platform):
872
+ assert platform in ["espidf"], f"Unsupported feature '{self.name}' for platform '{platform}'"
873
+ # TODO: espidf.demo_mode, disable wdt, runtime stats,
874
+ return {}
875
+
876
+ def get_platform_config(self, platform):
877
+ assert platform in ["espidf"], f"Unsupported feature '{self.name}' for platform '{platform}'"
878
+ # TODO: espidf.demo_mode, disable wdt, runtime stats,
879
+ return {}
880
+
881
+
882
+ @register_feature("cachesim")
883
+ class CacheSim(TargetFeature):
884
+ """Collect information on cache misses etc. with spike target"""
885
+
886
+ DEFAULTS = {
887
+ **FeatureBase.DEFAULTS,
888
+ "ic_enable": False,
889
+ "ic_config": "64:8:32",
890
+ "dc_enable": False,
891
+ "dc_config": "64:8:32",
892
+ "l2_enable": False,
893
+ "l2_config": "262144:8:32", # TODO: find a meaningful value
894
+ "log_misses": False,
895
+ "detailed": False,
896
+ }
897
+
898
+ REQUIRED = []
899
+
900
+ def __init__(self, features=None, config=None):
901
+ super().__init__("cachesim", features=features, config=config)
902
+
903
+ @property
904
+ def ic_enable(self):
905
+ value = self.config["ic_enable"]
906
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
907
+
908
+ @property
909
+ def ic_config(self):
910
+ return self.config["ic_config"]
911
+
912
+ @property
913
+ def dc_enable(self):
914
+ value = self.config["dc_enable"]
915
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
916
+
917
+ @property
918
+ def dc_config(self):
919
+ return self.config["dc_config"]
920
+
921
+ @property
922
+ def l2_enable(self):
923
+ value = self.config["l2_enable"]
924
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
925
+
926
+ @property
927
+ def l2_config(self):
928
+ return self.config["l2_config"]
929
+
930
+ @property
931
+ def log_misses(self):
932
+ value = self.config["log_misses"]
933
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
934
+
935
+ @property
936
+ def detailed(self):
937
+ value = self.config["detailed"]
938
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
939
+
940
+ def add_target_config(self, target, config):
941
+ assert target in ["spike"], f"Unsupported feature '{self.name}' for target '{target}'"
942
+ if self.enabled:
943
+ spike_args = config.get(f"{target}.extra_args", [])
944
+ if self.ic_enable:
945
+ assert self.ic_config is not None and len(self.ic_config) > 0
946
+ spike_args.append(f"--ic={self.ic_config}")
947
+ if self.dc_enable:
948
+ assert self.dc_config is not None and len(self.dc_config) > 0
949
+ spike_args.append(f"--dc={self.dc_config}")
950
+ if self.l2_enable:
951
+ assert self.l2_config is not None and len(self.l2_config) > 0
952
+ spike_args.append(f"--l2={self.l2_config}")
953
+ if self.log_misses:
954
+ spike_args.append("--log-cache-miss")
955
+ config.update({f"{target}.extra_args": spike_args})
956
+
957
+ def get_target_callbacks(self, target):
958
+ assert target in ["spike"], f"Unsupported feature '{self.name}' for target '{target}'"
959
+ if self.enabled:
960
+
961
+ def cachesim_callback(stdout, metrics, artifacts):
962
+ """Callback which parses the targets output and updates the generated metrics and artifacts."""
963
+ expr = (
964
+ r"(D|I|L2)\$ ((?:Bytes (?:Read|Written))|(?:Read|Write) "
965
+ r"(?:Accesses|Misses)|(?:Writebacks)|(?:Miss Rate)):\s*(\d+\.?\d*%?)*"
966
+ )
967
+ matches = re.compile(expr).findall(stdout)
968
+ prefixes = [
969
+ x for (x, y) in zip(["I", "D", "L2"], [self.ic_enable, self.dc_enable, self.l2_enable]) if y
970
+ ]
971
+ for groups in matches:
972
+ assert len(groups) == 3
973
+ prefix, label, value = groups
974
+ if not self.detailed:
975
+ if "Rate" not in label:
976
+ continue
977
+ value = int(value) if "%" not in value else float(value[:-1]) / 100
978
+ if prefix in prefixes:
979
+ for m in metrics:
980
+ m.add(f"{prefix}-Cache {label}", value)
981
+ return stdout
982
+
983
+ return None, cachesim_callback
984
+
985
+
986
+ @register_feature("log_instrs")
987
+ class LogInstructions(TargetFeature):
988
+ """Enable logging of the executed instructions of a simulator-based target."""
989
+
990
+ DEFAULTS = {**FeatureBase.DEFAULTS, "to_file": False}
991
+
992
+ def __init__(self, features=None, config=None):
993
+ super().__init__("log_instrs", features=features, config=config)
994
+
995
+ @property
996
+ def to_file(self):
997
+ value = self.config["to_file"]
998
+ return str2bool(value, allow_none=True) if not isinstance(value, (bool, int)) else value
999
+
1000
+ def add_target_config(self, target, config):
1001
+ assert target in ["spike", "etiss_pulpino", "ovpsim", "gvsoc_pulp"]
1002
+ if not self.enabled:
1003
+ return
1004
+ if target == "spike":
1005
+ extra_args_new = config.get("extra_args", [])
1006
+ extra_args_new.append("-l")
1007
+ # if self.to_file:
1008
+ # extra_args_new.append("--log=?")
1009
+ config.update({f"{target}.extra_args": extra_args_new})
1010
+ elif target == "etiss_pulpino":
1011
+ plugins_new = config.get("plugins", [])
1012
+ plugins_new.append("PrintInstruction")
1013
+ config.update({f"{target}.plugins": plugins_new})
1014
+ elif target == "ovpsim":
1015
+ extra_args_new = config.get("extra_args", [])
1016
+ extra_args_new.append("--trace")
1017
+ # if self.to_file:
1018
+ # extra_args_new.append("--tracefile")
1019
+ config.update({f"{target}.extra_args": extra_args_new})
1020
+ elif target == "gvsoc_pulp":
1021
+ extra_args_new = config.get("extra_args", [])
1022
+ if self.to_file:
1023
+ extra_args_new.append(f"--trace=insn:{target}_instrs.log")
1024
+ """
1025
+ TODO: The above code will generate a instruction log.
1026
+ But it will not be recorded by Artifact (which should be done in get_target_callbacks).
1027
+ The code to let it be recorded by Artifact is currently not added because of the following reasons:
1028
+ 1. This feature is rarely used.
1029
+ 2. GVSOC can directly write the instruction log into a file which should be much faster than
1030
+ read/write from the output. This makes GVSOC special and difficult to be adapted in the current
1031
+ code.
1032
+ 3. This difficulty reflected in that the methods add_target_config and get_target_callbacks should
1033
+ have a consensus about where in the system file system the instruction log is written to and can be
1034
+ read from. This is not feasible in current code and the realization requires a workaround.
1035
+ """
1036
+ else:
1037
+ extra_args_new.append("--trace=insn")
1038
+ config.update({f"{target}.extra_args": extra_args_new})
1039
+
1040
+ def get_target_callbacks(self, target):
1041
+ assert target in [
1042
+ "spike",
1043
+ "etiss_pulpino",
1044
+ "ovpsim",
1045
+ "gvsoc_pulp",
1046
+ ], f"Unsupported feature '{self.name}' for target '{target}'"
1047
+ if self.enabled:
1048
+ if not target == "gvsoc_pulp":
1049
+
1050
+ def log_instrs_callback(stdout, metrics, artifacts):
1051
+ """Callback which parses the targets output and updates the generated metrics and artifacts."""
1052
+ new_lines = []
1053
+ if self.to_file:
1054
+ # TODO: update stdout and remove log_instrs lines
1055
+ instrs = []
1056
+ for line in stdout.split("\n"):
1057
+ if target == "etiss_pulpino":
1058
+ expr = re.compile(r"0x[a-fA-F0-9]+: .* \[.*\]")
1059
+ elif target == "spike":
1060
+ expr = re.compile(r"core\s+\d+: 0x[a-fA-F0-9]+ \(0x[a-fA-F0-9]+\) .*")
1061
+ elif target == "ovpsim":
1062
+ expr = re.compile(
1063
+ r"Info 'riscvOVPsim\/cpu',\s0x[0-9abcdef]+\(.*\):\s[0-9abcdef]+\s+\w+\s+.*"
1064
+ )
1065
+ match = expr.match(line)
1066
+ if match is not None:
1067
+ instrs.append(line)
1068
+ else:
1069
+ new_lines.append(line)
1070
+ instrs_artifact = Artifact(
1071
+ f"{target}_instrs.log",
1072
+ content="\n".join(instrs),
1073
+ fmt=ArtifactFormat.TEXT,
1074
+ flags=(self.name, target),
1075
+ )
1076
+ artifacts.append(instrs_artifact)
1077
+ return "\n".join(new_lines)
1078
+ else:
1079
+ return stdout
1080
+
1081
+ return None, log_instrs_callback
1082
+ return None, None
1083
+
1084
+
1085
+ @register_feature("arm_mvei")
1086
+ class ArmMvei(SetupFeature, TargetFeature, PlatformFeature):
1087
+ """Enable MVEI extension for supported ARM targets"""
1088
+
1089
+ def __init__(self, features=None, config=None):
1090
+ super().__init__("arm_mvei", features=features, config=config)
1091
+
1092
+ def get_target_config(self, target):
1093
+ assert target in ["corstone300"]
1094
+ return {
1095
+ f"{target}.enable_mvei": True, # TODO: remove if not required (only enforce m33/m55)
1096
+ }
1097
+
1098
+ def get_required_cache_flags(self):
1099
+ return {
1100
+ "cmsisnn.lib": ["mvei"],
1101
+ "tflmc.exe": ["mvei"],
1102
+ }
1103
+
1104
+ def get_platform_defs(self, platform):
1105
+ return {"ARM_MVEI": self.enabled}
1106
+
1107
+
1108
+ @register_feature("arm_dsp")
1109
+ class ArmDsp(SetupFeature, TargetFeature, PlatformFeature):
1110
+ """Enable DSP extension for supported ARM targets"""
1111
+
1112
+ def __init__(self, features=None, config=None):
1113
+ super().__init__("arm_dsp", features=features, config=config)
1114
+
1115
+ def get_target_config(self, target):
1116
+ assert target in ["corstone300"]
1117
+ return {
1118
+ f"{target}.enable_dsp": True, # TODO: remove if not required (only enforce m33/m55)
1119
+ }
1120
+
1121
+ def get_required_cache_flags(self):
1122
+ # These will be merged automatically with existing ones
1123
+ return {
1124
+ "cmsisnn.lib": ["dsp"],
1125
+ "tflmc.exe": ["dsp"],
1126
+ }
1127
+
1128
+ def get_platform_defs(self, platform):
1129
+ return {"ARM_DSP": self.enabled}
1130
+
1131
+
1132
+ @register_feature("target_optimized")
1133
+ class TargetOptimized(RunFeature):
1134
+ """Overwrite backend options according to chosen target."""
1135
+
1136
+ DEFAULTS = {
1137
+ **FeatureBase.DEFAULTS,
1138
+ }
1139
+
1140
+ def __init__(self, features=None, config=None):
1141
+ super().__init__("target_optimized", features=features, config=config)
1142
+
1143
+ def get_run_config(self):
1144
+ return {"run.target_to_backend": self.enabled}
1145
+
1146
+
1147
+ # Needs: vext
1148
+ # RISC-V only
1149
+ # Warning: Auto-vectorization is turned on by default quite low optimization levels
1150
+ # Therfore this feature is mainly for debugging the auto-vectorization procedure
1151
+ @register_feature("auto_vectorize")
1152
+ class AutoVectorize(PlatformFeature):
1153
+ """Enable auto_vectorization for supported MLIF platform targets."""
1154
+
1155
+ DEFAULTS = {
1156
+ **FeatureBase.DEFAULTS,
1157
+ "verbose": False,
1158
+ "loop": True,
1159
+ "slp": True,
1160
+ }
1161
+
1162
+ def __init__(self, features=None, config=None):
1163
+ super().__init__("auto_vectorize", features=features, config=config)
1164
+
1165
+ @property
1166
+ def verbose(self):
1167
+ value = self.config["verbose"]
1168
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
1169
+
1170
+ @property
1171
+ def loop(self):
1172
+ value = self.config["loop"]
1173
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
1174
+
1175
+ @property
1176
+ def slp(self):
1177
+ value = self.config["slp"]
1178
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
1179
+
1180
+ def get_platform_defs(self, platform):
1181
+ return {
1182
+ "RISCV_AUTO_VECTORIZE": self.enabled,
1183
+ "RISCV_AUTO_VECTORIZE_VERBOSE": self.verbose,
1184
+ "RISCV_AUTO_VECTORIZE_LOOP": self.loop and self.enabled,
1185
+ "RISCV_AUTO_VECTORIZE_SLP": self.slp and self.enabled,
1186
+ }
1187
+
1188
+
1189
+ @register_feature("benchmark")
1190
+ class Benchmark(PlatformFeature, TargetFeature):
1191
+ """Profile code using supported platforms."""
1192
+
1193
+ # TODO: would make sense to move end_to_end here as well!
1194
+
1195
+ DEFAULTS = {
1196
+ **FeatureBase.DEFAULTS,
1197
+ "num_runs": 1,
1198
+ "num_repeat": 1,
1199
+ "total": False,
1200
+ "aggregate": "avg", # Allowed: avg, max, min, none, all
1201
+ }
1202
+
1203
+ REQUIRED = []
1204
+
1205
+ def __init__(self, features=None, config=None):
1206
+ super().__init__("benchmark", features=features, config=config)
1207
+
1208
+ @property
1209
+ def num_runs(self):
1210
+ return int(self.config["num_runs"])
1211
+
1212
+ @property
1213
+ def num_repeat(self):
1214
+ return int(self.config["num_repeat"])
1215
+
1216
+ @property
1217
+ def total(self):
1218
+ value = self.config["total"]
1219
+ return str2bool(value) if not isinstance(value, (bool, int)) else value
1220
+
1221
+ @property
1222
+ def aggregate(self):
1223
+ value = self.config["aggregate"]
1224
+ assert value in ["avg", "all", "max", "min", "none"]
1225
+ return value
1226
+
1227
+ def get_platform_config(self, platform):
1228
+ supported = ["mlif", "tvm"] # TODO: support microtvm and espidf
1229
+ assert platform in supported, f"Unsupported feature '{self.name}' for platform '{platform}'"
1230
+
1231
+ if platform in ["tvm", "microtvm"]:
1232
+ return {
1233
+ f"{platform}.number": self.num_runs,
1234
+ f"{platform}.repeat": self.num_repeat,
1235
+ f"{platform}.aggregate": self.aggregate,
1236
+ f"{platform}.total_time": self.total,
1237
+ }
1238
+ else:
1239
+ return {}
1240
+
1241
+ def get_target_config(self, target):
1242
+ return {
1243
+ f"{target}.repeat": self.num_repeat,
1244
+ }
1245
+
1246
+ def get_platform_defs(self, platform):
1247
+ supported = ["mlif", "espidf", "tvm", "microtvm", "zephyr"] # TODO: support microtvm and espidf
1248
+ assert platform in supported, f"Unsupported feature '{self.name}' for platform '{platform}'"
1249
+
1250
+ if platform == "mlif":
1251
+ return {"NUM_RUNS": self.num_runs}
1252
+ elif platform == "espidf":
1253
+ return {"MLONMCU_NUM_RUNS": self.num_runs}
1254
+ else:
1255
+ return {}
1256
+
1257
+ def get_target_callbacks(self, target):
1258
+ if self.enabled:
1259
+
1260
+ def benchmark_callback(stdout, metrics, artifacts):
1261
+ if len(metrics) <= 1:
1262
+ return
1263
+ metrics_ = metrics[1:] # drop first run (warmup)
1264
+
1265
+ # TODO: this currently processes all numeric metrics, should probably ignore stuff like MIPS etc.
1266
+ data_ = [
1267
+ {
1268
+ key: (float(value) / self.num_runs) if self.num_runs > 1 else value
1269
+ for key, value in m.data.items()
1270
+ if "cycle" in key.lower() or "time" in key.lower()
1271
+ }
1272
+ for m in metrics_
1273
+ ]
1274
+
1275
+ df = pd.DataFrame(data_)
1276
+
1277
+ if self.aggregate == "all":
1278
+ aggs = ["mean", "min", "max"]
1279
+ elif self.aggregate in ["avg", "mean"]:
1280
+ aggs = ["mean"]
1281
+ elif self.aggregate == "min":
1282
+ aggs = ["min"]
1283
+ elif self.aggregate == "max":
1284
+ aggs = ["max"]
1285
+ elif self.aggregate == "none":
1286
+ aggs = []
1287
+
1288
+ if len(aggs) == 0:
1289
+ data = {}
1290
+ else:
1291
+ df_ = df.agg(aggs)
1292
+
1293
+ # rename columns
1294
+ index_mapping = {
1295
+ "mean": "Average",
1296
+ "min": "Min",
1297
+ "max": "Max",
1298
+ }
1299
+
1300
+ df_ = df_.rename(index=index_mapping)
1301
+
1302
+ data = df_.to_dict()
1303
+
1304
+ data = {f"{prefix} {key}": value for key, temp in data.items() for prefix, value in temp.items()}
1305
+ if self.total:
1306
+ data.update(
1307
+ {
1308
+ f"Total {key}": ((value * self.num_runs) if self.num_runs > 1 else value)
1309
+ for key, value in data_[-1].items()
1310
+ if "cycle" in key.lower() or "time" in key.lower()
1311
+ }
1312
+ )
1313
+ metrics_ = metrics_[-1]
1314
+ metrics_.data.update(data)
1315
+
1316
+ for key in data_[-1].keys():
1317
+ if key in metrics_.order:
1318
+ if self.total:
1319
+ metrics_.order.append(f"Total {key}")
1320
+ metrics_.order.remove(key)
1321
+ for key in data.keys():
1322
+ if key not in metrics_.order:
1323
+ metrics_.order.append(key)
1324
+ metrics.clear()
1325
+ metrics.append(metrics_)
1326
+ return stdout
1327
+
1328
+ benchmark_callback.priority = 0
1329
+
1330
+ return None, benchmark_callback
1331
+
1332
+
1333
+ @register_feature("tvm_rpc")
1334
+ class TvmRpc(PlatformFeature):
1335
+ """Run TVM models on a RPC device."""
1336
+
1337
+ DEFAULTS = {**FeatureBase.DEFAULTS, "hostname": None, "port": None, "key": None} # tracker
1338
+
1339
+ def __init__(self, features=None, config=None):
1340
+ super().__init__("tvm_rpc", features=features, config=config)
1341
+
1342
+ @property
1343
+ def use_rpc(self):
1344
+ return self.config["use_rpc"]
1345
+
1346
+ @property
1347
+ def hostname(self):
1348
+ return self.config["hostname"]
1349
+
1350
+ @property
1351
+ def port(self):
1352
+ return self.config["port"]
1353
+
1354
+ @property
1355
+ def key(self):
1356
+ return self.config["key"]
1357
+
1358
+ def get_platform_config(self, platform):
1359
+ assert platform in ["tvm", "microtvm"]
1360
+ return filter_none(
1361
+ {
1362
+ f"{platform}.use_rpc": self.enabled,
1363
+ f"{platform}.rpc_hostname": self.hostname,
1364
+ f"{platform}.rpc_port": self.port,
1365
+ f"{platform}.rpc_key": self.key,
1366
+ }
1367
+ )
1368
+
1369
+
1370
+ @register_feature("tvm_profile")
1371
+ class TvmProfile(PlatformFeature):
1372
+ """Profile code using TVM Platform."""
1373
+
1374
+ DEFAULTS = {
1375
+ **FeatureBase.DEFAULTS,
1376
+ }
1377
+
1378
+ REQUIRED = []
1379
+
1380
+ def __init__(self, features=None, config=None):
1381
+ super().__init__("tvm_profile", features=features, config=config)
1382
+
1383
+ def get_platform_config(self, platform):
1384
+ supported = ["tvm", "microtvm"]
1385
+ assert platform in supported, f"Unsupported feature '{self.name}' for platform '{platform}'"
1386
+ return {
1387
+ f"{platform}.profile": self.enabled,
1388
+ }
1389
+
1390
+
1391
+ @register_feature("xpulp")
1392
+ class Xpulp(TargetFeature, PlatformFeature, SetupFeature):
1393
+ DEFAULTS = {
1394
+ **FeatureBase.DEFAULTS,
1395
+ "xpulp_version": 2,
1396
+ "nopostmod": False,
1397
+ "noindregreg": False,
1398
+ "novect": False,
1399
+ "nohwloop": False,
1400
+ "hwloopmin": 2,
1401
+ "hwloopalign": False,
1402
+ "nomac": False,
1403
+ "nopartmac": False,
1404
+ "nominmax": False,
1405
+ "noabs": False,
1406
+ "nobitop": False,
1407
+ "nosext": False,
1408
+ "noclip": False,
1409
+ "noaddsubnormround": False,
1410
+ "noshufflepack": False,
1411
+ "nomulmacnormround": False,
1412
+ "noshufflepack": False,
1413
+ }
1414
+
1415
+ REQUIRED = ["pulp_gcc.install_dir", "pulp_gcc.name"]
1416
+
1417
+ def __init__(self, features=None, config=None):
1418
+ super().__init__("xpulp", features=features, config=config)
1419
+
1420
+ # Except the "enabled" in FeatureBase.DEFAULTS and "xpulp_version"
1421
+ # every key in DEFAULTS should in principle have a getter function with the same name as the key
1422
+ # These getter functions will be stored in getter_functions array.
1423
+ # Default getter function for the keys whose corresponding value has bool type:
1424
+ # def getter_bool(self, key_name):
1425
+ # return self.generalized_str2bool(self.config[key_name])
1426
+ # Default getter function for the keys whose corresponding value has int type:
1427
+ # def getter_int(self, key_name):
1428
+ # return int(self.config["<key_name>"])
1429
+ # No default, i.e. customized getter functions are defined separately
1430
+
1431
+ # Default getter functions:
1432
+ @staticmethod
1433
+ def generalized_str2bool(input: Union[str, bool, int]) -> bool:
1434
+ return str2bool(input) if isinstance(input, str) else input
1435
+
1436
+ def getter_bool(self, key_name: Union[str, bool, int]) -> bool:
1437
+ return self.generalized_str2bool(self.config[key_name])
1438
+
1439
+ def getter_int(self, key_name: Union[str, bool, int]) -> int:
1440
+ return int(self.config[key_name])
1441
+
1442
+ # No default, i.e. customized getter functions are defined in the following (now empty)
1443
+
1444
+ # custom_config_getter contains customized @property function which do not follow the pattern above.
1445
+ getter_functions = {
1446
+ "nopostmod": getter_bool,
1447
+ "noindregreg": getter_bool,
1448
+ "novect": getter_bool,
1449
+ "nohwloop": getter_bool,
1450
+ "hwloopmin": getter_int,
1451
+ "hwloopalign": getter_bool,
1452
+ "nomac": getter_bool,
1453
+ "nopartmac": getter_bool,
1454
+ "nominmax": getter_bool,
1455
+ "noabs": getter_bool,
1456
+ "nobitop": getter_bool,
1457
+ "nosext": getter_bool,
1458
+ "noclip": getter_bool,
1459
+ "noaddsubnormround": getter_bool,
1460
+ "noshufflepack": getter_bool,
1461
+ "nomulmacnormround": getter_bool,
1462
+ "noshufflepack": getter_bool,
1463
+ }
1464
+
1465
+ @property
1466
+ def xpulp_version(self):
1467
+ value = self.config["xpulp_version"]
1468
+ value = int(value) if not isinstance(value, int) else value # convert to int
1469
+ assert value in [None, 2, 3], f"xpulp_version must be None, 2 or 3, but get {value}"
1470
+ return value
1471
+
1472
+ def get_platform_defs(self, platform):
1473
+ # The following create EXTRA_FLAGS (type is str) for gcc
1474
+ # example
1475
+ # {"nopostmod": True, "novect": True, ...} ==> EXTRA_FLAGS = "-mnopostmod -mnovect ..."
1476
+ EXTRA_FLAGS = ""
1477
+ for key in self.getter_functions:
1478
+ if isinstance(self.getter_functions[key](self, key), bool):
1479
+ if self.getter_functions[key](self, key):
1480
+ EXTRA_FLAGS += f" -m{key}"
1481
+ continue
1482
+ if isinstance(self.getter_functions[key](self, key), int):
1483
+ EXTRA_FLAGS += f" -m{key}={self.getter_functions[key](self, key)}"
1484
+ continue
1485
+ EXTRA_FLAGS = "'" + EXTRA_FLAGS.strip() + "'"
1486
+ return {
1487
+ # EXTRA_CMAKE_C_FLAGS will be directly append to CMAKE_C_FLAGS in mlonmcu_sw/mlif/tootchains/Pulp.cmake
1488
+ "EXTRA_CMAKE_C_FLAGS": EXTRA_FLAGS,
1489
+ # EXTRA_CMAKE_CXX_FLAGS will be directly append to CMAKE_CXX_FLAGS in mlonmcu_sw/mlif/tootchains/Pulp.cmake
1490
+ "EXTRA_CMAKE_CXX_FLAGS": EXTRA_FLAGS,
1491
+ }
1492
+
1493
+ def add_platform_defs(self, platform, defs):
1494
+ addition_defs = self.get_platform_defs(platform)
1495
+ self.merge_dicts(defs, addition_defs)
1496
+
1497
+ @staticmethod
1498
+ def merge_dicts(dict1, dict2):
1499
+ """
1500
+ This function tries to merge dict1 and dict2 into dict1
1501
+ :param dict1: A dictionary
1502
+ :param dict2: A dictionary to be added
1503
+ :return: Void
1504
+ Example 1:
1505
+ dict1 = {"a": 1, "b": "hello", "c": [1, 2, 3]}
1506
+ dict2 = {"f": 3, "b": "world", "c": [4, 5, 6]}
1507
+ merge_dicts(dict1, dict2)
1508
+ print(dict1)
1509
+ ==>
1510
+ {"a": 1, "b": "hello world", "c": [1, 2, 3, 4, 5, 6], "f":3}
1511
+ Note: Here "hello" and "world" are merged as two string join.
1512
+ Here [1,2,3] and [4,5,6] are merged as list addition
1513
+ Example 2:
1514
+ dict1 = {"a": 1}
1515
+ dict2 = {"a": 3}
1516
+ merge_dicts(dict1, dict2)
1517
+ ==>
1518
+ RuntimeError: The method to merge a: 1 and a: 3 is not defined
1519
+ """
1520
+ for key in dict2.keys():
1521
+ if key in dict1.keys():
1522
+ dict1_value = dict1[key]
1523
+ dict2_value = dict2[key]
1524
+ if isinstance(dict1_value, (str, list)) and type(dict1_value) == type(dict2_value):
1525
+ if isinstance(dict1_value, str):
1526
+ dict1[key] = dict1_value + " " + dict2_value
1527
+ else:
1528
+ dict1[key] = dict1_value + dict2_value
1529
+ else:
1530
+ raise RuntimeError(
1531
+ f"The method to merge {key}: {dict1_value} and {key}: {dict2_value} is not defined"
1532
+ )
1533
+ else:
1534
+ dict1[key] = dict2[key]
1535
+
1536
+ def get_target_config(self, target):
1537
+ return filter_none({f"{target}.xpulp_version": self.xpulp_version})