chore: import upstream snapshot with attribution
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:25 +08:00
commit 26446540fa
3151 changed files with 974126 additions and 0 deletions
+672
View File
@@ -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()
+4
View File
@@ -0,0 +1,4 @@
*.md
!README.md
*.csv
*.pkl
+64
View File
@@ -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
```
+221
View File
@@ -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,
)
+75
View File
@@ -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}))")
+255
View File
@@ -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__)"
+106
View File
@@ -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")
+31
View File
@@ -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
+37
View File
@@ -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
+43
View File
@@ -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
+32
View File
@@ -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
+31
View File
@@ -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
+38
View File
@@ -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
+47
View File
@@ -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"
+66
View File
@@ -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} \
"$@"
+185
View File
@@ -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
+27
View File
@@ -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
View File
@@ -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
+44
View File
@@ -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"
+36
View File
@@ -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 ..