chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
.. 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.
|
||||
|
||||
.. _ci_guide:
|
||||
|
||||
Using TVM's CI
|
||||
==============
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
TVM uses a combination of Jenkins and GitHub Actions for continuous integration (CI).
|
||||
|
||||
- **Jenkins** runs Linux CI tests on
|
||||
`branches <https://ci.tlcpack.ai/job/tvm/>`_ and
|
||||
`pull requests <https://ci.tlcpack.ai/job/tvm/view/change-requests/>`_ through a
|
||||
build configuration specified in `Jenkinsfile templates <https://github.com/apache/tvm/blob/main/ci/jenkins/templates/>`_.
|
||||
Jenkins is the primary CI step that is codified to block merging.
|
||||
- **GitHub Actions** runs `linting <https://github.com/apache/tvm/blob/main/.github/workflows/lint.yml>`_
|
||||
(via pre-commit hooks) on pushes and pull requests, as well as minimal
|
||||
Windows and macOS build-and-test jobs.
|
||||
|
||||
This page describes how contributors and committers can use TVM's CI to verify their code. You can
|
||||
read more about the design of TVM CI in the `tlc-pack/ci <https://github.com/tlc-pack/ci>`_ repo.
|
||||
|
||||
For Contributors
|
||||
----------------
|
||||
|
||||
A standard Jenkins CI run looks something like this viewed in `Jenkins' BlueOcean viewer <https://ci.tlcpack.ai/blue/organizations/jenkins/tvm/activity>`_.
|
||||
CI runs usually take a couple hours to complete and pull requests (PRs) cannot be merged before CI
|
||||
has successfully completed. To diagnose failing steps, click through to the failing
|
||||
pipeline stage then to the failing step to see the output logs. For GitHub Actions jobs (lint,
|
||||
Windows, macOS), check the "Actions" tab on the pull request or repository page.
|
||||
|
||||
.. image:: https://github.com/tlc-pack/web-data/raw/main/images/contribute/ci.png
|
||||
:width: 800
|
||||
:alt: The Jenkins UI for a CI run
|
||||
|
||||
|
||||
Debugging Failures
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When CI fails for some reason, there are several methods to diagnose the issue.
|
||||
|
||||
Jenkins Logs
|
||||
""""""""""""
|
||||
|
||||
.. |pytest| replace:: ``pytest``
|
||||
.. _pytest: https://docs.pytest.org/en/stable/
|
||||
|
||||
The first place to look for a failure is in the CI logs, follow the red Xs on
|
||||
the failing job to view the logs. Note:
|
||||
|
||||
* Jenkins does not display the full log by default, at the top of the log viewer
|
||||
is a button "Show complete log" which will take you to a plaintext version of the log
|
||||
* |pytest|_ failures are summarized at the bottom of the log but you will likely
|
||||
need to scroll up to view the actual failure.
|
||||
|
||||
Reproduce Failures
|
||||
""""""""""""""""""
|
||||
|
||||
Most TVM Python tests run under |pytest|_ and can be run as described in :ref:`pr-testing`.
|
||||
|
||||
|
||||
Reporting Issues
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Issues with CI should be `reported on GitHub <https://github.com/apache/tvm/issues/new?assignees=&labels=&template=ci-problem.md&title=%5BCI+Problem%5D+>`_
|
||||
with a link to the relevant jobs, commits, or PRs.
|
||||
|
||||
|
||||
|
||||
For Maintainers
|
||||
---------------
|
||||
|
||||
This section discusses processes ran by TVM Maintainers.
|
||||
|
||||
|
||||
Procedures for Keeping CI Green
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This section talks about common procedures used to keep CI passing.
|
||||
|
||||
Broken CI due to Simultaneous Merge
|
||||
"""""""""""""""""""""""""""""""""""
|
||||
|
||||
Developers rely on the TVM CI to get signal on their PRs before merging. Occasionally, two
|
||||
different PRs can pass CI individually but break ``main`` when both land. This in turn causes an
|
||||
error to show up on an unrelated PR that is based on the broken commit(s). Broken commits can be
|
||||
identified `through GitHub <https://github.com/apache/tvm/commits/main>`_ via the commit status icon
|
||||
or via `Jenkins <https://ci.tlcpack.ai/blue/organizations/jenkins/tvm/activity?branch=main>`_.
|
||||
|
||||
In these situations it is ultimately the responsibility of the TVM Committer who merged the PR to
|
||||
fix CI (others are encouraged to help). Typical responses to this situation are:
|
||||
1. revert the offending commit
|
||||
2. submit a forward fix to address the issue.
|
||||
|
||||
It is up to the committer and commit author which option to choose. A broken CI affects all TVM
|
||||
developers and should be fixed as soon as possible, while a revert may be especially painful for the
|
||||
author of the offending PR when that PR is large.
|
||||
|
||||
|
||||
Dealing with Flakiness
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you notice a failure on your PR that seems unrelated to your change, you should
|
||||
search `recent GitHub issues related to flaky tests <https://github.com/apache/tvm/issues?q=is%3Aissue+%5BCI+Problem%5D+Flaky>`_ and
|
||||
`file a new issue <https://github.com/apache/tvm/issues/new?assignees=&labels=&template=ci-problem.md&title=%5BCI+Problem%5D>`_
|
||||
if you don't see any reports of the failure. If a certain test or class of tests affects
|
||||
several PRs or commits on ``main`` with flaky failures, the test should be disabled via
|
||||
`pytest's @xfail decorator <https://docs.pytest.org/en/stable/how-to/skipping.html#xfail-mark-test-functions-as-expected-to-fail>`_ with `strict=False <https://docs.pytest.org/en/stable/how-to/skipping.html#strict-parameter>`_ and the relevant issue linked in the
|
||||
disabling PR.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="Flaky test: https://github.com/apache/tvm/issues/1234")
|
||||
def test_something_flaky():
|
||||
pass
|
||||
|
||||
Then submit a PR as usual
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git add <test file>
|
||||
git commit -m'[skip ci][ci] Disable flaky test: ``<test_name>``
|
||||
|
||||
See #<issue number>
|
||||
'
|
||||
gh pr create
|
||||
|
||||
|
||||
Skipping CI
|
||||
^^^^^^^^^^^
|
||||
|
||||
For reverts and trivial forward fixes, adding ``[skip ci]`` to the revert's
|
||||
PR title will cause Jenkins CI to shortcut and only run lint. Committers should
|
||||
take care that they only merge CI-skipped PRs to fix a failure on ``main`` and
|
||||
not in cases where the submitter wants to shortcut CI to merge a change faster.
|
||||
The PR title is checked when the build is first run (specifically during the Jenkins lint
|
||||
step, so changes after that has run do not affect CI and will require the job to
|
||||
be re-triggered by another ``git push``). Note that GitHub Actions lint always
|
||||
runs independently via pre-commit hooks.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Revert HEAD commit, make sure to insert '[skip ci]' at the beginning of
|
||||
# the commit subject
|
||||
git revert HEAD
|
||||
git checkout -b my_fix
|
||||
# After you have pushed your branch, create a PR as usual.
|
||||
git push my_repo
|
||||
# Example: Skip CI on a branch with an existing PR
|
||||
# Adding this commit to an existing branch will cause a new CI run where
|
||||
# Jenkins is skipped
|
||||
git commit --allow-empty --message "[skip ci] Trigger skipped CI"
|
||||
git push my_repo
|
||||
|
||||
|
||||
Docker Images
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Each CI job runs most of its work inside a Docker container, built from files
|
||||
in the `docker/ <https://github.com/apache/tvm/tree/main/docker>`_ folder.
|
||||
|
||||
|
||||
Updating a Docker Image Tag
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
To update a tag, a new image needs to be built and uploaded to Docker Hub, then
|
||||
the image tags in `docker-images.ini <https://github.com/apache/tvm/tree/main/ci/jenkins/docker-images.ini>`_
|
||||
need to be updated to match the image tags on Docker Hub.
|
||||
|
||||
Docker images are built automatically nightly via the `tvm-docker <https://ci.tlcpack.ai/job/tvm-docker/>`_,
|
||||
which uploads the built images to https://hub.docker.com/u/tlcpackstaging once
|
||||
they have passed CI. Post-merge CI runs on ``main`` build Docker images ad-hoc
|
||||
and upload them to the ``tlcpackstaging`` Docker Hub account as well. There is an
|
||||
auto-promotion process for ``tlcpackstaging`` Docker images to be moved to the
|
||||
``tlcpack`` account. This means that image tags from ``tlcpackstaging`` can be
|
||||
used in CI and they will be automatically moved to ``tlcpack`` after a successful
|
||||
post-merge CI run on ``main``. So the steps to update the image are:
|
||||
|
||||
1. Merge a PR that changes the Dockerfiles under ``docker/`` or scripts in ``docker/install``.
|
||||
2. Do either of:
|
||||
|
||||
a. Wait for the post-merge CI build from the PR to complete and upload the newly built image to the `tlcpackstaging <https://hub.docker.com/u/tlcpackstaging>`_ Docker Hub.
|
||||
b. Wait for the nightly Docker image build to complete and upload the newly built image to the `tlcpackstaging <https://hub.docker.com/u/tlcpackstaging>`_ Docker Hub.
|
||||
|
||||
3. Find the newly uploaded image tag on the `tlcpackstaging <https://hub.docker.com/u/tlcpackstaging>`_ Docker Hub, for example ``20221208-070144-22ff38dff`` and update the tag in ``ci/jenkins/docker-images.ini`` to use the tlcpackstaging tag but under the tlcpack account, e.g. ``tlcpack/ci-arm:20221208-070144-22ff38dff``. Send in a PR with these changes and wait for it to run through CI to ensure the new images are valid.
|
||||
4. Merge the ``docker-images.ini`` update PR. Once post-merge CI finishes running on ``main`` the ``tlcpackstaging`` tag will be re-uploaded to ``tlcpack`` automatically.
|
||||
|
||||
Adding a New Docker Image
|
||||
"""""""""""""""""""""""""
|
||||
|
||||
New docker images can be added to test TVM on a variety of platforms. Here are the steps for adding
|
||||
a new CI image:
|
||||
|
||||
1. Define the ``docker/Dockerfile.ci_foo`` and associated scripts in ``docker/install``. Create a PR containing only these changes (no ``Jenkinsfile`` changes).
|
||||
|
||||
Example: https://github.com/apache/tvm/pull/12230/files
|
||||
|
||||
2. A committer verifies the image builds locally and then reviews/approves this PR.
|
||||
3. A committer creates the ci-foo repos in https://hub.docker.com/u/tlcpack and https://hub.docker.com/u/tlcpackstaging.
|
||||
4. Create a PR to create an ECR repo for the image in tlcpack/ci: https://github.com/tlc-pack/ci/pull/46/files
|
||||
5. A committer creates and gets merged a PR to add the image to the ``Jenkinsfile``
|
||||
|
||||
Example: https://github.com/apache/tvm/pull/12369/files.
|
||||
|
||||
**NOTE**: The PR must be opened from a branch in apache/tvm, not from a branch in a forked repo.
|
||||
|
||||
6. A committer adds this image to the daily docker rebuild/validation run in tlcpack.
|
||||
|
||||
Example: https://github.com/tlc-pack/tlcpack/pull/131
|
||||
|
||||
|
||||
``ci-docker-staging``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The `ci-docker-staging <https://github.com/apache/tvm/tree/ci-docker-staging>`_
|
||||
branch is typically used to test updates to Docker images and ``Jenkinsfile`` changes. When
|
||||
running a build for a normal PR from a forked repository, Jenkins uses the code
|
||||
from the PR except for the ``Jenkinsfile`` itself, which comes from the base branch.
|
||||
When branches are built, the ``Jenkinsfile`` in the branch is used, so a committer
|
||||
with write access must push PRs to a branch in apache/tvm to properly test
|
||||
``Jenkinsfile`` changes. If your PR makes changes to the ``Jenkinsfile``, make sure
|
||||
to @ a `committer <https://github.com/apache/tvm/tree/main/CONTRIBUTORS.md>`_
|
||||
and ask them to push your PR as a branch to test the changes.
|
||||
|
||||
|
||||
CI Monitoring Rotation
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some tests are also flaky and occasionally fail for reasons unrelated to the PR. The
|
||||
`CI monitoring rotation <https://github.com/apache/tvm/wiki/CI-Monitoring-Runbook>`_ watches for these failures and
|
||||
disables tests as necessary. It is the responsibility of those who wrote the test to ultimately fix
|
||||
and re-enable the test.
|
||||
@@ -0,0 +1,185 @@
|
||||
.. 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.
|
||||
|
||||
.. _code_guide:
|
||||
|
||||
Code Guide and Tips
|
||||
===================
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
This is a document used to record tips in TVM codebase for reviewers and contributors.
|
||||
Most of them are summarized through lessons during the contributing and process.
|
||||
|
||||
|
||||
C++ Code Styles
|
||||
---------------
|
||||
- Use the Google C/C++ style.
|
||||
- The public facing functions are documented in doxygen format.
|
||||
- Favor concrete type declaration over ``auto`` as long as it is short.
|
||||
- Favor passing by const reference (e.g. ``const Expr&``) over passing by value.
|
||||
Except when the function consumes the value by copy constructor or move,
|
||||
pass by value is better than pass by const reference in such cases.
|
||||
- Favor ``const`` member function when possible.
|
||||
|
||||
We use ``clang-format`` to enforce the code style. Because different version
|
||||
of clang-format might change by its version, it is recommended to use the same
|
||||
version of the clang-format as the main one.
|
||||
You can use pre-commit hooks to run formatting checks:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Run clang-format on all files
|
||||
pre-commit run clang-format --all-files
|
||||
|
||||
# Run all linters (Python + C++ + custom checks)
|
||||
pre-commit run --all-files
|
||||
|
||||
|
||||
clang-format is also not perfect, when necessary, you can use disble clang-format on certain code regions.
|
||||
|
||||
.. code :: c
|
||||
|
||||
// clang-format off
|
||||
void Test() {
|
||||
// clang-format will be disabled in this region.
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
Because clang-format may not recognize macros, it is recommended to use macro like normal function styles.
|
||||
|
||||
|
||||
.. code :: c
|
||||
|
||||
#define MACRO_IMPL { custom impl; }
|
||||
#define MACRO_FUNC(x)
|
||||
|
||||
// not preferred, because clang-format might recognize it as types.
|
||||
virtual void Func1() MACRO_IMPL
|
||||
|
||||
// preferred
|
||||
virtual void Func2() MACRO_IMPL;
|
||||
|
||||
void Func3() {
|
||||
// preferred
|
||||
MACRO_FUNC(xyz);
|
||||
}
|
||||
|
||||
|
||||
Python Code Styles
|
||||
------------------
|
||||
- The functions and classes are documented in `numpydoc <https://numpydoc.readthedocs.io/en/latest/>`_ format.
|
||||
- Check your code style using ``pre-commit run --all-files``
|
||||
- Stick to language features in ``python 3.10``
|
||||
|
||||
- For functions with early returns, prefer ``if``/``elif``/``else``
|
||||
chains for functions with parallel and short bodies to the
|
||||
conditions, such as functions that apply a simple mapping to the
|
||||
arguments. For more procedural functions, especially where the
|
||||
final ``else`` block would be much longer than the ``if`` and
|
||||
``elif`` blocks, prefer having the final ``else`` case unindented.
|
||||
|
||||
The pylint check ``no-else-return`` is disabled to allow for this
|
||||
distinction. See further discussion `here
|
||||
<https://github.com/apache/tvm/pull/11327>`_.
|
||||
|
||||
.. code:: python
|
||||
|
||||
# All cases have bodies with similar flow control. While this could
|
||||
# be expressed as a sequence of if conditions, a reader would need to
|
||||
# inspect the body of each condition to know that only one conditional
|
||||
# body may be reached.
|
||||
def sign(x):
|
||||
if x > 0:
|
||||
return "+"
|
||||
elif x < 0:
|
||||
return "-"
|
||||
else:
|
||||
return ""
|
||||
|
||||
# The initial special case is an early return for a special case,
|
||||
# followed by a more general method. Using an else block for the
|
||||
# condition would add unnecessary indentation for the remainder of the
|
||||
# function.
|
||||
def num_unique_subsets(values):
|
||||
if len(values)==0:
|
||||
return 1
|
||||
|
||||
# Longer, more general solution here
|
||||
...
|
||||
|
||||
Writing Python Tests
|
||||
--------------------
|
||||
We use `pytest <https://docs.pytest.org/en/stable/>`_ for all Python testing. Regular tests live
|
||||
under ``tests/python``, while environment-specific nightly tests live under ``tests/nightly/python``.
|
||||
See :doc:`testing` for details on running tests, target parametrization,
|
||||
and the target-specific marks used by CI.
|
||||
|
||||
If you want your test to run over a variety of targets, parametrize over ``target`` with ``@pytest.mark.parametrize``, tag GPU targets with ``@pytest.mark.gpu`` so the CI routes them to GPU nodes, and skip a target that is unavailable on the current machine with :py:func:`tvm.testing.device_enabled`. For example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
@pytest.mark.parametrize("target", ["llvm", pytest.param("cuda", marks=pytest.mark.gpu)])
|
||||
def test_mytest(target):
|
||||
if not tvm.testing.device_enabled(target):
|
||||
pytest.skip(f"{target} not enabled")
|
||||
dev = tvm.device(target)
|
||||
...
|
||||
|
||||
will run ``test_mytest`` with ``target="llvm"`` and ``target="cuda"``, skipping any target whose device is not present. If you only want to test against a single target, drop the parametrization and hardcode the target. Mark GPU tests with ``@pytest.mark.gpu`` so the CI can select them, and skip when the required feature is unavailable with ``@pytest.mark.skipif``. For example, CUDA tests use:
|
||||
|
||||
.. code:: python
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not tvm.testing.env.has_cuda(), reason="need cuda")
|
||||
def test_mycudatest():
|
||||
...
|
||||
|
||||
The ``tvm.testing.env`` module exposes a ``has_*()`` probe for each runtime and hardware feature (e.g. ``has_cuda()``, ``has_rocm()``, ``has_vulkan()``, ``has_llvm()``). To skip a test when an optional Python package is missing, use ``pytest.importorskip("package_name")``.
|
||||
|
||||
|
||||
Network Resources
|
||||
-----------------
|
||||
|
||||
In CI, downloading files from the Internet is a big source of flaky test failures (e.g. remote
|
||||
server can go down or be slow), so try to avoid using the network at all during tests. In some cases
|
||||
this isn't a reasonable proposition (e.g. the docs tutorials which need to download models).
|
||||
|
||||
New network downloads are rejected by the CI `request hook
|
||||
<https://github.com/apache/tvm/blob/main/tests/python/request_hook.py>`_. Prefer
|
||||
checked-in fixtures or generated data. If a download is unavoidable, arrange a stable
|
||||
project-managed mirror with the maintainers and add an explicit ``URL_MAP`` entry.
|
||||
|
||||
|
||||
Handle Integer Constant Expression
|
||||
----------------------------------
|
||||
We often need to handle constant integer expressions in TVM. Before we do so, the first question we want to ask is that is it really necessary to get a constant integer. If symbolic expression also works and let the logic flow, we should use symbolic expression as much as possible. So the generated code works for shapes that are not known ahead of time.
|
||||
|
||||
Note that in some cases we cannot know certain information, e.g. sign of symbolic variable, it is ok to make assumptions in certain cases. While adding precise support if the variable is constant.
|
||||
|
||||
If we do have to get constant integer expression, we should get the constant value using type ``int64_t`` instead of ``int``, to avoid potential integer overflow. We can always reconstruct an integer with the corresponding expression type via ``make_const``. The following code gives an example.
|
||||
|
||||
.. code:: c++
|
||||
|
||||
Expr CalculateExpr(Expr value) {
|
||||
int64_t int_value = GetConstInt<int64_t>(value);
|
||||
int_value = CalculateExprInInt64(int_value);
|
||||
return make_const(value.type(), int_value);
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
.. 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.
|
||||
|
||||
.. _code_review_guide:
|
||||
|
||||
|
||||
Code Reviews
|
||||
============
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
Open source code is maintained by a community with diverse backgrounds, interests, and goals.
|
||||
Hence it is important to provide clear, documented and maintainable code and processes. Code reviews are a
|
||||
shepherding process used to collectively spot potential problems, improve quality of the code, and educate both contributors
|
||||
and reviewers about the code base and its assumptions. It is also one mechanism to ensure there are multiple people who can
|
||||
maintain a related piece of code together. Contributors are encouraged to polish the code to a reviewable
|
||||
state before requesting reviews. This is especially important for committer candidates, as committers are expected
|
||||
to participate in not only writing code but also reviewing it.
|
||||
|
||||
This document is a living guideline for code review in open source. Please also take sometime to read
|
||||
:ref:`community_guide` about the general development process.
|
||||
|
||||
Building Trust
|
||||
--------------
|
||||
|
||||
First and foremost, we are building a community that based on trust, which takes time
|
||||
and effort to both build and maintain. We expect our community members to work together in a
|
||||
constructive way and work together with common sense. Although we all have different sets of backgrounds,
|
||||
interests and goals we must work together to find solutions that work for the larger community.
|
||||
Trust-based collaboration is also a key tenant of the Apache way and an important factor to consider in growing the community,
|
||||
and promoting members to official roles.
|
||||
|
||||
Community Participation
|
||||
-----------------------
|
||||
|
||||
Everyone is welcomed to comment on PRs. We encourage committers to wait for some period of time(e.g. three days)
|
||||
before merging PR that contains a major architecture change. The goal is to give people time to speak up and
|
||||
express interest in reviewing and participate.
|
||||
|
||||
Remembering that we are all coming from different backgrounds is important here. For example some community members
|
||||
work in different time zones, only work on open source during work hours, or may be traveling or having other events
|
||||
going on in their lives. An important part of working in a large project is ensuring there is collective understanding,
|
||||
so no one person is a bottleneck. While it is important to allow time for participation in code review we also can not
|
||||
block all changes on all reviewers. Remember that helping people land PRs is a great way to encourage broader
|
||||
participation, especially for those who volunteer their time to contribute.
|
||||
|
||||
Part of this is trusting and communicating with fellow maintainers that if changes need to be applied in the future
|
||||
that PR authors will later follow through on their promises. It is the responsibility of committers to listen to all
|
||||
feedback whether from PMC members or new contributors and consider what actions need to be taken.
|
||||
|
||||
Read the code carefully
|
||||
-----------------------
|
||||
|
||||
Sometimes we may quickly read through the code and only pick up on a selective aspects of the code. These type of comments
|
||||
are usually helpful and should be welcomed in the community. However, they are only part of performing code review and
|
||||
should be part of more comprehensive feedback. A good and careful code review is a large time investment and sometimes
|
||||
can be longer than writing the actual contribution.
|
||||
|
||||
For example receiving only highly critical feedback on minor aspects of your PR rarely feels good, and it can be discouraging
|
||||
if your time and effort was not reciprocated during review. Practicing empathy when acting both as a contributor and committer
|
||||
is important and can help make you a more effective code reviewer and contributor.
|
||||
|
||||
We expect that all committers carefully read and understand the code before signing off. There is a lot of trust involved when
|
||||
a committer hits the merge button. In the meantime, we acknowledge that sometimes problems slip through, in that case, the
|
||||
merger is responsible for ensuring the correct follow up actions are taken.
|
||||
|
||||
Be Respectful
|
||||
-------------
|
||||
|
||||
- To everyone who are making comments: making constructive comment will help new contributors to land their PRs
|
||||
timely and help us welcome new members to the community.
|
||||
|
||||
- To authors: reviewers should spend significant time reading the code, and a careful review could be as time intensive
|
||||
as writing the code from scratch. Respectfully address review comments and reciprocate the review by helping review
|
||||
others changes in the future.
|
||||
|
||||
Most importantly focus on having a constructive conversation, and try to assume best intentions when interacting as a reviewer.
|
||||
If there is something in the process not working, consider getting some face time with the other contributors and discussing
|
||||
how to improve the process or communication.
|
||||
|
||||
Factors to Consider about Code Quality
|
||||
--------------------------------------
|
||||
|
||||
High quality code is critical to the long term success of the project. There are many factors of code quality to consider
|
||||
during a code review:
|
||||
|
||||
- F0: Overall architecture. This includes the definition of public modules, key data structures and public interfaces.
|
||||
Good architectural choices are critical to the success of the project in the long run.
|
||||
- F1: Architectural consistency. There are usually multiple ways to implement a new feature. We must ensure new
|
||||
features are consistent with previous overall architectural choices and interact well with the existing code.
|
||||
Every new feature increases the complexity of the project, and a consistent design ideally minimizes the increase
|
||||
in complexity bought by a new feature, making it easier to maintain code in the long run.
|
||||
- F2: Code robustness and test coverage. Ensure code runs correctly in all possible settings(platforms), ensure
|
||||
test coverage of the new feature. Clear error messages for user facing errors.
|
||||
- F3: User facing API documentation: documentation of public user facing APIs and key module interfaces are mandatory.
|
||||
This includes the API, data structures that appears in the public interface (i.e., `include/tvm` and user facing python APIs).
|
||||
We generally encourage well documented code and include some form of documentations for internal APIs that are used in
|
||||
multiple places, see also F4.
|
||||
- F4: Code readability. Readability involves multiple aspects: instructive and consistent function names, clear implementation
|
||||
of the overall flow, descriptive comments for complex code logic and internal functions. Readable code is easier to maintain.
|
||||
|
||||
Architectural design and consistency are the most important factors since they are likely to introduce the most long term technical debt.
|
||||
As a result, committers should most carefully consider these factors before merging the code.
|
||||
|
||||
Test coverage and API documentation are expected for code contributions.
|
||||
|
||||
Code readability is relatively a subjective matter compared to the other ones.
|
||||
Different people have different thoughts on how to best write code. Reviewers should make constructive and actionable comments.
|
||||
In the meantime, code review should not be used as a way to get others to write code exactly the way you would.
|
||||
Conversely you should also consider that what you may easily understand, or find acceptable might not work for the larger
|
||||
community or other members. Use your judgment on what is appropriate based on the content and the scope of the contribution
|
||||
and where the contributor is coming from.
|
||||
|
||||
We follow common :ref:`code_guide` when writing code. Style guides help ensure that code is readable and maintainable by others,
|
||||
long after the original author has moved on. Style guides are more than about code formatting — they also pertain
|
||||
to the correct way to document code, variable naming, and other conventions that are not enforced by automatic formatters.
|
||||
|
||||
Consensus Building
|
||||
------------------
|
||||
|
||||
Disagreements can happen during code reviews. We encourage building consensus among the people involved. We are working together
|
||||
and building trust with each other in OSS. The nature of OSS means sometimes we make compromises on less significant issues to
|
||||
make steady progress and welcome broader participation in the community. Compromise unfortunately means sometimes the world will
|
||||
not be exactly as we would like, this true even for leaders of the community.
|
||||
|
||||
- Be civil and build consensus through constructive technical-based conversations.
|
||||
- A committer who owns the area can serve as a shepherd to drive the discussion by taking all the conversations into consideration,
|
||||
and suggest a resolution with to move forward.
|
||||
- Because a lot of trust is involved on the committer(shepherd), they should read the PR carefully before sign off. Additionally,
|
||||
the merger should also take the responsibility to followup in case there are problems caused by the merge.
|
||||
|
||||
Consistency
|
||||
-----------
|
||||
|
||||
A final remark is that we are all human and its hard to always be perfectly consistent. If contributors feel that you didn't apply these guidelines
|
||||
in a consistent way it is important to listen and hear folks out. We will constantly have to iterate on processes and guidelines as we evolve as a community.
|
||||
Our goal is to strive to be consistent and objective but all of us are unfortunately human and imperfect and will need to adjust and learn.
|
||||
|
||||
Additional Recommendations
|
||||
--------------------------
|
||||
|
||||
Deliberate on API and Data Structures
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A minimum and stable API is critical to the project’s life. A good API makes a huge difference. Always think very carefully about all the aspects including naming, argument definitions and behavior.
|
||||
|
||||
When possible, pay more attention still to the proposed API design during code reviews.
|
||||
Remember, it is easier to improve code implementation, but it is extremely hard to change an API once accepted.
|
||||
We should treat data structures that are shared across modules(e.g. AST) in the same way.
|
||||
If/when uncertain, start a conversation with more developers before committing.
|
||||
|
||||
Here are some useful principles for designing APIs:
|
||||
|
||||
- Be consistent with existing well-known package’s APIs if the features overlap.
|
||||
For example, tensor operation APIs should always be consistent with the numpy API.
|
||||
- Be consistent with existing APIs in the same project.
|
||||
For example, we should use the same argument ordering across all the optimization passes,
|
||||
so there is no "surprise" when using them.
|
||||
- Think about whether the API will change in the future.
|
||||
For example, we will have more options like loop_unrolling and device placement policy
|
||||
as we add more optimizations in build. We can package optimization knobs into a build
|
||||
configuration object. In this way, the build API is stable over time, even though it may be enriched.
|
||||
- Write documentation. Documentation is mandatory for APIs and sometimes writing documents helps
|
||||
us to think further about the design as well as whether we need to add further clarifications.
|
||||
- Minimum. Think about how many lines of code a user has to write to use the API.
|
||||
Remove layers of abstraction when possible.
|
||||
|
||||
Minimize Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
Always be cautious in introducing dependencies. While it is important to reuse code and avoid reinventing the wheel,
|
||||
dependencies can increase burden of users in deployment. A good design principle is that a feature or function
|
||||
should only have a dependency if/when a user actually use it.
|
||||
|
||||
Concise Implementation
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Some basic principles applied here: favor vectorized array code over loops, use existing APIs that solve the problem.
|
||||
|
||||
Document Lessons in Code Reviews
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When you find there are some common or recurring lessons that can be summarized,
|
||||
add it to the :ref:`code_guide`.
|
||||
It is always good to refer to the guideline document when requesting changes,
|
||||
so the lessons can be shared to all the community.
|
||||
|
||||
|
||||
Learn from other Code Reviews
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
There can be multiple reviewers reviewing the same changes. Many times other reviewers
|
||||
may spot things you did not find. Try to learn from other code reviews, when possible, document these lessons.
|
||||
|
||||
Approve and Request Changes Explicitly
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The contributor and code owner can request code reviews from multiple reviewers.
|
||||
Remember to approve changes when your comments are addressed in a code review.
|
||||
To do so -- please click on changes tab in the pull request, then select approve,
|
||||
or comment on the code and click request changes.
|
||||
Code owner can decide if the code can be merged in case by case if some of the reviewers
|
||||
did not respond in time(e.g. a week) and existing reviews are sufficient.
|
||||
|
||||
Reviewers
|
||||
~~~~~~~~~
|
||||
Reviewers should strive to leave timely feedback on pull requests for which their
|
||||
review was requested. Reviewing code is an important part of the project's health
|
||||
and should be considered a regular responsibility for contributors. Automated
|
||||
tooling helps out in this regard, as PRs with no activity for a set amount of
|
||||
time will get a bot comment pinging the relevant parties.
|
||||
@@ -0,0 +1,121 @@
|
||||
.. 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.
|
||||
|
||||
.. _committer_guide:
|
||||
|
||||
Committer Guide
|
||||
===============
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
This is an evolving document to provide some helpful tips for committers.
|
||||
Most of them are lessons learned during development.
|
||||
We welcome every committer to contribute to this document.
|
||||
See the :ref:`community_guide` for an overview of
|
||||
the committership and the general development process.
|
||||
|
||||
Community First
|
||||
---------------
|
||||
The collective effort of the community moves the project forward and
|
||||
makes the project awesome for everyone.
|
||||
When we make a decision, it is always helpful to keep the community in mind.
|
||||
Here are some example questions that we can ask:
|
||||
|
||||
- How can I encourage new contributors to get more involved in the project?
|
||||
- Can I help to save my fellow committers' time?
|
||||
- Have I enabled the rest of the community to participate the
|
||||
design proposals?
|
||||
|
||||
|
||||
Public Archive Principle
|
||||
------------------------
|
||||
While private channels such as face to face discussion are useful for development,
|
||||
they also create barriers for the broader community's participation.
|
||||
The Apache way of development requires all decisions
|
||||
to be made in public channels, which are archived and accessible to everyone.
|
||||
As a result, any contributor can keep up with the development by watching the
|
||||
archives and join the development anytime.
|
||||
|
||||
While this principle applies to every contributor,
|
||||
it is especially important for committers.
|
||||
Here are some example applications of this principle:
|
||||
|
||||
- When getting a project-related question from a personal channel,
|
||||
encourage the person to open a public thread in the discuss forum,
|
||||
so others in the community can benefit from the answer.
|
||||
- After an in-person discussion, send a summary to public channels
|
||||
(as an RFC or a discuss thread).
|
||||
|
||||
|
||||
Independent Project Management
|
||||
------------------------------
|
||||
|
||||
Everyone is presumed to be wearing their Apache committer hat when participating in the project.
|
||||
That is, committers should act - in the context of the project activities - in the best interests of the project.
|
||||
Separating your hat between committer and any other roles you may have is important in all aspects.
|
||||
|
||||
In the context of project participation, it can be helpful to state which hat you are wearing in cases where that
|
||||
can cause confusion, especially in cases where you are not wearing committer hat. Two examples:
|
||||
|
||||
- "Wearing [foo] hat: [message when serving as foo's role and not as committer]".
|
||||
- "Wearing Apache TVM hat: [messages when serving as committer]".
|
||||
|
||||
Shepherd a Pull Request
|
||||
-----------------------
|
||||
|
||||
Here are some tips to shepherd a pull request.
|
||||
You can also take a look at the :ref:`code_review_guide`.
|
||||
|
||||
- Assign the PR to yourself, so that other committers
|
||||
know that the PR has already been tended to.
|
||||
- Make use of the status label to indicate the current status.
|
||||
- Check if an RFC needs to be sent.
|
||||
- If the contributor has not requested a reviewer, kindly
|
||||
ask the contributor to do so.
|
||||
If the PR comes from a new contributor,
|
||||
help the contributor to request reviewers
|
||||
and ask the contributor to do so next time.
|
||||
- Moderate the reviews, ask reviewers to approve explicitly.
|
||||
- Mark the PR as accepted and acknowledge the contributor/reviewers.
|
||||
- Merge the PR :)
|
||||
|
||||
|
||||
Time Management
|
||||
---------------
|
||||
There are many things that a committer can do, such as
|
||||
moderating discussions, pull request reviews and
|
||||
code contributions.
|
||||
|
||||
Working on an open source project can be rewarding,
|
||||
but also be a bit overwhelming sometimes.
|
||||
A little bit of time management might be helpful to alleviate the problem.
|
||||
For example, some committers have a "community day" in a week
|
||||
when they actively manage outstanding PRs,
|
||||
but watch the community less frequently in the rest of the time.
|
||||
|
||||
Remember that your merit will never go away, so please
|
||||
take your time and pace when contributing to the project :)
|
||||
|
||||
|
||||
Broad Collaboration
|
||||
-------------------
|
||||
Sometimes, we tend to only interact with people we know.
|
||||
However, broad collaborations are necessary to the success of the project.
|
||||
Try to keep that in mind, shepherd PRs for, and request code reviews from
|
||||
community members who you do not interact physically.
|
||||
@@ -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.
|
||||
|
||||
.. _community_guide:
|
||||
|
||||
TVM Community Guidelines
|
||||
========================
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
|
||||
TVM adopts the Apache style model and governs by merit. We believe that it is important to create an inclusive community where everyone can use, contribute to, and influence the direction of the project. See `CONTRIBUTORS.md <https://github.com/apache/tvm/blob/main/CONTRIBUTORS.md>`_ for the current list of contributors.
|
||||
|
||||
General Development Process
|
||||
---------------------------
|
||||
Everyone in the community is welcomed to send patches, documents, and propose new directions to the project. The key guideline here is to enable everyone in the community to get involved and participate the decision and development. When major changes are proposed, an RFC should be sent to allow discussion by the community. We encourage public discussion, archivable channels such as issues, discuss forum and mailing-list, so that everyone in the community can participate and review the process later.
|
||||
|
||||
Code reviews are one of the key ways to ensure the quality of the code. High-quality code reviews prevent technical debt for long-term and are crucial to the success of the project. A pull request needs to be reviewed before it gets merged. A committer who has the expertise of the corresponding area would moderate the pull request and the merge the code when it is ready. The corresponding committer could request multiple reviewers who are familiar with the area of the code. We encourage contributors to request code reviews themselves and help review each other's code -- remember everyone is volunteering their time to the community, high-quality code review itself costs as much as the actual code contribution, you could get your code quickly reviewed if you do others the same favor.
|
||||
|
||||
The community should strive to reach a consensus on technical decisions through discussion. We expect committers and PMCs to moderate technical discussions in a diplomatic way, and provide suggestions with clear technical reasoning when necessary.
|
||||
|
||||
Strategy Decision Process
|
||||
-------------------------
|
||||
It takes lazy 2/3 majority (at least 3 votes and twice as many +1 votes as -1 votes) of binding decisions to make the following
|
||||
strategic decisions in the TVM community:
|
||||
|
||||
- Adoption of a guidance-level community strategy to enable new directions or overall project evolution.
|
||||
- Establishment of a new module in the project.
|
||||
- Adoption of a new codebase: When the codebase for an existing, released product is to be replaced with an alternative codebase.
|
||||
If such a vote fails to gain approval, the existing code base will continue. This also covers the creation of new sub-projects within the project.
|
||||
|
||||
All these decisions are made after community conversations that get captured as part of the summary.
|
||||
|
||||
|
||||
Committers
|
||||
----------
|
||||
Committers are individuals who are granted the write access to the project. A committer is usually responsible for a certain area or several areas of the code where they oversee the code review process. The area of contribution can take all forms, including code contributions and code reviews, documents, education, and outreach. Committers are essential for a high quality and healthy project. The community actively look for new committers from contributors. Here is a list of useful traits that help the community to recognize potential committers:
|
||||
|
||||
- Sustained contribution to the project, demonstrated by discussion over RFCs, code reviews and proposals of new features, and other development activities. Being familiar with, and being able to take ownership on one or several areas of the project.
|
||||
- Quality of contributions: High-quality, readable code contributions indicated by pull requests that can be merged without a substantial code review. History of creating clean, maintainable code and including good test cases. Informative code reviews to help other contributors that adhere to a good standard.
|
||||
- Community involvement: active participation in the discussion forum, promote the projects via tutorials, talks and outreach. We encourage committers to collaborate broadly, e.g. do code reviews and discuss designs with community members that they do not interact physically.
|
||||
|
||||
The `Project Management Committee (PMC) <https://projects.apache.org/committee.html?tvm>`_ consists group of active committers that moderate the discussion, manage the project release, and proposes new committer/PMC members. Potential candidates are usually proposed via an internal discussion among PMCs, followed by a consensus approval, (i.e. at least 3 +1 votes, and no vetoes). Any veto must be accompanied by reasoning. PMCs should serve the community by upholding the community practices and guidelines TVM a better community for everyone. PMCs should strive to only nominate new candidates outside of their own organization.
|
||||
|
||||
|
||||
Reviewers
|
||||
---------
|
||||
Reviewers are individuals who actively contributed to the project and are willing to participate in the code review of new contributions. We identify reviewers from active contributors. The committers should explicitly solicit reviews from reviewers. High-quality code reviews prevent technical debt for long-term and are crucial to the success of the project. A pull request to the project has to be reviewed by at least one reviewer in order to be merged.
|
||||
@@ -0,0 +1,257 @@
|
||||
.. 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.
|
||||
|
||||
.. _doc_guide:
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
TVM documentation loosely follows the `formal documentation style described by
|
||||
Divio <https://documentation.divio.com>`_. This system has been chosen because
|
||||
it is a "simple, comprehensive and nearly universally-applicable scheme. It is
|
||||
proven in practice across a wide variety of fields and applications."
|
||||
|
||||
This document describes the organization of TVM documentation, and how to write
|
||||
new documentation. See `docs/README.md <https://github.com/apache/tvm/tree/main/docs#build-locally>`_
|
||||
for instructions on building the docs.
|
||||
|
||||
The Four Document Types
|
||||
***********************
|
||||
|
||||
Introductory Tutorials
|
||||
----------------------
|
||||
|
||||
These are step by step guides to introduce new users to a project. An
|
||||
introductory tutorial is designed to get a user engaged with the software
|
||||
without necessarily explaining why the software works the way it does. Those
|
||||
explanations can be saved for other document types. An introductory tutorial
|
||||
focuses on a successful first experience. These are the most important docs to
|
||||
turning newcomers into new users and developers. A fully end-to-end
|
||||
tutorial — from installing TVM and supporting ML software, to creating and
|
||||
training a model, to compiling to different architectures — will give a new
|
||||
user the opportunity to use TVM in the most efficient way possible. A tutorial
|
||||
teaches a beginner something they need to know. This is in contrast with a
|
||||
how-to, which is meant to be an answer to a question that a user with some
|
||||
experience would ask.
|
||||
|
||||
Tutorials need to be repeatable and reliable, because the lack of success means
|
||||
a user will look for other solutions.
|
||||
|
||||
How-to Guides
|
||||
-------------
|
||||
|
||||
These are step by step guides on how to solve particular problems. The user can
|
||||
ask meaningful questions, and the documents provide answers. An examples of
|
||||
this type of document might be, "how do I compile an optimized model for ARM
|
||||
architecture?" or "how do I compile and optimize a PyTorch model?" These
|
||||
documents should be open enough that a user could see how to apply it to a new
|
||||
use case. Practical usability is more important than completeness. The title
|
||||
should tell the user what problem the how-to is solving.
|
||||
|
||||
How are tutorials different from how-tos? A tutorial is oriented towards the
|
||||
new developer, and focuses on successfully introducing them to the software and
|
||||
community. A how-to, in contrast, focuses on accomplishing a specific task
|
||||
within the context of basic understanding. A tutorial helps to on-board and
|
||||
assumes no prior knowledge. A how-to assumes minimum knowledge, and is meant to
|
||||
guide someone to accomplish a specific task.
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
Reference documentation describes how the software is configured and operated.
|
||||
APIs, key functions, commands, and interfaces are all candidates for reference
|
||||
documentation. These are the technical manuals that let users build their own
|
||||
interfaces and programs. They are information oriented, focused on lists and
|
||||
descriptions. You can assume that the audience has a grasp on how the software
|
||||
works and is looking for specific answers to specific questions. Ideally, the
|
||||
reference documentation should have the same structure as the code base and be
|
||||
generated automatically as much as possible.
|
||||
|
||||
Architecture Guides
|
||||
-------------------
|
||||
|
||||
Architecture Guides are explanations are background material on a topic. These
|
||||
documents help to illuminate and understand the application environment. Why
|
||||
are things the way they are? What were the design decisions, what alternatives
|
||||
were considered, what are the RFCs describing the existing system? This
|
||||
includes academic papers and links to publications relevant to the software.
|
||||
Within these documents you can explore contradictory and conflicting position,
|
||||
and help the reader make sense of how and why the software was built the way it
|
||||
is. It's not the place for how-tos and descriptions on how to accomplish tasks.
|
||||
They instead focus on higher level concepts that help with the understanding of
|
||||
the project. Generally these are written by the architects and developers of
|
||||
the project, but can useful to help both users and developers to have a deeper
|
||||
understanding of why the software works the way it does, and how to contribute
|
||||
to it in ways that are consistent with the underlying design principles.
|
||||
|
||||
Special considerations for TVM
|
||||
------------------------------
|
||||
|
||||
The TVM community has some special considerations that require deviation from
|
||||
the simple docs style outlined by Divio. The first consideration is that there
|
||||
is frequently overlap between the user and developer communities. Many projects
|
||||
document the developer and user experience with separate systems, but it is
|
||||
appropriate to consider both in this system, with differentiations where
|
||||
appropriate. As a result the tutorials and how-tos will be divided between
|
||||
"User Guides" that focus on the user experience, and "Developer Guides" that
|
||||
focus on the developer experience.
|
||||
|
||||
The next consideration is that there are special topics within the TVM
|
||||
community that benefit from additional attention. Special "Topic Guides" can be
|
||||
created to index existing material, and provide context on how to navigate that
|
||||
material most effectively.
|
||||
|
||||
To facilitate newcomers, a special "Getting Started" section with installation
|
||||
instructions, a overview of why to use TVM, and other first-experience
|
||||
documents will be produced.
|
||||
|
||||
|
||||
Technical Details
|
||||
*****************
|
||||
|
||||
We use the `Sphinx <https://www.sphinx-doc.org>`_ for the main documentation.
|
||||
Sphinx supports both reStructuredText and markdown. When possible, we
|
||||
encourage reStructuredText as it has richer features. Note that the
|
||||
Python doc-string and tutorials allow you to embed reStructuredText syntax.
|
||||
|
||||
See
|
||||
`docs/README.md <https://github.com/apache/tvm/tree/main/docs#build-locally>`_
|
||||
for instructions on building the docs.
|
||||
|
||||
|
||||
Python Reference Documentation
|
||||
------------------------------
|
||||
|
||||
We use the `numpydoc <https://numpydoc.readthedocs.io/en/latest/>`_ format to
|
||||
document the function and classes. The following snippet gives an example
|
||||
docstring. We always document all the public functions, and when necessary,
|
||||
provide a usage example of the features we support (as shown below).
|
||||
|
||||
.. code:: python
|
||||
|
||||
def myfunction(arg1, arg2, arg3=3):
|
||||
"""Briefly describe my function.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg1 : Type1
|
||||
Description of arg1
|
||||
|
||||
arg2 : Type2
|
||||
Description of arg2
|
||||
|
||||
arg3 : Type3, optional
|
||||
Description of arg3
|
||||
|
||||
Returns
|
||||
-------
|
||||
rv1 : RType1
|
||||
Description of return type one
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. code:: python
|
||||
|
||||
# Example usage of myfunction
|
||||
x = myfunction(1, 2)
|
||||
"""
|
||||
return rv1
|
||||
|
||||
Be careful to leave blank lines between sections of your documents. In the
|
||||
above case, there has to be a blank line before ``Parameters``, ``Returns`` and
|
||||
``Examples`` in order for the doc to be built correctly. To add a new function to
|
||||
the docs, we need to add the `sphinx.autodoc
|
||||
<https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_ rules to
|
||||
`docs/reference/api/python <https://github.com/apache/tvm/tree/main/docs/reference/api/python>`_.
|
||||
You can refer to the existing files under this folder on how to add the
|
||||
functions.
|
||||
|
||||
C++ Reference Documentation
|
||||
---------------------------
|
||||
|
||||
We use the doxygen format to document c++ functions. The following snippet
|
||||
shows an example of c++ docstring.
|
||||
|
||||
.. code:: c++
|
||||
|
||||
/*!
|
||||
* \brief Description of my function
|
||||
* \param arg1 Description of arg1
|
||||
* \param arg2 Description of arg2
|
||||
* \returns describe return value
|
||||
*/
|
||||
int myfunction(int arg1, int arg2) {
|
||||
// When necessary, also add comment to clarify internal logics
|
||||
}
|
||||
|
||||
Besides documenting function usages, we also highly recommend contributors to
|
||||
add comments about code logics to improve readability.
|
||||
|
||||
Sphinx Gallery How-Tos
|
||||
----------------------
|
||||
|
||||
We use `sphinx-gallery <https://sphinx-gallery.github.io/>`_ to build many
|
||||
Python how-tos. You can find the source code under `docs/how_to/tutorials
|
||||
<https://github.com/apache/tvm/tree/main/docs/how_to/tutorials>`_.
|
||||
One thing that worth noting is that the comment blocks are written in
|
||||
reStructuredText instead of markdown so be aware of the syntax.
|
||||
|
||||
The how-to code will run on our build server to generate the document page. So
|
||||
we may have a restriction like not being able to access a remote Raspberry Pi,
|
||||
in such case add a flag variable to the tutorial (e.g. ``use_rasp``) and allow
|
||||
users to easily switch to the real device by changing one flag. Then use the
|
||||
existing environment to demonstrate the usage.
|
||||
|
||||
If you add a new categorization of how-to, you will need to add references to
|
||||
`conf.py <https://github.com/apache/tvm/tree/main/docs/conf.py>`_ and the
|
||||
`top-level docs index <https://github.com/apache/tvm/tree/main/docs/index.rst>`_
|
||||
(how-to entries are registered there directly, not in a separate how-to index).
|
||||
|
||||
Refer to Another Location in the Document
|
||||
-----------------------------------------
|
||||
Please use sphinx's ``:ref:`` markup to refer to another location in the same doc.
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. _document-my-section-tag
|
||||
|
||||
My Section
|
||||
----------
|
||||
|
||||
You can use :ref:`document-my-section-tag` to refer to My Section.
|
||||
|
||||
Documents with Images / Figures
|
||||
-------------------------------
|
||||
reStructuredText's `figure <https://docutils.sourceforge.io/docs/ref/rst/directives.html#figure>`_
|
||||
and `image <https://docutils.sourceforge.io/docs/ref/rst/directives.html#image>`_
|
||||
elements allow a document to include an image URL.
|
||||
|
||||
Image files created for TVM documentation should reside in the `<https://github.com/tlc-pack/web-data>`_
|
||||
repository, while the `.rst` files *using* those images should reside in the main TVM repostitory
|
||||
(`<https://github.com/apache/tvm>`_).
|
||||
|
||||
This will require two GitHub Pull Requests, one for the image files and another for the `.rst` files.
|
||||
Discussion between the contributor and reviewers may be necessary to coordinate the review process.
|
||||
|
||||
*IMPORTANT NOTE:* When using two Pull Requests as described above, please merge the
|
||||
Pull Request in `<https://github.com/tlc-pack/web-data>`_ *before* merging
|
||||
the Pull Request in `<https://github.com/apache/tvm>`_.
|
||||
This helps ensure that all URL links in TVM's online documentation are valid.
|
||||
@@ -0,0 +1,97 @@
|
||||
.. 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.
|
||||
|
||||
.. _error-handling-guide:
|
||||
|
||||
Error Handling Guide
|
||||
====================
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
TVM contains structured error classes to indicate specific types of error.
|
||||
Please raise a specific error type when possible, so that users can
|
||||
write code to handle a specific error category if necessary.
|
||||
You can directly raise the specific error object in python.
|
||||
In other languages like c++, you simply add ``<ErrorType>:`` prefix to
|
||||
the error message(see below).
|
||||
|
||||
.. note::
|
||||
|
||||
Please refer to :py:mod:`tvm.error` for the list of errors.
|
||||
|
||||
Raise a Specific Error in C++
|
||||
-----------------------------
|
||||
You can add ``<ErrorType>:`` prefix to your error message to
|
||||
raise an error of the corresponding type.
|
||||
Note that you do not have to add a new type
|
||||
:py:class:`tvm.error.InternalError` will be raised by default when
|
||||
there is no error type prefix in the message.
|
||||
This mechanism works for both ``LOG(FATAL)`` and ``TVM_FFI_ICHECK`` macros.
|
||||
The following code gives an example on how to do so.
|
||||
|
||||
.. code:: c
|
||||
|
||||
// src/api_test.cc
|
||||
void ErrorTest(int x, int y) {
|
||||
TVM_FFI_ICHECK_EQ(x, y) << "ValueError: expect x and y to be equal."
|
||||
if (x == 1) {
|
||||
LOG(FATAL) << "InternalError: cannot reach here";
|
||||
}
|
||||
}
|
||||
|
||||
When a C++ function registered via the FFI raises an error with a typed prefix,
|
||||
the TVM FFI system will automatically map it to the corresponding Python exception
|
||||
class. For example, a ``ValueError:`` prefix in the error message will raise a Python
|
||||
``ValueError``, and an ``InternalError:`` prefix will raise ``tvm.error.InternalError``.
|
||||
|
||||
TVM's FFI system combines both the Python and C++ stacktraces into a single message,
|
||||
and generates the corresponding error class automatically.
|
||||
|
||||
|
||||
How to choose an Error Type
|
||||
---------------------------
|
||||
You can go through the error types are listed below, try to use common
|
||||
sense and also refer to the choices in the existing code.
|
||||
We try to keep a reasonable amount of error types.
|
||||
If you feel there is a need to add a new error type, do the following steps:
|
||||
|
||||
- Send a RFC proposal with a description and usage examples in the current codebase.
|
||||
- Add the new error type to :py:mod:`tvm.error` with clear documents.
|
||||
- Update the list in this file to include the new error type.
|
||||
- Change the code to use the new error type.
|
||||
|
||||
We also recommend to use less abstraction when creating the short error messages.
|
||||
The code is more readable in this way, and also opens path to craft specific
|
||||
error messages when necessary.
|
||||
|
||||
.. code:: python
|
||||
|
||||
def preferred():
|
||||
# Very clear about what is being raised and what is the error message.
|
||||
raise OpNotImplemented("Operator relu is not implemented in the ONNX frontend")
|
||||
|
||||
def _op_not_implemented(op_name):
|
||||
return OpNotImplemented("Operator {} is not implemented.").format(op_name)
|
||||
|
||||
def not_preferred():
|
||||
# Introduces another level of indirection.
|
||||
raise _op_not_implemented("relu")
|
||||
|
||||
If we need to introduce a wrapper function that constructs multi-line error messages,
|
||||
please put wrapper in the same file so other developers can look up the implementation easily.
|
||||
@@ -0,0 +1,143 @@
|
||||
.. 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.
|
||||
|
||||
.. _git-howto:
|
||||
|
||||
|
||||
Git Usage Tips
|
||||
==============
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
Here are some tips for git workflow.
|
||||
|
||||
How to resolve a conflict with ``main``
|
||||
---------------------------------------
|
||||
|
||||
- First rebase to most recent main
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# The first two steps can be skipped after you do it once.
|
||||
git remote add upstream [url to tvm repo]
|
||||
git fetch upstream
|
||||
git rebase upstream/main
|
||||
|
||||
|
||||
- The git may show some conflicts it cannot merge, say ``conflicted.py``.
|
||||
|
||||
- Manually modify the file to resolve the conflict.
|
||||
- After you resolved the conflict, mark it as resolved by
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git add conflicted.py
|
||||
|
||||
- Then you can continue rebase by
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git rebase --continue
|
||||
|
||||
- Finally push to your fork, you may need to force push here.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git push --force
|
||||
|
||||
|
||||
How to combine multiple commits into one
|
||||
----------------------------------------
|
||||
|
||||
Sometimes we want to combine multiple commits, especially when later commits are only fixes to previous ones,
|
||||
to create a PR with set of meaningful commits. You can do it by following steps.
|
||||
|
||||
- Before doing so, configure the default editor of git if you haven't done so before.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git config core.editor the-editor-you-like
|
||||
|
||||
- Assume we want to merge last 3 commits, type the following commands
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git rebase -i HEAD~3
|
||||
|
||||
- It will pop up an text editor. Set the first commit as ``pick``, and change later ones to ``squash``.
|
||||
- After you saved the file, it will pop up another text editor to ask you modify the combined commit message.
|
||||
- Push the changes to your fork, you need to force push.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git push --force
|
||||
|
||||
|
||||
Reset to the most recent main branch
|
||||
------------------------------------
|
||||
|
||||
You can always use git reset to reset your version to the most recent main.
|
||||
Note that **all your local changes will get lost**.
|
||||
So only do it when you do not have local changes or when your pull request just get merged.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git fetch origin main
|
||||
git reset --hard FETCH_HEAD
|
||||
|
||||
|
||||
Recover a Previous Commit after Reset
|
||||
-------------------------------------
|
||||
Sometimes we could mistakenly reset a branch to a wrong commit.
|
||||
When that happens, you can use the following command to show the list
|
||||
of recent commits
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git reflog
|
||||
|
||||
Once you get the right hashtag, you can use git reset again to change
|
||||
the head to the right commit.
|
||||
|
||||
|
||||
Apply only k-Latest Commits on to the main
|
||||
------------------------------------------
|
||||
|
||||
Sometimes it is useful to only apply your k-latest changes on top of the main.
|
||||
This usually happens when you have other m-commits that are already merged
|
||||
before these k-commits. Directly rebase against the main might cause merge conflicts
|
||||
on these first m-commits (which can be safely discarded).
|
||||
|
||||
You can instead use the following command
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# k is the concrete number
|
||||
# Put HEAD~2 for the last 1 commit.
|
||||
git rebase --onto upstream/main HEAD~k
|
||||
|
||||
You can then force push to the main. Note that the above command will discard
|
||||
all the commits before tha last k ones.
|
||||
|
||||
|
||||
What is the consequence of force push
|
||||
-------------------------------------
|
||||
|
||||
The previous two tips requires force push, this is because we altered the path of the commits.
|
||||
It is fine to force push to your own fork, as long as the commits changed are only yours.
|
||||
@@ -0,0 +1,53 @@
|
||||
.. 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.
|
||||
|
||||
Contributor Guide
|
||||
=================
|
||||
|
||||
TVM has been developed by community members.
|
||||
Everyone is welcomed to contribute.
|
||||
We value all forms of contributions, including, but not limited to:
|
||||
|
||||
- Code reviewing of the existing patches.
|
||||
- Documentation and usage examples
|
||||
- Community participation in forums and issues.
|
||||
- Code readability and developer guide
|
||||
|
||||
- We welcome contributions that add code comments
|
||||
to improve readability
|
||||
- We also welcome contributions to docs to explain the
|
||||
design choices of the internal.
|
||||
|
||||
- Test cases to make the codebase more robust
|
||||
- Tutorials, blog posts, talks that promote the project.
|
||||
|
||||
Here are guidelines for contributing to various aspect of the project:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
community
|
||||
pull_request
|
||||
code_review
|
||||
committer_guide
|
||||
document
|
||||
code_guide
|
||||
testing
|
||||
git_howto
|
||||
ci
|
||||
release_process
|
||||
error_handling
|
||||
@@ -0,0 +1,267 @@
|
||||
.. 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.
|
||||
|
||||
Submit a Pull Request
|
||||
=====================
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
Guidelines
|
||||
----------
|
||||
|
||||
- We recommend authors send well scoped PRs that are easy to review and revert in case there is a problem. As such, authors should avoid merging multiple unrelated changes into a single PR
|
||||
- Before you submit a PR, please rebase your code on the most recent version of ``main``, you can do it by
|
||||
running
|
||||
|
||||
.. code:: bash
|
||||
|
||||
git remote add upstream [url to tvm repo]
|
||||
git fetch upstream
|
||||
git rebase upstream/main
|
||||
|
||||
- Make sure code passes lint checks
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# Run all lint checks via pre-commit hooks
|
||||
pre-commit run --all-files
|
||||
|
||||
# Run specific linters individually
|
||||
pre-commit run ruff-check --all-files # Python lint
|
||||
pre-commit run ruff-format --all-files # Python format
|
||||
pre-commit run clang-format --all-files # C++ format
|
||||
|
||||
- Add test-cases to cover the new features or bugfix the patch introduces.
|
||||
- Document the code you wrote, see more at :ref:`doc_guide`
|
||||
- `Create a pull request <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request>`_ and fix the problems reported by CI checks.
|
||||
- Request code reviews from other contributors and improve your patch according
|
||||
to their reviews by ``@``-ing them in your pull request. Use relevant topic
|
||||
tags in PR titles to make the affected area clear (e.g. ``[microTVM] Add a
|
||||
cool change`` and not ``a cool change for microTVM``).
|
||||
Please see the Commit Message Guideline below on the guidelines about the tags
|
||||
in a PR/commit title and how to write good PR/commit messages.
|
||||
|
||||
- To get your code reviewed quickly, we encourage you to help review others' code so they can do the favor in return.
|
||||
- Code review is a shepherding process that helps to improve contributor's code quality.
|
||||
We should treat it proactively, to improve the code as much as possible before the review.
|
||||
We highly value patches that can get in without extensive reviews.
|
||||
- The detailed guidelines and summarizes useful lessons.
|
||||
|
||||
- The PR can be merged after the reviewers approve the pull request.
|
||||
|
||||
Commit Message Guideline
|
||||
------------------------
|
||||
|
||||
Apache TVM uses the GitHub (GH) platform for patch submission and code review
|
||||
via Pull Requests (PRs). The final commit (title and body) that is merged into
|
||||
the Apache TVM main tree is composed of the PR's title and body and must be kept
|
||||
updated and reflecting the new changes in the code as per the reviews and
|
||||
discussions.
|
||||
|
||||
Although these guidelines apply essentially to the PRs’ title and body messages,
|
||||
because GH auto-generates the PR’s title and body from the commits on a given
|
||||
branch, it’s recommended to follow these guidelines right from the beginning,
|
||||
when preparing commits in general to be submitted to the Apache TVM project.
|
||||
This will ease the creation of a new PR, avoiding rework, and also will help the
|
||||
review.
|
||||
|
||||
The rules below will help to achieve uniformity that has several benefits, both
|
||||
for review and for the code base maintenance as a whole, helping you to write
|
||||
commit messages with a good quality suitable for the Apache TVM project,
|
||||
allowing fast log searches, bisecting, and so on.
|
||||
|
||||
*PR/commit title*:
|
||||
|
||||
- Guarantee a title exists (enforced);
|
||||
- Don’t use GitHub usernames in the title, like @username (enforced);
|
||||
- A tag must be present as a hint about what component(s) of the code
|
||||
the PRs / commits “touch” (enforced). For example [BugFix], [CI], [microTVM],
|
||||
and [TVMC]. Tags go between square brackets and appear first in the title. If
|
||||
more than one tag exist, multiple brackets should be used, like [BugFix][CI].
|
||||
The case recommended for tags, in geral, is the upper camel case. For example,
|
||||
prefer the forms [Fix], [BugFix], and [Docker] instead of [fix], [bug_fix],
|
||||
and [docker]. Acronyms should be kept as such so, for example, use [CI] and
|
||||
[TVMC] instead of [ci] and [tvmc]. Tags help reviewers to identify the PRs
|
||||
they can/want to review and also help the release folks when generating the
|
||||
release notes;
|
||||
- Use an imperative mood. Avoid titles like “Added operator X” and “Updated
|
||||
image Y in the CI”, instead use the forms “Add feature X” and “Update image Y
|
||||
in the CI” instead;
|
||||
- Observe proper use of caps at the beginning (uppercase for the first letter)
|
||||
and for acronyms, like, for instance, TVM, FVP, OpenCL. Hence instead of
|
||||
“fix tvm use of opencl library”, write it as “Fix TVM use of OpenCL library”;
|
||||
- Do not put a period at the end of the title.
|
||||
|
||||
*PR/commit body*:
|
||||
|
||||
- Guarantee a body exists (enforced);
|
||||
- Don’t use GitHub usernames in body text, like @username (enforced);
|
||||
- Avoid “bullet” commit message bodies: “bullet” commit message bodies are not
|
||||
bad per se, but “bullet” commit messages without any description or
|
||||
explanation is likely as bad as commits without any description, rationale,
|
||||
or explanation in the body.
|
||||
|
||||
For minor deviations from these guidelines, the community will normally favor
|
||||
reminding the contributor of this policy over reverting or blocking a commit /
|
||||
PR.
|
||||
|
||||
Commits and PRs without a title and/or a body are not considered minor
|
||||
deviations from these guidelines and hence must be avoided.
|
||||
|
||||
Most importantly, the contents of the commit message, especially the body,
|
||||
should be written to convey the intention of the change, so it should avoid
|
||||
being vague. For example, commits with a title like “Fix”, “Cleanup”, and
|
||||
“Fix flaky test” and without any body text should be avoided. Also, for the
|
||||
review, it will leave the reviewer wondering about what exactly was fixed or
|
||||
changed and why the change is necessary, slowing the review.
|
||||
|
||||
Below is an example that can be used as a model:
|
||||
|
||||
::
|
||||
|
||||
[microTVM] Zephyr: Remove zephyr_board option from build, flash, and open_transport methods
|
||||
|
||||
Currently it’s necessary to pass the board type via ‘zephyr_board’ option to
|
||||
the Project API build, flash, and open_transport methods.
|
||||
|
||||
However, since the board type is already configured when the project is
|
||||
created (i.e. when the generate_project method is called), it’s possible to
|
||||
avoid this redundancy by obtaining the board type from the project
|
||||
configuration files.
|
||||
|
||||
This commit adds code to obtain the board type from the project CMake files,
|
||||
removing this option from build, flash, and open_transport methods, so it’s
|
||||
only necessary to specify the ‘zephyr_board’ option when calling
|
||||
generate_project.
|
||||
|
||||
This commit also moves the ‘verbose’ and ‘west_cmd’ options from ‘build’
|
||||
method to ‘generate_project’, reducing further the number of required options
|
||||
when building a project, since the ‘build’ method is usually called more often
|
||||
than the ‘generate_project’.
|
||||
|
||||
After a new PR is created and the review starts it’s common that reviewers will
|
||||
request changes. Usually the author will address the reviewers’ comments and
|
||||
push additional commits on top of the initial ones. For these additional commits
|
||||
there is no recommendation regarding the commit messages. However if the
|
||||
additional commits render the PR title and/or body outdated then it's the
|
||||
author's responsibility to keep the PR title and body in sync with new changes
|
||||
in the code and updated the PR title and body accordingly (remember that the PR
|
||||
title and body will be used to compose the final commit message that will land
|
||||
in the main tree).
|
||||
|
||||
Committers will seek to fix any issues with the commit message prior to
|
||||
committing but they retain the right to inform the author of the rules and
|
||||
encourage them to follow them in future. Also, they retain the right to ask to
|
||||
the author to update the PR title and/or body when they are not correctly
|
||||
updated or fixed.
|
||||
|
||||
CI Environment
|
||||
--------------
|
||||
We use Docker images to create stable CI environments that can be deployed to multiple machines.
|
||||
Follow the steps in `this issue template <https://github.com/apache/tvm/issues/new?assignees=&labels=&template=ci-image.md&title=%5BCI+Image%5D+>`_
|
||||
to update a CI Docker image.
|
||||
|
||||
.. _pr-testing:
|
||||
|
||||
Testing
|
||||
-------
|
||||
Even though we have hooks to run unit tests automatically for each pull request, it's always recommended to run unit tests
|
||||
locally beforehand to reduce reviewers' burden and speedup review process.
|
||||
|
||||
Docker (recommended)
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
``tests/scripts/ci.py`` replicates the CI environment locally and provides a user-friendly interface.
|
||||
The same Docker images and scripts used in CI are used directly to run tests. It also deposits builds
|
||||
in different folders so you can maintain multiple test environments without rebuilding from scratch
|
||||
each time (e.g. you can test a change in CPU and GPU while retaining incremental rebuilds).
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# see all available platforms
|
||||
python tests/scripts/ci.py --help
|
||||
python tests/scripts/ci.py cpu --help
|
||||
|
||||
# run the CPU build in the ci_cpu docker container (build will be left in
|
||||
# the build-cpu/ folder)
|
||||
# note: the CPU and GPU Docker images are quite large and may take some
|
||||
# time to download on their first use
|
||||
python tests/scripts/ci.py cpu
|
||||
|
||||
# run the CPU build in the ci_cpu docker container and then run unittests
|
||||
python tests/scripts/ci.py cpu --unittest
|
||||
|
||||
# quickly iterate by running a specific test and skipping the rebuild each time
|
||||
python tests/scripts/ci.py cpu --skip-build --tests tests/python/s_tir/schedule/test_tir_schedule_rolling_buffer.py::test_upscale
|
||||
|
||||
# run the CPU build and drop into a shell in the container
|
||||
python tests/scripts/ci.py cpu --interactive
|
||||
|
||||
We regularly update our docker images and, over time, stale images may unnecessarily consume disk
|
||||
space. You can remove stale images that aren't used in the presently checked-out branch plus any
|
||||
other worktrees using the following command:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
docker/clear-stale-images.sh
|
||||
|
||||
Consult the ``--help`` for more options.
|
||||
|
||||
C++ (local)
|
||||
^^^^^^^^^^^
|
||||
|
||||
Running the C++ tests requires installation of gtest, following the instructions in
|
||||
:ref:`install-from-source-cpp-tests`
|
||||
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# assume you are in tvm source root
|
||||
TVM_ROOT=`pwd`
|
||||
|
||||
./tests/scripts/task_cpp_unittest.sh
|
||||
|
||||
Python (local)
|
||||
^^^^^^^^^^^^^^
|
||||
Necessary dependencies:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pip install --user pytest pytest-xdist Cython
|
||||
|
||||
If you want to run all tests:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# build tvm (see install-from-source for CMake build instructions)
|
||||
cd build && cmake .. && cmake --build . --parallel $(nproc) && cd ..
|
||||
|
||||
python -m pytest -vvs -n auto tests/python
|
||||
|
||||
If you want to run a single test:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
# let python know where to find tvm related libraries
|
||||
export PYTHONPATH=python
|
||||
rm -rf python/tvm/*.pyc python/tvm/*/*.pyc python/tvm/*/*/*.pyc
|
||||
|
||||
python -m pytest -v tests/python/tirx-transform/test_tir_transform_storage_rewrite.py
|
||||
|
||||
# Additionally if you want to run a single test, for example test_add_one_2d inside a file.
|
||||
python -m pytest -v -k "test_add_one_2d" tests/python/relax/test_frontend_tflite.py
|
||||
@@ -0,0 +1,314 @@
|
||||
.. 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.
|
||||
|
||||
.. _release_process:
|
||||
|
||||
Release Process
|
||||
===============
|
||||
|
||||
.. contents::
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
The release manager role in TVM means you are responsible for a few different things:
|
||||
|
||||
- Preparing release notes
|
||||
- Preparing your setup
|
||||
- Preparing for release candidates
|
||||
|
||||
- Cutting a release branch
|
||||
- Informing the community of timing
|
||||
- Making any necessary code changes in that branch (versions are derived from Git tags, so there are no manual version-number edits)
|
||||
|
||||
- Running the voting process for a release
|
||||
|
||||
- Creating release candidates
|
||||
- Calling votes and triaging issues
|
||||
|
||||
- Finalizing and posting a release:
|
||||
|
||||
- Updating the TVM website
|
||||
- Finalizing release notes
|
||||
- Announcing the release
|
||||
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
TVM's version is derived automatically from the most recent Git tag by
|
||||
`setuptools_scm <https://setuptools-scm.readthedocs.io/>`_ at build time (configured
|
||||
under ``[tool.setuptools_scm]`` in ``pyproject.toml``). There are **no version numbers
|
||||
to edit by hand** in ``pyproject.toml``, ``python/tvm/libinfo.py`` or
|
||||
``include/tvm/runtime/base.h``; releasing is driven entirely by pushing Git tags:
|
||||
|
||||
- ``main`` carries a ``vMAJOR.MINOR.devN`` tag (e.g. ``v0.7.dev0``). Commits after it
|
||||
are versioned ``0.7.devN`` where ``N`` is the number of commits since the tag. This
|
||||
is why the next dev tag must be pushed on ``main`` when a release branch is cut:
|
||||
without it, follow-up commits would keep deriving their version from the previous
|
||||
cycle's tag.
|
||||
- A release branch (e.g. ``v0.6``) is tagged ``v0.6.0.rc0`` for a candidate (wheel
|
||||
version ``0.6.0rc0``) and ``v0.6.0`` for the formal release (wheel version
|
||||
``0.6.0``). Release wheels are built on the exact tag, so the version is the tag
|
||||
itself.
|
||||
|
||||
The legacy ``version.py`` stamping script has been removed. ``web/package.json`` (npm,
|
||||
a separate ecosystem) is no longer auto-stamped; bump it by hand when starting a new dev
|
||||
cycle or cutting a release. ``docs/conf.py`` reads ``tvm.__version__`` directly.
|
||||
|
||||
|
||||
Prepare the Release Notes
|
||||
-------------------------
|
||||
|
||||
Release note contains new features, improvement, bug fixes, known issues and deprecation, etc. TVM provides `monthly dev report <https://discuss.tvm.apache.org/search?q=TVM%20Monthly%20%23Announcement>`_ collects developing progress each month. It could be helpful to who writes the release notes.
|
||||
|
||||
It is recommended to open a GitHub issue to collect feedbacks for the release note draft before cutting the release branch. See the scripts in ``tests/scripts/release`` for some starting points.
|
||||
|
||||
|
||||
Prepare the Release Candidate
|
||||
-----------------------------
|
||||
|
||||
There may be some code changes necessary on the release branch before the release (for
|
||||
example cherry-picked fixes). Version numbers are derived from the release tags (see
|
||||
`Versioning`_), so there are no version numbers to update by hand.
|
||||
|
||||
|
||||
Prepare the GPG Key
|
||||
-------------------
|
||||
|
||||
You can skip this section if you have already uploaded your key.
|
||||
|
||||
After generating the gpg key, you need to upload your key to a public key server. Please refer to https://www.apache.org/dev/openpgp.html#generate-key for details.
|
||||
|
||||
If you want to do the release on another machine, you can transfer your gpg key to that machine via the ``gpg --export`` and ``gpg --import`` commands.
|
||||
|
||||
The last step is to update the KEYS file with your code signing key https://www.apache.org/dev/openpgp.html#export-public-key. Check in the changes to the TVM main branch, as well as ASF SVN,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# the --depth=files will avoid checkout existing folders
|
||||
svn co --depth=files "https://dist.apache.org/repos/dist/dev/tvm" svn-tvm
|
||||
cd svn-tvm
|
||||
# edit KEYS file
|
||||
svn ci --username $ASF_USERNAME --password "$ASF_PASSWORD" -m "Update KEYS"
|
||||
# update downloads.apache.org (note that only PMC members can update the dist/release directory)
|
||||
svn rm --username $ASF_USERNAME --password "$ASF_PASSWORD" https://dist.apache.org/repos/dist/release/tvm/KEYS -m "Update KEYS"
|
||||
svn cp --username $ASF_USERNAME --password "$ASF_PASSWORD" https://dist.apache.org/repos/dist/dev/tvm/KEYS https://dist.apache.org/repos/dist/release/tvm/ -m "Update KEYS"
|
||||
|
||||
|
||||
Cut a Release Candidate
|
||||
-----------------------
|
||||
|
||||
To cut a release candidate for the ``v0.6`` release:
|
||||
|
||||
#. On the ``main`` commit that should be the last one included in the release, push the
|
||||
**next** dev-cycle tag ``v0.7.dev0``. This tag is what makes subsequent ``main``
|
||||
commits versioned ``0.7.devN`` (see `Versioning`_), so it must be pushed *before*
|
||||
branching.
|
||||
#. Cut the release branch off that same commit. Branches are named with the base
|
||||
release version without the patch, e.g. ``v0.6`` for the ``v0.6.0`` release.
|
||||
#. Push the first release-candidate tag ``v0.6.0.rc0`` on the release branch. CI then
|
||||
builds the candidate wheel (version ``0.6.0rc0``) for PyPI/TestPyPI testing. Keep
|
||||
this tag on a ``v0.6`` branch commit that is **not** also the ``v0.7.dev0``-tagged
|
||||
branch point: when two tags share one commit, which one ``setuptools_scm`` picks is
|
||||
fragile, so put the candidate tag on a release-prep commit on the branch.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/apache/tvm.git
|
||||
cd tvm/
|
||||
|
||||
# 1. Tag the next dev cycle on main (drives main's 0.7.devN version),
|
||||
# on the last commit to be included in the release.
|
||||
git checkout <last-commit-for-release>
|
||||
git tag v0.7.dev0
|
||||
git push origin refs/tags/v0.7.dev0
|
||||
|
||||
# 2. Cut the release branch off that same commit.
|
||||
git branch v0.6
|
||||
git push --set-upstream origin v0.6
|
||||
|
||||
# 3. Tag the first release candidate on the release branch. Keep this tag on a
|
||||
# release-prep commit, NOT the v0.7.dev0-tagged branch point, so the two tags
|
||||
# never share a commit.
|
||||
git checkout v0.6
|
||||
# ... make any release-prep commits (release notes, etc.) here ...
|
||||
git tag v0.6.0.rc0
|
||||
git push origin refs/tags/v0.6.0.rc0
|
||||
|
||||
The wheel/distribution version is derived from these tags by ``setuptools_scm`` at build
|
||||
time, so no source files need editing and you no longer run ``version.py`` to stamp the
|
||||
version (see `Versioning`_).
|
||||
|
||||
Go to the GitHub repositories "releases" tab and click "Draft a new release",
|
||||
|
||||
- Verify the release by checking the version numbers and ensuring that TVM can build and run the unit tests.
|
||||
- Provide the release tag in the form of ``v1.0.0.rc0`` where 0 means it's the first release candidate. The tag must match this pattern ``v[0-9]+\.[0-9]+\.[0-9]+\.rc[0-9]`` exactly!
|
||||
- Select the commit by clicking Target: branch > Recent commits > $commit_hash
|
||||
- Copy and paste release note draft into the description box
|
||||
- Select "This is a pre-release"
|
||||
- Click "Publish release"
|
||||
|
||||
Notice that one can still apply changes to the branch after the cut, while the tag is fixed. If any change is required for this release, a new tag has to be created.
|
||||
|
||||
Remove previous release candidate (if applied),
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git push --delete origin v0.6.0.rc1
|
||||
|
||||
Create source code artifacts,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Replace v0.6.0 with the relevant version
|
||||
git clone git@github.com:apache/tvm.git apache-tvm-src-v0.6.0
|
||||
cd apache-tvm-src-v0.6.0
|
||||
git checkout v0.6
|
||||
git submodule update --init --recursive
|
||||
git checkout v0.6.0.rc0
|
||||
rm -rf .DS_Store
|
||||
find . -name ".git*" -print0 | xargs -0 rm -rf
|
||||
cd ..
|
||||
brew install gnu-tar
|
||||
gtar -czvf apache-tvm-src-v0.6.0.rc0.tar.gz apache-tvm-src-v0.6.0
|
||||
|
||||
Use your GPG key to sign the created artifact. First make sure your GPG is set to use the correct private key,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat ~/.gnupg/gpg.conf
|
||||
default-key F42xxxxxxxxxxxxxxx
|
||||
|
||||
Create GPG signature as well as the hash of the file,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
gpg --armor --output apache-tvm-src-v0.6.0.rc0.tar.gz.asc --detach-sig apache-tvm-src-v0.6.0.rc0.tar.gz
|
||||
shasum -a 512 apache-tvm-src-v0.6.0.rc0.tar.gz > apache-tvm-src-v0.6.0.rc0.tar.gz.sha512
|
||||
|
||||
|
||||
Update TVM Version on ``main``
|
||||
------------------------------
|
||||
|
||||
The next dev-cycle tag pushed on ``main`` during the cut (step 1 above, e.g. ``v0.7.dev0``)
|
||||
is what gives ``main`` its ``0.7.devN`` version — ``setuptools_scm`` derives it from that
|
||||
tag, so there are **no source version numbers to bump** (the old two-commit ``[Dont Squash]``
|
||||
bump and the ``python version.py`` stamping step are no longer needed). Make sure that tag
|
||||
sits on the ``main`` commit immediately after the last one included in the release branch;
|
||||
it is required so that nightly/dev packages built from ``main`` carry the correct
|
||||
``0.7.devN`` version.
|
||||
|
||||
Upload the Release Candidate
|
||||
----------------------------
|
||||
|
||||
Edit the release page on GitHub and upload the artifacts created by the previous steps.
|
||||
|
||||
The release manager also needs to upload the artifacts to ASF SVN,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# the --depth=files will avoid checkout existing folders
|
||||
svn co --depth=files "https://dist.apache.org/repos/dist/dev/tvm" svn-tvm
|
||||
cd svn-tvm
|
||||
mkdir tvm-v0.6.0-rc0
|
||||
# copy files into it
|
||||
svn add tvm-0.6.0-rc0
|
||||
svn ci --username $ASF_USERNAME --password "$ASF_PASSWORD" -m "Add RC"
|
||||
|
||||
|
||||
Cherry-Picking
|
||||
--------------
|
||||
After a release branch has been cut but before the release has been voted on, the release manager may cherry-pick commits from ``main``. Since release branches are protected on GitHub, to merge this fixes into the release branch (e.g. ``v0.11``), the release manager must file a PR with the cherry-picked changes against the release branch. The PR should roughly match the original one from ``main`` with extra details on why the commit is being cherry-picked. The community then goes through a normal review and merge process for these PRs. Note that these PRs against the release branches must be `signed <https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits>`_.
|
||||
|
||||
|
||||
Call a Vote on the Release Candidate
|
||||
------------------------------------
|
||||
|
||||
The first voting takes place on the Apache TVM developers list (dev@tvm.apache.org). To get more attention, one can create a GitHub issue start with "[VOTE]" instead, it will be mirrored to dev@ automatically. Look at past voting threads to see how this proceeds. The email should follow this format.
|
||||
|
||||
- Provide the link to the draft of the release notes in the email
|
||||
- Provide the link to the release candidate artifacts
|
||||
- Make sure the email is in text format and the links are correct
|
||||
|
||||
For the dev@ vote, there must be at least 3 binding +1 votes and more +1 votes than -1 votes. Once the vote is done, you should also send out a summary email with the totals, with a subject that looks something like [VOTE][RESULT] ....
|
||||
|
||||
In ASF, votes are open at least 72 hours (3 days). If you don't get enough number of binding votes within that time, you cannot close the voting deadline. You need to extend it.
|
||||
|
||||
If the vote fails, the community needs to modify the release accordingly: create a new release candidate and re-run the voting process.
|
||||
|
||||
|
||||
Post the Release
|
||||
----------------
|
||||
|
||||
After the vote passes, to upload the binaries to Apache mirrors, you move the binaries from dev directory (this should be where they are voted) to release directory. This "moving" is the only way you can add stuff to the actual release directory. (Note: only PMC can move to release directory)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export SVN_EDITOR=vim
|
||||
svn mkdir https://dist.apache.org/repos/dist/release/tvm
|
||||
svn mv https://dist.apache.org/repos/dist/dev/tvm/tvm-v0.6.0-rc2 https://dist.apache.org/repos/dist/release/tvm/tvm-v0.6.0
|
||||
|
||||
# If you've added your signing key to the KEYS file, also update the release copy.
|
||||
svn co --depth=files "https://dist.apache.org/repos/dist/release/tvm" svn-tvm
|
||||
curl "https://dist.apache.org/repos/dist/dev/tvm/KEYS" > svn-tvm/KEYS
|
||||
(cd svn-tvm && svn ci --username $ASF_USERNAME --password "$ASF_PASSWORD" -m"Update KEYS")
|
||||
|
||||
Remember to create a new release TAG (v0.6.0 in this case) on GitHub and remove the pre-release candidate TAG.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git push --delete origin v0.6.0.rc2
|
||||
|
||||
|
||||
Update the TVM Website
|
||||
----------------------
|
||||
|
||||
The website repository is located at `https://github.com/apache/tvm-site <https://github.com/apache/tvm-site>`_. Modify the download page to include the release artifacts as well as the GPG signature and SHA hash. Since TVM's docs are continually updated, upload a fixed version of the release docs. If CI has deleted the docs from the release by the time you go to update the website, you can restart the CI build for the release branch on Jenkins. See the example code below for a starting point.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/apache/tvm-site.git
|
||||
pushd tvm-site
|
||||
git checkout asf-site
|
||||
pushd docs
|
||||
|
||||
# make release docs directory
|
||||
mkdir v0.9.0
|
||||
pushd v0.9.0
|
||||
|
||||
# download the release docs from CI
|
||||
# find this URL by inspecting the CI logs for the most recent build of the release branch
|
||||
curl -LO https://tvm-jenkins-artifacts-prod.s3.us-west-2.amazonaws.com/tvm/v0.9.0/1/docs/docs.tgz
|
||||
tar xf docs.tgz
|
||||
rm docs.tgz
|
||||
|
||||
# add the docs and push
|
||||
git add .
|
||||
git commit -m "Add v0.9.0 docs"
|
||||
git push
|
||||
|
||||
|
||||
Afterwards, modify the `downloads page <https://tvm.apache.org/download>`_ to support the latest release. An example of how to do this is `here <https://github.com/apache/tvm-site/pull/38>`_.
|
||||
|
||||
Post the Announcement
|
||||
---------------------
|
||||
|
||||
Send out an announcement email to announce@apache.org, and dev@tvm.apache.org. The announcement should include the link to release note and download page.
|
||||
|
||||
Patch Releases
|
||||
--------------
|
||||
Patch releases should be reserved for critical bug fixes. Patch releases must go through the same process as normal releases, with the option at the release manager's discretion of a shortened release candidate voting window of 24 hours to ensure that fixes are delivered quickly. A patch release is cut purely by tagging the release base branch (e.g. ``v0.11``): push ``v0.11.1.rc0`` for the candidate and ``v0.11.1`` for the formal patch release; no source version numbers need bumping.
|
||||
@@ -0,0 +1,312 @@
|
||||
.. 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.
|
||||
|
||||
Testing TVM
|
||||
===========
|
||||
|
||||
This page describes how to write and run Python tests for TVM,
|
||||
including the target parametrization utilities used by CI.
|
||||
|
||||
Python Target Parametrization
|
||||
-----------------------------
|
||||
|
||||
Summary
|
||||
~~~~~~~
|
||||
|
||||
For any supported runtime, TVM should produce numerically
|
||||
correct results. Therefore, when writing unit tests that validate
|
||||
the numeric output, these unit tests should be run on all supported
|
||||
runtimes. Since this is a very common use case, TVM has helper
|
||||
functions to parametrize unit tests such that they will run on all
|
||||
targets that are enabled and have a compatible device.
|
||||
|
||||
A single Python function in the test suite can expand to several
|
||||
parameterized unit tests, each of which tests a single target device.
|
||||
In order for a test to be run, all of the following must be true.
|
||||
|
||||
- The test exists in a file or directory that has been passed to
|
||||
`pytest`.
|
||||
|
||||
- The pytest marks applied to the function, either explicitly or
|
||||
through target parametrization, must be compatible with the
|
||||
expression passed to pytest's `-m` argument.
|
||||
|
||||
- For parametrized tests using the `target` fixture, the target must
|
||||
appear in the environment variable `TVM_TEST_TARGETS`.
|
||||
|
||||
- For parametrized tests using the `target` fixture, the build
|
||||
configuration in `config.cmake` must enable the corresponding
|
||||
runtime.
|
||||
|
||||
Unit-Test File Contents
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. _pytest-marks: https://docs.pytest.org/en/stable/how-to/mark.html
|
||||
|
||||
The recommended way to run a test on multiple targets is to parametrize
|
||||
over ``target`` with ``@pytest.mark.parametrize``. Tag each GPU target
|
||||
with ``pytest.mark.gpu`` so the CI routes it to a GPU node, skip a target
|
||||
that cannot run on the current machine with
|
||||
:py:func:`tvm.testing.device_enabled`, and obtain its device with
|
||||
``tvm.device(target)``. The function is run once per target, the
|
||||
success/failure of each is reported separately, and a target whose device
|
||||
is disabled in ``config.cmake`` or absent from the machine is reported as
|
||||
skipped.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"target",
|
||||
["llvm", pytest.param("cuda", marks=pytest.mark.gpu)],
|
||||
)
|
||||
def test_function(target):
|
||||
if not tvm.testing.device_enabled(target):
|
||||
pytest.skip(f"{target} not enabled")
|
||||
dev = tvm.device(target)
|
||||
# Test code goes here
|
||||
|
||||
For a test that only applies to a single target, omit the parametrization
|
||||
and gate the test with ``@pytest.mark.skipif`` (plus ``@pytest.mark.gpu``
|
||||
for a GPU target):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(
|
||||
not tvm.testing.device_enabled("cuda"), reason="cuda not enabled"
|
||||
)
|
||||
def test_function():
|
||||
target = "cuda"
|
||||
dev = tvm.device(target)
|
||||
# Test code goes here
|
||||
|
||||
To exclude a target, leave it out of the parametrize list. To mark a
|
||||
target as expected to fail, wrap it with
|
||||
``pytest.param("target", marks=pytest.mark.xfail(reason=...))``.
|
||||
|
||||
Additional parameters can be combined with the target parametrization by
|
||||
stacking ``@pytest.mark.parametrize`` decorators, or by listing tuples of
|
||||
arguments. Tag the GPU rows with ``pytest.mark.gpu`` and skip in the body
|
||||
as above:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.parametrize("target,impl", [
|
||||
("llvm", cpu_implementation),
|
||||
pytest.param("cuda", gpu_implementation_small_batch, marks=pytest.mark.gpu),
|
||||
pytest.param("cuda", gpu_implementation_large_batch, marks=pytest.mark.gpu),
|
||||
])
|
||||
def test_function(target, impl):
|
||||
if not tvm.testing.device_enabled(target):
|
||||
pytest.skip(f"{target} not enabled")
|
||||
dev = tvm.device(target)
|
||||
# Test code goes here
|
||||
|
||||
|
||||
Tests gate on hardware and carry metadata using
|
||||
`pytest marks <pytest-marks>`_. The most frequently applied
|
||||
marks are as follows.
|
||||
|
||||
- ``@pytest.mark.gpu`` - Tags a function as using GPU
|
||||
capabilities. This has no effect on its own, but can be paired with
|
||||
the command-line arguments ``-m gpu`` or ``-m 'not gpu'`` to restrict
|
||||
which tests pytest will execute. Apply it to any test that needs a
|
||||
GPU so that the CI runs it only on GPU nodes.
|
||||
|
||||
- ``@pytest.mark.skipif(not tvm.testing.env.has_X(), reason=...)`` -
|
||||
Skips a test when a required runtime or hardware feature is not
|
||||
available. The :py:mod:`tvm.testing.env` module exposes one memoized
|
||||
probe per capability (e.g. ``has_cuda()``, ``has_rocm()``,
|
||||
``has_vulkan()``, ``has_gpu()``, ``has_llvm()``), each of which
|
||||
returns ``False`` when the runtime is disabled in ``config.cmake`` or
|
||||
no compatible device is present. Pair it with ``@pytest.mark.gpu``
|
||||
for tests that use the GPU::
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not tvm.testing.env.has_cuda(), reason="need cuda")
|
||||
def test_cuda_vectorize_add():
|
||||
# Test code goes here
|
||||
|
||||
- ``pytest.importorskip("package_name")`` - Skips a test (or the whole
|
||||
module, when called at import time) if an optional Python package is
|
||||
not installed. Use this instead of a ``skipif`` for package
|
||||
dependencies.
|
||||
|
||||
Tests that execute on a local GPU must put the complete live-device
|
||||
lifetime in a small callback passed to
|
||||
:py:func:`tvm.testing.run_with_gpu_lock`. Target construction and
|
||||
compilation remain outside so that pytest-xdist workers can compile in
|
||||
parallel. Device creation, allocation, execution, synchronization,
|
||||
host conversion, result checks, and child-process teardown remain inside
|
||||
the callback so no device-backed object outlives the lock.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not tvm.testing.env.has_cuda(), reason="need cuda")
|
||||
def test_cuda_add_one():
|
||||
target = tvm.target.Target("cuda -arch=sm_90")
|
||||
executable = tvm.compile(make_add_one_module(), target)
|
||||
host_input = np.arange(16, dtype="float32")
|
||||
|
||||
def run_and_check():
|
||||
dev = tvm.cuda(0)
|
||||
device_input = tvm.runtime.tensor(host_input, dev)
|
||||
device_output = tvm.runtime.empty(host_input.shape, "float32", dev)
|
||||
executable(device_input, device_output)
|
||||
dev.sync()
|
||||
tvm.testing.assert_allclose(device_output.numpy(), host_input + 1)
|
||||
|
||||
tvm.testing.run_with_gpu_lock(run_and_check)
|
||||
|
||||
The wrapper uses the existing :py:class:`tvm_ffi.utils.FileLock` with a
|
||||
persistent machine-local path. A process exit releases the kernel lock;
|
||||
the remaining file is not stale ownership. Test startup must never
|
||||
delete or rotate it, because another process could then lock a different
|
||||
inode. Set ``TVM_TEST_LOCK_DIR`` only when all cooperating processes need
|
||||
an explicitly configured shared machine-local directory. The default
|
||||
temporary path coordinates processes running as the same user. Multi-user
|
||||
runners sharing a GPU must use one administrator-provisioned directory and
|
||||
persistent lock file that every contender can write, or enforce exclusivity
|
||||
through the runner. A per-user lock path cannot protect a GPU shared across
|
||||
users because each user would lock a different file.
|
||||
|
||||
There also exists a ``tvm.testing.enabled_targets()`` that returns
|
||||
all targets that are enabled and runnable on the current machine,
|
||||
based on the environment variable ``TVM_TEST_TARGETS``, the build
|
||||
configuration, and the physical hardware present. Some legacy tests
|
||||
explicitly loop over the targets returned from ``enabled_targets()``,
|
||||
but this style should not be used for new tests. The pytest output
|
||||
for this style silently skips runtimes that are disabled in
|
||||
``config.cmake``, or do not have a device on which they can run. In
|
||||
addition, the test halts on the first target to fail, which is
|
||||
ambiguous as to whether the error occurs on a particular target, or on
|
||||
every target.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Old style, do not use.
|
||||
def test_function():
|
||||
for target, dev in tvm.testing.enabled_targets():
|
||||
# Test code goes here
|
||||
|
||||
|
||||
|
||||
Running Locally
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
To run the Python unit tests locally, use the command ``pytest`` in
|
||||
the ``${TVM_HOME}`` directory.
|
||||
|
||||
- Environment variables
|
||||
- ``TVM_TEST_TARGETS`` should be a semicolon-separated list of
|
||||
targets to run. If unset, will default to the targets defined in
|
||||
``tvm.testing.DEFAULT_TEST_TARGETS``.
|
||||
|
||||
Note: If ``TVM_TEST_TARGETS`` does not contain any targets that
|
||||
are both enabled, and have an accessible device of that type,
|
||||
then the tests will fall back to running on the ``llvm`` target
|
||||
only.
|
||||
|
||||
- ``TVM_LIBRARY_PATH`` should be a path to the ``libtvm.so``
|
||||
library. This can be used, for example, to run tests using a
|
||||
debug build. If unset, will search for ``libtvm.so`` relative to
|
||||
the TVM source directory.
|
||||
|
||||
- Command-line arguments
|
||||
|
||||
- Passing a path to a folder or file will run only the unit tests
|
||||
in that folder or file. This can be useful, for example, to
|
||||
avoid running tests located in ``tests/python/contrib`` on a
|
||||
system without a specific backend installed.
|
||||
|
||||
- The ``-m`` argument only runs unit tests that are tagged with a
|
||||
specific pytest marker. The most frequent usage is to use
|
||||
``-m gpu`` to run only tests that are marked with
|
||||
``@pytest.mark.gpu`` and use a GPU to run. It can also be used
|
||||
to run only tests that do not use a GPU, by passing ``not gpu``
|
||||
as the marker expression to ``-m``.
|
||||
|
||||
Note: This filtering takes place after the selection of targets
|
||||
based on the ``TVM_TEST_TARGETS`` environment variable. Even if
|
||||
``-m gpu`` is specified, if ``TVM_TEST_TARGETS`` does not
|
||||
contain GPU targets, no GPU tests will be run.
|
||||
|
||||
Running in a Local Docker Container
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. _tlcpack: https://hub.docker.com/u/tlcpack
|
||||
|
||||
The ``docker/bash.sh`` script can be used to run unit tests inside the
|
||||
same docker image as is used by the CI. The first argument should
|
||||
specify which docker image to run (e.g. ``docker/bash.sh ci_gpu``).
|
||||
Allowed image names are defined in ``ci/jenkins/data.py`` in the TVM source directory,
|
||||
and map to images at `tlcpack`_.
|
||||
|
||||
If no additional arguments are given, the docker image will be loaded
|
||||
with an interactive bash session. If a script is passed as an
|
||||
optional argument (e.g. ``docker/bash.sh ci_gpu tests/scripts/task_python_unittest.sh``), then that script will be
|
||||
executed inside the docker image.
|
||||
|
||||
Note: The docker images contain all system dependencies, but do not
|
||||
include the ``build/config.cmake`` configuration file for those
|
||||
systems. The TVM source directory is used as the home directory of
|
||||
the docker image, and so this will default to using the same
|
||||
config/build directories as the local config. One solution is to
|
||||
maintain separate ``build_local`` and ``build_docker`` directories,
|
||||
and make a symlink from ``build`` to the appropriate folder when
|
||||
entering/exiting docker.
|
||||
|
||||
Running in CI
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Everything in the CI starts from the task definitions present in the
|
||||
Jenkinsfile. This includes defining which docker image gets used,
|
||||
what the compile-time configuration is, and which tests are included
|
||||
in which stages.
|
||||
|
||||
- Docker images
|
||||
|
||||
Each task of the Jenkinsfile (e.g. 'BUILD: CPU') makes calls to
|
||||
``docker/bash.sh``. The argument following the call to
|
||||
docker/bash.sh defines the docker image in CI, just as it does
|
||||
locally.
|
||||
|
||||
- Compile-time configuration
|
||||
|
||||
The docker image does not have the ``config.cmake`` file built into
|
||||
it, so this is the first step in each of the ``BUILD`` tasks. This
|
||||
is done using the ``tests/scripts/task_config_build_*.sh`` scripts.
|
||||
Which script is used depends on the build being tested, and is
|
||||
specified in the Jenkinsfile.
|
||||
|
||||
Each ``BUILD`` task concludes by packing a library for use in later
|
||||
tests.
|
||||
|
||||
- Which tests run
|
||||
|
||||
The ``Unit Test`` stage of the Jenkinsfile determines how ``pytest``
|
||||
is called. Each task starts by unpacking a
|
||||
compiled library that was previous compiled in the ``BUILD`` stage,
|
||||
then runs a test script
|
||||
(e.g. ``tests/scripts/task_python_unittest.sh``). These scripts set
|
||||
the files/folders and command-line options that are passed to
|
||||
``pytest``.
|
||||
|
||||
Several of these scripts include the ``-m gpu`` option, which
|
||||
restricts the tests to only run tests that include the
|
||||
``@pytest.mark.gpu`` mark.
|
||||
Reference in New Issue
Block a user