Skip to content

Commit f1ce4b2

Browse files
committed
add unit test and refine build flow
1 parent c7aae8c commit f1ce4b2

File tree

8 files changed

+101
-21
lines changed

8 files changed

+101
-21
lines changed

backends/qualcomm/scripts/build.sh

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ if [ "$BUILD_AARCH64" = true ]; then
6969
# If we build debug type, we need to change flatcc to flatcc_d
7070
cmake .. \
7171
-DCMAKE_INSTALL_PREFIX=$BUILD_ROOT \
72-
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
7372
-DEXECUTORCH_BUILD_QNN=ON \
7473
-DEXECUTORCH_BUILD_SDK=ON \
7574
-DFLATCC_TEST=OFF \
@@ -81,17 +80,8 @@ if [ "$BUILD_AARCH64" = true ]; then
8180
-DPYTHON_EXECUTABLE=$PYTHON_EXECUTABLE \
8281
-DBUCK2=$BUCK2 \
8382
-B$BUILD_ROOT
84-
# The following commands are to enable etdump to
85-
# build flatcc on x86 host (from ExternalProject_Add)
86-
# and to allow backend and runner to link to
87-
# the arch64 flatcc library (from install target).
88-
rm -f $PRJ_ROOT/third-party/flatcc/lib/*
89-
rm -f $PRJ_ROOT/third-party/flatcc/bin/*
90-
cmake --build $BUILD_ROOT -j16 --target install --config Release
91-
rm -f $PRJ_ROOT/third-party/flatcc/lib/*
92-
rm -f $PRJ_ROOT/third-party/flatcc/bin/*
93-
rm -f $BUILD_ROOT/lib/libflatcc.a
94-
cmake --build $BUILD_ROOT -j16 --target install --config Release
83+
84+
cmake --build $BUILD_ROOT -j16 --target install
9585

9686
EXAMPLE_ROOT=examples/qualcomm
9787
CMAKE_PREFIX_PATH="${BUILD_ROOT}/lib/cmake/ExecuTorch;${BUILD_ROOT}/third-party/gflags;"

backends/qualcomm/serialization/schema.fbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ table QnnExecuTorchOptions {
147147
/// Check if on-device graph construction. Default is false.
148148
online_prepare:bool;
149149

150-
/// Profliing level of the delegate and the backend. Default is off.
150+
/// Profiling level of the delegate and the backend. Default is off.
151151
profile_level:QnnExecuTorchProfileLevel;
152152
}
153153

backends/qualcomm/tests/test_qnn_delegate.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def setUp(self):
4444
debug=False,
4545
saver=False,
4646
online_prepare=TestQNN.online_prepare,
47-
profile=False,
47+
profile=TestQNN.enable_profile,
4848
)
4949

5050
def test_qnn_backend_arange(self):
@@ -374,7 +374,7 @@ def setUp(self):
374374
debug=False,
375375
saver=False,
376376
online_prepare=TestQNN.online_prepare,
377-
profile=False,
377+
profile=TestQNN.enable_profile,
378378
)
379379

380380
def test_qnn_backend_conv1d_relu_log_softmax(self):
@@ -466,7 +466,7 @@ def setUp(self):
466466
debug=False,
467467
saver=False,
468468
online_prepare=TestQNN.online_prepare,
469-
profile=False,
469+
profile=TestQNN.enable_profile,
470470
)
471471

472472
def test_qnn_backend_arange(self):
@@ -843,7 +843,7 @@ def setUp(self):
843843
debug=False,
844844
saver=False,
845845
online_prepare=TestQNN.online_prepare,
846-
profile=False,
846+
profile=TestQNN.enable_profile,
847847
)
848848

849849
def test_qnn_backend_conv1d_relu_log_softmax(self):
@@ -974,6 +974,23 @@ def test_qnn_backend_skip_node_op(self):
974974
skip_node_op_set={"aten.add.Tensor"},
975975
)
976976

977+
def test_qnn_backend_profile_op(self):
978+
TestQNN.compiler_specs = generate_qnn_executorch_compiler_spec(
979+
is_fp16=True,
980+
soc_model=self.arch_table[TestQNN.model],
981+
debug=False,
982+
saver=False,
983+
profile=True,
984+
)
985+
module = SimpleModel() # noqa: F405
986+
sample_input = (torch.ones(1, 32, 28, 28), torch.ones(1, 32, 28, 28))
987+
self.lower_module_and_test_output(
988+
module,
989+
sample_input,
990+
expected_partitions=1,
991+
expected_profile_events=25,
992+
)
993+
977994

978995
class TestQNNQuantizedUtils(TestQNN):
979996
def setUp(self):
@@ -1008,6 +1025,24 @@ def test_qnn_backend_skip_node_op(self):
10081025
skip_node_op_set={"aten.add.Tensor"},
10091026
)
10101027

1028+
def test_qnn_backend_profile_op(self):
1029+
TestQNN.compiler_specs = generate_qnn_executorch_compiler_spec(
1030+
is_fp16=False,
1031+
soc_model=self.arch_table[TestQNN.model],
1032+
debug=False,
1033+
saver=False,
1034+
profile=True,
1035+
)
1036+
module = SimpleModel() # noqa: F405
1037+
sample_input = (torch.ones(1, 32, 28, 28), torch.ones(1, 32, 28, 28))
1038+
module = self.get_qdq_module(module, sample_input)
1039+
self.lower_module_and_test_output(
1040+
module,
1041+
sample_input,
1042+
expected_partitions=1,
1043+
expected_profile_events=26,
1044+
)
1045+
10111046

10121047
class TestExampleScript(TestQNN):
10131048
def required_envs(self, conditions=None) -> bool:
@@ -1389,6 +1424,12 @@ def setup_environment():
13891424
help="Conduct on-device graph compilation",
13901425
action="store_true",
13911426
)
1427+
parser.add_argument(
1428+
"-P",
1429+
"--enable_profile",
1430+
help="Profile the performance of each operator with kProfileDetailed profile level",
1431+
action="store_true",
1432+
)
13921433
parser.add_argument(
13931434
"-e",
13941435
"--error_only",
@@ -1406,6 +1447,7 @@ def setup_environment():
14061447
TestQNN.image_dataset = args.image_dataset
14071448
TestQNN.pretrained_weight = args.pretrained_weight
14081449
TestQNN.online_prepare = args.online_prepare
1450+
TestQNN.enable_profile = args.enable_profile
14091451
TestQNN.error_only = args.error_only
14101452
return sys.argv[:1] + ns_args
14111453

backends/qualcomm/tests/utils.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66
import collections
7+
import copy
78
import os
89
import tempfile
910
import unittest
@@ -27,6 +28,8 @@
2728

2829
from executorch.exir.backend.backend_api import to_backend
2930
from executorch.exir.backend.compile_spec_schema import CompileSpec
31+
from executorch.sdk import generate_etrecord
32+
from executorch.sdk.inspector import Inspector
3033
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
3134

3235

@@ -51,6 +54,7 @@ class TestQNN(unittest.TestCase):
5154
artifact_dir: Literal = ""
5255
image_dataset: Literal = ""
5356
pretrained_weight: Literal = ""
57+
enable_profile: bool = False
5458
online_prepare: bool = False
5559

5660
def _assert_outputs_equal(self, model_output, ref_output):
@@ -100,6 +104,7 @@ def lower_module_and_test_output(
100104
module: torch.nn.Module,
101105
sample_inputs: Tuple[torch.Tensor],
102106
expected_partitions: int = 1,
107+
expected_profile_events: int = -1,
103108
assert_output_equal: bool = True,
104109
skip_node_id_set: set = None,
105110
skip_node_op_set: set = None,
@@ -108,6 +113,10 @@ def lower_module_and_test_output(
108113
self.compiler_specs, skip_node_id_set, skip_node_op_set
109114
)
110115
delegated_program = capture_program(module, sample_inputs)
116+
117+
# this is needed for the ETRecord as lowering modifies the graph in-place
118+
edge_copy = copy.deepcopy(delegated_program)
119+
111120
delegated_program.exported_program = to_backend(
112121
delegated_program.exported_program, qnn_partitioner
113122
)
@@ -123,8 +132,12 @@ def lower_module_and_test_output(
123132
QnnBackend.__name__,
124133
)
125134

135+
etrecord_path = "etrecord.bin"
136+
if self.enable_profile:
137+
generate_etrecord(etrecord_path, edge_copy, exec_prog)
138+
126139
# Check numerics
127-
if assert_output_equal:
140+
if assert_output_equal or expected_profile_events != -1:
128141
with tempfile.TemporaryDirectory() as tmp_dir:
129142
(
130143
input_list,
@@ -137,6 +150,7 @@ def lower_module_and_test_output(
137150
tmp_dir,
138151
)
139152

153+
etdump_path = f"{tmp_dir}/etdump.etdp"
140154
device_output_dir = f"{tmp_dir}/outputs"
141155
device_outputs = []
142156

@@ -149,6 +163,14 @@ def post_process():
149163
output = torch.from_numpy(output).reshape(ref_outputs[i].shape)
150164
device_outputs.append(output)
151165

166+
def validate_profile():
167+
inspector = Inspector(
168+
etdump_path=etdump_path, etrecord=etrecord_path
169+
)
170+
self.assertTrue(
171+
len(inspector.to_dataframe().index) == expected_profile_events
172+
)
173+
152174
adb = SimpleADB(
153175
qnn_sdk=os.getenv("QNN_SDK_ROOT"),
154176
artifact_path=self.build_folder,
@@ -164,6 +186,9 @@ def post_process():
164186
adb.pull(output_path=tmp_dir, callback=post_process)
165187
self._assert_outputs_equal(device_outputs, ref_outputs)
166188

189+
if expected_profile_events != -1:
190+
adb.pull_etdump(etdump_path, callback=validate_profile)
191+
167192
def get_qdq_module(
168193
self,
169194
module: torch.nn.Module,

examples/qualcomm/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ if(NOT TORCH_ROOT)
2323
set(TORCH_ROOT ${EXECUTORCH_ROOT}/third-party/pytorch)
2424
endif()
2525

26+
if(NOT CMAKE_BUILD_TYPE)
27+
set(CMAKE_BUILD_TYPE Debug)
28+
endif()
29+
2630
# Find prebuilt libraries. executorch package should contain
2731
# portable_ops_lib, etdump, bundled_program.
2832
find_package(executorch CONFIG REQUIRED)
33+
target_compile_options(executorch INTERFACE -DET_EVENT_TRACER_ENABLED)
2934
find_package(gflags REQUIRED)
3035

3136
set(_common_compile_options -Wno-deprecated-declarations -fPIC)
@@ -56,6 +61,10 @@ generate_bindings_for_kernels(
5661
${EXECUTORCH_ROOT}/kernels/portable/functions.yaml ""
5762
)
5863
gen_operators_lib("full_portable_ops_lib" portable_kernels executorch)
64+
target_compile_options(full_portable_ops_lib
65+
INTERFACE
66+
-DET_EVENT_TRACER_ENABLED
67+
)
5968
target_include_directories(full_portable_ops_lib
6069
PUBLIC
6170
${_common_include_directories}
@@ -89,7 +98,7 @@ target_link_libraries(qnn_executor_runner
8998
qnn_executorch_backend
9099
full_portable_ops_lib
91100
etdump
92-
flatcc
101+
${FLATCC_LIB}
93102
gflags
94103
)
95104
target_compile_options(qnn_executor_runner

examples/qualcomm/executor_runner/qnn_executor_runner.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,11 @@ int main(int argc, char** argv) {
317317
// file.
318318
etdump_result result = etdump_gen.get_etdump_data();
319319
if (result.buf != nullptr && result.size > 0) {
320-
ET_LOG(Info, "write etdump");
320+
ET_LOG(
321+
Info,
322+
"Write etdump to %s, Size = %zu",
323+
FLAGS_etdump_path.c_str(),
324+
result.size);
321325
FILE* f = fopen(FLAGS_etdump_path.c_str(), "w+");
322326
fwrite((uint8_t*)result.buf, 1, result.size, f);
323327
fclose(f);

examples/qualcomm/scripts/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(
5151
self.host_id = host_id
5252
self.working_dir = Path(self.pte_path).parent.absolute()
5353
self.input_list_filename = "input_list.txt"
54+
self.etdump_path = f"{self.workspace}/etdump.etdp"
5455
self.output_folder = f"{self.workspace}/outputs"
5556
arch_table = {
5657
"SM8650": "75",
@@ -117,6 +118,7 @@ def execute(self):
117118
f"--model_path {os.path.basename(self.pte_path)}",
118119
f"--output_folder_path {self.output_folder}",
119120
f"--input_list_path {self.input_list_filename}",
121+
f"--etdump_path {self.etdump_path}",
120122
]
121123
)
122124
qnn_executor_runner_cmds = " ".join(
@@ -134,6 +136,11 @@ def pull(self, output_path, callback=None):
134136
if callback:
135137
callback()
136138

139+
def pull_etdump(self, output_path, callback=None):
140+
self._adb(["pull", f"{self.etdump_path}", output_path])
141+
if callback:
142+
callback()
143+
137144

138145
def build_executorch_binary(
139146
model, # noqa: B006

sdk/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ add_library(bundled_program_schema INTERFACE
9696
${_bundled_program_schema__outputs})
9797

9898
# Ensure the host tool is built before the main project
99-
add_dependencies(etdump_schema flatcc_cli)
99+
add_dependencies(flatcc etdump_schema)
100100

101101
file(MAKE_DIRECTORY ${_program_schema__include_dir}/executorch/sdk/etdump)
102102
file(MAKE_DIRECTORY
@@ -108,6 +108,9 @@ add_custom_command(
108108
${CMAKE_SOURCE_DIR}/third-party/flatcc/bin/flatcc -cwr -o
109109
${_program_schema__include_dir}/executorch/sdk/etdump
110110
${_etdump_schema__srcs}
111+
COMMAND
112+
rm -f ${CMAKE_SOURCE_DIR}/third-party/flatcc/bin/*
113+
${CMAKE_SOURCE_DIR}/third-party/flatcc/lib/*
111114
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/sdk
112115
DEPENDS flatcc_project
113116
COMMENT "Generating etdump headers"

0 commit comments

Comments
 (0)