Add LiteRT-LM DEP and build scripts Add a DEP on the LiteRT-LM mirror so that it can be checked out via gclient for building and running benchmarks. The necessary prebuilts (typically shipped for the GitHub repo via Git LFS) and an open gemma-3n-E4B-it-int4.litertlm model are mirrored to an experimental CIPD bucket as a temporary prototype location. With the GN action it is now possible to build the benchmark binary with: autoninja -C out/active third_party/litert-lm:litert_lm_advanced_main This binary can be manually run, and will in a follow up be configured to run via LUCI recipe. Bug: 521332988 Change-Id: Ibfbdaa7e5659525cdb06bdea17c0c06dfe43b3dc Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/320135 Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Natalie Chouinard <chouinard@google.com>
diff --git a/.gitignore b/.gitignore index 519a97e..2a7da1d 100644 --- a/.gitignore +++ b/.gitignore
@@ -34,6 +34,8 @@ /third_party/libc++/src /third_party/libc++abi/src /third_party/libprotobuf-mutator/src +/third_party/litert-lm/data +/third_party/litert-lm/src /third_party/llvm-build /third_party/markupsafe /third_party/mesa/src
diff --git a/.gitmodules b/.gitmodules index 90046ec..923dfa5 100644 --- a/.gitmodules +++ b/.gitmodules
@@ -209,3 +209,7 @@ path = third_party/partition_alloc url = https://chromium.googlesource.com/chromium/src/base/allocator/partition_allocator.git gclient-condition = dawn_standalone +[submodule "third_party/litert-lm/src"] + path = third_party/litert-lm/src + url = https://chromium.googlesource.com/external/github.com/google-ai-edge/LiteRT-LM.git + gclient-condition = checkout_litert_lm
diff --git a/BUILD.gn b/BUILD.gn index f423dc1..e1b1a61 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -103,6 +103,13 @@ deps = [ "tools/android" ] } + if (dawn_build_litert_lm) { + group("litert_lm") { + testonly = true + deps = [ "third_party/litert-lm:litert_lm_advanced_main" ] + } + } + if (dawn_build_emdawnwebgpu) { # These targets are only valid when the Wasm toolchain is available. assert(dawn_wasm,
diff --git a/DEPS b/DEPS index 97a91e1..dedf134 100644 --- a/DEPS +++ b/DEPS
@@ -85,6 +85,10 @@ # Checkout //tools/code_coverage from Chromium and fetches the # prebuilt versions of llvm-cov and llvm-profdata. 'checkout_clang_coverage_tools': False, + + # Checkout LiteRT-LM and its data dependencies. + # Not actually depended on by Dawn/Tint, only used to run benchmark tests on them. + 'checkout_litert_lm': False, } deps = { @@ -572,7 +576,7 @@ }, 'tools/bazelisk': { - 'condition': 'fetch_bazel', + 'condition': 'fetch_bazel or checkout_litert_lm', 'packages': [{ 'package': 'infra/3pp/tools/bazelisk/${{platform}}', 'version': Var('dawn_bazelisk_version'), @@ -654,6 +658,23 @@ 'url': '{chromium_git}/chromium/src.git' + '@' + Var('chromium_revision'), 'condition': 'checkout_placeholder_chromium', }, + + 'third_party/litert-lm/src': { + 'url': '{chromium_git}/external/github.com/google-ai-edge/LiteRT-LM.git@27106e37122bff03bb8c15589127e0d97011d0c3', + 'condition': 'checkout_litert_lm', + }, + + 'third_party/litert-lm/data': { + 'packages': [ + { + # TODO(crbug.com/527944617): Replace experimental CIPD dependency. + 'package': 'experimental/chouinard_at_google.com/litert_lm_benchmark_data', + 'version': 'latest', + } + ], + 'dep_type': 'cipd', + 'condition': 'checkout_litert_lm', + }, } hooks = [
diff --git a/scripts/dawn_features.gni b/scripts/dawn_features.gni index 72ddb5e..caaebec 100644 --- a/scripts/dawn_features.gni +++ b/scripts/dawn_features.gni
@@ -33,6 +33,9 @@ # Sets defaults for other features so that we build as much as possible on the # current host OS. dawn_maximal = false + + # Build the LiteRT-LM benchmark binary using Bazel. + dawn_build_litert_lm = false } declare_args() {
diff --git a/third_party/litert-lm/BUILD.gn b/third_party/litert-lm/BUILD.gn new file mode 100644 index 0000000..64e4b9a --- /dev/null +++ b/third_party/litert-lm/BUILD.gn
@@ -0,0 +1,33 @@ +# Copyright 2026 The Dawn & Tint Authors +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +action("litert_lm_advanced_main") { + script = "build_litert_lm.py" + args = + [ rebase_path("$root_out_dir/litert_lm_advanced_main", root_build_dir) ] + outputs = [ "$root_out_dir/litert_lm_advanced_main" ] +}
diff --git a/third_party/litert-lm/build_litert_lm.py b/third_party/litert-lm/build_litert_lm.py new file mode 100644 index 0000000..7698ce8 --- /dev/null +++ b/third_party/litert-lm/build_litert_lm.py
@@ -0,0 +1,113 @@ +#!/usr/bin/env vpython3 +# Copyright 2026 The Dawn & Tint Authors +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Invokes the hermetic Bazelisk binary to build LiteRT-LM and copy the output binary to GN's output directory. +""" + +import os +import shutil +import subprocess +import sys + +BAZEL_TARGET = '//runtime/engine:litert_lm_advanced_main' +BAZEL_BIN_SUBPATH = 'runtime/engine/litert_lm_advanced_main' + + +def main(): + if len(sys.argv) < 2: + print("Error: Missing output path argument.", file=sys.stderr) + print("Usage: build_litert_lm.py <output_path>", file=sys.stderr) + sys.exit(1) + + dest_path = os.path.abspath(sys.argv[1]) + + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.abspath(os.path.join(script_dir, '..', '..')) + litert_lm_dir = os.path.join(script_dir, 'src') + + bazelisk_path = os.path.join(project_root, 'tools', 'bazelisk', 'bazelisk') + prebuilt_cipd_dir = os.path.join(script_dir, 'data', 'prebuilt') + prebuilt_src_dir = os.path.join(litert_lm_dir, 'prebuilt') + backup_dir = prebuilt_src_dir + "_backup" + + # Back up the original Git LFS smudge prebuilt directory. + if os.path.exists( + prebuilt_src_dir) and not os.path.islink(prebuilt_src_dir): + shutil.move(prebuilt_src_dir, backup_dir) + + try: + # Symlink the CIPD-unpacked prebuilts directly so Bazel can resolve + # targets. + if os.path.exists(prebuilt_cipd_dir): + print( + "Symlinking prebuilt binaries from CIPD to LiteRT-LM workspace..." + ) + os.symlink(prebuilt_cipd_dir, prebuilt_src_dir) + + # Compile the target using Bazelisk inside LiteRT-LM's standalone + # workspace. + print(f"Building Bazel target: {BAZEL_TARGET}...") + build_cmd = [ + bazelisk_path, + 'build', + '--compilation_mode=opt', + '--define=litert_link_capi_so=true', + '--define=resolve_symbols_in_exec=false', + BAZEL_TARGET, + ] + + proc = subprocess.run(build_cmd, cwd=litert_lm_dir) + if proc.returncode != 0: + print("Error: Bazel build failed.", file=sys.stderr) + sys.exit(proc.returncode) + + finally: + # Restore the original Git-tracked prebuilt directory regardless of + # success or failure. This keeps the Git tree clean for gclient sync. + print("Restoring original Git-tracked prebuilt directory...") + if os.path.islink(prebuilt_src_dir): + os.remove(prebuilt_src_dir) + if os.path.exists(backup_dir): + shutil.move(backup_dir, prebuilt_src_dir) + + # Locate and copy the compiled binary into the GN target directory. + compiled_path = os.path.join(litert_lm_dir, 'bazel-bin', BAZEL_BIN_SUBPATH) + if not os.path.exists(compiled_path): + print( + f"Error: Compiled binary not found at expected path: {compiled_path}", + file=sys.stderr) + sys.exit(1) + + print(f"Copying compiled binary to: {dest_path}") + shutil.copy2(compiled_path, dest_path) + os.chmod(dest_path, 0o755) + + print("Build and copy successful.") + + +if __name__ == '__main__': + main()
diff --git a/third_party/litert-lm/src b/third_party/litert-lm/src new file mode 160000 index 0000000..27106e3 --- /dev/null +++ b/third_party/litert-lm/src
@@ -0,0 +1 @@ +Subproject commit 27106e37122bff03bb8c15589127e0d97011d0c3