GR00T-N1.7-3B-p150 / code /models /experimental /gr00t /benchmarks /mb0_generic_op_hello.py
changh95's picture
Add files using upload-large-folder tool
1d30035 verified
Raw History Blame Contribute Delete
7.08 kB
# SPDX-License-Identifier: Apache-2.0
"""MB0: prove the ``ttnn.generic_op`` + ``UnifiedKernelDescriptor`` plumbing works on the full 11x10 grid.
Device probe for docs/research/device-stack-smoke.md (target 5). It
1. opens the device and records the compute grid, DRAM grid, the runtime
``get_optimal_dram_bank_to_logical_worker_assignment`` list (the harvest-pattern question of
unified-kernels-11x10-audit.md section 1.3) and any harvesting info exposed by the bindings;
2. builds a HEIGHT_SHARDED uint32 output tensor with one [32, 32] shard per compute core;
3. compiles ``kernels/hello_kernel.cpp`` through ``UnifiedKernelDescriptor`` (the same descriptor path the
deepseek_v3_b1 micro-ops use) for every core of the grid and runs it via ``ttnn.generic_op``;
4. checks that each core wrote (logical_x, logical_y, row-major linear id, magic) into its own shard;
5. reports cold (JIT compile) and warm (program cache) wall times.
Run through the device lock::
bin/with-device.sh python models/experimental/gr00t/benchmarks/mb0_generic_op_hello.py
"""
from __future__ import annotations
import os
import sys
import time
import torch
import ttnn
from models.demos.deepseek_v3_b1.unified_kernel_descriptor import (
UnifiedCompileTimeCoreDescriptor,
UnifiedKernelDescriptor,
)
KERNEL = "models/experimental/gr00t/benchmarks/kernels/hello_kernel.cpp"
MAGIC = 0x00C0FFEE
SHARD = (32, 32) # 1024 uint32 words per core; we only use the first 4
def _probe_device_facts(device) -> None:
grid = device.compute_with_storage_grid_size()
dram = device.dram_grid_size()
print(
f"FACT arch={ttnn.get_arch_name()} compute_grid={grid.x}x{grid.y} ({grid.x * grid.y} cores) dram_grid={dram.x}x{dram.y}"
)
workers = device.get_optimal_dram_bank_to_logical_worker_assignment(ttnn.NOC.NOC_0)
print(f"FACT optimal_dram_bank_workers(NOC_0)={[(c.x, c.y) for c in workers]}")
workers1 = device.get_optimal_dram_bank_to_logical_worker_assignment(ttnn.NOC.NOC_1)
print(f"FACT optimal_dram_bank_workers(NOC_1)={[(c.x, c.y) for c in workers1]}")
pinned = [(0, 9), (0, 0), (0, 7), (0, 3), (7, 9), (7, 1), (7, 6), (7, 4)]
print(f"FACT deepseek_pinned_list_matches_runtime={[(c.x, c.y) for c in workers] == pinned}")
for name in dir(device):
if "harvest" in name.lower():
try:
print(f"FACT device.{name}={getattr(device, name)()}")
except Exception as exc: # noqa: BLE001 - probe only
print(f"FACT device.{name} -> {exc!r}")
for x in range(grid.x):
for y in (0, grid.y - 1):
phys = device.worker_core_from_logical_core(ttnn.CoreCoord(x, y))
print(f"FACT logical({x},{y}) -> noc0/virtual ({phys.x},{phys.y})")
def run_hello(device, grid_end: ttnn.CoreCoord, tag: str) -> float:
"""Compile+run the hello kernel on the rectangle (0,0)-(grid_end); return the wall time in seconds."""
grid = ttnn.CoreRangeSet([ttnn.CoreRange(ttnn.CoreCoord(0, 0), grid_end)])
num_cores = (grid_end.x + 1) * (grid_end.y + 1)
torch_out = torch.zeros((num_cores * SHARD[0], SHARD[1]), dtype=torch.int32)
shard_spec = ttnn.ShardSpec(grid, list(SHARD), ttnn.ShardOrientation.ROW_MAJOR)
mem = ttnn.MemoryConfig(ttnn.TensorMemoryLayout.HEIGHT_SHARDED, ttnn.BufferType.L1, shard_spec)
out_t = ttnn.from_torch(torch_out, dtype=ttnn.uint32, layout=ttnn.TILE_LAYOUT, device=device, memory_config=mem)
# generic_op insists on >= 1 input and >= 1 output tensor (generic_op_device_operation.cpp:135); the kernel
# never reads this dummy input, it only exists to satisfy that precondition.
in_t = ttnn.from_torch(torch.zeros(32, 32, dtype=torch.int32), dtype=ttnn.uint32, layout=ttnn.TILE_LAYOUT, device=device)
out_cb = 0
cb = ttnn.cb_descriptor_from_sharded_tensor(out_cb, out_t)
num_pages = 1
cb.format_descriptors[0].page_size = SHARD[0] * SHARD[1] * 4
ncrisc_args = [
("hello_out_cb", out_cb),
("hello_num_pages", num_pages),
("hello_grid_start_x", 0),
("hello_grid_start_y", 0),
("hello_grid_end_x", grid_end.x),
("hello_grid_end_y", grid_end.y),
]
ukd = UnifiedKernelDescriptor(
kernel_source=KERNEL,
core_ranges=grid,
ncrisc_named_compile_time_args=ncrisc_args,
brisc_named_compile_time_args=[],
trisc_named_compile_time_args=[],
ncrisc_common_runtime_args=[MAGIC],
trisc_compute_config=ttnn.ComputeConfigDescriptor(
math_fidelity=ttnn.MathFidelity.LoFi, math_approx_mode=False, fp32_dest_acc_en=False, dst_full_sync_en=False
),
unified_compile_time_core_descriptors=[
UnifiedCompileTimeCoreDescriptor(
named_compile_time_arg="is_active_core", core_range=grid, value=1, other_value=0
)
],
)
program = ttnn.ProgramDescriptor(kernels=ukd.get_kernel_descriptors().kernels, cbs=[cb])
t0 = time.perf_counter()
ttnn.generic_op([in_t, out_t], program)
ttnn.synchronize_device(device)
dt = time.perf_counter() - t0
got = ttnn.to_torch(out_t).view(num_cores, SHARD[0] * SHARD[1])
bad = []
for x in range(grid_end.x + 1):
for y in range(grid_end.y + 1):
lin = y * (grid_end.x + 1) + x # row-major id, matches linear_id_in_grid<true>
# HEIGHT_SHARDED shards are laid out in ROW_MAJOR core order -> shard index == lin
words = got[lin, :4].tolist()
if words != [x, y, lin, MAGIC]:
bad.append(((x, y), words))
status = "OK" if not bad else f"MISMATCH on {len(bad)} cores, first {bad[:4]}"
print(
f"RESULT hello[{tag}] cores={num_cores} grid=(0,0)-({grid_end.x},{grid_end.y}) wall={dt * 1e3:.2f} ms {status}"
)
if bad:
raise SystemExit(f"hello kernel verification failed: {status}")
ttnn.deallocate(out_t)
ttnn.deallocate(in_t)
return dt
def main() -> int:
print(
f"ENV TT_METAL_CACHE={os.environ.get('TT_METAL_CACHE', '<default>')} slow_dispatch={os.environ.get('TT_METAL_SLOW_DISPATCH_MODE')}"
)
t0 = time.perf_counter()
device = ttnn.open_device(device_id=0)
print(f"RESULT open_device {time.perf_counter() - t0:.2f} s")
try:
_probe_device_facts(device)
grid = device.compute_with_storage_grid_size()
full = ttnn.CoreCoord(grid.x - 1, grid.y - 1)
cold = run_hello(device, full, "cold")
warm = run_hello(device, full, "warm")
warm2 = run_hello(device, full, "warm2")
# A second grid shape forces a second JIT (different CT args) - measures compile alone (firmware cached)
cold_small = run_hello(device, ttnn.CoreCoord(grid.x - 1, 0), "cold_1row")
print(
f"RESULT compile_estimate full_grid={cold - warm:.3f} s (cold {cold:.3f} s, warm {warm:.4f}/{warm2:.4f} s); "
f"second-variant cold={cold_small:.3f} s"
)
finally:
ttnn.close_device(device)
return 0
if __name__ == "__main__":
sys.exit(main())