From 19e7adeb25371251ee6ec1be035670806b15cbcb Mon Sep 17 00:00:00 2001 From: runwangdl Date: Thu, 20 Aug 2026 12:31:33 +0000 Subject: [PATCH] Make --profileMicrobenchmark work on GAP9 The flag was accepted and emitted nothing. Four things had to be true and none of them were: - `PULPMicrobenchmark` was in PULPOpen's two tiling transformers but not in GAP9's, so no instrumentation was generated at all. The tell is that the cycle count with the flag was identical to the cycle count without it. - `perf_utils.h` was only in PULPOpen's include list. - The header aliases `PI_PERF_*` to the PULP SDK's `CSR_PCER_*`, which the GAP9 SDK does not define; it provides the `PI_PERF_*` names itself. They are enum constants, so `#ifndef` cannot see them and the test has to be on the platform. Two counters are also spelled differently there: `PI_PERF_JR_STALL` and `PI_PERF_BTAKEN`. - Both guards read `pi_core_id() == 0`. GAP9 runs the sequential network code on the cluster controller, whose id is `pi_cl_cluster_nb_cores()` (8, with 8 workers) -- never 0. On PULPOpen and Siracusa the cluster master is core 0, which is why this went unnoticed. KeywordSpotting on GAP9 now reports 17 per-layer blocks with 0 errors. Without the flag it is 719,671 cycles, unchanged, and no instrumentation is emitted. Known wart, pre-existing and not addressed here: with the flag on, the `Runtime:` total is meaningless (2,647 for the run above), because `perf_bench_init` resets the same counters `getCycles()` reads. The per-layer numbers are the usable output. --- CHANGELOG.md | 2 ++ Deeploy/Targets/GAP9/Bindings.py | 3 +++ Deeploy/Targets/GAP9/Platform.py | 2 +- .../PULPMicrobenchmark.py | 4 ++-- TargetLibraries/PULPOpen/inc/perf_utils.h | 17 ++++++++++++++--- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d15ac5bafd..5d589bdada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid - Fix GAP9 L3 Board Tests: readfs Flash Ordering and Duplicate Input Data [#196](https://github.com/pulp-platform/Deeploy/pull/196) - Add SoCDAML Part III: hands-on lab for adding a new int8 operator [#194](https://github.com/pulp-platform/Deeploy/pull/194) +- Make `--profileMicrobenchmark` Work on GAP9 [#208](https://github.com/pulp-platform/Deeploy/pull/208) ### Added - tests for Regular and DW Conv2D with 3x3 kernel - Neureka's engine-aware DW lowering pass `NeurekaNCHWtoNHWCDwConvPass` @@ -82,6 +83,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid - Fix GAP9 board tests with `--defaultMemLevel L3` reading garbage inputs: place all gapy `--flash-property` options before the positional subcommand and use `image flash run` so the readfs partition (input hex files) is flashed to the device - Fix Deeploy 101 tutorial errors: `--profileTiling` usage and the moved intrinsics inventory path +- `--profileMicrobenchmark` silently emitted nothing on GAP9: the pass was absent from the GAP9 code transformers, `perf_utils.h` was neither included nor portable to the GAP9 SDK's counter names, and its core guard never matched GAP9's cluster controller ### Removed - removed experimental `enable3x3` flag, from Neureka Engine. Now, 3x3 mode is enabled by default. - `testDMA.py` was an old test; we now have `test_dmas.py` instead. diff --git a/Deeploy/Targets/GAP9/Bindings.py b/Deeploy/Targets/GAP9/Bindings.py index 2bda98af8f..b29b5b6aa7 100644 --- a/Deeploy/Targets/GAP9/Bindings.py +++ b/Deeploy/Targets/GAP9/Bindings.py @@ -32,6 +32,7 @@ from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPClusterSynch import PULPSynchCoresPass from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPClusterTiling import PULPClusterTiling from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPL3Tiling import PULPL3Tiling +from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPMicrobenchmark import PULPMicrobenchmark from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPProfileUntiled import PULPProfileUntiled from Deeploy.Targets.PULPOpen.DataTypes import PULPDMAFuture from Deeploy.Targets.PULPOpen.Templates import ConvTemplate, DMASliceTemplate, FloatAddTemplate, FloatConvTemplate, \ @@ -64,6 +65,7 @@ MemoryManagementGeneration("L2"), MemoryManagementGeneration("L3.*"), MemoryManagementGeneration(), + PULPMicrobenchmark(), ]) # GAP9-specific cluster transformer using cl_dma.h API @@ -83,6 +85,7 @@ MemoryManagementGeneration("L2"), MemoryManagementGeneration("L3.*"), MemoryManagementGeneration(), + PULPMicrobenchmark(), ]) # Simple transformer for non-tiling cases diff --git a/Deeploy/Targets/GAP9/Platform.py b/Deeploy/Targets/GAP9/Platform.py index bad6f8d859..f32f543a10 100644 --- a/Deeploy/Targets/GAP9/Platform.py +++ b/Deeploy/Targets/GAP9/Platform.py @@ -244,7 +244,7 @@ class GAP9StructBuffer(StructBuffer): deallocTemplate = NodeTemplate("") -_includeList = ["pmsis.h", "DeeployGAP9Math.h", "pulp_nn_kernels.h", "DeeployMchan.h"] +_includeList = ["pmsis.h", "DeeployGAP9Math.h", "pulp_nn_kernels.h", "DeeployMchan.h", "perf_utils.h"] class GAP9ClusterEngine(DeploymentEngine): diff --git a/Deeploy/Targets/PULPOpen/CodeTransformationPasses/PULPMicrobenchmark.py b/Deeploy/Targets/PULPOpen/CodeTransformationPasses/PULPMicrobenchmark.py index bb35f32d47..4ea8c0f795 100644 --- a/Deeploy/Targets/PULPOpen/CodeTransformationPasses/PULPMicrobenchmark.py +++ b/Deeploy/Targets/PULPOpen/CodeTransformationPasses/PULPMicrobenchmark.py @@ -12,7 +12,7 @@ class PULPMicrobenchmark(CodeTransformationPass): _preTemplate = NodeTemplate(""" perf_stats_t ${op}_perf_start, ${op}_perf_end, ${op}_perf_total; - if (pi_core_id() == 0) { + if (pi_core_id() == 0 || pi_core_id() == (unsigned int)pi_cl_cluster_nb_cores()) { perf_bench_init(); perf_bench_start(); perf_bench_read(&${op}_perf_start); @@ -20,7 +20,7 @@ class PULPMicrobenchmark(CodeTransformationPass): """) _postTemplate = NodeTemplate(""" - if (pi_core_id() == 0) { + if (pi_core_id() == 0 || pi_core_id() == (unsigned int)pi_cl_cluster_nb_cores()) { perf_bench_stop(); perf_bench_read(&${op}_perf_end); perf_bench_diff(&${op}_perf_total, &${op}_perf_end, &${op}_perf_start); diff --git a/TargetLibraries/PULPOpen/inc/perf_utils.h b/TargetLibraries/PULPOpen/inc/perf_utils.h index c710402ed2..0bc67e89a7 100644 --- a/TargetLibraries/PULPOpen/inc/perf_utils.h +++ b/TargetLibraries/PULPOpen/inc/perf_utils.h @@ -11,7 +11,10 @@ #include "pmsis.h" -// Performance event IDs (compatible with PMSIS) +// Performance event IDs. The PULP SDK spells these CSR_PCER_*; the GAP9 SDK's +// pmsis provides the PI_PERF_* names itself, as enum constants the preprocessor +// cannot see -- hence the platform test rather than #ifndef. +#ifndef __GAP9__ #define PI_PERF_CYCLES CSR_PCER_CYCLES #define PI_PERF_INSTR CSR_PCER_INSTR #define PI_PERF_LD_STALL CSR_PCER_LD_STALL @@ -28,6 +31,11 @@ #define PI_PERF_LD_EXT_CYC CSR_PCER_LD_EXT_CYC #define PI_PERF_ST_EXT_CYC CSR_PCER_ST_EXT_CYC #define PI_PERF_TCDM_CONT CSR_PCER_TCDM_CONT +#else +// Same two counters, different spelling in the GAP9 enum. +#define PI_PERF_JMP_STALL PI_PERF_JR_STALL +#define PI_PERF_TAKEN_BRANCH PI_PERF_BTAKEN +#endif // Benchmark statistics structure typedef struct { @@ -88,9 +96,12 @@ static inline void perf_bench_read(perf_stats_t *stats) { stats->tcdm_cont = pi_perf_read(PI_PERF_TCDM_CONT); } -// Print performance statistics (core 0 only to avoid clutter) +// Print performance statistics (one core only, to avoid clutter). GAP9 runs the +// sequential network code on the cluster controller, whose id is nb_cores, not +// 0. static inline void perf_bench_print(const char *label, perf_stats_t *stats) { - if (pi_core_id() == 0) { + if (pi_core_id() == 0 || + pi_core_id() == (unsigned int)pi_cl_cluster_nb_cores()) { printf("\n=== Performance Statistics: %s ===\n", label); printf("Cycles: %10u\n", stats->cycles); printf("Instructions: %10u\n", stats->instr);