litert-cli 0.1.0__py3-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.
- examples/litert_cli.ipynb +313 -0
- examples/models/presets/default.py +19 -0
- examples/run_cli_demo.sh +38 -0
- examples/run_cli_npu.sh +89 -0
- examples/run_commands.sh +67 -0
- examples/run_models.sh +63 -0
- examples/run_smoke_tests.sh +58 -0
- examples/utils.ps1 +163 -0
- examples/utils.sh +184 -0
- litert_cli/__init__.py +15 -0
- litert_cli/commands/benchmark/__init__.py +16 -0
- litert_cli/commands/benchmark/android.py +212 -0
- litert_cli/commands/benchmark/cli.py +294 -0
- litert_cli/commands/benchmark/desktop.py +228 -0
- litert_cli/commands/benchmark/gcp.py +336 -0
- litert_cli/commands/clean.py +73 -0
- litert_cli/commands/compile.py +211 -0
- litert_cli/commands/convert/__init__.py +20 -0
- litert_cli/commands/convert/cli.py +255 -0
- litert_cli/commands/convert/generic.py +211 -0
- litert_cli/commands/convert/huggingface.py +175 -0
- litert_cli/commands/delete.py +56 -0
- litert_cli/commands/download.py +274 -0
- litert_cli/commands/import.py +124 -0
- litert_cli/commands/list.py +132 -0
- litert_cli/commands/lm.py +74 -0
- litert_cli/commands/quantize.py +193 -0
- litert_cli/commands/run/__init__.py +16 -0
- litert_cli/commands/run/android.py +394 -0
- litert_cli/commands/run/cli.py +297 -0
- litert_cli/commands/run/desktop.py +340 -0
- litert_cli/commands/visualize.py +234 -0
- litert_cli/core/android_utils.py +304 -0
- litert_cli/core/android_utils_test.py +236 -0
- litert_cli/core/constants.py +131 -0
- litert_cli/core/deps.py +180 -0
- litert_cli/core/deps_test.py +101 -0
- litert_cli/core/inputs.py +203 -0
- litert_cli/core/inputs_test.py +176 -0
- litert_cli/core/log_filters.py +50 -0
- litert_cli/core/models.py +96 -0
- litert_cli/core/npu_utils.py +382 -0
- litert_cli/core/targets_manager.py +192 -0
- litert_cli/core/utils.py +58 -0
- litert_cli/litert.py +119 -0
- litert_cli/litert_help_test.py +51 -0
- litert_cli/litert_test.py +88 -0
- litert_cli/models/__init__.py +145 -0
- litert_cli/models/asr/__init__.py +15 -0
- litert_cli/models/asr/asr_model.py +108 -0
- litert_cli/models/asr/parakeet_ctc.py +165 -0
- litert_cli/models/asr/runner.py +482 -0
- litert_cli/models/base.py +57 -0
- litert_cli/test_data/dummy_calib_data.py +26 -0
- litert_cli/test_data/dummy_cv_model.py +52 -0
- litert_cli/test_data/dummy_cv_model.tflite +0 -0
- litert_cli/test_data/generate_test_inputs.py +51 -0
- litert_cli/test_data/mobilenet_v3_calib_data.py +25 -0
- litert_cli/test_data/quantize_recipe.json +16 -0
- litert_cli/test_data/resnet18.py +31 -0
- litert_cli-0.1.0.dist-info/METADATA +38 -0
- litert_cli-0.1.0.dist-info/RECORD +67 -0
- litert_cli-0.1.0.dist-info/WHEEL +5 -0
- litert_cli-0.1.0.dist-info/entry_points.txt +2 -0
- litert_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
- litert_cli-0.1.0.dist-info/top_level.txt +3 -0
- tools/build_wheels.py +122 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
|
|
16
|
+
"""CLI Benchmark Module providing commands to benchmark LiteRT models.
|
|
17
|
+
|
|
18
|
+
This module defines the `benchmark` command using Click. It supports:
|
|
19
|
+
1. Benchmarking on a local Android device via adb (Default).
|
|
20
|
+
2. Benchmarking on Google Cloud Platform (GCP) via AI Edge Portal Cloud API.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import pathlib
|
|
26
|
+
import textwrap
|
|
27
|
+
|
|
28
|
+
import click
|
|
29
|
+
from litert_cli.core import constants
|
|
30
|
+
from litert_cli.core import utils
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.command(
|
|
34
|
+
"benchmark",
|
|
35
|
+
help="""\b
|
|
36
|
+
Benchmark LiteRT models on different platforms.
|
|
37
|
+
\b
|
|
38
|
+
MODEL: Path to the LiteRT model file.
|
|
39
|
+
\b
|
|
40
|
+
Examples:
|
|
41
|
+
\b
|
|
42
|
+
# Benchmark on Desktop with CPU (Default) or GPU
|
|
43
|
+
\b
|
|
44
|
+
$ litert benchmark model.tflite
|
|
45
|
+
$ litert benchmark model.tflite --gpu
|
|
46
|
+
\b
|
|
47
|
+
# Benchmark on Android with CPU (Default) or GPU or NPU
|
|
48
|
+
$ litert benchmark model.tflite --android
|
|
49
|
+
$ litert benchmark model.tflite --android --gpu
|
|
50
|
+
$ litert benchmark model.tflite --android --npu
|
|
51
|
+
\b
|
|
52
|
+
# Benchmark on Google AI Edge Portal in Google Cloud. Prerequisites:
|
|
53
|
+
# - Set up your Google AI Edge Portal account by following up the instructions at:
|
|
54
|
+
# https://ai.google.dev/edge/ai-edge-portal
|
|
55
|
+
# - Set up authentication by running: gcloud auth login
|
|
56
|
+
# - You can set the default GCP project by setting the environment variable LITERT_GCP_PROJECT,
|
|
57
|
+
# or by providing the --gcp-project option.
|
|
58
|
+
#
|
|
59
|
+
$ litert benchmark model.tflite --gcp --device "pixel 7"
|
|
60
|
+
$ litert benchmark model.tflite --gcp --device "pixel 7" --gcp-project "your-gcp-project-id"
|
|
61
|
+
$ litert benchmark model.tflite --gcp --devices "pixel 7, sm-s931u1" --gpu
|
|
62
|
+
""",
|
|
63
|
+
)
|
|
64
|
+
@click.argument("model", type=str)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--android",
|
|
67
|
+
"target",
|
|
68
|
+
flag_value="android",
|
|
69
|
+
default=True,
|
|
70
|
+
help="Benchmark on Android device (Default)",
|
|
71
|
+
)
|
|
72
|
+
@click.option(
|
|
73
|
+
"--gcp",
|
|
74
|
+
"target",
|
|
75
|
+
flag_value="gcp",
|
|
76
|
+
help="Benchmark on Google AI Edge Portal in Google Cloud.",
|
|
77
|
+
)
|
|
78
|
+
@click.option(
|
|
79
|
+
"--desktop",
|
|
80
|
+
"target",
|
|
81
|
+
flag_value="desktop",
|
|
82
|
+
help="Benchmark on local Desktop machine.",
|
|
83
|
+
)
|
|
84
|
+
@click.option(
|
|
85
|
+
"--cpu",
|
|
86
|
+
"accelerator",
|
|
87
|
+
flag_value="cpu",
|
|
88
|
+
default=True,
|
|
89
|
+
help="Use CPU accelerator (Default)",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--gpu",
|
|
93
|
+
"accelerator",
|
|
94
|
+
flag_value="gpu",
|
|
95
|
+
help="Use GPU accelerator",
|
|
96
|
+
)
|
|
97
|
+
@click.option(
|
|
98
|
+
"--npu",
|
|
99
|
+
"accelerator",
|
|
100
|
+
flag_value="npu",
|
|
101
|
+
help="Use NPU accelerator",
|
|
102
|
+
)
|
|
103
|
+
@click.option(
|
|
104
|
+
"--jit",
|
|
105
|
+
"compilation_mode",
|
|
106
|
+
flag_value="jit",
|
|
107
|
+
default=True,
|
|
108
|
+
help="Use JIT (Just-in-time) compilation mode for NPU (Default).",
|
|
109
|
+
)
|
|
110
|
+
@click.option(
|
|
111
|
+
"--aot",
|
|
112
|
+
"compilation_mode",
|
|
113
|
+
flag_value="aot",
|
|
114
|
+
help="Use AOT (Ahead-of-time) compilation mode for NPU.",
|
|
115
|
+
)
|
|
116
|
+
@click.option(
|
|
117
|
+
"--soc-model",
|
|
118
|
+
type=str,
|
|
119
|
+
default="SM8750",
|
|
120
|
+
help="Target SoC model name for NPU AOT mode (e.g., 'SM8750').",
|
|
121
|
+
)
|
|
122
|
+
@click.option(
|
|
123
|
+
"--device",
|
|
124
|
+
"--devices",
|
|
125
|
+
"devices",
|
|
126
|
+
type=str,
|
|
127
|
+
multiple=True,
|
|
128
|
+
default=["pixel 7"],
|
|
129
|
+
help=(
|
|
130
|
+
"Target device model name(s) (e.g., 'pixel 7'). Can be specified"
|
|
131
|
+
" --device multiple times or use --devices 'pixel 7, sm-s931u1'."
|
|
132
|
+
" Default is 'pixel 7'"
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
@click.option(
|
|
136
|
+
"--gcp-project",
|
|
137
|
+
type=str,
|
|
138
|
+
help="GCP project ID for benchmarking (Only for GCP target).",
|
|
139
|
+
)
|
|
140
|
+
@click.option(
|
|
141
|
+
"--gcp-bucket",
|
|
142
|
+
type=str,
|
|
143
|
+
help="GCS bucket name for uploading model (Only for GCP target).",
|
|
144
|
+
)
|
|
145
|
+
@click.option(
|
|
146
|
+
"--num-runs",
|
|
147
|
+
type=int,
|
|
148
|
+
default=50,
|
|
149
|
+
help="Target number of benchmark iterations. Default is 50.",
|
|
150
|
+
)
|
|
151
|
+
@click.option(
|
|
152
|
+
"--warmup-runs",
|
|
153
|
+
type=int,
|
|
154
|
+
default=1,
|
|
155
|
+
help="Number of warmup iterations before benchmarking. Default is 1.",
|
|
156
|
+
)
|
|
157
|
+
@click.option(
|
|
158
|
+
"--min-secs",
|
|
159
|
+
type=float,
|
|
160
|
+
default=1.0,
|
|
161
|
+
help="Minimum seconds to run. Default is 1.0.",
|
|
162
|
+
)
|
|
163
|
+
@click.option(
|
|
164
|
+
"--max-secs",
|
|
165
|
+
type=float,
|
|
166
|
+
default=150.0,
|
|
167
|
+
help="Maximum seconds to run. Default is 150.0.",
|
|
168
|
+
)
|
|
169
|
+
@click.option(
|
|
170
|
+
"--warmup-min-secs",
|
|
171
|
+
type=float,
|
|
172
|
+
default=0.5,
|
|
173
|
+
help="Minimum warmup duration in seconds. Default is 0.5.",
|
|
174
|
+
)
|
|
175
|
+
@click.option(
|
|
176
|
+
"--input-layer-value-range",
|
|
177
|
+
type=str,
|
|
178
|
+
help=(
|
|
179
|
+
"A map-like string representing value range for input layers (e.g."
|
|
180
|
+
" input1,1.0,2.0:input2,0,254)."
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
@click.option(
|
|
184
|
+
"--signature-key",
|
|
185
|
+
type=str,
|
|
186
|
+
help=(
|
|
187
|
+
"The signature key to benchmark. If not specified, the default"
|
|
188
|
+
" signature is used."
|
|
189
|
+
),
|
|
190
|
+
)
|
|
191
|
+
def benchmark_cmd(
|
|
192
|
+
model: str,
|
|
193
|
+
target: str,
|
|
194
|
+
accelerator: str,
|
|
195
|
+
devices: tuple[str, ...],
|
|
196
|
+
compilation_mode: str,
|
|
197
|
+
soc_model: str,
|
|
198
|
+
gcp_project: str | None = None,
|
|
199
|
+
gcp_bucket: str | None = None,
|
|
200
|
+
num_runs: int = 50,
|
|
201
|
+
warmup_runs: int = 1,
|
|
202
|
+
min_secs: float = 1.0,
|
|
203
|
+
max_secs: float = 150.0,
|
|
204
|
+
warmup_min_secs: float = 0.5,
|
|
205
|
+
input_layer_value_range: str | None = None,
|
|
206
|
+
signature_key: str | None = None,
|
|
207
|
+
) -> None:
|
|
208
|
+
"""Benchmarks LiteRT models on different platforms.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
model: Path to the LiteRT model file or Model Reference.
|
|
212
|
+
target: Target platform for benchmark (android, gcp, desktop).
|
|
213
|
+
accelerator: Accelerator to use (cpu, gpu, npu).
|
|
214
|
+
devices: Target device model(s) (e.g., 'pixel 7').
|
|
215
|
+
compilation_mode: Compilation mode for NPU (jit, aot).
|
|
216
|
+
soc_model: Target SoC model for NPU AOT mode.
|
|
217
|
+
gcp_project: GCP project ID for benchmarking.
|
|
218
|
+
gcp_bucket: GCS bucket name for uploading model.
|
|
219
|
+
num_runs: Target number of benchmark iterations.
|
|
220
|
+
warmup_runs: Number of warmup iterations before benchmarking.
|
|
221
|
+
min_secs: Minimum seconds to run.
|
|
222
|
+
max_secs: Maximum seconds to run.
|
|
223
|
+
warmup_min_secs: Minimum warmup duration in seconds.
|
|
224
|
+
input_layer_value_range: Value range for input layers.
|
|
225
|
+
signature_key: The signature key to benchmark.
|
|
226
|
+
"""
|
|
227
|
+
from litert_cli.core import models as core_models
|
|
228
|
+
|
|
229
|
+
# Quiet if default is true
|
|
230
|
+
if constants.DEFAULT_QUIET:
|
|
231
|
+
utils.enable_quiet_mode()
|
|
232
|
+
|
|
233
|
+
resolved_model_path, _ = core_models.resolve_model_reference(model)
|
|
234
|
+
|
|
235
|
+
if resolved_model_path != model:
|
|
236
|
+
click.echo(f"Resolved model '{model}' to '{resolved_model_path}'")
|
|
237
|
+
|
|
238
|
+
model_path = pathlib.Path(resolved_model_path)
|
|
239
|
+
|
|
240
|
+
if target == "android":
|
|
241
|
+
# pylint: disable=g-import-not-at-top
|
|
242
|
+
from litert_cli.commands.benchmark import android
|
|
243
|
+
|
|
244
|
+
if not model_path.exists():
|
|
245
|
+
raise click.ClickException(f"Local model file not found: {model_path}")
|
|
246
|
+
|
|
247
|
+
android.run_android(
|
|
248
|
+
model_path=model_path,
|
|
249
|
+
accelerator=accelerator,
|
|
250
|
+
num_runs=num_runs,
|
|
251
|
+
warmup_runs=warmup_runs,
|
|
252
|
+
min_secs=min_secs,
|
|
253
|
+
max_secs=max_secs,
|
|
254
|
+
warmup_min_secs=warmup_min_secs,
|
|
255
|
+
input_layer_value_range=input_layer_value_range,
|
|
256
|
+
signature_key=signature_key,
|
|
257
|
+
)
|
|
258
|
+
elif target == "desktop":
|
|
259
|
+
# pylint: disable=g-import-not-at-top
|
|
260
|
+
from litert_cli.commands.benchmark import desktop
|
|
261
|
+
|
|
262
|
+
if not model_path.exists():
|
|
263
|
+
raise click.ClickException(f"Local model file not found: {model_path}")
|
|
264
|
+
|
|
265
|
+
desktop.run_desktop(
|
|
266
|
+
model_path=model_path,
|
|
267
|
+
accelerator=accelerator,
|
|
268
|
+
num_runs=num_runs,
|
|
269
|
+
warmup_runs=warmup_runs,
|
|
270
|
+
min_secs=min_secs,
|
|
271
|
+
max_secs=max_secs,
|
|
272
|
+
warmup_min_secs=warmup_min_secs,
|
|
273
|
+
input_layer_value_range=input_layer_value_range,
|
|
274
|
+
signature_key=signature_key,
|
|
275
|
+
)
|
|
276
|
+
elif target == "gcp":
|
|
277
|
+
# pylint: disable=g-import-not-at-top
|
|
278
|
+
from litert_cli.commands.benchmark import gcp
|
|
279
|
+
|
|
280
|
+
if accelerator != "npu":
|
|
281
|
+
compilation_mode = None
|
|
282
|
+
soc_model = None
|
|
283
|
+
|
|
284
|
+
gcp.run_gcp(
|
|
285
|
+
str(model_path),
|
|
286
|
+
accelerator,
|
|
287
|
+
devices,
|
|
288
|
+
gcp_project,
|
|
289
|
+
gcp_bucket,
|
|
290
|
+
compilation_mode,
|
|
291
|
+
soc_model,
|
|
292
|
+
)
|
|
293
|
+
else:
|
|
294
|
+
click.secho(f"Target '{target}' is not yet supported.", fg="red")
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Copyright 2026 The LiteRT CLI Authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
|
|
16
|
+
"""Desktop Benchmark Module."""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import pathlib
|
|
21
|
+
import platform
|
|
22
|
+
import subprocess
|
|
23
|
+
import sys
|
|
24
|
+
|
|
25
|
+
import click
|
|
26
|
+
from litert_cli.core import constants
|
|
27
|
+
import requests
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _ensure_desktop_binary(tool_name: str) -> pathlib.Path:
|
|
31
|
+
"""Downloads the pre-built binary for the current desktop platform if not cached."""
|
|
32
|
+
system = sys.platform.lower()
|
|
33
|
+
machine = platform.machine().lower()
|
|
34
|
+
|
|
35
|
+
if system.startswith("linux"):
|
|
36
|
+
if machine in ("arm64", "aarch64"):
|
|
37
|
+
plat = "linux_arm64"
|
|
38
|
+
elif machine in ("x86_64", "amd64"):
|
|
39
|
+
plat = "linux_x86_64"
|
|
40
|
+
else:
|
|
41
|
+
raise click.ClickException(f"Unsupported Linux architecture: {machine}")
|
|
42
|
+
elif system == "darwin":
|
|
43
|
+
if machine in ("arm64", "aarch64"):
|
|
44
|
+
plat = "macos_arm64"
|
|
45
|
+
else:
|
|
46
|
+
raise click.ClickException(
|
|
47
|
+
f"Unsupported macOS architecture: {machine}. Only macos_arm64 is"
|
|
48
|
+
" currently supported."
|
|
49
|
+
)
|
|
50
|
+
elif system == "win32":
|
|
51
|
+
raise click.ClickException("Windows benchmarking is not yet supported.")
|
|
52
|
+
else:
|
|
53
|
+
raise click.ClickException(
|
|
54
|
+
f"Unsupported desktop operating system: {system}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
base_url = f"{constants.LITERT_BINARIES_BASE_URL}/{plat}"
|
|
58
|
+
download_url = f"{base_url}/{tool_name}"
|
|
59
|
+
|
|
60
|
+
cache_dir = pathlib.Path(constants.LITERT_CLI_CACHE_DIR) / "binaries" / plat
|
|
61
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
|
|
63
|
+
cached_file_path = cache_dir / tool_name
|
|
64
|
+
if cached_file_path.exists():
|
|
65
|
+
if system == "darwin":
|
|
66
|
+
subprocess.run(
|
|
67
|
+
["xattr", "-c", str(cached_file_path)],
|
|
68
|
+
check=False,
|
|
69
|
+
stdout=subprocess.DEVNULL,
|
|
70
|
+
stderr=subprocess.DEVNULL,
|
|
71
|
+
)
|
|
72
|
+
subprocess.run(
|
|
73
|
+
["codesign", "-s", "-", str(cached_file_path)],
|
|
74
|
+
check=False,
|
|
75
|
+
stdout=subprocess.DEVNULL,
|
|
76
|
+
stderr=subprocess.DEVNULL,
|
|
77
|
+
)
|
|
78
|
+
return cached_file_path
|
|
79
|
+
|
|
80
|
+
click.secho(
|
|
81
|
+
f"Downloading {tool_name!r} for desktop platform {plat!r}...", fg="cyan"
|
|
82
|
+
)
|
|
83
|
+
tmp_cached_file = cached_file_path.with_suffix(".tmp")
|
|
84
|
+
try:
|
|
85
|
+
with requests.get(download_url, stream=True, timeout=10) as response:
|
|
86
|
+
response.raise_for_status()
|
|
87
|
+
content_length = response.headers.get("Content-Length")
|
|
88
|
+
total_size = int(content_length) if content_length else 0
|
|
89
|
+
|
|
90
|
+
bar_length = total_size if total_size > 0 else None
|
|
91
|
+
bar_label = f"Downloading {tool_name}"
|
|
92
|
+
if bar_length is None:
|
|
93
|
+
click.secho(
|
|
94
|
+
f"Content-Length header not found for {tool_name!r}, using"
|
|
95
|
+
" indeterminate progress bar.",
|
|
96
|
+
fg="yellow",
|
|
97
|
+
)
|
|
98
|
+
bar_label += " (size unknown)"
|
|
99
|
+
|
|
100
|
+
with click.progressbar(length=bar_length, label=bar_label) as bar:
|
|
101
|
+
with open(tmp_cached_file, "wb") as f:
|
|
102
|
+
for buffer in response.iter_content(chunk_size=8192):
|
|
103
|
+
f.write(buffer)
|
|
104
|
+
bar.update(len(buffer))
|
|
105
|
+
|
|
106
|
+
tmp_cached_file.rename(cached_file_path)
|
|
107
|
+
cached_file_path.chmod(0o755)
|
|
108
|
+
if system == "darwin":
|
|
109
|
+
subprocess.run(
|
|
110
|
+
["xattr", "-c", str(cached_file_path)],
|
|
111
|
+
check=False,
|
|
112
|
+
stdout=subprocess.DEVNULL,
|
|
113
|
+
stderr=subprocess.DEVNULL,
|
|
114
|
+
)
|
|
115
|
+
subprocess.run(
|
|
116
|
+
["codesign", "-s", "-", str(cached_file_path)],
|
|
117
|
+
check=False,
|
|
118
|
+
stdout=subprocess.DEVNULL,
|
|
119
|
+
stderr=subprocess.DEVNULL,
|
|
120
|
+
)
|
|
121
|
+
return cached_file_path
|
|
122
|
+
except (requests.exceptions.RequestException, OSError) as e:
|
|
123
|
+
if cached_file_path.exists():
|
|
124
|
+
cached_file_path.unlink()
|
|
125
|
+
if tmp_cached_file.exists():
|
|
126
|
+
tmp_cached_file.unlink()
|
|
127
|
+
raise click.ClickException(
|
|
128
|
+
f"Failed to download {tool_name!r} from {download_url!r}: {e}"
|
|
129
|
+
) from e
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def run_desktop(
|
|
133
|
+
*,
|
|
134
|
+
model_path: pathlib.Path,
|
|
135
|
+
accelerator: str,
|
|
136
|
+
num_runs: int = 50,
|
|
137
|
+
warmup_runs: int = 1,
|
|
138
|
+
min_secs: float = 1.0,
|
|
139
|
+
max_secs: float = 150.0,
|
|
140
|
+
warmup_min_secs: float = 0.5,
|
|
141
|
+
input_layer_value_range: str | None = None,
|
|
142
|
+
signature_key: str | None = None,
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Runs the benchmark_model binary on the local desktop machine.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
model_path: Path to the local LiteRT model file.
|
|
148
|
+
accelerator: Hardware accelerator to use (cpu, gpu, npu).
|
|
149
|
+
num_runs: Target number of benchmark iterations.
|
|
150
|
+
warmup_runs: Number of warmup iterations before benchmarking.
|
|
151
|
+
min_secs: Minimum seconds to run.
|
|
152
|
+
max_secs: Maximum seconds to run.
|
|
153
|
+
warmup_min_secs: Minimum warmup duration in seconds.
|
|
154
|
+
input_layer_value_range: Value range for input layers.
|
|
155
|
+
signature_key: The signature key to benchmark.
|
|
156
|
+
|
|
157
|
+
Raises:
|
|
158
|
+
click.ClickException: If execution fails.
|
|
159
|
+
"""
|
|
160
|
+
click.echo("Preparing to run benchmark on local desktop...")
|
|
161
|
+
|
|
162
|
+
if not model_path.exists():
|
|
163
|
+
raise click.ClickException(f"Local model file not found: {model_path}")
|
|
164
|
+
|
|
165
|
+
benchmark_bin = _ensure_desktop_binary("benchmark_model")
|
|
166
|
+
|
|
167
|
+
click.echo(f"Executing benchmark locally using {benchmark_bin.name}...\n")
|
|
168
|
+
try:
|
|
169
|
+
bench_args = [
|
|
170
|
+
str(benchmark_bin),
|
|
171
|
+
f"--graph={model_path.resolve()}",
|
|
172
|
+
]
|
|
173
|
+
if accelerator == "gpu":
|
|
174
|
+
bench_args.append("--use_gpu=true")
|
|
175
|
+
elif accelerator == "npu":
|
|
176
|
+
click.secho(
|
|
177
|
+
"Warning: NPU benchmarking via benchmark_model on desktop is not"
|
|
178
|
+
" fully supported yet.",
|
|
179
|
+
fg="yellow",
|
|
180
|
+
)
|
|
181
|
+
bench_args.append("--use_npu=true")
|
|
182
|
+
|
|
183
|
+
if num_runs != 50:
|
|
184
|
+
bench_args.append(f"--num_runs={num_runs}")
|
|
185
|
+
if warmup_runs != 1:
|
|
186
|
+
bench_args.append(f"--warmup_runs={warmup_runs}")
|
|
187
|
+
if min_secs != 1.0:
|
|
188
|
+
bench_args.append(f"--min_secs={min_secs}")
|
|
189
|
+
if max_secs != 150.0:
|
|
190
|
+
bench_args.append(f"--max_secs={max_secs}")
|
|
191
|
+
if warmup_min_secs != 0.5:
|
|
192
|
+
bench_args.append(f"--warmup_min_secs={warmup_min_secs}")
|
|
193
|
+
if input_layer_value_range:
|
|
194
|
+
bench_args.append(f"--input_layer_value_range={input_layer_value_range}")
|
|
195
|
+
if signature_key:
|
|
196
|
+
bench_args.append(f"--signature_to_run_for={signature_key}")
|
|
197
|
+
|
|
198
|
+
process = subprocess.Popen(
|
|
199
|
+
bench_args,
|
|
200
|
+
stdout=subprocess.PIPE,
|
|
201
|
+
stderr=subprocess.STDOUT,
|
|
202
|
+
text=True,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
from litert_cli.core.log_filters import BenchmarkLogFilter
|
|
206
|
+
|
|
207
|
+
output_lines = []
|
|
208
|
+
log_filter = BenchmarkLogFilter(constants.DEFAULT_QUIET)
|
|
209
|
+
|
|
210
|
+
for line in process.stdout:
|
|
211
|
+
output_lines.append(line)
|
|
212
|
+
if log_filter.should_show(line):
|
|
213
|
+
click.echo(line, nl=False)
|
|
214
|
+
|
|
215
|
+
process.wait()
|
|
216
|
+
if process.returncode != 0:
|
|
217
|
+
click.secho(
|
|
218
|
+
f"Execution failed on desktop with exit code {process.returncode}",
|
|
219
|
+
fg="red",
|
|
220
|
+
)
|
|
221
|
+
click.echo("Full output for debugging:")
|
|
222
|
+
for line in output_lines:
|
|
223
|
+
click.echo(line, nl=False)
|
|
224
|
+
raise click.ClickException("Benchmark failed on desktop.")
|
|
225
|
+
except click.ClickException:
|
|
226
|
+
raise
|
|
227
|
+
except Exception as e:
|
|
228
|
+
raise click.ClickException(f"Failed to execute benchmark on desktop: {e}")
|