Skip to content

Commit 8a2dabd

Browse files
committed
Updates for dynamic
stack-info: PR: #58, branch: drisspg/stack/16
1 parent 7483e2a commit 8a2dabd

5 files changed

Lines changed: 113 additions & 5 deletions

File tree

transformer_nuggets/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from transformer_nuggets import quant as quant, utils as utils
2+
import logging
23

34

4-
def init_logging():
5+
def init_logging(level=logging.INFO):
56
"""
67
Configure logging for transformer_nuggets library at INFO level.
78
Adds a StreamHandler if none exists.
89
"""
910
import logging
1011

1112
logger = logging.getLogger("transformer_nuggets")
12-
logger.setLevel(logging.INFO)
13+
logger.setLevel(level)
1314

1415
if not logger.handlers:
1516
handler = logging.StreamHandler()

transformer_nuggets/cute/cache.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,19 @@ def _generate_cache_key(*args, **kwargs) -> str:
6868

6969
for arg in args:
7070
if isinstance(arg, cute.Tensor):
71-
key_parts.append(f"tensor_shape={arg.shape}_dtype={arg._dtype}")
71+
# Get string representation and extract the shape:stride pattern
72+
tensor_str = str(arg)
73+
# Format is: Tensor<address@mem o (shape):(stride)>
74+
# We want just the (shape):(stride) part
75+
76+
if " o " in tensor_str and ")>" in tensor_str:
77+
# Extract everything after ' o ' and before '>'
78+
inner_part = tensor_str.split(" o ")[1].rstrip(">")
79+
# inner_part should be like "(?,?):(?,1)"
80+
key_parts.append(f"tensor_{inner_part}_dtype={arg._dtype}")
81+
else:
82+
# Fallback if format is different
83+
key_parts.append(f"tensor_shape={arg.shape}_dtype={arg._dtype}")
7284
elif hasattr(arg, "__name__"):
7385
key_parts.append(f"op={arg.__name__}")
7486
else:
@@ -78,6 +90,7 @@ def _generate_cache_key(*args, **kwargs) -> str:
7890
key_parts.append(f"{k}={v}")
7991

8092
key_str = "_".join(key_parts)
93+
logger.debug(f"Generated cache key: {key_str}")
8194
return hashlib.sha256(key_str.encode()).hexdigest()[:16]
8295

8396

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import torch
2+
from operator import add
3+
4+
import cutlass
5+
import cutlass.cute as cute
6+
from cutlass.cute.runtime import from_dlpack
7+
8+
from transformer_nuggets.utils.benchmark import benchmark_cuda_function_in_microseconds
9+
from transformer_nuggets.cute.cache import cute_compile_and_cache, get_cache_stats
10+
from transformer_nuggets.cute.element_wise import elementwise_apply_kernel
11+
from rich import print
12+
from transformer_nuggets import init_logging
13+
import logging
14+
15+
init_logging(logging.INFO)
16+
17+
18+
@cute.jit
19+
def elem_kernel_parameterized(
20+
op: cutlass.Constexpr,
21+
mA: cute.Tensor,
22+
mB: cute.Tensor,
23+
mC: cute.Tensor,
24+
thr_m: cutlass.Constexpr,
25+
thr_n: cutlass.Constexpr,
26+
val_m: cutlass.Constexpr,
27+
val_n: cutlass.Constexpr,
28+
):
29+
"""Parameterized kernel that accepts layout dimensions as constexpr"""
30+
thr_layout = cute.make_layout((thr_m, thr_n), stride=(thr_n, 1))
31+
val_layout = cute.make_layout((val_m, val_n), stride=(val_n, 1))
32+
tiler_mn, tv_layout = cute.make_layout_tv(thr_layout, val_layout)
33+
34+
gA = cute.zipped_divide(mA, tiler_mn)
35+
gB = cute.zipped_divide(mB, tiler_mn)
36+
gC = cute.zipped_divide(mC, tiler_mn)
37+
38+
elementwise_apply_kernel(op, gA, gB, gC, tv_layout).launch(
39+
grid=[cute.size(gC, mode=[1]), 1, 1],
40+
block=[cute.size(tv_layout, mode=[0]), 1, 1],
41+
)
42+
43+
44+
def elementwise_op_dynamic(
45+
op: cutlass.Constexpr,
46+
a: torch.Tensor,
47+
b: torch.Tensor,
48+
) -> torch.Tensor:
49+
M, N = a.shape
50+
c = torch.empty(M, N, device="cuda", dtype=torch.float16)
51+
52+
# Choose parameters based on size
53+
total_elements = M * N
54+
if total_elements < 1024 * 1024:
55+
thr_m, thr_n, val_m, val_n = 8, 32, 2, 8
56+
elif total_elements < 16 * 1024 * 1024:
57+
thr_m, thr_n, val_m, val_n = 4, 64, 4, 8
58+
else:
59+
thr_m, thr_n, val_m, val_n = 2, 128, 8, 8
60+
61+
# Create tensors with optimization hints
62+
mA = from_dlpack(a, assumed_align=16).mark_layout_dynamic(1)
63+
mB = from_dlpack(b, assumed_align=16).mark_layout_dynamic(1)
64+
mC = from_dlpack(c, assumed_align=16).mark_layout_dynamic(1)
65+
66+
# Convert to compile-time constants - this creates separate kernels for each configuration
67+
compiled_kernel = cute_compile_and_cache(
68+
elem_kernel_parameterized, op, mA, mB, mC, thr_m, thr_n, val_m, val_n
69+
)
70+
compiled_kernel(mA, mB, mC)
71+
return c
72+
73+
74+
if __name__ == "__main__":
75+
shapes = [(2**i, 2**i) for i in range(8, 14)]
76+
shapes.extend([(1000, 1000), (1234, 5678), (3333, 7777), (999, 1001)])
77+
for M, N in shapes:
78+
a = torch.randn(M, N, device="cuda", dtype=torch.float16)
79+
b = torch.randn(M, N, device="cuda", dtype=torch.float16)
80+
81+
# Test the new API that takes regular PyTorch tensors
82+
out = elementwise_op_dynamic(add, a, b)
83+
torch.testing.assert_close(out, add(a, b))
84+
85+
time_torch = benchmark_cuda_function_in_microseconds(lambda: add(a, b))
86+
time_cute = benchmark_cuda_function_in_microseconds(
87+
lambda: elementwise_op_dynamic(add, a, b)
88+
)
89+
print(f"M = {M}, N = {N}")
90+
print(f"torch GB/s = {M * N * 3 * out.element_size() / time_torch * 1e-3}")
91+
print(f"cute GB/s = {M * N * 3 * out.element_size() / time_cute * 1e-3}")
92+
93+
stats = get_cache_stats()
94+
print(f"Cache stats: {stats}")
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def elementwise_op(
120120
return compiled_kernel(mA, mB, mC)
121121

122122

123-
def benchmark(callable, tensor_a, *, num_warmups=5, num_iterations=200):
123+
def benchmark(callable, tensor_a):
124124
time = benchmark_cuda_function_in_microseconds(callable)
125125
avg_time = time / 1e3
126126

@@ -166,7 +166,7 @@ def benchmark(callable, tensor_a, *, num_warmups=5, num_iterations=200):
166166
benchmark(partial(torch.add, a, b, out=c), a)
167167

168168
print("3. Optimized elementwise add kernel (with caching):")
169-
benchmark(partial(elementwise_op, add, a, b, c, assumed_align=128), a)
169+
benchmark(partial(elementwise_op, add, a, b, c, assumed_align=16), a)
170170

171171
print("\nCache Statistics:")
172172
stats = get_cache_stats()

transformer_nuggets/cute/utils.py

Whitespace-only changes.

0 commit comments

Comments
 (0)