Yougori's picture
Add files using upload-large-folder tool
e7654c2 verified
Raw History Blame Contribute Delete
3.34 kB
"""Decode speed of the Ling-mini-2.0 megakernel.
python bench.py one chat: 10 launches of 256 greedy tokens after a 32-token prompt, median
python bench.py --chats 3 three chats at once, each on its share of the SMs: tokens/s each and in total,
and whether each chat wrote the same 128 tokens as alone
The GPU is warmed up first (Windows lowers an idle GPU's clocks): launches run until they stop
getting faster for two seconds.
"""
from __future__ import annotations
import argparse
import statistics
import sys
import time
import torch
from ling_kernel import HERE, LingKernel, State
PROMPTS = [
"The history of the printing press begins in the fifteenth century, when Johannes Gutenberg combined "
"movable metal type, oil-based ink and a wooden press adapted from those used to make wine.",
"def merge_sort(items):\n \"\"\"Return a new list with the items in ascending order.\"\"\"\n"
" if len(items) <= 1:\n return list(items)\n middle = len(items) // 2\n",
]
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--chats", type=int, default=1)
args = ap.parse_args()
sys.stdout.reconfigure(encoding="utf-8")
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained(HERE)
mk = LingKernel(max_pos=1024, log=lambda s: print(s, flush=True))
prompts = [tok(p)["input_ids"][:32] for p in PROMPTS]
firsts = [mk.forced(p)[-1] for p in prompts]
best, since, start = float("inf"), time.time(), time.time()
while time.time() - start < 30:
s = mk.timed_greedy(firsts[0], len(prompts[0]), 64)
if s < 0.97 * best:
best, since = s, time.time()
elif time.time() - since > 2:
break
if args.chats <= 1:
mk.forced(prompts[0])
times = [mk.timed_greedy(firsts[0], len(prompts[0]), 256) for _ in range(10)]
per = statistics.median(times) / 256
print(f"one chat: {1 / per:.0f} tokens/s (median of 10 launches of 256 tokens; best {256 / min(times):.0f})")
return
n = args.chats
nb = max(16, mk.sms // n)
states = [State(1024) for _ in range(n)]
streams = [torch.cuda.Stream() for _ in range(n)]
pr = [prompts[i % 2] for i in range(n)]
for i in range(n): # each chat reads its prompt
mk.launch_async(states[i], pr[i], 0, len(pr[i]), True, nb, streams[i])
torch.cuda.synchronize()
first = [states[i].out[len(pr[i]) - 1].item() for i in range(n)]
alone = []
for i in range(2):
mk.forced(prompts[i])
alone.append(mk.greedy(firsts[i], len(prompts[i]), 128))
def round_(k: int) -> float:
torch.cuda.synchronize()
t = time.perf_counter()
for i in range(n):
mk.launch_async(states[i], [first[i]], len(pr[i]), k, False, nb, streams[i])
torch.cuda.synchronize()
return time.perf_counter() - t
round_(128)
same = [states[i].out[:128].tolist() == alone[i % 2] for i in range(n)]
t = statistics.median(round_(256) for _ in range(6))
print(f"{n} chats at once, {nb} SMs each: {256 / t:.0f} tokens/s each, {n * 256 / t:.0f} in total; "
f"each wrote the same 128 tokens as alone: {same}")
if __name__ == "__main__":
main()