Skip to content

Commit b6b940a

Browse files
Qualcomm AI Engine Direct - Optimize UT execution time (pytorch#16865)
### Summary - Currently all tests will push same libs, which is redundant. With this PR it only push once, and reduce execution time from two to three times for operator's tests. ### Test plan ``` python backends/qualcomm/tests/test_qnn_delegate.py -k TestQNNFloatingPointOperator --device <device> --host <host> --model SM8650 --build_folder build-android --executorch_root . --artifact all_artifact ``` without optimization <img width="429" height="136" alt="image" src="https://github.com/user-attachments/assets/a0a6d40a-6876-469d-af46-c8e4ebfa7cb8" /> with optimization <img width="442" height="130" alt="image" src="https://github.com/user-attachments/assets/9249b3eb-c85f-4d64-99c2-12fafdd7ae77" /> cc @cccclai @cbilgin
1 parent 1aada89 commit b6b940a

3 files changed

Lines changed: 67 additions & 32 deletions

File tree

‎backends/qualcomm/tests/test_qnn_delegate.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8131,8 +8131,15 @@ def test_cli(self):
81318131
self.build_folder,
81328132
"--input_list",
81338133
f"{tmp_dir}/input_list",
8134+
"--model",
8135+
self.model,
8136+
"--host",
8137+
self.host,
8138+
"--target",
8139+
self.target,
8140+
"--device",
8141+
self.device,
81348142
]
8135-
self.add_default_cmds(cmds)
81368143
subprocess.run(cmds, stdout=subprocess.DEVNULL)
81378144
self.assertTrue(os.path.isfile(f"{tmp_dir}/e_out/Result_0/output_0.pt"))
81388145

‎backends/qualcomm/tests/utils.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,25 @@ class TestQNN(unittest.TestCase):
185185
inference_speed: float = 0.0
186186
inference_speed_output_path = "outputs/inference_speed.txt"
187187

188+
@classmethod
189+
def setUpClass(cls):
190+
if not cls.enable_x86_64 and not cls.compile_only:
191+
# init device once
192+
adb = SimpleADB(
193+
qnn_sdk=os.getenv("QNN_SDK_ROOT"),
194+
build_path=cls.build_folder,
195+
pte_path=[],
196+
workspace="/data/local/tmp/qnn_executorch_test",
197+
device_id=cls.device,
198+
host_id=cls.host,
199+
soc_model=cls.model,
200+
error_only=cls.error_only,
201+
target=cls.target,
202+
)
203+
adb.push(
204+
init_env=True,
205+
)
206+
188207
def _assert_outputs_equal(self, model_output, ref_output):
189208
self.assertTrue(len(ref_output) == len(model_output))
190209
for i in range(len(ref_output)):
@@ -489,6 +508,7 @@ def validate_intermediate_tensor():
489508
adb.push(
490509
inputs=[processed_inputs],
491510
files=op_package_paths,
511+
init_env=False,
492512
)
493513
adb.extra_cmds += extra_cmds
494514
if save_inference_speed:

‎examples/qualcomm/utils.py‎

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ def __init__(
9898
self.workspace = workspace
9999
self.device_id = device_id
100100
self.host_id = host_id
101-
self.working_dir = Path(self.pte_path[0]).parent.absolute()
101+
if len(self.pte_path) > 0:
102+
self.working_dir = Path(self.pte_path[0]).parent.absolute()
103+
else:
104+
self.working_dir = Path.cwd()
102105
self.input_list_filename = "input_list.txt"
103106
self.etdump_path = f"{self.workspace}/etdump.etdp"
104107
self.dump_intermediate_outputs = dump_intermediate_outputs
@@ -132,39 +135,42 @@ def _adb(self, cmd, output_callback: Optional[Callable[[str], None]] = None):
132135
)
133136

134137
def push(self, inputs=None, input_list=None, files=None, init_env=True):
135-
artifacts = []
138+
artifacts = [
139+
*self.pte_path,
140+
]
136141
if init_env:
137142
self._adb(["shell", f"rm -rf {self.workspace}"])
138143
self._adb(["shell", f"mkdir -p {self.workspace}"])
139144

140-
# necessary artifacts
141-
artifacts = {
142-
QnnExecuTorchBackendType.kHtpBackend: [
143-
f"{self.qnn_sdk}/lib/{self.target}/libQnnHtp.so",
144-
(
145-
f"{self.qnn_sdk}/lib/hexagon-v{self.htp_arch}/"
146-
f"unsigned/libQnnHtpV{self.htp_arch}Skel.so"
147-
),
148-
(
149-
f"{self.qnn_sdk}/lib/{self.target}/"
150-
f"libQnnHtpV{self.htp_arch}Stub.so"
151-
),
152-
f"{self.qnn_sdk}/lib/{self.target}/libQnnHtpPrepare.so",
153-
],
154-
QnnExecuTorchBackendType.kGpuBackend: [
155-
f"{self.qnn_sdk}/lib/{self.target}/libQnnGpu.so",
156-
],
157-
}[self.backend]
158-
159-
artifacts.extend(
160-
[
161-
*self.pte_path,
162-
f"{self.qnn_sdk}/lib/{self.target}/libQnnSystem.so",
163-
f"{self.build_path}/{self.runner}",
164-
f"{self.build_path}/backends/qualcomm/libqnn_executorch_backend.so",
165-
f"{self.qnn_sdk}/lib/{self.target}/libQnnModelDlc.so",
166-
]
167-
)
145+
# necessary artifacts
146+
artifacts.extend(
147+
{
148+
QnnExecuTorchBackendType.kHtpBackend: [
149+
f"{self.qnn_sdk}/lib/{self.target}/libQnnHtp.so",
150+
(
151+
f"{self.qnn_sdk}/lib/hexagon-v{self.htp_arch}/"
152+
f"unsigned/libQnnHtpV{self.htp_arch}Skel.so"
153+
),
154+
(
155+
f"{self.qnn_sdk}/lib/{self.target}/"
156+
f"libQnnHtpV{self.htp_arch}Stub.so"
157+
),
158+
f"{self.qnn_sdk}/lib/{self.target}/libQnnHtpPrepare.so",
159+
],
160+
QnnExecuTorchBackendType.kGpuBackend: [
161+
f"{self.qnn_sdk}/lib/{self.target}/libQnnGpu.so",
162+
],
163+
}[self.backend]
164+
)
165+
166+
artifacts.extend(
167+
[
168+
f"{self.qnn_sdk}/lib/{self.target}/libQnnSystem.so",
169+
f"{self.build_path}/{self.runner}",
170+
f"{self.build_path}/backends/qualcomm/libqnn_executorch_backend.so",
171+
f"{self.qnn_sdk}/lib/{self.target}/libQnnModelDlc.so",
172+
]
173+
)
168174
with tempfile.TemporaryDirectory() as tmp_dir:
169175
input_list_file, input_files = generate_inputs(
170176
tmp_dir, self.input_list_filename, inputs
@@ -205,6 +211,7 @@ def execute(
205211
method_index=0,
206212
output_callback: Optional[Callable[[str], None]] = None,
207213
):
214+
self._adb(["shell", f"rm -rf {self.output_folder}"])
208215
self._adb(["shell", f"mkdir -p {self.output_folder}"])
209216
# run the delegation
210217
if custom_runner_cmd is None:
@@ -472,7 +479,8 @@ def build_executorch_binary(
472479
else:
473480
quantizer = custom_quantizer or make_quantizer(quant_dtype=quant_dtype)
474481
# ptq calibration
475-
annotated_model = ptq_calibrate(captured_model, quantizer, dataset)
482+
with torch.no_grad():
483+
annotated_model = ptq_calibrate(captured_model, quantizer, dataset)
476484

477485
quantized_model = convert_pt2e(annotated_model)
478486
edge_prog_mgr = to_edge_transform_and_lower_to_qnn(

0 commit comments

Comments
 (0)