Skip to content

Commit 6c56d63

Browse files
committed
Added roll operator
1 parent c60cab5 commit 6c56d63

5 files changed

Lines changed: 618 additions & 0 deletions

File tree

benchmark/test_roll_perf.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from typing import Generator
2+
3+
import pytest
4+
import torch
5+
6+
import flag_gems
7+
from benchmark.attri_util import DEFAULT_METRICS, FLOAT_DTYPES
8+
from benchmark.performance_utils import Benchmark, generate_tensor_input
9+
10+
11+
class RollBenchmark(Benchmark):
12+
"""
13+
Benchmark for single-dimension roll operation.
14+
"""
15+
16+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["gbps"]
17+
18+
def set_more_shapes(self):
19+
# 1D: various sizes
20+
# 2D: square and rectangular
21+
# 3D: cube-like
22+
# 4D: large batched tensors
23+
return [
24+
(1024,),
25+
(1024, 1024),
26+
(64, 64, 64),
27+
(16, 128, 128, 128),
28+
]
29+
30+
def get_input_iter(self, cur_dtype) -> Generator:
31+
for shape in self.shapes:
32+
inp = generate_tensor_input(shape, cur_dtype, self.device)
33+
shift = shape[0] // 3 if len(shape) > 0 else 1
34+
dim = 0
35+
yield inp, shift, dim
36+
37+
def get_gbps(self, op, *args, **kwargs):
38+
inp = op[0]
39+
latency = kwargs.get("latency")
40+
numel = inp.numel()
41+
element_size = inp.element_size()
42+
gb = 2 * numel * element_size / 1e9
43+
return gb / (latency * 1e-3)
44+
45+
46+
@pytest.mark.roll
47+
def test_perf_roll():
48+
def torch_op(inp, shift, dim):
49+
return torch.roll(inp, shift, dims=dim)
50+
51+
bench = RollBenchmark(
52+
op_name="roll",
53+
torch_op=torch_op,
54+
dtypes=FLOAT_DTYPES,
55+
)
56+
bench.run()
57+
58+
59+
class RollMultiDimBenchmark(Benchmark):
60+
"""
61+
Benchmark for multi-dimension roll operation.
62+
"""
63+
64+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["gbps"]
65+
66+
def set_more_shapes(self):
67+
return [
68+
(64, 64, 64),
69+
(128, 256, 256),
70+
(16, 128, 128, 128),
71+
]
72+
73+
def get_input_iter(self, cur_dtype) -> Generator:
74+
for shape in self.shapes:
75+
inp = generate_tensor_input(shape, cur_dtype, self.device)
76+
rank = len(shape)
77+
if rank >= 2:
78+
shifts = [shape[0] // 3, shape[1] // 4]
79+
dims = [0, 1]
80+
else:
81+
shifts = [shape[0] // 3]
82+
dims = [0]
83+
yield inp, shifts, dims
84+
85+
def get_gbps(self, op, *args, **kwargs):
86+
inp = op[0]
87+
latency = kwargs.get("latency")
88+
numel = inp.numel()
89+
element_size = inp.element_size()
90+
gb = 2 * numel * element_size / 1e9
91+
return gb / (latency * 1e-3)
92+
93+
94+
@pytest.mark.roll
95+
def test_perf_roll_multi_dim():
96+
def torch_op(inp, shifts, dims):
97+
return torch.roll(inp, shifts, dims=dims)
98+
99+
bench = RollMultiDimBenchmark(
100+
op_name="roll_multi",
101+
torch_op=torch_op,
102+
dtypes=FLOAT_DTYPES,
103+
)
104+
bench.run()
105+
106+
107+
class RollFlattenBenchmark(Benchmark):
108+
"""
109+
Benchmark for flattened roll (dims=None).
110+
"""
111+
112+
DEFAULT_METRICS = DEFAULT_METRICS[:] + ["gbps"]
113+
114+
def set_more_shapes(self):
115+
return [
116+
(1024, 1024),
117+
(64, 64, 64),
118+
(128, 256, 256),
119+
]
120+
121+
def get_input_iter(self, cur_dtype) -> Generator:
122+
for shape in self.shapes:
123+
inp = generate_tensor_input(shape, cur_dtype, self.device)
124+
shift = inp.numel() // 3
125+
yield inp, shift
126+
127+
def get_gbps(self, op, *args, **kwargs):
128+
inp = op[0]
129+
latency = kwargs.get("latency")
130+
numel = inp.numel()
131+
element_size = inp.element_size()
132+
gb = 2 * numel * element_size / 1e9
133+
return gb / (latency * 1e-3)
134+
135+
136+
@pytest.mark.roll
137+
def test_perf_roll_flatten():
138+
def torch_op(inp, shift):
139+
return torch.roll(inp, shift, dims=None)
140+
141+
bench = RollFlattenBenchmark(
142+
op_name="roll_flatten",
143+
torch_op=torch_op,
144+
dtypes=FLOAT_DTYPES,
145+
)
146+
bench.run()

src/flag_gems/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ def torch_ge(v):
345345
("resolve_conj", resolve_conj),
346346
("resolve_neg", resolve_neg),
347347
("rms_norm", rms_norm),
348+
("roll", roll),
348349
("rrelu_with_noise_backward", rrelu_with_noise_backward),
349350
("rsqrt", rsqrt),
350351
("rsqrt_", rsqrt_),

src/flag_gems/ops/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
from flag_gems.ops.resolve_conj import resolve_conj
236236
from flag_gems.ops.resolve_neg import resolve_neg
237237
from flag_gems.ops.rms_norm import rms_norm, rms_norm_backward, rms_norm_forward
238+
from flag_gems.ops.roll import roll
238239
from flag_gems.ops.rrelu_with_noise_backward import rrelu_with_noise_backward
239240
from flag_gems.ops.rsqrt import rsqrt, rsqrt_
240241
from flag_gems.ops.scaled_softmax import scaled_softmax_backward, scaled_softmax_forward
@@ -585,6 +586,7 @@
585586
"resolve_neg",
586587
"rms_norm",
587588
"rms_norm_backward",
589+
"roll",
588590
"rms_norm_forward",
589591
"rrelu_with_noise_backward",
590592
"rsqrt",

0 commit comments

Comments
 (0)