Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletions .github/workflows/ci_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,13 @@ jobs:

lint:
needs: [prepare]
if: >
needs.prepare.outputs.should_skip_ci_commit != 'true' &&
needs.prepare.outputs.should_skip_ci_docs_only != 'true'
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install dependencies
run: |
pip install black pylint ruff
sudo apt-get install -y clang-format-15

- name: Lint
run: |
tests/scripts/task_lint.sh

- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1

test:
needs: [prepare]
needs: [lint, prepare]
if: >
needs.prepare.outputs.should_skip_ci_commit != 'true' &&
needs.prepare.outputs.should_skip_ci_docs_only != 'true'
Expand Down
51 changes: 50 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,29 @@
# specific language governing permissions and limitations
# under the License.

# TODO(@junrushao): adding a few extra hooks:
# - Python type checking via mypy or ty
# - CMake linters
# - Conventional commits
default_install_hook_types:
- pre-commit
repos:
# Standard hooks
- repo: local
hooks:
- id: check-asf-header
name: check ASF Header
entry: python tests/lint/check_asf_header.py --check
language: system
pass_filenames: false
verbose: false
- repo: local
hooks:
- id: check-file-type
name: check file types
entry: python tests/lint/check_file_type.py
language: system
pass_filenames: false
verbose: false
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
Expand All @@ -28,3 +49,31 @@ repos:
- id: mixed-line-ending
- id: requirements-txt-fixer
- id: trailing-whitespace
- id: check-yaml
- id: check-toml
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.3
hooks:
- id: ruff-check
types_or: [python, pyi, jupyter]
args: [--fix]
- id: ruff-format
types_or: [python, pyi, jupyter]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v20.1.8"
hooks:
- id: clang-format
- repo: https://github.com/MarcoGorelli/cython-lint
rev: v0.16.7
hooks:
- id: cython-lint
args: [--max-line-length=120]
- id: double-quote-cython-strings
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
hooks:
- id: shfmt
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,3 @@
# tvm ffi

[![CI](https://github.com/apache/tvm-ffi/actions/workflows/ci_test.yml/badge.svg)](https://github.com/apache/tvm-ffi/actions/workflows/ci_test.yml)


2 changes: 1 addition & 1 deletion docs/_static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
See: https://github.com/executablebooks/sphinx-book-theme/issues/732 */
#rtd-footer-container {
margin: 0px !important;
}
}
7 changes: 3 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# under the License.
# -*- coding: utf-8 -*-
import os
import sys

import tomli

Expand Down Expand Up @@ -198,7 +197,7 @@ def footer_html():
<div class="dropdown">
<button class="btn btn-link dropdown-toggle" type="button" id="footerDropdown" data-bs-toggle="dropdown"
aria-expanded="false" style="font-size: 0.9em; color: #6c757d; text-decoration: none; padding: 0; border: none; background: none;">
{footer_dropdown['name']}
{footer_dropdown["name"]}
</button>
<ul class="dropdown-menu" aria-labelledby="footerDropdown" style="font-size: 0.9em;">
{dropdown_items} </ul>
Expand Down Expand Up @@ -226,6 +225,6 @@ def footer_html():
"conf_py_path": "/docs/",
}

html_static_path = ['_static']
html_static_path = ["_static"]

html_css_files = ['custom.css']
html_css_files = ["custom.css"]
1 change: 0 additions & 1 deletion docs/get_started/quick_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,3 @@ The main takeaway points are:
- **ffi::Tensor** is a universal tensor structure that enables zero-copy exchange of array data
- **Module loading** is provided by tvm ffi APIs in multiple languages.
- **C ABI** is provided for easy low-level integration

23 changes: 11 additions & 12 deletions docs/guides/compiler_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,14 @@ with various kernel DSLs and libraries.

## Runtime and State Management for Compilers

While TVM FFI provides a standard ABI for compiler-generated kernels, many compilers and domain-specific languages
(DSLs) require their own **runtime** to manage states like dynamic shapes, workspace memory, or other
application-specific data. This runtime can be a separate shared library accessible to all kernels from a specific
While TVM FFI provides a standard ABI for compiler-generated kernels, many compilers and domain-specific languages
(DSLs) require their own **runtime** to manage states like dynamic shapes, workspace memory, or other
application-specific data. This runtime can be a separate shared library accessible to all kernels from a specific
compiler.

### Recommended Approach for State Management

The recommended approach for managing compiler-specific state is to define the state within a **separate shared library**.
The recommended approach for managing compiler-specific state is to define the state within a **separate shared library**.
This library exposes its functionality by registering functions as global `tvm::ffi::Function`s.

Here's a breakdown of the process:
Expand All @@ -144,21 +144,21 @@ Here's a breakdown of the process:
This method allows both C++ and Python to access the runtime state through a consistent API.
3. **Access State from Kernels**: Within your compiler-generated kernels, you can use
`GetGlobalRequired("mylang.get_global_state")` in C++ or the C equivalent
`TVMFFIGetGlobalFunction("mylang.get_global_state", ...)` to get the function and then call it to retrieve the state
`TVMFFIGetGlobalFunction("mylang.get_global_state", ...)` to get the function and then call it to retrieve the state
pointer.

### Distributing the Runtime

For a user to use a kernel from your compiler, they must have access to your runtime library. The preferred method is to
package the runtime shared library (e.g., `libmylang_runtime.so`) as part of a Python or C++ package. Users must install
and import this package before loading any kernels compiled by your system.
For a user to use a kernel from your compiler, they must have access to your runtime library. The preferred method is to
package the runtime shared library (e.g., `libmylang_runtime.so`) as part of a Python or C++ package. Users must install
and import this package before loading any kernels compiled by your system.
This approach ensures the state is shared among different kernels.

### Common vs. Custom State

It's important to distinguish between compiler-specific state and **common state** managed by TVM FFI. TVM FFI handles
common states like **streams** and **memory allocators** through environment functions (e.g., `TVMFFIEnvGetStream`),
allowing kernels to access these without managing their own. However, for any unique state required by your compiler,
It's important to distinguish between compiler-specific state and **common state** managed by TVM FFI. TVM FFI handles
common states like **streams** and **memory allocators** through environment functions (e.g., `TVMFFIEnvGetStream`),
allowing kernels to access these without managing their own. However, for any unique state required by your compiler,
the global function registration approach is the most suitable method.

## Advanced: Custom Modules
Expand Down Expand Up @@ -196,4 +196,3 @@ the overall import relations from `<import_tree>` and return the final composed
As long as the compiler generates the `__tvm_ffi__library_bin` in the above format, {py:func}`tvm_ffi.load_module` will correctly
handle the loading and recover the original module. Note that we will need the custom module class definition to be available
during loading, either by importing another runtime DLL, or embedding it in the generated library.

2 changes: 1 addition & 1 deletion docs/guides/python_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ torch.testing.assert_close(x + 1, y)
```

The above code defines a C++ function `add_one_cpu` in Python script, compiles it on the fly and then loads the compiled
{py:class}`tvm_ffi.Module` object via {py:func}`tvm_ffi.cpp.load_inline`. You can then call the function `add_one_cpu`
{py:class}`tvm_ffi.Module` object via {py:func}`tvm_ffi.cpp.load_inline`. You can then call the function `add_one_cpu`
from the module as usual.

## Error Handling
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
autodocsumm
exhale
breathe
exhale
linkify-it-py
matplotlib
myst-parser
Expand Down
1 change: 0 additions & 1 deletion examples/packaging/python/my_ffi_extension/_ffi_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import tvm_ffi

# make sure lib is loaded first
from .base import _LIB

# this is a short cut to register all the global functions
# prefixed by `my_ffi_extension.` to this module
Expand Down
1 change: 0 additions & 1 deletion examples/quick_start/run_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
except ImportError:
torch = None

import ctypes

import numpy

Expand Down
2 changes: 1 addition & 1 deletion examples/quick_start/run_example.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
Expand All @@ -14,7 +15,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#!/bin/bash
set -ex

cmake -B build -S .
Expand Down
20 changes: 10 additions & 10 deletions include/tvm/ffi/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,16 @@ typedef struct {
*/
uint32_t small_str_len;
};
union { // 8 bytes
int64_t v_int64; // integers
double v_float64; // floating-point numbers
void* v_ptr; // typeless pointers
const char* v_c_str; // raw C-string
TVMFFIObject* v_obj; // ref counted objects
DLDataType v_dtype; // data type
DLDevice v_device; // device
char v_bytes[8]; // small string
uint64_t v_uint64; // uint64 repr mainly used for hashing
union { // 8 bytes
int64_t v_int64; // integers
double v_float64; // floating-point numbers
void* v_ptr; // typeless pointers
const char* v_c_str; // raw C-string
TVMFFIObject* v_obj; // ref counted objects
DLDataType v_dtype; // data type
DLDevice v_device; // device
char v_bytes[8]; // small string
uint64_t v_uint64; // uint64 repr mainly used for hashing
};
} TVMFFIAny;

Expand Down
8 changes: 4 additions & 4 deletions include/tvm/ffi/reflection/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class AttachFieldFlag : public FieldInfoTrait {
* \returns The byteoffset
*/
template <typename Class, typename T>
TVM_FFI_INLINE int64_t GetFieldByteOffsetToObject(T Class::*field_ptr) {
TVM_FFI_INLINE int64_t GetFieldByteOffsetToObject(T Class::* field_ptr) {
int64_t field_offset_to_class =
reinterpret_cast<int64_t>(&(static_cast<Class*>(nullptr)->*field_ptr));
return field_offset_to_class - details::ObjectUnsafe::GetObjectOffsetToSubclass<Class>();
Expand Down Expand Up @@ -350,7 +350,7 @@ class ObjectDef : public ReflectionDefBase {
* \return The reflection definition.
*/
template <typename T, typename BaseClass, typename... Extra>
TVM_FFI_INLINE ObjectDef& def_ro(const char* name, T BaseClass::*field_ptr, Extra&&... extra) {
TVM_FFI_INLINE ObjectDef& def_ro(const char* name, T BaseClass::* field_ptr, Extra&&... extra) {
RegisterField(name, field_ptr, false, std::forward<Extra>(extra)...);
return *this;
}
Expand All @@ -369,7 +369,7 @@ class ObjectDef : public ReflectionDefBase {
* \return The reflection definition.
*/
template <typename T, typename BaseClass, typename... Extra>
TVM_FFI_INLINE ObjectDef& def_rw(const char* name, T BaseClass::*field_ptr, Extra&&... extra) {
TVM_FFI_INLINE ObjectDef& def_rw(const char* name, T BaseClass::* field_ptr, Extra&&... extra) {
static_assert(Class::_type_mutable, "Only mutable classes are supported for writable fields");
RegisterField(name, field_ptr, true, std::forward<Extra>(extra)...);
return *this;
Expand Down Expand Up @@ -430,7 +430,7 @@ class ObjectDef : public ReflectionDefBase {
}

template <typename T, typename BaseClass, typename... ExtraArgs>
void RegisterField(const char* name, T BaseClass::*field_ptr, bool writable,
void RegisterField(const char* name, T BaseClass::* field_ptr, bool writable,
ExtraArgs&&... extra_args) {
static_assert(std::is_base_of_v<BaseClass, Class>, "BaseClass must be a base class of Class");
TVMFFIFieldInfo info;
Expand Down
1 change: 1 addition & 0 deletions python/tvm_ffi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
"""TVM FFI Python package."""

# order matters here so we need to skip isort here
# isort: skip_file
# base always go first to load the libtvm_ffi
Expand Down
1 change: 1 addition & 0 deletions python/tvm_ffi/_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
"""Conversion utilities to bring python objects into ffi values."""

from numbers import Number
from typing import Any

Expand Down
6 changes: 5 additions & 1 deletion python/tvm_ffi/_dtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
"""dtype class."""

# pylint: disable=invalid-name
from enum import IntEnum

Expand Down Expand Up @@ -83,7 +84,10 @@ def with_lanes(self, lanes):
The new dtype with the given number of lanes.
"""
cdtype = core._create_dtype_from_tuple(
core.DataType, self.__tvm_ffi_dtype__.type_code, self.__tvm_ffi_dtype__.bits, lanes
core.DataType,
self.__tvm_ffi_dtype__.type_code,
self.__tvm_ffi_dtype__.bits,
lanes,
)
val = str.__new__(dtype, str(cdtype))
val.__tvm_ffi_dtype__ = cdtype
Expand Down
1 change: 1 addition & 0 deletions python/tvm_ffi/_ffi_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
"""FFI API."""

from . import registry

registry.init_ffi_api("ffi", __name__)
1 change: 1 addition & 0 deletions python/tvm_ffi/_optional_torch_c_dlpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
This module will load slowly at first time due to JITing,
subsequent calls will be much faster.
"""

import warnings

from . import libinfo
Expand Down
1 change: 1 addition & 0 deletions python/tvm_ffi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# under the License.
# coding: utf-8
"""Base library for TVM FFI."""

import ctypes
import logging
import os
Expand Down
24 changes: 18 additions & 6 deletions python/tvm_ffi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,28 @@ def __main__():
description="Get various configuration information needed to compile with tvm-ffi"
)

parser.add_argument("--includedir", action="store_true", help="Print include directory")
parser.add_argument(
"--dlpack-includedir", action="store_true", help="Print dlpack include directory"
"--includedir", action="store_true", help="Print include directory"
)
parser.add_argument(
"--dlpack-includedir",
action="store_true",
help="Print dlpack include directory",
)
parser.add_argument(
"--cmakedir", action="store_true", help="Print library directory"
)
parser.add_argument(
"--sourcedir", action="store_true", help="Print source directory"
)
parser.add_argument(
"--libfiles", action="store_true", help="Fully qualified library filenames"
)
parser.add_argument("--cmakedir", action="store_true", help="Print library directory")
parser.add_argument("--sourcedir", action="store_true", help="Print source directory")
parser.add_argument("--libfiles", action="store_true", help="Fully qualified library filenames")
parser.add_argument("--libdir", action="store_true", help="Print library directory")
parser.add_argument("--libs", action="store_true", help="Libraries to be linked")
parser.add_argument("--cython-lib-path", action="store_true", help="Print cython path")
parser.add_argument(
"--cython-lib-path", action="store_true", help="Print cython path"
)
parser.add_argument("--cxxflags", action="store_true", help="Print cxx flags")
parser.add_argument("--cflags", action="store_true", help="Print c flags")
parser.add_argument("--ldflags", action="store_true", help="Print ld flags")
Expand Down
Loading
Loading