chore: import upstream snapshot with attribution
This commit is contained in:
Executable
+672
@@ -0,0 +1,672 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ruff: noqa: E501, RUF005
|
||||
|
||||
import argparse
|
||||
import getpass
|
||||
import grp
|
||||
import inspect
|
||||
import json
|
||||
import multiprocessing
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import typing
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
SCRIPT_DIR = REPO_ROOT / ".ci-py-scripts"
|
||||
NPROC = multiprocessing.cpu_count()
|
||||
|
||||
|
||||
class col:
|
||||
BLUE = "\033[94m"
|
||||
CYAN = "\033[96m"
|
||||
GREEN = "\033[92m"
|
||||
YELLOW = "\033[93m"
|
||||
RED = "\033[91m"
|
||||
RESET = "\033[0m"
|
||||
BOLD = "\033[1m"
|
||||
UNDERLINE = "\033[4m"
|
||||
|
||||
|
||||
def print_color(color: str, msg: str, bold: bool, **kwargs: Any) -> None:
|
||||
if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
|
||||
bold_code = col.BOLD if bold else ""
|
||||
print(bold_code + color + msg + col.RESET, **kwargs)
|
||||
else:
|
||||
print(msg, **kwargs)
|
||||
|
||||
|
||||
warnings: list[str] = []
|
||||
|
||||
|
||||
def clean_exit(msg: str) -> None:
|
||||
print_color(col.RED, msg, bold=True, file=sys.stderr)
|
||||
|
||||
for warning in warnings:
|
||||
print_color(col.YELLOW, warning, bold=False, file=sys.stderr)
|
||||
|
||||
exit(1)
|
||||
|
||||
|
||||
def cmd(commands: list[Any], **kwargs: Any):
|
||||
commands = [str(s) for s in commands]
|
||||
command_str = " ".join(commands)
|
||||
print_color(col.BLUE, command_str, bold=True)
|
||||
proc = subprocess.run(commands, **kwargs)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(f"Command failed: '{command_str}'")
|
||||
return proc
|
||||
|
||||
|
||||
def get_build_dir(name: str) -> str:
|
||||
build_dir = REPO_ROOT / f"build-{name}"
|
||||
return str(build_dir.relative_to(REPO_ROOT))
|
||||
|
||||
|
||||
def check_docker():
|
||||
executable = shutil.which("docker")
|
||||
if executable is None:
|
||||
clean_exit("'docker' executable not found, install it first (e.g. 'apt install docker.io')")
|
||||
|
||||
if sys.platform == "linux":
|
||||
# Check that the user is in the docker group before running
|
||||
try:
|
||||
group = grp.getgrnam("docker")
|
||||
if getpass.getuser() not in group.gr_mem:
|
||||
warnings.append(
|
||||
f"Note: User '{getpass.getuser()}' is not in the 'docker' group, either:\n"
|
||||
" * run with 'sudo'\n"
|
||||
" * add user to 'docker': sudo usermod -aG docker $(whoami), then log out and back in",
|
||||
)
|
||||
except KeyError:
|
||||
warnings.append("Note: 'docker' group does not exist")
|
||||
|
||||
|
||||
def check_gpu():
|
||||
if not (sys.platform == "linux" and shutil.which("lshw")):
|
||||
# Can't check GPU on non-Linux platforms
|
||||
return
|
||||
|
||||
# See if we can check if a GPU is present in case of later failures,
|
||||
# but don't block on execution since this isn't critical
|
||||
try:
|
||||
proc = cmd(
|
||||
["lshw", "-json", "-C", "display"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
stdout = proc.stdout.strip().strip(",")
|
||||
stdout = json.loads(stdout)
|
||||
except (subprocess.CalledProcessError, json.decoder.JSONDecodeError):
|
||||
# Do nothing if any step failed
|
||||
return
|
||||
|
||||
if isinstance(stdout, dict):
|
||||
# Sometimes lshw outputs a single item as a dict instead of a list of
|
||||
# dicts, so wrap it up if necessary
|
||||
stdout = [stdout]
|
||||
if not isinstance(stdout, list):
|
||||
return
|
||||
|
||||
vendors = [s.get("vendor", "").lower() for s in stdout]
|
||||
if not any("nvidia" in vendor for vendor in vendors):
|
||||
warnings.append(
|
||||
"nvidia GPU not found in 'lshw', maybe use --cpu flag when running 'docs' command?"
|
||||
)
|
||||
|
||||
|
||||
def gen_name(s: str) -> str:
|
||||
# random 4 letters
|
||||
suffix = "".join([random.choice(string.ascii_lowercase) for i in range(5)])
|
||||
return f"{s}-{suffix}"
|
||||
|
||||
|
||||
def docker(
|
||||
name: str,
|
||||
image: str,
|
||||
scripts: list[str],
|
||||
env: dict[str, str],
|
||||
interactive: bool,
|
||||
additional_flags: dict[str, str] | None = None,
|
||||
):
|
||||
"""
|
||||
Invoke a set of bash scripts through docker/bash.sh
|
||||
|
||||
name: container name
|
||||
image: docker image name
|
||||
scripts: list of bash commands to run
|
||||
env: environment to set
|
||||
"""
|
||||
check_docker()
|
||||
|
||||
# As sccache is added to these images these can be uncommented
|
||||
sccache_images = {
|
||||
"ci_gpu",
|
||||
"ci_cpu",
|
||||
# "ci_wasm",
|
||||
"ci_cortexm",
|
||||
"ci_arm",
|
||||
"ci_riscv",
|
||||
"ci_adreno",
|
||||
}
|
||||
|
||||
if image in sccache_images and os.getenv("USE_SCCACHE", "1") == "1":
|
||||
scripts = [
|
||||
"sccache --start-server",
|
||||
] + scripts
|
||||
# Set the C/C++ compiler so CMake picks them up in the build
|
||||
env["CC"] = "/opt/sccache/cc"
|
||||
env["CXX"] = "/opt/sccache/c++"
|
||||
env["SCCACHE_CACHE_SIZE"] = os.getenv("SCCACHE_CACHE_SIZE", "50G")
|
||||
env["SCCACHE_SERVER_PORT"] = os.getenv("SCCACHE_SERVER_PORT", "4226")
|
||||
|
||||
env["PLATFORM"] = name
|
||||
|
||||
docker_bash = REPO_ROOT / "docker" / "bash.sh"
|
||||
|
||||
command = [docker_bash]
|
||||
if sys.stdout.isatty():
|
||||
command.append("-t")
|
||||
|
||||
command.append("--name")
|
||||
command.append(name)
|
||||
if interactive:
|
||||
command.append("-i")
|
||||
scripts = ["interact() {", " bash", "}", "trap interact 0", ""] + scripts
|
||||
|
||||
for key, value in env.items():
|
||||
command.append("--env")
|
||||
command.append(f"{key}={value}")
|
||||
|
||||
if additional_flags is not None:
|
||||
for key, value in additional_flags.items():
|
||||
command.append(key)
|
||||
command.append(value)
|
||||
|
||||
SCRIPT_DIR.mkdir(exist_ok=True)
|
||||
|
||||
script_file = SCRIPT_DIR / f"{name}.sh"
|
||||
with open(script_file, "w") as f:
|
||||
f.write("set -eux\n\n")
|
||||
f.write("\n".join(scripts))
|
||||
f.write("\n")
|
||||
|
||||
command += [image, "bash", str(script_file.relative_to(REPO_ROOT))]
|
||||
|
||||
try:
|
||||
cmd(command)
|
||||
except RuntimeError as e:
|
||||
clean_exit(f"Error invoking Docker: {e}")
|
||||
except KeyboardInterrupt:
|
||||
cmd(["docker", "stop", "--time", "1", name])
|
||||
finally:
|
||||
if os.getenv("DEBUG", "0") != "1":
|
||||
script_file.unlink()
|
||||
|
||||
|
||||
def docs(
|
||||
tutorial_pattern: str | None = None,
|
||||
cpu: bool = False,
|
||||
full: bool = False,
|
||||
interactive: bool = False,
|
||||
skip_build: bool = False,
|
||||
docker_image: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Build the documentation from gallery/ and docs/. By default this builds only
|
||||
the Python docs without any tutorials.
|
||||
|
||||
arguments:
|
||||
full -- Build all language docs, not just Python (cannot be used with --cpu)
|
||||
cpu -- Use the 'ci_cpu' Docker image (useful for building docs on a machine without a GPU)
|
||||
tutorial-pattern -- Regex for which tutorials to execute when building docs (cannot be used with --cpu)
|
||||
skip_build -- skip build and setup scripts
|
||||
interactive -- start a shell after running build / test scripts
|
||||
docker-image -- manually specify the docker image to use
|
||||
"""
|
||||
build_dir = get_build_dir("gpu")
|
||||
|
||||
extra_setup = []
|
||||
image = "ci_gpu" if docker_image is None else docker_image
|
||||
if cpu:
|
||||
# TODO: Change this to tlcpack/docs once that is uploaded
|
||||
image = "ci_cpu" if docker_image is None else docker_image
|
||||
build_dir = get_build_dir("cpu")
|
||||
config_script = " && ".join(
|
||||
[
|
||||
f"mkdir -p {build_dir}",
|
||||
f"pushd {build_dir}",
|
||||
"cp ../cmake/config.cmake .",
|
||||
"popd",
|
||||
]
|
||||
)
|
||||
|
||||
# These are taken from the ci-gpu image via pip freeze, consult that
|
||||
# if there are any changes: https://github.com/apache/tvm/tree/main/docs#native
|
||||
requirements = [
|
||||
"Sphinx==8.1.3",
|
||||
"sphinx_autodoc_annotation~=1.0",
|
||||
"sphinx-gallery==0.20.0",
|
||||
"sphinx-book-theme==1.1.4",
|
||||
"pydata-sphinx-theme==0.15.4",
|
||||
"autodocsumm==0.2.14",
|
||||
"image==1.5.33",
|
||||
"matplotlib==3.10.8",
|
||||
"commonmark==0.9.1",
|
||||
"docutils==0.21.2",
|
||||
"Pillow==12.1.1",
|
||||
]
|
||||
|
||||
extra_setup = [
|
||||
"uv pip install " + " ".join(requirements),
|
||||
]
|
||||
else:
|
||||
check_gpu()
|
||||
config_script = f"./tests/scripts/task_config_build_gpu.sh {build_dir}"
|
||||
|
||||
scripts = extra_setup + [
|
||||
config_script,
|
||||
f"./tests/scripts/task_build.py --build-dir {build_dir}",
|
||||
]
|
||||
|
||||
if skip_build:
|
||||
scripts = []
|
||||
|
||||
scripts.append("./tests/scripts/task_python_docs.sh")
|
||||
|
||||
if tutorial_pattern is None:
|
||||
tutorial_pattern = os.getenv("TVM_TUTORIAL_EXEC_PATTERN", ".py" if full else "none")
|
||||
|
||||
env = {
|
||||
"TVM_TUTORIAL_EXEC_PATTERN": tutorial_pattern,
|
||||
"PYTHON_DOCS_ONLY": "0" if full else "1",
|
||||
"IS_LOCAL": "1",
|
||||
"TVM_LIBRARY_PATH": str(REPO_ROOT / build_dir),
|
||||
}
|
||||
docker(name=gen_name("docs"), image=image, scripts=scripts, env=env, interactive=interactive)
|
||||
print_color(
|
||||
col.GREEN,
|
||||
"Done building the docs. You can view them by running "
|
||||
"'python3 tests/scripts/ci.py serve-docs' and visiting:"
|
||||
" http://localhost:8000 in your browser.",
|
||||
bold=True,
|
||||
)
|
||||
|
||||
|
||||
def serve_docs(directory: str = "_docs") -> None:
|
||||
"""
|
||||
Serve the docs using Python's http server
|
||||
|
||||
arguments:
|
||||
directory -- Directory to serve from
|
||||
"""
|
||||
directory_path = Path(directory)
|
||||
if not directory_path.exists():
|
||||
clean_exit("Docs have not been built, run 'ci.py docs' first")
|
||||
cmd([sys.executable, "-m", "http.server"], cwd=directory_path)
|
||||
|
||||
|
||||
def lint(interactive: bool = False, docker_image: str | None = None) -> None:
|
||||
"""
|
||||
Run lint checks locally.
|
||||
|
||||
arguments:
|
||||
interactive -- start a shell after running build / test scripts when using --docker-image
|
||||
docker-image -- manually specify a docker image to use
|
||||
"""
|
||||
scripts = ["pre-commit run --all-files"]
|
||||
if docker_image is None:
|
||||
if interactive:
|
||||
clean_exit("--interactive requires --docker-image")
|
||||
cmd(scripts[0].split())
|
||||
return
|
||||
|
||||
docker(
|
||||
name=gen_name("lint"),
|
||||
image=docker_image,
|
||||
scripts=scripts,
|
||||
env={},
|
||||
interactive=interactive,
|
||||
)
|
||||
|
||||
|
||||
Option = tuple[str, list[str]]
|
||||
|
||||
|
||||
def generate_command(
|
||||
name: str,
|
||||
options: dict[str, Option],
|
||||
help: str,
|
||||
precheck: Callable[[], None] | None = None,
|
||||
post_build: list[str] | None = None,
|
||||
additional_flags: dict[str, str] | None = None,
|
||||
env: dict[str, str] | None = None,
|
||||
):
|
||||
"""
|
||||
Helper to generate CLIs that:
|
||||
1. Build a with a config matching a specific CI Docker image (e.g. 'cpu')
|
||||
2. Run tests (either a pre-defined set from scripts or manually via invoking
|
||||
pytest)
|
||||
3. (optional) Drop down into a terminal into the Docker container
|
||||
"""
|
||||
|
||||
def fn(
|
||||
tests: list[str] | None = None,
|
||||
skip_build: bool = False,
|
||||
interactive: bool = False,
|
||||
docker_image: str | None = None,
|
||||
verbose: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
arguments:
|
||||
tests -- pytest test IDs (e.g. tests/python or tests/python/a_file.py::a_test[param=1])
|
||||
skip_build -- skip build and setup scripts
|
||||
interactive -- start a shell after running build / test scripts
|
||||
docker-image -- manually specify the docker image to use
|
||||
verbose -- run verbose build
|
||||
"""
|
||||
if precheck is not None:
|
||||
precheck()
|
||||
|
||||
build_dir = get_build_dir(name)
|
||||
|
||||
if skip_build:
|
||||
scripts = []
|
||||
else:
|
||||
scripts = [
|
||||
f"./tests/scripts/task_config_build_{name}.sh {build_dir}",
|
||||
f"./tests/scripts/task_build.py --build-dir {build_dir}",
|
||||
]
|
||||
|
||||
if post_build is not None:
|
||||
scripts += post_build
|
||||
|
||||
# Check that a test suite was not used alongside specific test names
|
||||
if any(v for v in kwargs.values()) and tests is not None:
|
||||
option_flags = ", ".join([f"--{k}" for k in options.keys()])
|
||||
clean_exit(f"{option_flags} cannot be used with --tests")
|
||||
|
||||
if tests is not None:
|
||||
scripts.append(f"python3 -m pytest {' '.join(tests)}")
|
||||
|
||||
# Add named test suites
|
||||
for option_name, (_, extra_scripts) in options.items():
|
||||
if kwargs.get(option_name, False):
|
||||
scripts.extend(script.format(build_dir=build_dir) for script in extra_scripts)
|
||||
|
||||
docker_env = {
|
||||
# Need to specify the library path manually or else TVM can't
|
||||
# determine which build directory to use (i.e. if there are
|
||||
# multiple copies of libtvm_compiler.so / libtvm_runtime.so laying around)
|
||||
"TVM_LIBRARY_PATH": str(REPO_ROOT / get_build_dir(name)),
|
||||
"VERBOSE": "true" if verbose else "false",
|
||||
}
|
||||
|
||||
if env is not None:
|
||||
docker_env.update(env)
|
||||
|
||||
docker(
|
||||
name=gen_name(f"ci-{name}"),
|
||||
image=f"ci_{name}" if docker_image is None else docker_image,
|
||||
scripts=scripts,
|
||||
env=docker_env,
|
||||
interactive=interactive,
|
||||
additional_flags=additional_flags,
|
||||
)
|
||||
|
||||
fn.__name__ = name
|
||||
|
||||
return fn, options, help
|
||||
|
||||
|
||||
def check_arm_qemu() -> None:
|
||||
"""
|
||||
Check if a machine is ready to run an ARM Docker image
|
||||
"""
|
||||
machine = platform.machine().lower()
|
||||
if "arm" in machine or "aarch64" in machine:
|
||||
# No need to check anything if the machine runs ARM
|
||||
return
|
||||
|
||||
binfmt = Path("/proc/sys/fs/binfmt_misc")
|
||||
if not binfmt.exists() or len(list(binfmt.glob("qemu-*"))) == 0:
|
||||
clean_exit(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
You must run a one-time setup to use ARM containers on x86 via QEMU:
|
||||
|
||||
sudo apt install -y qemu binfmt-support qemu-user-static
|
||||
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
|
||||
See https://www.stereolabs.com/docs/docker/building-arm-container-on-x86/ for details""".strip(
|
||||
"\n"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def cli_name(s: str) -> str:
|
||||
return s.replace("_", "-")
|
||||
|
||||
|
||||
def typing_get_origin(annotation):
|
||||
return typing.get_origin(annotation)
|
||||
|
||||
|
||||
def typing_get_args(annotation):
|
||||
return typing.get_args(annotation)
|
||||
|
||||
|
||||
def is_optional_type(annotation):
|
||||
return (
|
||||
hasattr(annotation, "__origin__")
|
||||
and (typing_get_origin(annotation) == typing.Union)
|
||||
and (type(None) in typing_get_args(annotation))
|
||||
)
|
||||
|
||||
|
||||
def add_subparser(
|
||||
func: Callable,
|
||||
subparsers: Any,
|
||||
options: dict[str, Option] | None = None,
|
||||
help: str | None = None,
|
||||
) -> Any:
|
||||
"""
|
||||
Utility function to make it so subparser commands can be defined locally
|
||||
as a function rather than directly via argparse and manually dispatched
|
||||
out.
|
||||
"""
|
||||
|
||||
# Each function is intended follow the example for arguments in PEP257, so
|
||||
# split apart the function documentation from the arguments
|
||||
split = [s.strip() for s in func.__doc__.split("arguments:\n")]
|
||||
if len(split) == 1:
|
||||
args_help = None
|
||||
command_help = split[0]
|
||||
else:
|
||||
command_help, args_help = split
|
||||
|
||||
if help is not None:
|
||||
command_help = help
|
||||
|
||||
# Parse out the help text for each argument if present
|
||||
arg_help_texts = {}
|
||||
if args_help is not None:
|
||||
for line in args_help.split("\n"):
|
||||
line = line.strip()
|
||||
name, help_text = [t.strip() for t in line.split(" -- ")]
|
||||
arg_help_texts[cli_name(name)] = help_text
|
||||
|
||||
subparser = subparsers.add_parser(cli_name(func.__name__), help=command_help)
|
||||
|
||||
seen_prefixes = set()
|
||||
|
||||
# Add each parameter to the subparser
|
||||
signature = inspect.signature(func)
|
||||
for name, value in signature.parameters.items():
|
||||
if name == "kwargs":
|
||||
continue
|
||||
|
||||
arg_cli_name = cli_name(name)
|
||||
kwargs: dict[str, str | bool] = {"help": arg_help_texts[arg_cli_name]}
|
||||
|
||||
is_optional = is_optional_type(value.annotation)
|
||||
if is_optional:
|
||||
arg_type = typing_get_args(value.annotation)[0]
|
||||
else:
|
||||
arg_type = value.annotation
|
||||
|
||||
# Grab the default value if present
|
||||
has_default = False
|
||||
if value.default is not value.empty:
|
||||
kwargs["default"] = value.default
|
||||
has_default = True
|
||||
|
||||
# Check if it should be a flag
|
||||
if arg_type is bool:
|
||||
kwargs["action"] = "store_true"
|
||||
else:
|
||||
kwargs["required"] = not is_optional and not has_default
|
||||
|
||||
if str(arg_type).startswith("typing.List"):
|
||||
kwargs["action"] = "append"
|
||||
|
||||
if arg_cli_name[0] not in seen_prefixes:
|
||||
subparser.add_argument(f"-{arg_cli_name[0]}", f"--{arg_cli_name}", **kwargs)
|
||||
seen_prefixes.add(arg_cli_name[0])
|
||||
else:
|
||||
subparser.add_argument(f"--{arg_cli_name}", **kwargs)
|
||||
|
||||
if options is not None:
|
||||
for option_name, (help, _) in options.items():
|
||||
option_cli_name = cli_name(option_name)
|
||||
if option_cli_name[0] not in seen_prefixes:
|
||||
subparser.add_argument(
|
||||
f"-{option_cli_name[0]}", f"--{option_cli_name}", action="store_true", help=help
|
||||
)
|
||||
seen_prefixes.add(option_cli_name[0])
|
||||
else:
|
||||
subparser.add_argument(f"--{option_cli_name}", action="store_true", help=help)
|
||||
|
||||
return subparser
|
||||
|
||||
|
||||
CPP_UNITTEST = ("run c++ unitests", ["./tests/scripts/task_cpp_unittest.sh {build_dir}"])
|
||||
|
||||
generated = [
|
||||
generate_command(
|
||||
name="gpu",
|
||||
help="Run GPU build and test(s)",
|
||||
options={
|
||||
"cpp": CPP_UNITTEST,
|
||||
"unittest": (
|
||||
"run unit tests",
|
||||
[
|
||||
"./tests/scripts/task_java_unittest.sh",
|
||||
"./tests/scripts/task_python_unittest_gpuonly.sh",
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
generate_command(
|
||||
name="cpu",
|
||||
help="Run CPU build and test(s)",
|
||||
options={
|
||||
"cpp": CPP_UNITTEST,
|
||||
"unittest": (
|
||||
"run unit tests",
|
||||
[
|
||||
"./tests/scripts/task_python_unittest.sh",
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
generate_command(
|
||||
name="wasm",
|
||||
help="Run WASM build and test(s)",
|
||||
options={
|
||||
"cpp": CPP_UNITTEST,
|
||||
"test": ("run WASM tests", ["./tests/scripts/task_web_wasm.sh"]),
|
||||
},
|
||||
),
|
||||
generate_command(
|
||||
name="arm",
|
||||
help="Run ARM build and test(s) (native or via QEMU on x86)",
|
||||
precheck=check_arm_qemu,
|
||||
options={
|
||||
"cpp": CPP_UNITTEST,
|
||||
"python": (
|
||||
"run full Python tests",
|
||||
[
|
||||
"./tests/scripts/task_python_unittest.sh",
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
description = """
|
||||
Run CI jobs locally via Docker. This facilitates reproducing CI failures for
|
||||
fast iteration. Note that many of the Docker images required are large (the
|
||||
CPU and GPU images are both over 25GB) and may take some time to download on first use.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
subparsers = parser.add_subparsers(dest="command")
|
||||
|
||||
commands = {}
|
||||
|
||||
# Add manually defined commands
|
||||
for func in [docs, serve_docs, lint]:
|
||||
add_subparser(func, subparsers)
|
||||
commands[cli_name(func.__name__)] = func
|
||||
|
||||
# Add generated commands
|
||||
for func, options, help in generated:
|
||||
add_subparser(func, subparsers, options, help)
|
||||
commands[cli_name(func.__name__)] = func
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command is None:
|
||||
# Command not found in list, error out
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
|
||||
func = commands[args.command]
|
||||
|
||||
# Extract out the parsed args and invoke the relevant function
|
||||
kwargs = {k: getattr(args, k) for k in dir(args) if not k.startswith("_") and k != "command"}
|
||||
func(**kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,4 @@
|
||||
*.md
|
||||
!README.md
|
||||
*.csv
|
||||
*.pkl
|
||||
@@ -0,0 +1,64 @@
|
||||
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
|
||||
<!--- or more contributor license agreements. See the NOTICE file -->
|
||||
<!--- distributed with this work for additional information -->
|
||||
<!--- regarding copyright ownership. The ASF licenses this file -->
|
||||
<!--- to you under the Apache License, Version 2.0 (the -->
|
||||
<!--- "License"); you may not use this file except in compliance -->
|
||||
<!--- with the License. You may obtain a copy of the License at -->
|
||||
|
||||
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
|
||||
|
||||
<!--- Unless required by applicable law or agreed to in writing, -->
|
||||
<!--- software distributed under the License is distributed on an -->
|
||||
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
|
||||
<!--- KIND, either express or implied. See the License for the -->
|
||||
<!--- specific language governing permissions and limitations -->
|
||||
<!--- under the License. -->
|
||||
|
||||
These scripts can be helpful when creating release notes and testing release packages.
|
||||
|
||||
# Create release notes
|
||||
|
||||
```bash
|
||||
# example: create a csv file of all PRs since the v0.8 and v0.9.0 releases
|
||||
# the result will be in 2 CSV files based on the --threshold arg (small PRs vs large PRs)
|
||||
export GITHUB_TOKEN=<github oauth token>
|
||||
python release/gather_prs.py --from-commit $(git rev-parse v0.9.0) --to-commit $(git merge-base origin/main v0.8.0)
|
||||
```
|
||||
|
||||
After running the commands above, you will get a csv file named `out_pr_gathered.csv`. You can then import this CSV into a collaborative spreadsheet editor to distribute the work of categorizing PRs for the notes, **especially check the `pr_title_tags` column for each row and correct it if it's wrong**.
|
||||
|
||||
Once done, you can download the csv file assuming with name `out_pr_gathered_corrected.csv` and convert it to readable release notes using commands below:
|
||||
|
||||
```bash
|
||||
# example: use a csv of tags-corrected PRs to create a markdown file
|
||||
|
||||
# Export monthly report on forum:
|
||||
python make_notes.py --notes out_pr_gathered_corrected.csv --is-pr-with-link true > monthly_report.md
|
||||
|
||||
# Export release report on GitHub:
|
||||
python make_notes.py --notes out_pr_gathered_corrected.csv --is-pr-with-link true > release_report.md
|
||||
|
||||
# If release report exported but forget set `--is-pr-with-link true`,
|
||||
# you can append arg `--convert-with-link true`.
|
||||
python3 make_notes.py --notes ./release_report.md --convert-with-link true
|
||||
```
|
||||
|
||||
You can also create a list of RFCs
|
||||
|
||||
```bash
|
||||
git clone https://github.com/apache/tvm-rfcs.git
|
||||
|
||||
# example: list RFCs since a specific commit in the tvm-rfcs repo
|
||||
python list_rfcs.py --since-commit <hash> --rfcs-repo ./tvm-rfcs > rfc.md
|
||||
```
|
||||
|
||||
Finally, combine `rfc.md` and `out.md` along with some prose to create the final release notes.
|
||||
|
||||
# Test release packages
|
||||
|
||||
After uploading release (candidate) packages to apache.org or GitHub release page, you can validate packages step-by-step from downloading, verification and compiling use script below, but don't forget edit the `version` and `rc` number in script.
|
||||
|
||||
```bash
|
||||
test_release_package.sh
|
||||
```
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ruff: noqa: E402, F401
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
sys.path.append(str(REPO_ROOT / "ci" / "scripts" / "jenkins"))
|
||||
|
||||
from cmd_utils import tags_from_title
|
||||
from git_utils import GitHubRepo, git
|
||||
|
||||
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
|
||||
|
||||
|
||||
PRS_QUERY = """
|
||||
query ($owner: String!, $name: String!, $after: String, $pageSize: Int!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
defaultBranchRef {
|
||||
name
|
||||
target {
|
||||
... on Commit {
|
||||
oid
|
||||
history(after: $after, first: $pageSize) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
oid
|
||||
committedDate
|
||||
associatedPullRequests(first: 1) {
|
||||
nodes {
|
||||
number
|
||||
additions
|
||||
changedFiles
|
||||
deletions
|
||||
author {
|
||||
login
|
||||
}
|
||||
title
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def append_and_save(items, file):
|
||||
if not file.exists():
|
||||
data = []
|
||||
else:
|
||||
with open(file, "rb") as f:
|
||||
data = pickle.load(f)
|
||||
|
||||
data += items
|
||||
with open(file, "wb") as f:
|
||||
pickle.dump(data, f)
|
||||
|
||||
|
||||
def fetch_pr_data(args, cache):
|
||||
github = GitHubRepo(user=user, repo=repo, token=GITHUB_TOKEN)
|
||||
|
||||
if args.from_commit is None or args.to_commit is None:
|
||||
print("--from-commit and --to-commit must be specified if --skip-query is not used")
|
||||
exit(1)
|
||||
|
||||
i = 0
|
||||
page_size = 80
|
||||
cursor = f"{args.from_commit} {i}"
|
||||
|
||||
while True:
|
||||
try:
|
||||
r = github.graphql(
|
||||
query=PRS_QUERY,
|
||||
variables={
|
||||
"owner": user,
|
||||
"name": repo,
|
||||
"after": cursor,
|
||||
"pageSize": page_size,
|
||||
},
|
||||
)
|
||||
except RuntimeError as e:
|
||||
print(f"{e}\nPlease check enviroment variable GITHUB_TOKEN whether is valid.")
|
||||
exit(1)
|
||||
data = r["data"]["repository"]["defaultBranchRef"]["target"]["history"]
|
||||
if not data["pageInfo"]["hasNextPage"]:
|
||||
break
|
||||
cursor = data["pageInfo"]["endCursor"]
|
||||
results = data["nodes"]
|
||||
|
||||
to_add = []
|
||||
stop = False
|
||||
for r in results:
|
||||
if r["oid"] == args.to_commit:
|
||||
print(f"Found {r['oid']}, stopping")
|
||||
stop = True
|
||||
break
|
||||
else:
|
||||
to_add.append(r)
|
||||
|
||||
oids = [r["oid"] for r in to_add]
|
||||
print(oids)
|
||||
append_and_save(to_add, cache)
|
||||
if stop:
|
||||
break
|
||||
print(i)
|
||||
i += page_size
|
||||
|
||||
|
||||
def write_csv(
|
||||
filename: str, data: list[dict[str, Any]], threshold_filter: Callable[[dict[str, Any]], bool]
|
||||
) -> None:
|
||||
with open(filename, "w", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile, quotechar='"')
|
||||
writer.writerow(
|
||||
(
|
||||
"category",
|
||||
"subject",
|
||||
"date",
|
||||
"url",
|
||||
"author",
|
||||
"pr_title_tags",
|
||||
"pr_title",
|
||||
"additions",
|
||||
"deletions",
|
||||
"additions+deletions>threshold",
|
||||
"changed_files",
|
||||
)
|
||||
)
|
||||
for item in data:
|
||||
nodes = item["associatedPullRequests"]["nodes"]
|
||||
if len(nodes) == 0:
|
||||
continue
|
||||
pr = nodes[0]
|
||||
tags = tags_from_title(pr["title"])
|
||||
actual_tags = []
|
||||
for t in tags:
|
||||
items = [x.strip() for x in t.split(",")]
|
||||
actual_tags += items
|
||||
tags = actual_tags
|
||||
tags = [t.lower() for t in tags]
|
||||
category = tags[0] if len(tags) > 0 else ""
|
||||
author = pr["author"] if pr["author"] else "ghost"
|
||||
author = author.get("login", "") if isinstance(author, dict) else author
|
||||
writer.writerow(
|
||||
(
|
||||
category,
|
||||
"n/a",
|
||||
item["committedDate"],
|
||||
f"https://github.com/apache/tvm/pull/{pr['number']}",
|
||||
author,
|
||||
"/".join(tags),
|
||||
pr["title"].replace(",", " "),
|
||||
pr["additions"],
|
||||
pr["deletions"],
|
||||
1 if threshold_filter(pr) else 0,
|
||||
pr["changedFiles"],
|
||||
)
|
||||
)
|
||||
print(f"{filename} generated!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
help = "List out commits with attached PRs since a certain commit"
|
||||
parser = argparse.ArgumentParser(description=help)
|
||||
parser.add_argument("--from-commit", help="commit to start checking PRs from")
|
||||
parser.add_argument("--to-commit", help="commit to stop checking PRs from")
|
||||
parser.add_argument(
|
||||
"--threshold", default=0, help="sum of additions + deletions to consider large, such as 150"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-query", action="store_true", help="don't query GitHub and instead use cache file"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
user = "apache"
|
||||
repo = "tvm"
|
||||
threshold = int(args.threshold)
|
||||
|
||||
cache = Path("out.pkl")
|
||||
if not args.skip_query:
|
||||
fetch_pr_data(args, cache)
|
||||
|
||||
with open(cache, "rb") as f:
|
||||
data = pickle.load(f)
|
||||
|
||||
print(f"Found {len(data)} PRs")
|
||||
|
||||
write_csv(
|
||||
filename="out_pr_gathered.csv",
|
||||
data=data,
|
||||
threshold_filter=lambda pr: pr["additions"] + pr["deletions"] > threshold,
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
LINK_BASE = "https://github.com/apache/tvm-rfcs/blob/main/"
|
||||
COMMIT_BASE = "https://github.com/apache/tvm-rfcs/commit/"
|
||||
|
||||
|
||||
def sprint(*args):
|
||||
print(*args, file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
help = "List out RFCs since a commit"
|
||||
parser = argparse.ArgumentParser(description=help)
|
||||
parser.add_argument("--since-commit", required=True, help="last commit to include")
|
||||
parser.add_argument("--rfcs-repo", required=True, help="path to checkout of apache/tvm-rfcs")
|
||||
args = parser.parse_args()
|
||||
user = "apache"
|
||||
repo = "tvm"
|
||||
rfc_repo = args.rfcs_repo
|
||||
subprocess.run("git fetch origin main", cwd=rfc_repo, shell=True)
|
||||
subprocess.run("git checkout main", cwd=rfc_repo, shell=True)
|
||||
subprocess.run("git reset --hard origin/main", cwd=rfc_repo, shell=True)
|
||||
r = subprocess.run(
|
||||
f"git log {args.since_commit}..HEAD --format='%H %s'",
|
||||
cwd=rfc_repo,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
commits = r.stdout.strip().split("\n")
|
||||
for commit in commits:
|
||||
parts = commit.split()
|
||||
commit = parts[0]
|
||||
subject = " ".join(parts[1:])
|
||||
|
||||
r2 = subprocess.run(
|
||||
f"git diff-tree --no-commit-id --name-only -r {commit}",
|
||||
cwd=rfc_repo,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
files = r2.stdout.strip().split("\n")
|
||||
rfc_file = None
|
||||
for file in files:
|
||||
if file.startswith("rfcs/") and file.endswith(".md"):
|
||||
if rfc_file is not None:
|
||||
sprint(f"error on {commit} {subject}")
|
||||
rfc_file = file
|
||||
|
||||
if rfc_file is None:
|
||||
sprint(f"error on {commit} {subject}")
|
||||
continue
|
||||
|
||||
print(f" * [{subject}]({LINK_BASE + rfc_file}) ([`{commit[:7]}`]({COMMIT_BASE + commit}))")
|
||||
@@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env python3
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
sys.path.append(str(REPO_ROOT / "tests" / "scripts"))
|
||||
sys.path.append(str(REPO_ROOT / "tests" / "scripts" / "github"))
|
||||
sys.path.append(str(REPO_ROOT / "tests" / "scripts" / "jenkins"))
|
||||
|
||||
# Tag dictionary used to create a mapping relation to categorize PRs owning same tag.
|
||||
TAG_DICT = {
|
||||
"metaschedule": "MetaSchedule",
|
||||
"cuda": "cuda & cutlass & tensorrt",
|
||||
"cutlass": "cuda & cutlass & tensorrt",
|
||||
"tensorrt": "cuda & cutlass & tensorrt",
|
||||
"hexagon": "Hexagon",
|
||||
"metal": "Metal",
|
||||
"vulkan": "Vulkan",
|
||||
"clml": "OpenCL & CLML",
|
||||
"opencl": "OpenCL & CLML",
|
||||
"openclml": "OpenCL & CLML",
|
||||
"adreno": "Adreno",
|
||||
"acl": "ArmComputeLibrary",
|
||||
"rocm": "ROCm",
|
||||
"crt": "CRT",
|
||||
"web": "web",
|
||||
"wasm": "web",
|
||||
"runtime": "Runtime",
|
||||
"aot": "AOT",
|
||||
"arith": "Arith",
|
||||
"byoc": "BYOC",
|
||||
"community": "Community",
|
||||
"tensorir": "TIR",
|
||||
"tirx": "TIR",
|
||||
"tensorflow": "Frontend",
|
||||
"tflite": "Frontend",
|
||||
"pytorch": "Frontend",
|
||||
"torch": "Frontend",
|
||||
"keras": "Frontend",
|
||||
"frontend": "Frontend",
|
||||
"onnx": "Frontend",
|
||||
"roofline": "Misc",
|
||||
"rpc": "Misc",
|
||||
"tophub": "Misc",
|
||||
"ux": "Misc",
|
||||
"APP": "Misc",
|
||||
"docker": "Docker",
|
||||
"doc": "Docs",
|
||||
"docs": "Docs",
|
||||
"llvm": "LLVM",
|
||||
"sve": "LLVM",
|
||||
"ci": "CI",
|
||||
"test": "CI",
|
||||
"tests": "CI",
|
||||
"testing": "CI",
|
||||
"unittest": "CI",
|
||||
"bugfix": "BugFix",
|
||||
"fix": "BugFix",
|
||||
"bug": "BugFix",
|
||||
"hotfix": "BugFix",
|
||||
"qnn": "Relay",
|
||||
"quantization": "Relay",
|
||||
"relax": "Relax",
|
||||
"unity": "Relax",
|
||||
"transform": "Relax",
|
||||
"kvcache": "Relax",
|
||||
"s_tir": "S-TIR",
|
||||
"disco": "Disco",
|
||||
"tvmscript": "TVMScript",
|
||||
"tvmscripts": "TVMScript",
|
||||
"tvmc": "TVMC",
|
||||
"topi": "TOPI",
|
||||
}
|
||||
|
||||
|
||||
def strip_header(title: str, header: str) -> str:
|
||||
pos = title.lower().find(header.lower())
|
||||
if pos == -1:
|
||||
return title
|
||||
|
||||
return title[0:pos] + title[pos + len(header) :].strip()
|
||||
|
||||
|
||||
def sprint(*args):
|
||||
print(*args, file=sys.stderr)
|
||||
|
||||
|
||||
def create_pr_dict(cache: Path):
|
||||
with open(cache, "rb") as f:
|
||||
data = pickle.load(f)
|
||||
|
||||
sprint(data[1])
|
||||
pr_dict = {}
|
||||
for item in data:
|
||||
prs = item["associatedPullRequests"]["nodes"]
|
||||
if len(prs) != 1:
|
||||
continue
|
||||
|
||||
pr = prs[0]
|
||||
pr_dict[pr["number"]] = pr
|
||||
return pr_dict
|
||||
|
||||
|
||||
def categorize_csv_file(csv_path: str):
|
||||
headings = defaultdict(lambda: defaultdict(list))
|
||||
sprint("Opening CSV")
|
||||
with open(csv_path) as f:
|
||||
input_file = csv.DictReader(f)
|
||||
|
||||
i = 0
|
||||
blank_cate_set = {"Misc"}
|
||||
for row in input_file:
|
||||
# print(row)
|
||||
tags = row["pr_title_tags"].split("/")
|
||||
tags = ["misc"] if len(tags) == 0 else tags
|
||||
|
||||
categories = map(lambda t: TAG_DICT.get(t.lower(), "Misc"), tags)
|
||||
categories = list(categories)
|
||||
categories = list(set(categories) - blank_cate_set)
|
||||
category = "Misc" if len(categories) == 0 else categories[0]
|
||||
|
||||
subject = row["subject"].strip()
|
||||
pr_number = row["url"].split("/")[-1]
|
||||
|
||||
if category == "" or subject == "":
|
||||
sprint(f"Skipping {i}th pr with number: {pr_number}, row: {row}")
|
||||
continue
|
||||
|
||||
headings[category][subject].append(pr_number)
|
||||
i += 1
|
||||
# if i > 30:
|
||||
# break
|
||||
return headings
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
help = "List out commits with attached PRs since a certain commit"
|
||||
parser = argparse.ArgumentParser(description=help)
|
||||
parser.add_argument(
|
||||
"--notes", required=True, help="csv or markdown file of categorized PRs in order"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--is-pr-with-link",
|
||||
required=False,
|
||||
help="exported pr number with hyper-link for forum format",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--convert-with-link",
|
||||
required=False,
|
||||
help="make PR number in markdown file owning hyper-link",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
user = "apache"
|
||||
repo = "tvm"
|
||||
|
||||
if args.convert_with_link:
|
||||
with open(args.notes) as f:
|
||||
lines = f.readlines()
|
||||
formated = []
|
||||
for line in lines:
|
||||
match = re.search(r"#\d+", line)
|
||||
if match:
|
||||
pr_num_str = match.group()
|
||||
pr_num_int = pr_num_str.replace("#", "")
|
||||
pr_number_str = f"[#{pr_num_int}](https://github.com/apache/tvm/pull/{pr_num_int})"
|
||||
line = line.replace(pr_num_str, pr_number_str)
|
||||
formated.append(line)
|
||||
result = "".join(formated)
|
||||
print(result)
|
||||
exit(0)
|
||||
|
||||
# 1. Create PR dict from cache file
|
||||
cache = Path("out.pkl")
|
||||
if not cache.exists():
|
||||
sprint("run gather_prs.py first to generate out.pkl")
|
||||
exit(1)
|
||||
pr_dict = create_pr_dict(cache)
|
||||
|
||||
# 2. Categorize csv file as dict by category and subject (sub-category)
|
||||
headings = categorize_csv_file(args.notes)
|
||||
|
||||
# 3. Summarize and sort all categories
|
||||
def sorter(x):
|
||||
if x == "Misc":
|
||||
return 10
|
||||
return 0
|
||||
|
||||
keys = list(headings.keys())
|
||||
keys = list(sorted(keys))
|
||||
keys = list(sorted(keys, key=sorter))
|
||||
|
||||
# 4. Generate markdown by loop categorized csv file dict
|
||||
def pr_title(number, heading):
|
||||
# print(f"number:{number}, heading:{heading}, len(pr_dict):{len(pr_dict)}")
|
||||
try:
|
||||
title = pr_dict[int(number)]["title"]
|
||||
title = strip_header(title, heading)
|
||||
except Exception:
|
||||
sprint("The out.pkl file is not match with csv file.")
|
||||
exit(1)
|
||||
return title
|
||||
|
||||
output = ""
|
||||
for key in keys:
|
||||
value = headings[key]
|
||||
if key == "DO NOT INCLUDE":
|
||||
continue
|
||||
value = dict(value)
|
||||
output += f"### {key}\n"
|
||||
misc = []
|
||||
misc += value.get("n/a", [])
|
||||
misc += value.get("Misc", [])
|
||||
for pr_number in misc:
|
||||
if args.is_pr_with_link:
|
||||
pr_number_str = f"[#{pr_number}](https://github.com/apache/tvm/pull/{pr_number})"
|
||||
else:
|
||||
pr_number_str = f"#{pr_number}"
|
||||
pr_str = f" * {pr_number_str} - {pr_title(pr_number, '[' + key + ']')}\n"
|
||||
output += pr_str
|
||||
|
||||
for subheading, pr_numbers in value.items():
|
||||
if subheading == "DO NOT INCLUDE":
|
||||
continue
|
||||
if subheading == "n/a" or subheading == "Misc":
|
||||
continue
|
||||
else:
|
||||
output += f" * {subheading} - " + ", ".join([f"#{n}" for n in pr_numbers]) + "\n"
|
||||
# print(value)
|
||||
|
||||
output += "\n"
|
||||
|
||||
# 5. Print markdown-format output
|
||||
print(output)
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
set -exu
|
||||
|
||||
######################################################
|
||||
# Write current test version and rc number here
|
||||
######################################################
|
||||
# NOTE about "rc":
|
||||
# 1. Required for test candidate, such as "rc0"
|
||||
# 2. Not required for release, leave blank ""
|
||||
######################################################
|
||||
version="v0.16.0"
|
||||
rc="rc0"
|
||||
|
||||
######################################################
|
||||
# This script is used test release (cancdidate)
|
||||
# packages uploading to apache.org, github.com
|
||||
# before release vote starts or release.
|
||||
#
|
||||
# The release (candidate) package contains files
|
||||
# below:
|
||||
# 1. apache-tvm-src-${version_rc}.tar.gz.asc
|
||||
# 2. apache-tvm-src-${version_rc}.tar.gz.sha512
|
||||
# 3. apache-tvm-src-${version_rc}.tar.gz
|
||||
######################################################
|
||||
version_rc="${version}"
|
||||
apache_prefix="${version}"
|
||||
if [ "$rc" != "" ]; then
|
||||
apache_prefix="${version_rc}-${rc}"
|
||||
version_rc="${version_rc}.${rc}"
|
||||
fi
|
||||
mkdir test_tvm_${version_rc}
|
||||
cd test_tvm_${version_rc}
|
||||
|
||||
echo "[setup] Create an isolated virtualenv ..."
|
||||
# Used for the build, dependency install, and import below so this script never
|
||||
# pollutes the caller's environment and works on PEP 668 "externally-managed"
|
||||
# system pythons. Requires the venv module (e.g. the python3-venv package on Debian).
|
||||
python3 -m venv .venv
|
||||
export PATH="$PWD/.venv/bin:$PATH"
|
||||
python3 -m pip install --upgrade pip
|
||||
|
||||
echo "[1/10] Downloading from apache.org ..."
|
||||
mkdir apache
|
||||
cd apache
|
||||
wget -c https://dist.apache.org/repos/dist/dev/tvm/tvm-${apache_prefix}/apache-tvm-src-${version_rc}.tar.gz.sha512
|
||||
wget -c https://dist.apache.org/repos/dist/dev/tvm/tvm-${apache_prefix}/apache-tvm-src-${version_rc}.tar.gz.asc
|
||||
wget -c https://dist.apache.org/repos/dist/dev/tvm/tvm-${apache_prefix}/apache-tvm-src-${version_rc}.tar.gz
|
||||
md5sum ./* > ./md5sum.txt
|
||||
cd -
|
||||
|
||||
echo "[2/10] Downloading from github.com ..."
|
||||
mkdir github
|
||||
cd github
|
||||
wget -c https://github.com/apache/tvm/releases/download/${version_rc}/apache-tvm-src-${version_rc}.tar.gz.sha512
|
||||
wget -c https://github.com/apache/tvm/releases/download/${version_rc}/apache-tvm-src-${version_rc}.tar.gz.asc
|
||||
wget -c https://github.com/apache/tvm/releases/download/${version_rc}/apache-tvm-src-${version_rc}.tar.gz
|
||||
md5sum ./* > ./md5sum.txt
|
||||
cd -
|
||||
|
||||
echo "[3/10] Check difference between github.com and apache.org ..."
|
||||
diff github/md5sum.txt ./apache/md5sum.txt
|
||||
|
||||
echo "[4/10] Checking asc ..."
|
||||
cd github
|
||||
gpg --verify ./apache-tvm-src-${version_rc}.tar.gz.asc ./apache-tvm-src-${version_rc}.tar.gz
|
||||
|
||||
echo "[5/10] Checking sha512 ..."
|
||||
sha512sum -c ./apache-tvm-src-${version_rc}.tar.gz.sha512
|
||||
|
||||
echo "[6/10] Unzip ..."
|
||||
tar -zxf apache-tvm-src-${version_rc}.tar.gz
|
||||
|
||||
echo "[7/10] Checking whether binary in source code ..."
|
||||
output=`find apache-tvm-src-${version} -type f -exec file {} + | grep -w "ELF\|shared object" || true`
|
||||
if [[ -n "$output" ]]; then
|
||||
echo "Error: ELF or shared object files found:"
|
||||
echo "$output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[8/10] Compile and Python Import on Linux ..."
|
||||
cd apache-tvm-src-${version}
|
||||
mkdir build
|
||||
cd build
|
||||
cp ../cmake/config.cmake .
|
||||
cmake ..
|
||||
make -j16
|
||||
cd ..
|
||||
|
||||
echo "[9/10] Install Python runtime dependencies (declared in the source pyproject.toml) ..."
|
||||
# Single source of truth: install exactly the runtime deps the release declares, so
|
||||
# this never needs version/list maintenance when the project's dependencies change.
|
||||
deps=$(python3 - <<'PY'
|
||||
import re
|
||||
|
||||
text = open("pyproject.toml").read()
|
||||
match = re.search(r"(?ms)^dependencies\s*=\s*\[(.*?)\]", text)
|
||||
print(" ".join(re.findall(r'"([^"]+)"', match.group(1))))
|
||||
PY
|
||||
)
|
||||
echo "Installing declared runtime deps: ${deps}"
|
||||
python3 -m pip install ${deps}
|
||||
|
||||
echo "[10/10] Import TVM and print path ..."
|
||||
export TVM_HOME=$(pwd)
|
||||
export PYTHONPATH=$TVM_HOME/python:${PYTHONPATH:-}
|
||||
python3 -c "import tvm; print(tvm.__path__)"
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ruff: noqa: E402
|
||||
import argparse
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Hackery to enable importing of utils from ci/scripts/jenkins
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
sys.path.append(str(REPO_ROOT / "ci" / "scripts" / "jenkins"))
|
||||
from cmd_utils import REPO_ROOT, Sh, init_log
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_log()
|
||||
|
||||
parser = argparse.ArgumentParser(description="List pytest nodeids for a folder")
|
||||
parser.add_argument("--sccache-bucket", required=False, help="sccache bucket name")
|
||||
parser.add_argument("--sccache-region", required=False, help="sccache region")
|
||||
parser.add_argument("--build-dir", default="build", help="build folder")
|
||||
parser.add_argument("--cmake-target", help="optional build target")
|
||||
parser.add_argument("--debug", required=False, action="store_true", help="build in debug mode")
|
||||
args = parser.parse_args()
|
||||
sccache_exe = shutil.which("sccache")
|
||||
|
||||
if args.cmake_target in ["standalone_crt", "crttest"]:
|
||||
logging.info("Skipping standalone_crt build")
|
||||
exit(0)
|
||||
|
||||
use_sccache = sccache_exe is not None
|
||||
build_dir = Path(os.getcwd()) / args.build_dir
|
||||
build_dir = build_dir.relative_to(REPO_ROOT)
|
||||
env = {}
|
||||
|
||||
if use_sccache:
|
||||
if args.sccache_bucket and "AWS_ACCESS_KEY_ID" in os.environ:
|
||||
env["SCCACHE_BUCKET"] = args.sccache_bucket
|
||||
env["SCCACHE_REGION"] = args.sccache_region if args.sccache_region else "us-west-2"
|
||||
logging.info(f"Using sccache bucket: {args.sccache_bucket}")
|
||||
logging.info(f"Using sccache region: {env['SCCACHE_REGION']}")
|
||||
else:
|
||||
logging.info("No sccache bucket set, using local cache")
|
||||
if "SCCACHE_SERVER_PORT" in os.environ:
|
||||
env["SCCACHE_SERVER_PORT"] = os.getenv("SCCACHE_SERVER_PORT")
|
||||
env["CXX"] = "/opt/sccache/c++"
|
||||
env["CC"] = "/opt/sccache/cc"
|
||||
|
||||
else:
|
||||
if sccache_exe is None:
|
||||
reason = "'sccache' executable not found"
|
||||
else:
|
||||
reason = "<unknown>"
|
||||
logging.info(f"Not using sccache, reason: {reason}")
|
||||
|
||||
sh = Sh(env)
|
||||
|
||||
if use_sccache:
|
||||
sh.run("sccache --start-server", check=False)
|
||||
logging.info("===== sccache stats =====")
|
||||
sh.run("sccache --show-stats")
|
||||
|
||||
executors = int(os.environ.get("CI_NUM_EXECUTORS", 1))
|
||||
build_platform = os.environ.get("PLATFORM", None)
|
||||
|
||||
nproc = multiprocessing.cpu_count()
|
||||
|
||||
available_cpus = nproc // executors
|
||||
num_cpus = max(available_cpus, 1)
|
||||
|
||||
if args.debug:
|
||||
sh.run("cmake -GNinja -DCMAKE_BUILD_TYPE=Debug ..", cwd=build_dir)
|
||||
else:
|
||||
sh.run("cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..", cwd=build_dir)
|
||||
|
||||
target = ""
|
||||
if args.cmake_target:
|
||||
target = args.cmake_target
|
||||
|
||||
verbose = os.environ.get("VERBOSE", "true").lower() in {"1", "true", "yes"}
|
||||
ninja_args = [target, f"-j{num_cpus}"]
|
||||
if verbose:
|
||||
ninja_args.append("-v")
|
||||
|
||||
sh.run("cmake --build . -- " + " ".join(ninja_args), cwd=build_dir)
|
||||
|
||||
if use_sccache:
|
||||
logging.info("===== sccache stats =====")
|
||||
sh.run("sccache --show-stats")
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
BUILD_DIR=$1
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cp ../cmake/config.cmake .
|
||||
|
||||
echo set\(USE_SORT ON\) >> config.cmake
|
||||
echo set\(USE_RPC ON\) >> config.cmake
|
||||
echo set\(USE_LLVM llvm-config-17\) >> config.cmake
|
||||
echo set\(CMAKE_CXX_FLAGS -Werror\) >> config.cmake
|
||||
echo set\(USE_CCACHE OFF\) >> config.cmake
|
||||
echo set\(SUMMARIZE ON\) >> config.cmake
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
BUILD_DIR=$1
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cp ../cmake/config.cmake .
|
||||
|
||||
echo set\(USE_SORT ON\) >> config.cmake
|
||||
echo set\(USE_DNNL ON\) >> config.cmake
|
||||
echo set\(USE_EXAMPLE_NPU_CODEGEN ON\) >> config.cmake
|
||||
echo set\(USE_EXAMPLE_NPU_RUNTIME ON\) >> config.cmake
|
||||
echo set\(USE_LLVM \"/usr/bin/llvm-config-17 --link-static\"\) >> config.cmake
|
||||
echo set\(CMAKE_CXX_FLAGS \"-Wno-error=range-loop-construct -Wno-error=comment\"\) >> config.cmake
|
||||
echo set\(HIDE_PRIVATE_SYMBOLS ON\) >> config.cmake
|
||||
echo set\(USE_TENSORFLOW_PATH \"/tensorflow\"\) >> config.cmake
|
||||
echo set\(USE_TFLITE \"/opt/tflite\"\) >> config.cmake
|
||||
echo set\(USE_FLATBUFFERS_PATH \"/flatbuffers\"\) >> config.cmake
|
||||
echo set\(USE_CCACHE OFF\) >> config.cmake
|
||||
echo set\(SUMMARIZE ON\) >> config.cmake
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
BUILD_DIR=$1
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cp ../cmake/config.cmake .
|
||||
|
||||
echo set\(USE_CUBLAS ON\) >> config.cmake
|
||||
echo set\(USE_CUDNN ON\) >> config.cmake
|
||||
echo set\(USE_CUDA ON\) >> config.cmake
|
||||
echo set\(USE_VULKAN ON\) >> config.cmake
|
||||
echo set\(USE_OPENCL ON\) >> config.cmake
|
||||
echo set\(USE_OPENCL_GTEST \"/googletest\"\) >> config.cmake
|
||||
echo set\(USE_LLVM \"/usr/bin/llvm-config-15 --link-static\"\) >> config.cmake
|
||||
echo set\(USE_RPC ON\) >> config.cmake
|
||||
echo set\(USE_SORT ON\) >> config.cmake
|
||||
echo set\(USE_BLAS openblas\) >> config.cmake
|
||||
echo set\(CMAKE_CXX_FLAGS -Werror\) >> config.cmake
|
||||
echo set\(USE_TENSORRT_CODEGEN ON\) >> config.cmake
|
||||
echo set\(USE_CCACHE OFF\) >> config.cmake
|
||||
echo set\(SUMMARIZE ON\) >> config.cmake
|
||||
echo set\(HIDE_PRIVATE_SYMBOLS ON\) >> config.cmake
|
||||
echo set\(USE_CUTLASS ON\) >> config.cmake
|
||||
echo set\(CMAKE_CUDA_ARCHITECTURES 75\) >> config.cmake
|
||||
echo set\(USE_CLML ON\) >> config.cmake
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This file is a compiler test to ensure that runtimes can compile
|
||||
# correctly, even if they aren't actively tested in the CI.
|
||||
set -euxo pipefail
|
||||
|
||||
BUILD_DIR=$1
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cp ../cmake/config.cmake .
|
||||
|
||||
echo set\(USE_OPENCL ON\) >> config.cmake
|
||||
echo set\(USE_ROCM ON\) >> config.cmake
|
||||
echo set\(CMAKE_CXX_FLAGS -Werror\) >> config.cmake
|
||||
echo set\(USE_CCACHE OFF\) >> config.cmake
|
||||
echo set\(SUMMARIZE ON\) >> config.cmake
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
BUILD_DIR=$1
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cp ../cmake/config.cmake .
|
||||
|
||||
echo set\(USE_SORT ON\) >> config.cmake
|
||||
echo set\(USE_LLVM llvm-config-15\) >> config.cmake
|
||||
echo set\(CMAKE_CXX_FLAGS -Werror\) >> config.cmake
|
||||
echo set\(HIDE_PRIVATE_SYMBOLS ON\) >> config.cmake
|
||||
echo set\(USE_CCACHE OFF\) >> config.cmake
|
||||
echo set\(SUMMARIZE ON\) >> config.cmake
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
BUILD_DIR="$1"
|
||||
elif [ -n "${TVM_BUILD_PATH:-}" ]; then
|
||||
# TVM_BUILD_PATH may contain multiple space-separated paths. If
|
||||
# so, use the first one.
|
||||
BUILD_DIR=$(IFS=" "; set -- $TVM_BUILD_PATH; echo $1)
|
||||
else
|
||||
BUILD_DIR=build
|
||||
fi
|
||||
|
||||
# to avoid CI thread throttling.
|
||||
export TVM_BIND_THREADS=0
|
||||
export OMP_NUM_THREADS=1
|
||||
|
||||
pushd "${BUILD_DIR}"
|
||||
# run cpp test executable
|
||||
./cpptest
|
||||
popd
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
export PYTHONPATH=python
|
||||
export LD_LIBRARY_PATH="lib:${LD_LIBRARY_PATH:-}"
|
||||
|
||||
# to avoid CI CPU thread throttling.
|
||||
export TVM_BIND_THREADS=0
|
||||
export OMP_NUM_THREADS=1
|
||||
|
||||
CURR_DIR=$(cd `dirname $0`; pwd)
|
||||
SCRIPT_DIR=$CURR_DIR/../../jvm/core/src/test/scripts
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -rf "$TEMP_DIR"
|
||||
}
|
||||
trap cleanup 0
|
||||
|
||||
bash "$(dirname "$0")/task_jvm_build.sh"
|
||||
|
||||
# Skip the Java Tests for now
|
||||
exit 0
|
||||
|
||||
# expose tvm runtime lib to system env
|
||||
export LD_LIBRARY_PATH=$CURR_DIR/../../build/:$LD_LIBRARY_PATH
|
||||
python "$SCRIPT_DIR"/prepare_test_libs.py "$TEMP_DIR"
|
||||
JVM_TEST_ARGS="-DskipTests=false -Dtest.tempdir=$TEMP_DIR" \
|
||||
bash "$(dirname "$0")/task_jvm_build.sh"
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# Build the TVM JVM package (tvm4j) using Maven with platform detection.
|
||||
# Usage: task_jvm_build.sh [goal] [mvn-extra-args...]
|
||||
#
|
||||
# The first positional argument sets the Maven goal (default: "clean package").
|
||||
# Extra arguments after the goal are passed through to mvn, e.g.:
|
||||
# task_jvm_build.sh install
|
||||
# task_jvm_build.sh "clean package" -DskipTests=false -Dtest.tempdir=/tmp/foo
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
GOAL="${1:-clean package}"
|
||||
if [ "$#" -gt 0 ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
TVM_BUILD_PATH="${TVM_BUILD_PATH:-${ROOTDIR}/build}"
|
||||
TVM_BUILD_PATH="$(realpath "${TVM_BUILD_PATH}")"
|
||||
|
||||
DLPACK_PATH="${DLPACK_PATH:-${ROOTDIR}/3rdparty/tvm-ffi/3rdparty/dlpack}"
|
||||
|
||||
INCLUDE_FLAGS="-I${ROOTDIR}/include -I${DLPACK_PATH}/include"
|
||||
PKG_CFLAGS="-Wall -O3 ${INCLUDE_FLAGS} -fPIC"
|
||||
PKG_LDFLAGS=""
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
JVM_PKG_PROFILE="osx-x86_64"
|
||||
SHARED_LIBRARY_SUFFIX="dylib"
|
||||
elif [ "${OS:-}" = "Windows_NT" ]; then
|
||||
JVM_PKG_PROFILE="windows"
|
||||
SHARED_LIBRARY_SUFFIX="dll"
|
||||
else
|
||||
JVM_PKG_PROFILE="linux-x86_64"
|
||||
SHARED_LIBRARY_SUFFIX="so"
|
||||
fi
|
||||
|
||||
JVM_TEST_ARGS="${JVM_TEST_ARGS:--DskipTests -Dcheckstyle.skip=true}"
|
||||
|
||||
cd "${ROOTDIR}/jvm"
|
||||
# shellcheck disable=SC2086
|
||||
mvn ${GOAL} \
|
||||
"-P${JVM_PKG_PROFILE}" \
|
||||
"-Dcxx=${CXX:-g++}" \
|
||||
"-Dcflags=${PKG_CFLAGS}" \
|
||||
"-Dldflags=${PKG_LDFLAGS}" \
|
||||
"-Dcurrent_libdir=${TVM_BUILD_PATH}" \
|
||||
${JVM_TEST_ARGS} \
|
||||
"$@"
|
||||
Executable
+185
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
export PYTHONPATH="$(pwd)/python"
|
||||
|
||||
# to avoid CI CPU thread throttling.
|
||||
export TVM_BIND_THREADS=0
|
||||
export OMP_NUM_THREADS=1
|
||||
IS_LOCAL=${IS_LOCAL:-0}
|
||||
PYTHON_DOCS_ONLY=${PYTHON_DOCS_ONLY:-0}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -rf /tmp/$$.log.txt
|
||||
}
|
||||
trap cleanup 0
|
||||
|
||||
clean_files() {
|
||||
# cleanup old states
|
||||
rm -rf docs/_build
|
||||
rm -rf docs/_staging
|
||||
mkdir -p docs/_build/html
|
||||
mkdir -p docs/_staging/html
|
||||
rm -rf docs/gen_modules
|
||||
rm -rf docs/doxygen
|
||||
find . -type f -path "*.pyc" | xargs rm -f
|
||||
}
|
||||
|
||||
sphinx_precheck() {
|
||||
clean_files
|
||||
echo "PreCheck sphinx doc generation WARNINGS.."
|
||||
|
||||
# setup tvm-ffi into python folder
|
||||
uv pip install -v --target=python ./3rdparty/tvm-ffi/
|
||||
|
||||
pushd docs
|
||||
make clean
|
||||
TVM_TUTORIAL_EXEC_PATTERN=none make html 2>&1 | tee /tmp/$$.log.txt
|
||||
check_sphinx_warnings "docs"
|
||||
popd
|
||||
}
|
||||
|
||||
|
||||
function join_by { local IFS="$1"; shift; echo "$*"; }
|
||||
|
||||
|
||||
# These warnings are produced during the docs build for various reasons and are
|
||||
# known to not signficantly affect the output. Don't add anything new to this
|
||||
# list without special consideration of its effects, and don't add anything with
|
||||
# a '|' character.
|
||||
IGNORED_WARNINGS=(
|
||||
'__mro__'
|
||||
'UserWarning'
|
||||
'FutureWarning'
|
||||
'tensorflow'
|
||||
'Keras'
|
||||
'pytorch'
|
||||
'TensorFlow'
|
||||
'coremltools'
|
||||
'403'
|
||||
'git describe'
|
||||
'scikit-learn version'
|
||||
'doing serial write'
|
||||
'gen_gallery extension is not safe for parallel'
|
||||
'strategy:conv2d NHWC layout is not optimized for x86 with autotvm.'
|
||||
'strategy:depthwise_conv2d NHWC layout is not optimized for x86 with autotvm.'
|
||||
'strategy:depthwise_conv2d with layout NHWC is not optimized for arm cpu.'
|
||||
'strategy:dense is not optimized for arm cpu.'
|
||||
'autotvm:Cannot find config for target=llvm -keys=cpu'
|
||||
'autotvm:One or more operators have not been tuned. Please tune your model for better performance. Use DEBUG logging level to see more details.'
|
||||
'autotvm:Cannot find config for target=cuda -keys=cuda,gpu'
|
||||
'cannot cache unpickable configuration value:'
|
||||
'Invalid configuration value found: 'language = None'.'
|
||||
# Warning is thrown during TFLite quantization for micro_train tutorial
|
||||
'absl:For model inputs containing unsupported operations which cannot be quantized, the `inference_input_type` attribute will default to the original type.'
|
||||
'absl:Found untraced functions such as _jit_compiled_convolution_op'
|
||||
# TF C++ runtime prints this before absl logging is initialized
|
||||
'absl::InitializeLog'
|
||||
'absl:Please consider providing the trackable_obj argument'
|
||||
'You are using pip version'
|
||||
# Tutorial READMEs can be ignored, but other docs should be included
|
||||
"tutorials/README.rst: WARNING: document isn't included in any toctree"
|
||||
)
|
||||
|
||||
JOINED_WARNINGS=$(join_by '|' "${IGNORED_WARNINGS[@]}")
|
||||
|
||||
check_sphinx_warnings() {
|
||||
grep -v -E "$JOINED_WARNINGS" < /tmp/$$.log.txt > /tmp/$$.logclean.txt || true
|
||||
if grep --quiet -E "WARN" < /tmp/$$.logclean.txt; then
|
||||
echo "Lines with 'WARNING' found in the log, please fix them:"
|
||||
grep -E "WARN" < /tmp/$$.logclean.txt
|
||||
echo "You can reproduce locally by running 'python tests/scripts/ci.py $1'"
|
||||
exit 1
|
||||
fi
|
||||
echo "No WARNINGS to be fixed."
|
||||
}
|
||||
|
||||
# run precheck step first to fast-fail if there are problems with the docs
|
||||
if [ "$IS_LOCAL" != "1" ]; then
|
||||
echo "Running precheck"
|
||||
sphinx_precheck
|
||||
else
|
||||
# skip the precheck when doing local builds since it would add overhead to
|
||||
# re-runs (and tutorials are usually not enabled anyways)
|
||||
echo "Skipping precheck"
|
||||
fi
|
||||
|
||||
|
||||
clean_files
|
||||
|
||||
# cleanup stale log files
|
||||
find . -type f -path "*.log" | xargs rm -f
|
||||
find . -type f -path "*.pyc" | xargs rm -f
|
||||
|
||||
# setup tvm-ffi into python folder
|
||||
uv pip install -v --target=python ./3rdparty/tvm-ffi/
|
||||
|
||||
|
||||
cd docs
|
||||
PYTHONPATH=$(pwd)/../python make htmldepoly SPHINXOPTS='-j auto' |& tee /tmp/$$.log.txt
|
||||
if grep -E "failed to execute|Segmentation fault" < /tmp/$$.log.txt; then
|
||||
echo "Some of sphinx-gallery item example failed to execute."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_sphinx_warnings "docs --tutorial-pattern=.*"
|
||||
|
||||
cd ..
|
||||
|
||||
if [ "$IS_LOCAL" == "1" ] && [ "$PYTHON_DOCS_ONLY" == "1" ]; then
|
||||
echo "PYTHON_DOCS_ONLY was set, skipping other doc builds"
|
||||
rm -rf _docs
|
||||
mv docs/_build/html _docs
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# C++ doc
|
||||
doxygen docs/Doxyfile
|
||||
rm -f docs/doxygen/html/*.map docs/doxygen/html/*.md5
|
||||
|
||||
# Java doc
|
||||
(cd jvm && mvn "javadoc:javadoc" -Dnotimestamp=true)
|
||||
|
||||
# type doc
|
||||
cd web
|
||||
npm install
|
||||
npm run typedoc
|
||||
cd ..
|
||||
|
||||
# Prepare the doc dir
|
||||
rm -rf _docs
|
||||
mv docs/_build/html _docs
|
||||
rm -f _docs/.buildinfo
|
||||
mkdir -p _docs/reference/api
|
||||
mv docs/doxygen/html _docs/reference/api/doxygen
|
||||
mv jvm/core/target/site/apidocs _docs/reference/api/javadoc
|
||||
mv web/dist/docs _docs/reference/api/typedoc
|
||||
git rev-parse HEAD > _docs/commit_hash
|
||||
|
||||
if [ "$IS_LOCAL" != "1" ]; then
|
||||
echo "Start creating the docs tarball.."
|
||||
# make the tarball
|
||||
tar -C _docs -czf docs.tgz .
|
||||
echo "Finish creating the docs tarball"
|
||||
du -h docs.tgz
|
||||
|
||||
echo "Finish everything"
|
||||
fi
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
export PYTHONPATH="$(pwd)/python"
|
||||
export PYTEST_ADDOPTS="${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}"
|
||||
|
||||
# setup tvm-ffi into python folder
|
||||
uv pip install -v --target=python ./3rdparty/tvm-ffi/
|
||||
|
||||
python3 -m pytest -vvs -n auto -m "${TVM_TEST_MARKER:-not gpu}" tests/python
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
# Every GPU test carries the `gpu` marker; the specific backend is gated by skipif.
|
||||
export TVM_TEST_MARKER="gpu"
|
||||
|
||||
# Test most of the enabled runtimes here.
|
||||
# TODO: disabled opencl tests due to segmentation fault.
|
||||
export TVM_TEST_TARGETS='cuda;metal;rocm;nvptx'
|
||||
|
||||
./tests/scripts/task_python_unittest.sh
|
||||
|
||||
# Kept separate to avoid increasing time needed to run CI, testing
|
||||
# only minimal functionality of Vulkan runtime.
|
||||
export TVM_TEST_TARGETS='{"kind":"vulkan","from_device":0}'
|
||||
|
||||
export PYTHONPATH="$(pwd)/python"
|
||||
export PYTEST_ADDOPTS="${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}"
|
||||
|
||||
python3 -m pytest -vvs -n auto -m "${TVM_TEST_MARKER}" \
|
||||
tests/python/codegen/test_target_codegen_vulkan.py
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
echo "===== JENKINS INFO ====="
|
||||
echo "NODE_NAME=$NODE_NAME"
|
||||
echo "EXECUTOR_NUMBER=$EXECUTOR_NUMBER"
|
||||
echo "WORKSPACE=$WORKSPACE"
|
||||
echo "BUILD_NUMBER=$BUILD_NUMBER"
|
||||
echo "WORKSPACE=$WORKSPACE"
|
||||
|
||||
echo "===== EC2 INFO ====="
|
||||
function ec2_metadata() {
|
||||
# See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
|
||||
curl -w '\n' -fsSL "http://169.254.169.254/latest/meta-data/$1" || echo failed
|
||||
}
|
||||
|
||||
ec2_metadata ami-id
|
||||
ec2_metadata instance-id
|
||||
ec2_metadata instance-type
|
||||
ec2_metadata hostname
|
||||
ec2_metadata public-hostname
|
||||
|
||||
echo "===== RUNNER INFO ====="
|
||||
df --human-readable
|
||||
lscpu
|
||||
free
|
||||
nvidia-smi 2>/dev/null || echo "CUDA not found"
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
export PYTHONPATH=`pwd`/python
|
||||
|
||||
# setup tvm-ffi into python folder
|
||||
uv pip install -v --target=python ./3rdparty/tvm-ffi/
|
||||
|
||||
rm -rf .emscripten_cache
|
||||
cd web
|
||||
export EM_CACHE=`pwd`/.emscripten_cache
|
||||
make clean
|
||||
npm install
|
||||
npm run lint
|
||||
npm run prepwasm
|
||||
npm run bundle
|
||||
npm run test
|
||||
npm run typedoc
|
||||
cd ..
|
||||
Reference in New Issue
Block a user