Skip to content

Commit eb0b087

Browse files
authored
Merge branch 'main' into feature/tle_fix_extract_tile
2 parents 49a7547 + fd3ea29 commit eb0b087

31 files changed

Lines changed: 1143 additions & 114 deletions

File tree

.github/workflows/enflame3.6-gcu400-build-and-test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ jobs:
106106
python3 -m pytest python/test/tle \
107107
--ignore=python/test/tle/unit/test_tle_distributed_d2d.py \
108108
--ignore=python/test/tle/unit/test_tle_get_local_pe.py \
109-
--ignore=python/test/tle/unit/test_tle_d2d_barrier.py
109+
--ignore=python/test/tle/unit/test_tle_d2d_barrier.py \
110+
--ignore=python/test/tle/unit/test_tle_get_node_rank.py
110111
111112
## tle raw test
112113
python3 -m pytest third_party/enflame/python/test/tle/raw

.github/workflows/new-prs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
pull-requests: write
4141
steps:
4242
- id: labeler
43-
uses: actions/labeler@v6
43+
uses: actions/labeler@v7
4444
with:
4545
repo-token: "${{ secrets.GITHUB_TOKEN }}"
4646
sync-labels: true

.github/workflows/nvidia3.6-build-and-test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ jobs:
130130
python3 -m pytest -s python/test/tle/unit \
131131
--ignore=python/test/tle/unit/test_tle_distributed_d2d.py \
132132
--ignore=python/test/tle/unit/test_tle_get_local_pe.py \
133-
--ignore=python/test/tle/unit/test_tle_d2d_barrier.py
133+
--ignore=python/test/tle/unit/test_tle_d2d_barrier.py \
134+
--ignore=python/test/tle/unit/test_tle_get_node_rank.py
134135
## flagtree hints python tutorials
135136
python3 python/tutorials/hints/01/01-vector-add.py --only_unit_test
136137
# python3 python/tutorials/hints/02/02-fused-softmax.py --only_unit_test

packaging/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ A 36-minute compile in `override_dh_auto_build` is slow, hard to debug, and
3838
collides with `dh-python`'s expectations for a pure-Python `pyproject` build.
3939
The two-stage Docker approach builds the wheel once, then wraps it cheaply
4040
into a `.deb`/`.rpm` — keeping the heavy lifting in a controlled container.
41+
The wheel builders use the distro nlohmann-json headers through
42+
`JSON_SYSPATH=/usr`; backend-specific LLVM and device tools remain pinned to
43+
the versions expected by each backend.
4144

4245
## Build locally
4346

packaging/debian/build-helpers/Dockerfile.deb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ ENV PIP_ROOT_USER_ACTION=ignore
5959
RUN apt-get update && apt-get install -y --no-install-recommends \
6060
python3 python3-pip python3-dev python3-venv \
6161
build-essential cmake ninja-build git \
62-
zlib1g zlib1g-dev libxml2 libxml2-dev \
62+
zlib1g zlib1g-dev libxml2 libxml2-dev nlohmann-json3-dev \
6363
wget curl ca-certificates \
6464
&& apt-get clean && rm -rf /var/lib/apt/lists/*
6565

@@ -96,6 +96,7 @@ COPY CMakeLists.txt pyproject.toml setup.py MANIFEST.in LICENSE README.md /src/
9696
# tree and the LLVM tarball cache (~/.triton) would otherwise add
9797
# several GB and push CI runners into ENOSPC.
9898
RUN unset FLAGTREE_BACKEND && \
99+
JSON_SYSPATH=/usr \
99100
FLAGTREE_DEFAULT_BACKENDS=nvidia,amd \
100101
MAX_JOBS=4 python -m pip wheel . --no-build-isolation --no-deps -w /wheels -v && \
101102
ls -lh /wheels/ && \

packaging/rpm/helpers/Dockerfile.rpm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ RUN dnf install -y --setopt=install_weak_deps=False \
3838
gcc gcc-c++ make cmake ninja-build git \
3939
zlib-devel libxml2-devel \
4040
wget curl ca-certificates \
41+
&& (dnf install -y --setopt=install_weak_deps=False json-devel \
42+
|| dnf install -y --setopt=install_weak_deps=False nlohmann-json-devel) \
4143
&& dnf clean all
4244

4345
RUN python3 -m pip install --no-cache-dir --upgrade pip setuptools wheel build
@@ -67,6 +69,7 @@ COPY CMakeLists.txt pyproject.toml setup.py MANIFEST.in LICENSE README.md /src/
6769
# tree and the LLVM tarball cache (~/.triton) would otherwise add
6870
# several GB and push CI runners into ENOSPC.
6971
RUN unset FLAGTREE_BACKEND && \
72+
JSON_SYSPATH=/usr \
7073
MAX_JOBS=4 python3 -m pip wheel . --no-build-isolation --no-deps -w /wheels -v && \
7174
ls -lh /wheels/ && \
7275
test -n "$(ls /wheels/flagtree-*.whl 2>/dev/null)" && \

python/test/tle/unit/test_tle_distributed.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,16 @@ def __init__(self):
226226
self.builder = _LegacyDistributedBarrierBuilder()
227227

228228

229+
class TestShardId:
230+
231+
@pytest.mark.parametrize("axis", ("device", "node"))
232+
def test_rank_axis_requires_device_dptr(self, axis):
233+
mesh = tle.device_mesh({"node": 2, "device": 4})
234+
semantic = _FakeSemantic()
235+
with pytest.raises(ValueError, match=rf"device_dptr is required for axis '{axis}'"):
236+
tle.shard_id(mesh, axis, _semantic=semantic)
237+
238+
229239
class TestDistributedBarrierScope:
230240

231241
def test_distributed_barrier_full_cluster_mesh(self):
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import os
2+
3+
import torch
4+
import torch.distributed as dist
5+
import triton
6+
import triton.experimental.tle.language as tle
7+
import triton.language as tl
8+
9+
LOCAL_WORLD_SIZE = int(os.environ["LOCAL_WORLD_SIZE"])
10+
WORLD_SIZE = int(os.environ["WORLD_SIZE"])
11+
if WORLD_SIZE % LOCAL_WORLD_SIZE != 0:
12+
raise ValueError("WORLD_SIZE must be divisible by LOCAL_WORLD_SIZE")
13+
14+
DEVICE_MESH = tle.device_mesh(tle.MeshConfig(node=WORLD_SIZE // LOCAL_WORLD_SIZE, device=LOCAL_WORLD_SIZE))
15+
16+
17+
@triton.jit
18+
def _tle_node_rank_kernel(out_ptr, device_dptr: tl.constexpr, mesh: tl.constexpr):
19+
pid = tl.program_id(0)
20+
node_rank = tle.shard_id(mesh, "node", device_dptr=device_dptr)
21+
tl.store(out_ptr + pid, node_rank)
22+
23+
24+
def test_tle_get_node_rank():
25+
grid = 2
26+
with torch.cuda.use_mem_pool(tle.get_mem_pool()):
27+
source = torch.empty((1, ), dtype=torch.float32, device="cuda")
28+
device_dptr = tle.create_dist_tensor(source)
29+
node_rank_out = torch.empty((grid, ), dtype=torch.int32, device="cuda")
30+
31+
compiled = _tle_node_rank_kernel.warmup(
32+
out_ptr=node_rank_out,
33+
device_dptr=device_dptr,
34+
mesh=DEVICE_MESH,
35+
grid=(grid, ),
36+
num_ctas=1,
37+
num_warps=4,
38+
)
39+
assert "get_world_rank" in compiled.asm["ttgir"]
40+
assert "get_num_pes" in compiled.asm["ttgir"]
41+
assert "flagcxDevCommGetRank" in compiled.asm["ptx"]
42+
assert "flagcxDevCommGetIntraSize" in compiled.asm["ptx"]
43+
44+
_tle_node_rank_kernel[(grid, )](
45+
out_ptr=node_rank_out,
46+
device_dptr=device_dptr,
47+
mesh=DEVICE_MESH,
48+
)
49+
torch.cuda.synchronize()
50+
51+
rank = dist.get_rank()
52+
expected_node_rank = rank // LOCAL_WORLD_SIZE
53+
actual_node_ranks = node_rank_out.cpu().tolist()
54+
try:
55+
torch.testing.assert_close(
56+
node_rank_out,
57+
torch.full_like(node_rank_out, expected_node_rank),
58+
)
59+
except AssertionError:
60+
print(
61+
f"[Rank {rank}] FAILED: node ranks={actual_node_ranks}, "
62+
f"expected={expected_node_rank}",
63+
flush=True,
64+
)
65+
raise
66+
else:
67+
print(
68+
f"[Rank {rank}] PASSED: node ranks={actual_node_ranks}, "
69+
f"expected={expected_node_rank}",
70+
flush=True,
71+
)
72+
finally:
73+
tle.cleanup_communicator()
74+
75+
76+
if __name__ == "__main__":
77+
test_tle_get_node_rank()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
3+
if [ "$1" = "debug" ]; then
4+
export NCCL_DEBUG=INFO
5+
export NCCL_DEBUG_SUBSYS=all
6+
else
7+
unset NCCL_DEBUG
8+
unset NCCL_DEBUG_SUBSYS
9+
fi
10+
11+
export FLAGCX_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3,mlx5_6,mlx5_7,mlx5_8,mlx5_9
12+
export FLAGCX_USE_HETERO_COMM=1
13+
export FLAGCX_MEM_ENABLE=1
14+
export FLAGCX_VMM_ENABLE=0
15+
export FLAGCX_P2P_DISABLE=1
16+
export CUDA_VISIBLE_DEVICES=0,1
17+
18+
nproc_per_node=${NPROC_PER_NODE:-2}
19+
nnodes=${NNODES:-2}
20+
node_rank=${NODE_RANK:-0}
21+
master_addr=${MASTER_ADDR:-10.0.9.3}
22+
port=${MASTER_PORT:-8335}
23+
24+
if [ "${nnodes}" -eq 1 ]; then
25+
while ss -ltn | grep -q ":${port} "; do
26+
echo "Port ${port} is occupied, trying next..."
27+
port=$((port + 2))
28+
done
29+
fi
30+
31+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
32+
echo "Using master ${master_addr}:${port}, node ${node_rank}/${nnodes}"
33+
34+
torchrun \
35+
--nproc_per_node="${nproc_per_node}" \
36+
--nnodes="${nnodes}" \
37+
--node_rank="${node_rank}" \
38+
--master_addr="${master_addr}" \
39+
--master_port="${port}" \
40+
"${script_dir}/test_tle_get_node_rank.py"

python/test/tle/unit/test_tle_raw_cache_key.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ast
22
import textwrap
33

4+
import pytest
45
import triton.language as tl
56
from triton.experimental.tle.raw import dialect
67
from triton.experimental.tle.raw.cache_key import (
@@ -127,6 +128,7 @@ def make_cache_key() -> str:
127128

128129

129130
def test_mlir_dialect_cache_key_changes_with_edsl_source():
131+
pytest.importorskip("mlir", reason="requires the optional MLIR Python bindings")
130132

131133
@dialect(name="mlir")
132134
def edsl_v1():

0 commit comments

Comments
 (0)