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
15 changes: 14 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,17 @@ per-file-ignores =
# pd_vllm implements vLLM connector / abstract-profile interfaces, so many
# method params are unused by design (U100); black collapses the ``...``
# interface stubs onto one line (E704).
tilert/pd_vllm/*:U100,E704
#
# Since v0.1.6 the Python sources are recovered from the published wheel,
# which ships them without comments: per-line noqa's are not available and
# long string literals would need code edits to re-wrap. The remaining codes
# on the pd_vllm line and the entries below relax those checks per exported
# path instead. flake8 applies only the longest matching pattern, so each
# entry repeats the codes it still needs (e.g. F401 for __init__.py).
tilert/pd_vllm/*:U100,E704,B007,D205,D209,E501,E741,F401,R501,R504,R505,SIM105,SIM115,U101,VNE002,VNE003
tilert/models/glm_5_2_rocm/*:E501,F401,R504,SIM113,U100,VNE002
tilert/models/misc_rocm/*:E501,F401,U100
tilert/models/base_rocm.py:E501,U100
tilert/__init__.py:E501,F401
tilert/generate.py:E501
tilert/utils.py:E501
166 changes: 109 additions & 57 deletions README.md

Large diffs are not rendered by default.

Binary file added assets/glm5_3fp8_benchmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 51 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,30 @@ classifiers = [
]

dependencies = [
# Pinned to the exact ABI the v0.1.5 wheel was built against. ``torch`` must
# come from PyTorch's cu130 index (``--index-url
# https://download.pytorch.org/whl/cu130``); installing from PyPI yields a
# CUDA build that does not match the cu130-linked tilert binary.
"torch==2.11.0",
# The v0.1.6 wheel carries backends for two torch ABIs, hence the range:
# the CUDA backends (DeepSeek-V3.2, GLM-5) need ``torch==2.11.0+cu130``
# from PyTorch's cu130 index (``--index-url
# https://download.pytorch.org/whl/cu130``), the ROCm backend (GLM-5.2/5.3)
# needs ``torch==2.12.0+rocm7.14.0``. ``tilert.load_backend`` refuses a
# torch of the wrong version or flavor, so install the matching one first.
"torch>=2.11,<2.13",
"transformers>=4.46.3",
"tokenizers>=0.20.3",
"safetensors",
"numpy",
"scipy",
"einops",
]

[project.optional-dependencies]
# Runtime dependencies of the PD router and decode server (``tilert.pd_vllm``).
pd = [
"fastapi",
"uvicorn",
"httpx",
"requests",
"pydantic",
]
dev = [
"pytest>=7.0.0",
"black==25.1.0",
Expand Down Expand Up @@ -65,7 +76,10 @@ dev = [
Homepage = "https://github.com/tile-ai/TileRT"
Issues = "https://github.com/tile-ai/TileRT/issues"

# Note: this repository ships the public sources that match the v0.1.5 wheel.
# Note: this repository ships the public Python sources of the v0.1.6.post2
# wheel. They are recovered from the wheel itself, which ships them without
# docstrings or comments, and reformatted to this repo's lint config;
# ``tilert/generate.py`` also carries a CLI fix that no published wheel has yet.
# The wheel itself is built in the development repo (TileRT-dev/TileRT) with
# scikit-build-core; no [build-system] block is declared here on purpose so
# nobody accidentally runs ``pip wheel .`` against this presentation copy.
Expand Down Expand Up @@ -113,13 +127,41 @@ explicit_package_bases = true

# pd_vllm is glue over vLLM's connector API; its interface methods take
# ``Any``-typed params by contract, so full def-level annotation is low value.
# Relax annotation-completeness there, but keep real type checks (arg-type,
# union-attr, etc.) on so genuine mistakes still surface.
# Relax annotation-completeness there. Since v0.1.6 the sources are recovered
# from the published wheel, which ships them without comments, so per-line
# ``# type: ignore``s are not available either: the error codes that occur in
# the exported code are disabled, and the remaining checks still apply.
[[tool.mypy.overrides]]
module = "tilert.pd_vllm.*"
disallow_untyped_defs = false
disallow_incomplete_defs = false
warn_return_any = false
disable_error_code = [
"arg-type",
"assignment",
"attr-defined",
"func-returns-value",
"index",
"misc",
"return-value",
"type-var",
"union-attr",
"unreachable",
"var-annotated",
]

# The ROCm port (GLM-5.2/5.3 on MI350X/MI355X) comes from the same wheel export.
[[tool.mypy.overrides]]
module = [
"tilert.models.glm_5_2_rocm.*",
"tilert.models.misc_rocm.*",
"tilert.models.base_rocm",
"tilert.models.common_mxfp4",
]
disallow_untyped_defs = false
disallow_incomplete_defs = false
warn_return_any = false
disable_error_code = ["assignment", "attr-defined", "dict-item", "index", "union-attr"]

[tool.bandit]
exclude_dirs = ["tests", "3rd-party"]
Expand Down Expand Up @@ -202,7 +244,7 @@ args = ["--keep-percent-format", "--py311-plus"]
[tool.codespell]
skip = "3rd-party,*.git,*.pyc,build,dist,*.egg-info,.mypy_cache,.pytest_cache,"
check-hidden = true
ignore-words-list = "ThrID"
ignore-words-list = "ThrID,pres"

[tool.mdformat]
number = true
Expand Down
19 changes: 13 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
# Runtime dependencies for the v0.1.5 wheel, pinned to the exact ABI the
# wheel was built against. ``torch`` must be installed from PyTorch's cu130
# index — PyPI's default ``torch`` is a different CUDA build and will not load
# the cu130-linked tilert binary:
# Runtime dependencies of the v0.1.6 wheel. The wheel carries backends for two
# torch ABIs (hence the range below), so install the torch build that matches
# your GPUs first:
#
# # NVIDIA (DeepSeek-V3.2, GLM-5/5.1): PyTorch's cu130 build. PyPI's default
# # ``torch`` is a different CUDA build and will not load the cu130-linked
# # tilert binaries.
# pip install --index-url https://download.pytorch.org/whl/cu130 torch==2.11.0
#
# # AMD (GLM-5.2/5.3): torch==2.12.0+rocm7.14.0, preinstalled in the ROCm image
# # (ghcr.io/tile-ai/tilert-rocm-decode:0.1.6).
#
# pip install -r requirements.txt
#
# The recommended path remains the prebuilt Docker image (see README).
torch==2.11.0
# The recommended path remains the prebuilt Docker images (see README).
torch>=2.11,<2.13
transformers>=4.46.3
tokenizers>=0.20.3
safetensors
numpy
scipy
einops
63 changes: 30 additions & 33 deletions tilert/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
"""TileRT Python package.

Two backend libraries ship with TileRT — one per model family:

- ``libtilert_dsv32.so`` (DeepSeek-V3.2)
- ``libtilert_glm5.so`` (GLM-5)

They are NOT loaded at import time. The caller selects a backend via
``load_backend(model_type)`` (done automatically by ``tilert.generate``).
Only one backend may be loaded per process — both register the ``tilert``
torch-op namespace. Run DSv3.2 and GLM-5 in separate processes.
"""
"""TileRT: tile-based runtime for ultra-low-latency LLM inference."""

import ctypes
import logging
Expand All @@ -22,50 +11,65 @@

if not hasattr(torch, "ops"):
raise RuntimeError("PyTorch is required but torch.ops is not available")

try:
__version__ = pkg_version("tilert")
except PackageNotFoundError:
__version__ = "0.0.0"


def init_logging() -> logging.Logger:
"""Initialize logging configuration."""
level_name = os.environ.get("TILERT_LOG_LEVEL", "INFO").upper()
logging.basicConfig(
level=logging.DEBUG,
level=getattr(logging, level_name, logging.INFO),
format="%(filename)s:%(lineno)d [%(levelname)s]: %(message)s",
)
return logging.getLogger(__name__)


logger = init_logging()

_BACKENDS = {
"deepseek_v3_2": "libtilert_dsv32.so",
"glm5": "libtilert_glm5.so",
"glm5_2_rocm": "libtilert_glm52_rocm.so",
}
_TORCH_FOR_LIB = {
"libtilert_dsv32.so": ("2.11", False),
"libtilert_glm5.so": ("2.11", False),
"libtilert_glm52_rocm.so": ("2.12", True),
}


def _check_torch(so_name: str) -> None:
wanted = _TORCH_FOR_LIB.get(so_name)
if wanted is None:
return
version, needs_rocm = wanted
is_rocm = getattr(torch.version, "hip", None) is not None
if is_rocm != needs_rocm:
raise RuntimeError(
f"{so_name} needs a {('ROCm' if needs_rocm else 'CUDA')} build of torch; this interpreter has torch {torch.__version__}"
)
if not torch.__version__.startswith(f"{version}."):
raise RuntimeError(
f"{so_name} was built against torch {version}; this interpreter has torch {torch.__version__}"
)


_loaded_backend: str | None = None


def load_backend(model_type: str) -> None:
"""Load the backend for ``model_type`` (lazy, once per process).

DeepSeek-V3.2 and GLM-5 ship as separate libraries; the matching one is
loaded on first use. Loading a second, different backend in the same
process raises (both libraries define the ``tilert`` op namespace).
"""
global _loaded_backend
so_name = _BACKENDS.get(model_type)
if so_name is None:
raise ValueError(f"Unknown model_type {model_type!r}. Supported: {sorted(_BACKENDS)}")
if _loaded_backend is not None:
if _loaded_backend != so_name:
raise RuntimeError(
f"TileRT backend '{_loaded_backend}' already loaded; cannot load "
f"'{so_name}' in the same process. Run {model_type} in a fresh process."
f"TileRT backend '{_loaded_backend}' already loaded; cannot load '{so_name}' in the same process. Run {model_type} in a fresh process."
)
return
_check_torch(so_name)
pkg_dir = Path(__file__).parent
lib_path = pkg_dir / so_name
if not lib_path.exists():
Expand All @@ -76,16 +80,9 @@ def load_backend(model_type: str) -> None:
ctypes.CDLL(str(lib_path), mode=ctypes.RTLD_GLOBAL | os.RTLD_LAZY)
torch.ops.load_library(str(lib_path))
_loaded_backend = so_name
logger.info(
"Loaded TileRT backend %s (%s) for model_type=%s", so_name, lib_path.name, model_type
)
logger.info("Loaded TileRT backend %s for model_type=%s", lib_path.name, model_type)


from .tilert_init import tilert_init # noqa: E402

__all__ = [
"logger",
"load_backend",
"tilert_init",
"__version__",
]
__all__ = ["logger", "load_backend", "tilert_init", "__version__"]
Loading
Loading