IQ.Pilot Release Commit @ 0798119
This commit is contained in:
14
tinygrad_repo/extra/sqtt/README.md
Normal file
14
tinygrad_repo/extra/sqtt/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# SQTT Profiling
|
||||
|
||||
## Getting SQ Thread Trace
|
||||
|
||||
`VIZ=2` to enable SQTT profiling.
|
||||
|
||||
`SQTT_ITRACE_SE_MASK=X` to select shader engines for instruction tracing, -1 = all, 0 = disabled, >0 = SE bitmask, default 0b11.
|
||||
|
||||
`SQTT_BUFFER_SIZE=X` to change size of SQTT buffer (per shader engine, 6 SEs on 7900xtx) in megabytes, default 256.
|
||||
|
||||
## Viewing the traces
|
||||
|
||||
- Web UI: `tinygrad/viz/serve.py`
|
||||
- Command line: `python -m tinygrad.renderer.amd.sqtt`
|
||||
27
tinygrad_repo/extra/sqtt/examples/generate_examples.py
Normal file
27
tinygrad_repo/extra/sqtt/examples/generate_examples.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os, subprocess, sys, shlex
|
||||
from pathlib import Path
|
||||
from tinygrad.helpers import temp, getenv
|
||||
|
||||
EXAMPLES_DIR = Path(__file__).parent
|
||||
PROFILE_PATH = Path(temp("profile.pkl", append_user=True))
|
||||
|
||||
EXAMPLES = {
|
||||
"empty":"test/backend/test_custom_kernel.py TestCustomKernel.test_empty",
|
||||
"plus":"test/test_tiny.py TestTiny.test_plus",
|
||||
"gemm":"-c \"from tinygrad import Tensor; (Tensor.empty(N:=32, N)@Tensor.empty(N, N)).realize()\"",
|
||||
"sync":"test/amd/test_custom_kernel.py TestCustomKernel.test_lds_sync",
|
||||
"handwritten":"test/amd/test_custom_kernel.py TestCustomKernel.test_handwritten",
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
arch = subprocess.check_output(["python", "-c", "from tinygrad import Device; print(Device['AMD'].arch)"], text=True,
|
||||
env={**os.environ, "DEBUG":"0"}).rstrip()
|
||||
(EXAMPLES_DIR/arch).mkdir(exist_ok=True)
|
||||
for name,test in EXAMPLES.items():
|
||||
if getenv("NAME", name) != name: continue
|
||||
for i in range(2):
|
||||
# AM_RESET=1 gets a clear trace, does not work on mi300 machines
|
||||
subprocess.run([sys.executable, *shlex.split(test)], cwd=EXAMPLES_DIR.parent.parent.parent,
|
||||
env={**os.environ, "DEV":"AMD", "AM_RESET":"1" if not arch.startswith("gfx9") else "0", "VIZ":"-2", "PYTHONPATH":"."})
|
||||
PROFILE_PATH.rename(dest:=EXAMPLES_DIR/arch/f"profile_{name}_run_{i}.pkl")
|
||||
print(f"saved SQTT trace to {dest}")
|
||||
Binary file not shown.
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_gemm_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_gemm_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_gemm_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_gemm_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_plus_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_plus_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_plus_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_plus_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_sync_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_sync_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_sync_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1100/profile_sync_run_1.pkl
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_gemm_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_gemm_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_gemm_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_gemm_run_1.pkl
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_plus_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_plus_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_plus_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_plus_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_sync_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_sync_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_sync_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx1200/profile_sync_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_empty_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_empty_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_empty_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_empty_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_gemm_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_gemm_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_gemm_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_gemm_run_1.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_plus_run_0.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_plus_run_0.pkl
Normal file
Binary file not shown.
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_plus_run_1.pkl
Normal file
BIN
tinygrad_repo/extra/sqtt/examples/gfx950/profile_plus_run_1.pkl
Normal file
Binary file not shown.
23
tinygrad_repo/extra/sqtt/install_rocprof_decoder.py
Executable file
23
tinygrad_repo/extra/sqtt/install_rocprof_decoder.py
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
import os, platform, shutil, subprocess
|
||||
from pathlib import Path
|
||||
from tinygrad.helpers import fetch, OSX
|
||||
|
||||
VERSION = "0.1.6"
|
||||
DEST = Path("/usr/local/lib")
|
||||
DEST.mkdir(exist_ok=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if OSX:
|
||||
arch = "arm64" if platform.machine() == "arm64" else "x86_64"
|
||||
dmg = fetch(f"https://github.com/ROCm/rocprof-trace-decoder/releases/download/{VERSION}/rocprof-trace-decoder-macos-{arch}-{VERSION}-Darwin.dmg")
|
||||
mnt = Path(subprocess.check_output(["hdiutil", "attach", "-nobrowse", "-readonly", "-mountrandom", "/tmp", str(dmg)],
|
||||
text=True).split("\t")[-1].strip())
|
||||
try: shutil.copy2(next(mnt.rglob("librocprof-trace-decoder.dylib")), DEST)
|
||||
finally: subprocess.run(["hdiutil", "detach", str(mnt)], check=True)
|
||||
lib = DEST/"librocprof-trace-decoder.dylib"
|
||||
else:
|
||||
lib = DEST/"librocprof-trace-decoder.so"
|
||||
os.system(f"sudo curl -L https://github.com/ROCm/rocprof-trace-decoder/raw/{VERSION}/releases/linux_glibc_2_28_x86_64/librocprof-trace-decoder.so -o {lib}")
|
||||
os.system("sudo ldconfig")
|
||||
print(f"Installed {lib.name} ({VERSION}) to", DEST)
|
||||
347
tinygrad_repo/extra/sqtt/rgptool.py
Executable file
347
tinygrad_repo/extra/sqtt/rgptool.py
Executable file
@@ -0,0 +1,347 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
import argparse, ctypes, struct, hashlib, pickle, code, typing, functools
|
||||
import tinygrad.runtime.autogen.sqtt as sqtt
|
||||
from tinygrad.device import ProfileEvent, ProfileDeviceEvent, ProfileProgramEvent
|
||||
from tinygrad.runtime.ops_amd import ProfileSQTTEvent
|
||||
from tinygrad.helpers import round_up, flatten, all_same, temp
|
||||
from dataclasses import dataclass
|
||||
|
||||
CHUNK_CLASSES = {
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_ASIC_INFO: sqtt.struct_sqtt_file_chunk_asic_info,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DESC: sqtt.struct_sqtt_file_chunk_sqtt_desc,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DATA: sqtt.struct_sqtt_file_chunk_sqtt_data,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_API_INFO: sqtt.struct_sqtt_file_chunk_api_info,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_QUEUE_EVENT_TIMINGS: sqtt.struct_sqtt_file_chunk_queue_event_timings,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_CLOCK_CALIBRATION: sqtt.struct_sqtt_file_chunk_clock_calibration,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_CPU_INFO: sqtt.struct_sqtt_file_chunk_cpu_info,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_SPM_DB: sqtt.struct_sqtt_file_chunk_spm_db,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE: sqtt.struct_sqtt_file_chunk_code_object_database,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS: sqtt.struct_sqtt_file_chunk_code_object_loader_events,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION: sqtt.struct_sqtt_file_chunk_pso_correlation,
|
||||
}
|
||||
|
||||
def pretty(val, pad=0) -> str:
|
||||
if isinstance(val, (ctypes.Structure, ctypes.Union)):
|
||||
nl = '\n' # old python versions don't support \ in f-strings
|
||||
return f"{val.__class__.__name__}({nl}{' '*(pad+2)}{(f', {nl}'+' '*(pad+2)).join([f'{field[0]}={pretty(getattr(val, field[0]), pad=pad+2)}' for field in val._fields_])}{nl}{' '*pad})"
|
||||
if isinstance(val, ctypes.Array):
|
||||
return f"[{', '.join(map(pretty, val))}]"
|
||||
if isinstance(val, int) and val >= 1024: return hex(val)
|
||||
return repr(val)
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RGPChunk:
|
||||
header: sqtt.Structure
|
||||
data: list[typing.Any]|list[tuple[typing.Any, bytes]]|bytes|None = None
|
||||
def print(self):
|
||||
print(pretty(self.header))
|
||||
# if isinstance(self.data, bytes): print(repr(self.data))
|
||||
if isinstance(self.data, list):
|
||||
for dchunk in self.data:
|
||||
if isinstance(dchunk, tuple):
|
||||
print(pretty(dchunk[0]))
|
||||
# print(repr(dchunk[1]))
|
||||
else:
|
||||
print(pretty(dchunk))
|
||||
# TODO: `def fixup` and true immutability
|
||||
def to_bytes(self, offset:int) -> bytes:
|
||||
cid = self.header.header.chunk_id.type
|
||||
match cid:
|
||||
case _ if cid in {sqtt.SQTT_FILE_CHUNK_TYPE_ASIC_INFO, sqtt.SQTT_FILE_CHUNK_TYPE_CPU_INFO, sqtt.SQTT_FILE_CHUNK_TYPE_API_INFO, sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DESC}:
|
||||
self.header.header.size_in_bytes = ctypes.sizeof(self.header)
|
||||
return bytes(self.header)
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DATA:
|
||||
assert isinstance(self.data, bytes)
|
||||
self.header.header.size_in_bytes = ctypes.sizeof(self.header) + len(self.data)
|
||||
self.header.offset = offset+ctypes.sizeof(self.header)
|
||||
self.header.size = len(self.data)
|
||||
return bytes(self.header) + self.data
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE:
|
||||
assert isinstance(self.data, list)
|
||||
data_codb = typing.cast(list[tuple[sqtt.struct_sqtt_code_object_database_record, bytes]], self.data)
|
||||
ret = bytearray()
|
||||
sz = ctypes.sizeof(self.header)+sum([ctypes.sizeof(record_hdr)+round_up(len(record_blob), 4) for record_hdr,record_blob in data_codb])
|
||||
self.header.header.size_in_bytes = sz
|
||||
self.header.offset = offset
|
||||
self.header.record_count = len(data_codb)
|
||||
self.header.size = sz
|
||||
ret += self.header
|
||||
for record_hdr,record_blob in data_codb:
|
||||
record_hdr.size = round_up(len(record_blob), 4)
|
||||
ret += record_hdr
|
||||
ret += record_blob.ljust(4, b'\x00')
|
||||
return ret
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS:
|
||||
assert isinstance(self.data, list)
|
||||
data_lev = typing.cast(list[tuple[sqtt.struct_sqtt_code_object_loader_events_record]], self.data)
|
||||
self.header.header.size_in_bytes = ctypes.sizeof(self.header)+ctypes.sizeof(sqtt.struct_sqtt_code_object_loader_events_record)*len(data_lev)
|
||||
self.header.offset = offset
|
||||
self.header.record_size = ctypes.sizeof(sqtt.struct_sqtt_code_object_loader_events_record)
|
||||
self.header.record_count = len(data_lev)
|
||||
return bytes(self.header) + b''.join(map(bytes, data_lev))
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION:
|
||||
assert isinstance(self.data, list)
|
||||
data_pso = typing.cast(list[tuple[sqtt.struct_sqtt_pso_correlation_record]], self.data)
|
||||
self.header.header.size_in_bytes = ctypes.sizeof(self.header)+ctypes.sizeof(sqtt.struct_sqtt_pso_correlation_record)*len(data_pso)
|
||||
self.header.offset = offset
|
||||
self.header.record_size = ctypes.sizeof(sqtt.struct_sqtt_pso_correlation_record)
|
||||
self.header.record_count = len(data_pso)
|
||||
return bytes(self.header) + b''.join(map(bytes, data_pso))
|
||||
case _: raise NotImplementedError(pretty(self.header))
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RGP:
|
||||
header: sqtt.struct_sqtt_file_header
|
||||
chunks: list[RGPChunk]
|
||||
@staticmethod
|
||||
def from_bytes(blob: bytes) -> RGP:
|
||||
file_header = sqtt.struct_sqtt_file_header.from_buffer_copy(blob)
|
||||
assert file_header.magic_number == sqtt.SQTT_FILE_MAGIC_NUMBER and file_header.version_major == sqtt.SQTT_FILE_VERSION_MAJOR
|
||||
i = file_header.chunk_offset
|
||||
chunks = []
|
||||
while i < len(blob):
|
||||
assert i%4==0, hex(i)
|
||||
hdr = sqtt.struct_sqtt_file_chunk_header.from_buffer_copy(blob, i)
|
||||
cid = hdr.chunk_id.type
|
||||
header: ctypes.Structure
|
||||
match cid:
|
||||
case _ if cid in {sqtt.SQTT_FILE_CHUNK_TYPE_RESERVED, sqtt.SQTT_FILE_CHUNK_TYPE_QUEUE_EVENT_TIMINGS, sqtt.SQTT_FILE_CHUNK_TYPE_CLOCK_CALIBRATION, sqtt.SQTT_FILE_CHUNK_TYPE_SPM_DB}:
|
||||
chunk = None
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE:
|
||||
header = sqtt.struct_sqtt_file_chunk_code_object_database.from_buffer_copy(blob, i)
|
||||
j = header.offset + ctypes.sizeof(header)
|
||||
data: list = []
|
||||
while j < header.offset + header.size:
|
||||
rec_hdr: ctypes.Structure = sqtt.struct_sqtt_code_object_database_record.from_buffer_copy(blob, j)
|
||||
data.append((rec_hdr, elf:=blob[j+ctypes.sizeof(rec_hdr):j+ctypes.sizeof(rec_hdr)+rec_hdr.size]))
|
||||
assert elf[:4] == b'\x7fELF', repr(elf[:16])
|
||||
j += ctypes.sizeof(rec_hdr)+rec_hdr.size
|
||||
assert len(data) == header.record_count
|
||||
chunk = RGPChunk(header, data)
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS:
|
||||
header = sqtt.struct_sqtt_file_chunk_code_object_loader_events.from_buffer_copy(blob, i)
|
||||
data = [sqtt.struct_sqtt_code_object_loader_events_record.from_buffer_copy(blob, header.offset+ctypes.sizeof(header)+j*header.record_size)
|
||||
for j in range(header.record_count)]
|
||||
chunk = RGPChunk(header, data)
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION:
|
||||
header = sqtt.struct_sqtt_file_chunk_pso_correlation.from_buffer_copy(blob, i)
|
||||
data = [sqtt.struct_sqtt_pso_correlation_record.from_buffer_copy(blob, header.offset+ctypes.sizeof(header)+j*header.record_size)
|
||||
for j in range(header.record_count)]
|
||||
chunk = RGPChunk(header, data)
|
||||
case sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DATA:
|
||||
header = sqtt.struct_sqtt_file_chunk_sqtt_data.from_buffer_copy(blob, i)
|
||||
chunk = RGPChunk(header, blob[header.offset:header.offset+header.size])
|
||||
case _ if cid in {sqtt.SQTT_FILE_CHUNK_TYPE_ASIC_INFO, sqtt.SQTT_FILE_CHUNK_TYPE_CPU_INFO, sqtt.SQTT_FILE_CHUNK_TYPE_API_INFO,
|
||||
sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DESC}:
|
||||
chunk = RGPChunk(CHUNK_CLASSES[cid].from_buffer_copy(blob, i))
|
||||
case _:
|
||||
chunk = None
|
||||
print(f"unknown chunk id {cid}")
|
||||
if chunk is not None: chunks.append(chunk)
|
||||
i += hdr.size_in_bytes
|
||||
assert i == len(blob), f'{i} != {len(blob)}'
|
||||
return RGP(file_header, chunks)
|
||||
@staticmethod
|
||||
def from_profile(profile_pickled, device:str|None=None):
|
||||
profile: list[ProfileEvent] = pickle.loads(profile_pickled)
|
||||
def _is_base_dev(d): return all(p.isdigit() for p in d.split(":")[1:])
|
||||
device_events = {x.device:x for x in profile if isinstance(x, ProfileDeviceEvent) and x.device.startswith('AMD') and _is_base_dev(x.device)}
|
||||
if device is None:
|
||||
if len(device_events) == 0: raise RuntimeError('No supported devices found in profile')
|
||||
if len(device_events) > 1: raise RuntimeError(f"More than one supported device found, select which one to export: {', '.join(device_events.keys())}")
|
||||
_, device_event = device_events.popitem()
|
||||
else:
|
||||
if device not in device_events: raise RuntimeError(f"Device {device} not found in profile, devices in profile: {', '.join(device_events.keys())} ")
|
||||
device_event = device_events[device]
|
||||
sqtt_events = [x for x in profile if isinstance(x, ProfileSQTTEvent) and x.device == device_event.device]
|
||||
device_props = device_event.props
|
||||
# merge events per SE
|
||||
merged_sqtt_events:dict[int, ProfileSQTTEvent] = {}
|
||||
for ev in sqtt_events:
|
||||
if ev.se not in merged_sqtt_events: merged_sqtt_events[ev.se] = ev
|
||||
else:
|
||||
merged_sqtt_events[ev.se] = ProfileSQTTEvent(
|
||||
device=ev.device,
|
||||
kern=ev.kern,
|
||||
se=ev.se,
|
||||
itrace=merged_sqtt_events[ev.se].itrace or ev.itrace,
|
||||
blob=merged_sqtt_events[ev.se].blob + ev.blob,
|
||||
exec_tag=0,
|
||||
)
|
||||
sqtt_events = list(merged_sqtt_events.values())
|
||||
|
||||
if len(sqtt_events) == 0: raise RuntimeError(f"Device {device_event.device} doesn't contain SQTT data")
|
||||
gfx_ver = device_props['gfx_target_version'] // 10000
|
||||
gfx_iplvl = getattr(sqtt, f"SQTT_GFXIP_LEVEL_GFXIP_{device_props['gfx_target_version']//10000}_{(device_props['gfx_target_version']//100)%100}",
|
||||
getattr(sqtt, f"SQTT_GFXIP_LEVEL_GFXIP_{device_props['gfx_target_version']//10000}", None))
|
||||
sqtt_itrace_enabled = any([event.itrace for event in sqtt_events])
|
||||
sqtt_itrace_masked = not all_same([event.itrace for event in sqtt_events])
|
||||
sqtt_itrace_se_mask = functools.reduce(lambda a,b: a|b, [int(event.itrace) << event.se for event in sqtt_events], 0) if sqtt_itrace_masked else 0
|
||||
load_events = [x for x in profile if isinstance(x, ProfileProgramEvent) and x.device == device_event.device]
|
||||
loads = [(event.base, struct.unpack('<Q', hashlib.md5(event.lib).digest()[:8])*2) for event in load_events if event.base is not None and event.lib is not None]
|
||||
code_objects = list(dict.fromkeys([x.lib for x in load_events if x.lib is not None]).keys())
|
||||
if len(loads) == 0: raise RuntimeError('No load events in profile')
|
||||
# TODO: tons of stuff hardcoded for 7900xtx
|
||||
file_header = sqtt.struct_sqtt_file_header(
|
||||
magic_number=sqtt.SQTT_FILE_MAGIC_NUMBER,
|
||||
version_major=sqtt.SQTT_FILE_VERSION_MAJOR,
|
||||
version_minor=sqtt.SQTT_FILE_VERSION_MINOR,
|
||||
flags=sqtt.struct_sqtt_file_header_flags(value=1,),
|
||||
chunk_offset=ctypes.sizeof(sqtt.struct_sqtt_file_header),
|
||||
)
|
||||
chunks = [
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_cpu_info(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_CPU_INFO),
|
||||
major_version=0, minor_version=0,
|
||||
),
|
||||
cpu_timestamp_freq=1000000000,
|
||||
clock_speed=2994, # in mhz???
|
||||
num_logical_cores=64,
|
||||
num_physical_cores=32,
|
||||
system_ram_size=256*1024, # in mb???
|
||||
)),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_asic_info(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_ASIC_INFO),
|
||||
major_version=0, minor_version=5,
|
||||
),
|
||||
flags=0,
|
||||
trace_shader_core_clock=0x93f05080,
|
||||
trace_memory_clock=0x4a723a40,
|
||||
device_id={110000: 0x744c, 110003: 0x7480, 120001: 0x7550, 120000: 0x7550}[device_props['gfx_target_version']],
|
||||
device_revision_id=0xc8,
|
||||
vgprs_per_simd=1536,
|
||||
sgprs_per_simd=128*16,
|
||||
shader_engines=device_props['array_count'] // device_props['simd_arrays_per_engine'],
|
||||
compute_unit_per_shader_engine=device_props['simd_count'] // device_props['simd_per_cu'] // (device_props['array_count'] // device_props['simd_arrays_per_engine']),
|
||||
simd_per_compute_unit=device_props['simd_per_cu'],
|
||||
wavefronts_per_simd=device_props['max_waves_per_simd'],
|
||||
minimum_vgpr_alloc=4,
|
||||
vgpr_alloc_granularity=8,
|
||||
minimum_sgpr_alloc=128,
|
||||
sgpr_alloc_granularity=128,
|
||||
hardware_contexts=8,
|
||||
gpu_type=sqtt.SQTT_GPU_TYPE_DISCRETE,
|
||||
gfxip_level=gfx_iplvl,
|
||||
gpu_index=0,
|
||||
gds_size=0,
|
||||
gds_per_shader_engine=0,
|
||||
ce_ram_size=0,
|
||||
ce_ram_size_graphics=0,
|
||||
ce_ram_size_compute=0,
|
||||
max_number_of_dedicated_cus=0,
|
||||
vram_size=24 * 1024 * 1024 * 1024, # 24 GB
|
||||
vram_bus_width=384, # 384-bit
|
||||
l2_cache_size=6 * 1024 * 1024, # 6 MB
|
||||
l1_cache_size=32 * 1024, # 32 KB per SIMD (?)
|
||||
lds_size=device_props['lds_size_in_kb'] * 1024,
|
||||
gpu_name=b'NAVI31',
|
||||
alu_per_clock=0,
|
||||
texture_per_clock=0,
|
||||
prims_per_clock=6,
|
||||
pixels_per_clock=0,
|
||||
gpu_timestamp_frequency=100000000, # 100 MHz
|
||||
max_shader_core_clock=2500000000, # 2.5 GHz (boost clock)
|
||||
max_memory_clock=1250000000, # 1.25 GHz
|
||||
memory_ops_per_clock=16,
|
||||
memory_chip_type=sqtt.SQTT_MEMORY_TYPE_GDDR6,
|
||||
lds_granularity=512,
|
||||
cu_mask=((255, 255),)*6 + ((0,0),)*(32-6),
|
||||
gl1_cache_size=256 * 1024, # 256 KB
|
||||
instruction_cache_size=32 * 1024, # 32 KB
|
||||
scalar_cache_size=16 * 1024, # 16 KB
|
||||
mall_cache_size=96 * 1024 * 1024, # 96 MB
|
||||
)),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_api_info(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_API_INFO),
|
||||
major_version=0,
|
||||
minor_version=2,
|
||||
),
|
||||
api_type=5, # HIP, not in enum
|
||||
major_version=12, minor_version=0,
|
||||
profiling_mode=sqtt.SQTT_PROFILING_MODE_PRESENT,
|
||||
instruction_trace_mode=sqtt.SQTT_INSTRUCTION_TRACE_FULL_FRAME if sqtt_itrace_enabled else sqtt.SQTT_INSTRUCTION_TRACE_DISABLED,
|
||||
instruction_trace_data=sqtt.union_sqtt_instruction_trace_data(
|
||||
shader_engine_filter=sqtt.union_sqtt_instruction_trace_data_shader_engine_filter(mask=sqtt_itrace_se_mask),
|
||||
),
|
||||
)),
|
||||
*flatten([(
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_sqtt_desc(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DESC, index=sqtt_event.se),
|
||||
major_version=0, minor_version=2,
|
||||
),
|
||||
shader_engine_index=sqtt_event.se,
|
||||
sqtt_version={11: sqtt.SQTT_VERSION_3_2, 12: sqtt.SQTT_VERSION_3_3}.get(gfx_ver),
|
||||
v1=sqtt.struct_sqtt_file_chunk_sqtt_desc_v1(
|
||||
instrumentation_spec_version=1,
|
||||
instrumentation_api_version=0,
|
||||
compute_unit_index=0,
|
||||
)
|
||||
)),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_sqtt_data(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_SQTT_DATA, index=sqtt_event.se),
|
||||
major_version=0, minor_version=0,
|
||||
),
|
||||
), sqtt_event.blob),
|
||||
) for sqtt_event in sqtt_events]),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_code_object_database(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE),
|
||||
major_version=0, minor_version=0,
|
||||
),
|
||||
), [(sqtt.struct_sqtt_code_object_database_record(), lib) for lib in code_objects]),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_code_object_loader_events(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS),
|
||||
major_version=1, minor_version=0,
|
||||
),
|
||||
), [sqtt.struct_sqtt_code_object_loader_events_record(base_address=base, code_object_hash=hash) for base,hash in loads]),
|
||||
RGPChunk(sqtt.struct_sqtt_file_chunk_pso_correlation(
|
||||
header=sqtt.struct_sqtt_file_chunk_header(
|
||||
chunk_id=sqtt.struct_sqtt_file_chunk_id(type=sqtt.SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION),
|
||||
major_version=0, minor_version=0,
|
||||
),
|
||||
), [sqtt.struct_sqtt_pso_correlation_record(api_pso_hash=hash[0], pipeline_hash=hash) for _,hash in loads])
|
||||
]
|
||||
return RGP(file_header, chunks)
|
||||
def to_bytes(self) -> bytes:
|
||||
ret = bytearray()
|
||||
ret += self.header
|
||||
for chunk in self.chunks:
|
||||
ret += chunk.to_bytes(len(ret))
|
||||
return bytes(ret)
|
||||
def print(self):
|
||||
print(pretty(self.header))
|
||||
for chunk in self.chunks: chunk.print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(prog='rgptool', description='A tool to create (from pickled tinygrad profile), inspect and modify Radeon GPU Profiler files')
|
||||
parser.add_argument('command')
|
||||
parser.add_argument('input', nargs='?', default=temp("profile.pkl", append_user=True))
|
||||
parser.add_argument('-d', '--device')
|
||||
parser.add_argument('-o', '--output')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.input, 'rb') as fd: input_bytes = fd.read()
|
||||
|
||||
match args.command:
|
||||
case 'print':
|
||||
rgp = RGP.from_bytes(input_bytes)
|
||||
rgp.print()
|
||||
case 'create':
|
||||
rgp = RGP.from_profile(input_bytes, device=args.device)
|
||||
# rgp.to_bytes() # fixup
|
||||
# rgp.print()
|
||||
case 'repl':
|
||||
rgp = RGP.from_bytes(input_bytes)
|
||||
code.interact(local=locals())
|
||||
case _: raise RuntimeError(args.command)
|
||||
|
||||
if args.output is not None:
|
||||
with open(args.output, 'wb+') as fd: fd.write(rgp.to_bytes())
|
||||
print(f"Saved to {args.output}")
|
||||
241
tinygrad_repo/extra/sqtt/roc.py
Executable file
241
tinygrad_repo/extra/sqtt/roc.py
Executable file
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python3
|
||||
import ctypes, pathlib, argparse, pickle, dataclasses, threading, itertools
|
||||
from decimal import Decimal
|
||||
from typing import Generator
|
||||
from tinygrad.helpers import temp, unwrap, DEBUG
|
||||
from tinygrad.runtime.ops_amd import ProfileSQTTEvent
|
||||
from tinygrad.runtime.autogen import rocprof
|
||||
from tinygrad.renderer.amd.dsl import Inst
|
||||
from tinygrad.helpers import ProfileEvent, ProfileRangeEvent, ProfilePointEvent
|
||||
from tinygrad.device import ProfileProgramEvent
|
||||
from test.amd.disasm import disasm
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class InstExec:
|
||||
typ:str
|
||||
pc:int
|
||||
stall:int
|
||||
dur:int
|
||||
time:int
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class WaveSlot:
|
||||
wave_id:int
|
||||
cu:int
|
||||
simd:int
|
||||
se:int
|
||||
@property
|
||||
def cu_loc(self) -> str: return f"SE:{self.se} CU:{self.cu}"
|
||||
@property
|
||||
def wave_loc(self) -> str: return f"{self.cu_loc} SIMD:{self.simd} W:{self.wave_id}"
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class WaveExec(WaveSlot):
|
||||
begin_time:int
|
||||
end_time:int
|
||||
insts:bytearray
|
||||
def unpack_insts(self) -> Generator[InstExec, None, None]:
|
||||
sz = ctypes.sizeof(struct:=rocprof.rocprofiler_thread_trace_decoder_inst_t)
|
||||
insts_array = (struct*(len(self.insts)//sz)).from_buffer(self.insts)
|
||||
for inst in insts_array:
|
||||
inst_typ = rocprof.enum_rocprofiler_thread_trace_decoder_inst_category_t.get(inst.category)
|
||||
yield InstExec(inst_typ, inst.pc.address, inst.stall, inst.duration, inst.time)
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class OccEvent(WaveSlot):
|
||||
time:int
|
||||
start:int
|
||||
|
||||
RunKey = tuple[str, int]
|
||||
|
||||
class _ROCParseCtx:
|
||||
def __init__(self, sqtt_evs:list[ProfileSQTTEvent], disasms:dict[str, dict[int, Inst]]):
|
||||
self.sqtt_evs, self.disasms = iter(sqtt_evs), {k:{k2:(disasm(v2), v2.size()) for k2,v2 in v.items()} for k,v in disasms.items()}
|
||||
self.inst_execs:dict[RunKey, list[WaveExec]] = {}
|
||||
self.occ_events:dict[RunKey, list[OccEvent]] = {}
|
||||
|
||||
def next_sqtt(self):
|
||||
x = next(self.sqtt_evs, None)
|
||||
self.active_run = (x.kern, x.exec_tag) if x is not None else None
|
||||
self.active_se = x.se if x is not None else None
|
||||
self.active_blob = (ctypes.c_ubyte * len(x.blob)).from_buffer_copy(x.blob) if x is not None else None
|
||||
return self.active_blob
|
||||
|
||||
def on_occupancy_ev(self, ev:rocprof.rocprofiler_thread_trace_decoder_occupancy_t):
|
||||
if DEBUG >= 5: print(f"OCC {ev.time=} {self.active_se=} {ev.cu=} {ev.simd=} {ev.wave_id=} {ev.start=}")
|
||||
self.occ_events.setdefault(unwrap(self.active_run), []).append(OccEvent(ev.wave_id, ev.cu, ev.simd, unwrap(self.active_se), ev.time, ev.start))
|
||||
|
||||
def on_wave_ev(self, ev:rocprof.rocprofiler_thread_trace_decoder_wave_t):
|
||||
if DEBUG >= 5: print(f"WAVE {ev.wave_id=} {self.active_se=} {ev.cu=} {ev.simd=} {ev.contexts=} {ev.begin_time=} {ev.end_time=}")
|
||||
# Skip wave events without instruction timings, occupancy events give the start and duration.
|
||||
if ev.instructions_size == 0: return
|
||||
|
||||
insts_blob = bytearray(sz:=ev.instructions_size * ctypes.sizeof(rocprof.rocprofiler_thread_trace_decoder_inst_t))
|
||||
ctypes.memmove((ctypes.c_char * sz).from_buffer(insts_blob), ev.instructions_array, sz)
|
||||
|
||||
self.inst_execs.setdefault(unwrap(self.active_run), []).append(WaveExec(ev.wave_id, ev.cu, ev.simd, unwrap(self.active_se), ev.begin_time,
|
||||
ev.end_time, insts_blob))
|
||||
|
||||
def decode(sqtt_evs:list[ProfileSQTTEvent], disasms:dict[str, dict[int, Inst]]) -> _ROCParseCtx:
|
||||
ROCParseCtx = _ROCParseCtx(sqtt_evs, disasms)
|
||||
|
||||
@rocprof.rocprof_trace_decoder_se_data_callback_t
|
||||
def copy_cb(buf, buf_size, _):
|
||||
if (prof_info:=ROCParseCtx.next_sqtt()) is None: return 0
|
||||
buf[0] = ctypes.cast(prof_info, ctypes.POINTER(ctypes.c_ubyte))
|
||||
buf_size[0] = len(prof_info)
|
||||
return len(prof_info)
|
||||
|
||||
@rocprof.rocprof_trace_decoder_trace_callback_t
|
||||
def trace_cb(record_type, events_ptr, n, _):
|
||||
match record_type:
|
||||
case rocprof.ROCPROFILER_THREAD_TRACE_DECODER_RECORD_OCCUPANCY:
|
||||
for ev in (rocprof.rocprofiler_thread_trace_decoder_occupancy_t * n).from_address(events_ptr): ROCParseCtx.on_occupancy_ev(ev)
|
||||
case rocprof.ROCPROFILER_THREAD_TRACE_DECODER_RECORD_WAVE:
|
||||
for ev in (rocprof.rocprofiler_thread_trace_decoder_wave_t * n).from_address(events_ptr): ROCParseCtx.on_wave_ev(ev)
|
||||
case rocprof.ROCPROFILER_THREAD_TRACE_DECODER_RECORD_REALTIME:
|
||||
if DEBUG >= 5:
|
||||
pairs = [(ev.shader_clock, ev.realtime_clock) for ev in (rocprof.rocprofiler_thread_trace_decoder_realtime_t * n).from_address(events_ptr)]
|
||||
print(f"REALTIME {pairs}")
|
||||
case _:
|
||||
if DEBUG >= 5: print(rocprof.enum_rocprofiler_thread_trace_decoder_record_type_t.get(record_type), events_ptr, n)
|
||||
return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS
|
||||
|
||||
@rocprof.rocprof_trace_decoder_isa_callback_t
|
||||
def isa_cb(instr_ptr, mem_size_ptr, size_ptr, pc, _):
|
||||
instr, mem_size_ptr[0] = ROCParseCtx.disasms[unwrap(ROCParseCtx.active_run)[0]][pc.address]
|
||||
|
||||
# this is the number of bytes to next instruction, set to 0 for end_pgm
|
||||
if instr == "s_endpgm": mem_size_ptr[0] = 0
|
||||
if (max_sz:=size_ptr[0]) == 0: return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_ERROR_OUT_OF_RESOURCES
|
||||
|
||||
# truncate the instr if it doesn't fit
|
||||
if (str_sz:=len(instr_bytes:=instr.encode()))+1 > max_sz: str_sz = max_sz
|
||||
ctypes.memmove(instr_ptr, instr_bytes, str_sz)
|
||||
size_ptr[0] = str_sz
|
||||
|
||||
return rocprof.ROCPROFILER_THREAD_TRACE_DECODER_STATUS_SUCCESS
|
||||
|
||||
exc:Exception|None = None
|
||||
def worker():
|
||||
nonlocal exc
|
||||
try: rocprof.rocprof_trace_decoder_parse_data(copy_cb, trace_cb, isa_cb, None)
|
||||
except AttributeError as e:
|
||||
exc = RuntimeError("Failed to find rocprof-trace-decoder. Run sudo ./extra/sqtt/install_rocprof_decoder.py to install")
|
||||
exc.__cause__ = e
|
||||
(t:=threading.Thread(target=worker, daemon=True)).start()
|
||||
t.join()
|
||||
if exc is not None:
|
||||
raise exc
|
||||
return ROCParseCtx
|
||||
|
||||
def unpack_occ(viz_data, i:int, j:int, key:tuple[str, int], data:list, p:ProfileProgramEvent, target:str) -> dict:
|
||||
from tinygrad.viz.serve import amd_decode, create_step, row_tuple
|
||||
steps = viz_data.ctxs[i]["steps"]
|
||||
if len(steps[j+1:]) > 0: return {"steps":[{k:v for k,v in s.items() if k != "data"} for s in steps[j+1:]]}
|
||||
base = unwrap(p.base)
|
||||
disasm:dict[int, Inst] = {addr+base:inst for addr,inst in amd_decode(unwrap(p.lib), target).items()}
|
||||
rctx = decode(data, {p.tag:disasm})
|
||||
cu_events:dict[str, list[ProfileEvent]] = {}
|
||||
# ** inst traces
|
||||
wave_insts:dict[str, dict[str, dict]] = {}
|
||||
inst_units:dict[str, itertools.count] = {}
|
||||
for w in rctx.inst_execs.get(key, []):
|
||||
if (u:=w.wave_loc) not in inst_units: inst_units[u] = itertools.count(0)
|
||||
n = next(inst_units[u])
|
||||
if (events:=cu_events.get(w.cu_loc)) is None: cu_events[w.cu_loc] = events = []
|
||||
events.append(ProfileRangeEvent(f"SIMD:{w.simd}", loc:=f"INST WAVE:{w.wave_id} N:{n}", Decimal(w.begin_time), Decimal(w.end_time)))
|
||||
wave_insts.setdefault(w.cu_loc, {})[f"{u} N:{n}"] = {"wave":w, "disasm":disasm, "prg":p, "run_number":n, "loc":loc}
|
||||
# ** occ traces (only WAVESTART/WAVEEND)
|
||||
units:dict[str, itertools.count] = {}
|
||||
wave_start:dict[str, int] = {}
|
||||
for occ in rctx.occ_events.get(key, []):
|
||||
if (u:=occ.wave_loc) not in units: units[u] = itertools.count(0)
|
||||
if u in inst_units: continue
|
||||
if occ.start: wave_start[u] = occ.time
|
||||
else:
|
||||
if (events:=cu_events.get(occ.cu_loc)) is None: cu_events[occ.cu_loc] = events = []
|
||||
events.append(ProfileRangeEvent(f"SIMD:{occ.simd}", f"OCC WAVE:{occ.wave_id} N:{next(units[u])}", Decimal(wave_start.pop(u)),Decimal(occ.time)))
|
||||
# ** split graph by CU
|
||||
for cu in sorted(cu_events, key=row_tuple):
|
||||
steps.append(create_step(f"{cu} {len(cu_events[cu])}", ("/cu-sqtt", i, len(steps)), depth=1,
|
||||
data=[ProfilePointEvent(unit, "start", unit, ts=Decimal(0)) for unit in units]+cu_events[cu]))
|
||||
for k in sorted(wave_insts.get(cu, []), key=row_tuple):
|
||||
wd = wave_insts[cu][k]
|
||||
steps.append(create_step(k.replace(cu, ""), ("/amd-sqtt-insts", i, len(steps)), loc=wd["loc"], depth=2,
|
||||
data={"fxn":unpack_insts, "args":(wd,)}))
|
||||
return {"steps":[{k:v for k,v in s.items() if k != "data"} for s in steps[j+1:]]}
|
||||
|
||||
def unpack_insts(viz_data, i:int, j:int, data:dict) -> dict:
|
||||
columns = ["PC", "Instruction", "Hits", "Cycles", "Stall", "Type"]
|
||||
inst_columns = ["N", "Clk", "Idle", "Dur", "Stall"]
|
||||
# Idle: The total time gap between the completion of previous instruction and the beginning of the current instruction.
|
||||
# The idle time can be caused by:
|
||||
# * Arbiter loss
|
||||
# * Source or destination register dependency
|
||||
# * Instruction cache miss
|
||||
# Stall: The total number of cycles the hardware pipe couldn't issue an instruction.
|
||||
# Duration: Total latency in cycles, defined as "Stall time + Issue time" for gfx9 or "Stall time + Execute time" for gfx10+.
|
||||
prev_instr = (w:=data["wave"]).begin_time
|
||||
pc_to_inst = data["disasm"]
|
||||
start_pc = None
|
||||
rows:dict[int, dict] = {}
|
||||
for pc, inst in pc_to_inst.items():
|
||||
if start_pc is None: start_pc = pc
|
||||
rows[pc] = {"pc":pc-start_pc, "inst":str(inst), "hit_count":0, "dur":0, "stall":0, "type":"", "hits":{"cols":inst_columns, "rows":[]}}
|
||||
for e in w.unpack_insts():
|
||||
if not (inst:=rows[e.pc]).get("type"): inst["type"] = str(e.typ).split("_")[-1]
|
||||
inst["hit_count"] += 1
|
||||
inst["dur"] += e.dur
|
||||
inst["stall"] += e.stall
|
||||
inst["hits"]["rows"].append((inst["hit_count"]-1, e.time, max(0, e.time-prev_instr), e.dur, e.stall))
|
||||
prev_instr = max(prev_instr, e.time + e.dur)
|
||||
summary = [{"label":"Total Cycles", "value":w.end_time-w.begin_time}, {"label":"SE", "value":w.se}, {"label":"CU", "value":w.cu},
|
||||
{"label":"SIMD", "value":w.simd}, {"label":"Wave ID", "value":w.wave_id}, {"label":"Run number", "value":data["run_number"]}]
|
||||
return {"rows":[tuple(v.values()) for v in rows.values()], "cols":columns, "metadata":[summary], "ref":viz_data.ref_map.get(data["prg"].name)}
|
||||
|
||||
def print_data(data:dict) -> None:
|
||||
from tabulate import tabulate
|
||||
# plaintext
|
||||
if "src" in data: print(data["src"])
|
||||
# table format
|
||||
elif "cols" in data:
|
||||
print(tabulate([r[:len(data["cols"])] for r in data["rows"]], headers=data["cols"], tablefmt="github"))
|
||||
|
||||
def main() -> None:
|
||||
import tinygrad.viz.serve as viz
|
||||
from tinygrad.uop.ops import RewriteTrace
|
||||
data = viz.VizData()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--profile', type=pathlib.Path, metavar="PATH", help='Path to profile (optional file, default: latest profile)',
|
||||
default=pathlib.Path(temp("profile.pkl", append_user=True)))
|
||||
parser.add_argument('--kernel', type=str, default=None, metavar="NAME", help='Kernel to focus on (optional name, default: all kernels)')
|
||||
parser.add_argument('-n', type=int, default=3, metavar="NUM", help='Max traces to print (optional number, default: 3 traces)')
|
||||
args = parser.parse_args()
|
||||
|
||||
with args.profile.open("rb") as f: profile = pickle.load(f)
|
||||
|
||||
viz.get_profile(profile, data=data)
|
||||
|
||||
# List all kernels
|
||||
if args.kernel is None:
|
||||
for c in data.ctxs:
|
||||
print(c["name"])
|
||||
for s in c["steps"]: print(" "+s["name"])
|
||||
return None
|
||||
|
||||
# Find kernel trace
|
||||
trace = next((c for c in data.ctxs if c["name"] == f"SQTT {args.kernel}"), None)
|
||||
if not trace: raise RuntimeError(f"no matching trace for {args.kernel}")
|
||||
n = 0
|
||||
for s in trace["steps"]:
|
||||
if "PKTS" in s["name"]: continue
|
||||
print(s["name"])
|
||||
ret = viz.get_render(data, s["query"])
|
||||
print_data(ret)
|
||||
n += 1
|
||||
if n > args.n: break
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
845
tinygrad_repo/extra/sqtt/sqtt.h
Normal file
845
tinygrad_repo/extra/sqtt/sqtt.h
Normal file
@@ -0,0 +1,845 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// Original definition in pal is in c++ and clang2py can't autogen it correctly
|
||||
// Most of this is copy pasted from mesa/src/amd/common/ac_rgp.{h, c}
|
||||
|
||||
/*
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Copyright 2020 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define SQTT_FILE_MAGIC_NUMBER 0x50303042
|
||||
#define SQTT_FILE_VERSION_MAJOR 1
|
||||
#define SQTT_FILE_VERSION_MINOR 5
|
||||
|
||||
#define SQTT_GPU_NAME_MAX_SIZE 256
|
||||
#define SQTT_MAX_NUM_SE 32
|
||||
#define SQTT_SA_PER_SE 2
|
||||
#define SQTT_ACTIVE_PIXEL_PACKER_MASK_DWORDS 4
|
||||
|
||||
struct sqtt_data_info {
|
||||
uint32_t cur_offset;
|
||||
uint32_t trace_status;
|
||||
union {
|
||||
uint32_t gfx9_write_counter;
|
||||
uint32_t gfx10_dropped_cntr;
|
||||
};
|
||||
};
|
||||
|
||||
struct sqtt_data_se {
|
||||
struct sqtt_data_info info;
|
||||
void *data_ptr;
|
||||
uint32_t shader_engine;
|
||||
uint32_t compute_unit;
|
||||
};
|
||||
|
||||
|
||||
enum sqtt_version
|
||||
{
|
||||
SQTT_VERSION_NONE = 0x0,
|
||||
SQTT_VERSION_2_2 = 0x5, /* GFX8 */
|
||||
SQTT_VERSION_2_3 = 0x6, /* GFX9 */
|
||||
SQTT_VERSION_2_4 = 0x7, /* GFX10+ */
|
||||
SQTT_VERSION_3_2 = 0xb, /* GFX11+ */
|
||||
SQTT_VERSION_3_3 = 0xc, /* GFX12+ */
|
||||
};
|
||||
|
||||
enum sqtt_file_chunk_type
|
||||
{
|
||||
SQTT_FILE_CHUNK_TYPE_ASIC_INFO,
|
||||
SQTT_FILE_CHUNK_TYPE_SQTT_DESC,
|
||||
SQTT_FILE_CHUNK_TYPE_SQTT_DATA,
|
||||
SQTT_FILE_CHUNK_TYPE_API_INFO,
|
||||
SQTT_FILE_CHUNK_TYPE_RESERVED,
|
||||
SQTT_FILE_CHUNK_TYPE_QUEUE_EVENT_TIMINGS,
|
||||
SQTT_FILE_CHUNK_TYPE_CLOCK_CALIBRATION,
|
||||
SQTT_FILE_CHUNK_TYPE_CPU_INFO,
|
||||
SQTT_FILE_CHUNK_TYPE_SPM_DB,
|
||||
SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE,
|
||||
SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS,
|
||||
SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION,
|
||||
SQTT_FILE_CHUNK_TYPE_INSTRUMENTATION_TABLE,
|
||||
SQTT_FILE_CHUNK_TYPE_COUNT
|
||||
};
|
||||
|
||||
|
||||
struct sqtt_file_chunk_id {
|
||||
int32_t type : 8;
|
||||
int32_t index : 8;
|
||||
int32_t reserved : 16;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_header {
|
||||
struct sqtt_file_chunk_id chunk_id;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
int32_t size_in_bytes;
|
||||
int32_t padding;
|
||||
};
|
||||
|
||||
struct sqtt_file_header_flags {
|
||||
union {
|
||||
struct {
|
||||
uint32_t is_semaphore_queue_timing_etw : 1;
|
||||
uint32_t no_queue_semaphore_timestamps : 1;
|
||||
uint32_t reserved : 30;
|
||||
};
|
||||
|
||||
uint32_t value;
|
||||
};
|
||||
};
|
||||
|
||||
struct sqtt_file_header {
|
||||
uint32_t magic_number;
|
||||
uint32_t version_major;
|
||||
uint32_t version_minor;
|
||||
struct sqtt_file_header_flags flags;
|
||||
int32_t chunk_offset;
|
||||
int32_t second;
|
||||
int32_t minute;
|
||||
int32_t hour;
|
||||
int32_t day_in_month;
|
||||
int32_t month;
|
||||
int32_t year;
|
||||
int32_t day_in_week;
|
||||
int32_t day_in_year;
|
||||
int32_t is_daylight_savings;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_cpu_info {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t vendor_id[4];
|
||||
uint32_t processor_brand[12];
|
||||
uint32_t reserved[2];
|
||||
uint64_t cpu_timestamp_freq;
|
||||
uint32_t clock_speed;
|
||||
uint32_t num_logical_cores;
|
||||
uint32_t num_physical_cores;
|
||||
uint32_t system_ram_size;
|
||||
};
|
||||
|
||||
enum sqtt_file_chunk_asic_info_flags
|
||||
{
|
||||
SQTT_FILE_CHUNK_ASIC_INFO_FLAG_SC_PACKER_NUMBERING = (1 << 0),
|
||||
SQTT_FILE_CHUNK_ASIC_INFO_FLAG_PS1_EVENT_TOKENS_ENABLED = (1 << 1)
|
||||
};
|
||||
|
||||
enum sqtt_gpu_type
|
||||
{
|
||||
SQTT_GPU_TYPE_UNKNOWN = 0x0,
|
||||
SQTT_GPU_TYPE_INTEGRATED = 0x1,
|
||||
SQTT_GPU_TYPE_DISCRETE = 0x2,
|
||||
SQTT_GPU_TYPE_VIRTUAL = 0x3
|
||||
};
|
||||
|
||||
enum sqtt_gfxip_level
|
||||
{
|
||||
SQTT_GFXIP_LEVEL_NONE = 0x0,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_6 = 0x1,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_7 = 0x2,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_8 = 0x3,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_8_1 = 0x4,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_9 = 0x5,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_10_1 = 0x7,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_10_3 = 0x9,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_11_0 = 0xc,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_11_5 = 0xd,
|
||||
SQTT_GFXIP_LEVEL_GFXIP_12 = 0x10,
|
||||
};
|
||||
|
||||
enum sqtt_memory_type
|
||||
{
|
||||
SQTT_MEMORY_TYPE_UNKNOWN = 0x0,
|
||||
SQTT_MEMORY_TYPE_DDR = 0x1,
|
||||
SQTT_MEMORY_TYPE_DDR2 = 0x2,
|
||||
SQTT_MEMORY_TYPE_DDR3 = 0x3,
|
||||
SQTT_MEMORY_TYPE_DDR4 = 0x4,
|
||||
SQTT_MEMORY_TYPE_DDR5 = 0x5,
|
||||
SQTT_MEMORY_TYPE_GDDR3 = 0x10,
|
||||
SQTT_MEMORY_TYPE_GDDR4 = 0x11,
|
||||
SQTT_MEMORY_TYPE_GDDR5 = 0x12,
|
||||
SQTT_MEMORY_TYPE_GDDR6 = 0x13,
|
||||
SQTT_MEMORY_TYPE_HBM = 0x20,
|
||||
SQTT_MEMORY_TYPE_HBM2 = 0x21,
|
||||
SQTT_MEMORY_TYPE_HBM3 = 0x22,
|
||||
SQTT_MEMORY_TYPE_LPDDR4 = 0x30,
|
||||
SQTT_MEMORY_TYPE_LPDDR5 = 0x31,
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_asic_info {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint64_t flags;
|
||||
uint64_t trace_shader_core_clock;
|
||||
uint64_t trace_memory_clock;
|
||||
int32_t device_id;
|
||||
int32_t device_revision_id;
|
||||
int32_t vgprs_per_simd;
|
||||
int32_t sgprs_per_simd;
|
||||
int32_t shader_engines;
|
||||
int32_t compute_unit_per_shader_engine;
|
||||
int32_t simd_per_compute_unit;
|
||||
int32_t wavefronts_per_simd;
|
||||
int32_t minimum_vgpr_alloc;
|
||||
int32_t vgpr_alloc_granularity;
|
||||
int32_t minimum_sgpr_alloc;
|
||||
int32_t sgpr_alloc_granularity;
|
||||
int32_t hardware_contexts;
|
||||
enum sqtt_gpu_type gpu_type;
|
||||
enum sqtt_gfxip_level gfxip_level;
|
||||
int32_t gpu_index;
|
||||
int32_t gds_size;
|
||||
int32_t gds_per_shader_engine;
|
||||
int32_t ce_ram_size;
|
||||
int32_t ce_ram_size_graphics;
|
||||
int32_t ce_ram_size_compute;
|
||||
int32_t max_number_of_dedicated_cus;
|
||||
int64_t vram_size;
|
||||
int32_t vram_bus_width;
|
||||
int32_t l2_cache_size;
|
||||
int32_t l1_cache_size;
|
||||
int32_t lds_size;
|
||||
char gpu_name[SQTT_GPU_NAME_MAX_SIZE];
|
||||
float alu_per_clock;
|
||||
float texture_per_clock;
|
||||
float prims_per_clock;
|
||||
float pixels_per_clock;
|
||||
uint64_t gpu_timestamp_frequency;
|
||||
uint64_t max_shader_core_clock;
|
||||
uint64_t max_memory_clock;
|
||||
uint32_t memory_ops_per_clock;
|
||||
enum sqtt_memory_type memory_chip_type;
|
||||
uint32_t lds_granularity;
|
||||
uint16_t cu_mask[SQTT_MAX_NUM_SE][SQTT_SA_PER_SE];
|
||||
char reserved1[128];
|
||||
uint32_t active_pixel_packer_mask[SQTT_ACTIVE_PIXEL_PACKER_MASK_DWORDS];
|
||||
char reserved2[16];
|
||||
uint32_t gl1_cache_size;
|
||||
uint32_t instruction_cache_size;
|
||||
uint32_t scalar_cache_size;
|
||||
uint32_t mall_cache_size;
|
||||
char padding[4];
|
||||
};
|
||||
|
||||
enum sqtt_api_type
|
||||
{
|
||||
SQTT_API_TYPE_DIRECTX_12,
|
||||
SQTT_API_TYPE_VULKAN,
|
||||
SQTT_API_TYPE_GENERIC,
|
||||
SQTT_API_TYPE_OPENCL
|
||||
};
|
||||
|
||||
enum sqtt_instruction_trace_mode
|
||||
{
|
||||
SQTT_INSTRUCTION_TRACE_DISABLED = 0x0,
|
||||
SQTT_INSTRUCTION_TRACE_FULL_FRAME = 0x1,
|
||||
SQTT_INSTRUCTION_TRACE_API_PSO = 0x2,
|
||||
};
|
||||
|
||||
enum sqtt_profiling_mode
|
||||
{
|
||||
SQTT_PROFILING_MODE_PRESENT = 0x0,
|
||||
SQTT_PROFILING_MODE_USER_MARKERS = 0x1,
|
||||
SQTT_PROFILING_MODE_INDEX = 0x2,
|
||||
SQTT_PROFILING_MODE_TAG = 0x3,
|
||||
};
|
||||
|
||||
union sqtt_profiling_mode_data {
|
||||
struct {
|
||||
char start[256];
|
||||
char end[256];
|
||||
} user_marker_profiling_data;
|
||||
|
||||
struct {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} index_profiling_data;
|
||||
|
||||
struct {
|
||||
uint32_t begin_hi;
|
||||
uint32_t begin_lo;
|
||||
uint32_t end_hi;
|
||||
uint32_t end_lo;
|
||||
} tag_profiling_data;
|
||||
};
|
||||
|
||||
union sqtt_instruction_trace_data {
|
||||
struct {
|
||||
uint64_t api_pso_filter;
|
||||
} api_pso_data;
|
||||
|
||||
struct {
|
||||
uint32_t mask;
|
||||
} shader_engine_filter;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_api_info {
|
||||
struct sqtt_file_chunk_header header;
|
||||
enum sqtt_api_type api_type;
|
||||
uint16_t major_version;
|
||||
uint16_t minor_version;
|
||||
enum sqtt_profiling_mode profiling_mode;
|
||||
uint32_t reserved;
|
||||
union sqtt_profiling_mode_data profiling_mode_data;
|
||||
enum sqtt_instruction_trace_mode instruction_trace_mode;
|
||||
uint32_t reserved2;
|
||||
union sqtt_instruction_trace_data instruction_trace_data;
|
||||
};
|
||||
|
||||
|
||||
struct sqtt_code_object_database_record {
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_code_object_database {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
uint32_t size;
|
||||
uint32_t record_count;
|
||||
};
|
||||
|
||||
|
||||
struct sqtt_code_object_loader_events_record {
|
||||
uint32_t loader_event_type;
|
||||
uint32_t reserved;
|
||||
uint64_t base_address;
|
||||
uint64_t code_object_hash[2];
|
||||
uint64_t time_stamp;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_code_object_loader_events {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
uint32_t record_size;
|
||||
uint32_t record_count;
|
||||
};
|
||||
|
||||
struct sqtt_pso_correlation_record {
|
||||
uint64_t api_pso_hash;
|
||||
uint64_t pipeline_hash[2];
|
||||
char api_level_obj_name[64];
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_pso_correlation {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
uint32_t record_size;
|
||||
uint32_t record_count;
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_sqtt_desc {
|
||||
struct sqtt_file_chunk_header header;
|
||||
int32_t shader_engine_index;
|
||||
enum sqtt_version sqtt_version;
|
||||
union {
|
||||
struct {
|
||||
int32_t instrumentation_version;
|
||||
} v0;
|
||||
struct {
|
||||
int16_t instrumentation_spec_version;
|
||||
int16_t instrumentation_api_version;
|
||||
int32_t compute_unit_index;
|
||||
} v1;
|
||||
};
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_sqtt_data {
|
||||
struct sqtt_file_chunk_header header;
|
||||
int32_t offset; /* in bytes */
|
||||
int32_t size; /* in bytes */
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_queue_event_timings {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t queue_info_table_record_count;
|
||||
uint32_t queue_info_table_size;
|
||||
uint32_t queue_event_table_record_count;
|
||||
uint32_t queue_event_table_size;
|
||||
};
|
||||
|
||||
|
||||
enum sqtt_queue_type {
|
||||
SQTT_QUEUE_TYPE_UNKNOWN = 0x0,
|
||||
SQTT_QUEUE_TYPE_UNIVERSAL = 0x1,
|
||||
SQTT_QUEUE_TYPE_COMPUTE = 0x2,
|
||||
SQTT_QUEUE_TYPE_DMA = 0x3,
|
||||
};
|
||||
|
||||
enum sqtt_engine_type {
|
||||
SQTT_ENGINE_TYPE_UNKNOWN = 0x0,
|
||||
SQTT_ENGINE_TYPE_UNIVERSAL = 0x1,
|
||||
SQTT_ENGINE_TYPE_COMPUTE = 0x2,
|
||||
SQTT_ENGINE_TYPE_EXCLUSIVE_COMPUTE = 0x3,
|
||||
SQTT_ENGINE_TYPE_DMA = 0x4,
|
||||
SQTT_ENGINE_TYPE_HIGH_PRIORITY_UNIVERSAL = 0x7,
|
||||
SQTT_ENGINE_TYPE_HIGH_PRIORITY_GRAPHICS = 0x8,
|
||||
};
|
||||
|
||||
struct sqtt_queue_hardware_info {
|
||||
union {
|
||||
struct {
|
||||
int32_t queue_type : 8;
|
||||
int32_t engine_type : 8;
|
||||
uint32_t reserved : 16;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct sqtt_queue_info_record {
|
||||
uint64_t queue_id;
|
||||
uint64_t queue_context;
|
||||
struct sqtt_queue_hardware_info hardware_info;
|
||||
uint32_t reserved;
|
||||
};
|
||||
|
||||
enum sqtt_queue_event_type {
|
||||
SQTT_QUEUE_TIMING_EVENT_CMDBUF_SUBMIT,
|
||||
SQTT_QUEUE_TIMING_EVENT_SIGNAL_SEMAPHORE,
|
||||
SQTT_QUEUE_TIMING_EVENT_WAIT_SEMAPHORE,
|
||||
SQTT_QUEUE_TIMING_EVENT_PRESENT
|
||||
};
|
||||
|
||||
struct sqtt_queue_event_record {
|
||||
enum sqtt_queue_event_type event_type;
|
||||
uint32_t sqtt_cb_id;
|
||||
uint64_t frame_index;
|
||||
uint32_t queue_info_index;
|
||||
uint32_t submit_sub_index;
|
||||
uint64_t api_id;
|
||||
uint64_t cpu_timestamp;
|
||||
uint64_t gpu_timestamps[2];
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_clock_calibration {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint64_t cpu_timestamp;
|
||||
uint64_t gpu_timestamp;
|
||||
uint64_t reserved;
|
||||
};
|
||||
|
||||
enum elf_gfxip_level
|
||||
{
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX1100 = 0x041,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX1150 = 0x043,
|
||||
EF_AMDGPU_MACH_AMDGCN_GFX1200 = 0x04e,
|
||||
};
|
||||
|
||||
struct sqtt_file_chunk_spm_db {
|
||||
struct sqtt_file_chunk_header header;
|
||||
uint32_t flags;
|
||||
uint32_t preamble_size;
|
||||
uint32_t num_timestamps;
|
||||
uint32_t num_spm_counter_info;
|
||||
uint32_t spm_counter_info_size;
|
||||
uint32_t sample_interval;
|
||||
};
|
||||
|
||||
/**
|
||||
* Identifiers for RGP SQ thread-tracing markers (Table 1)
|
||||
*/
|
||||
enum rgp_sqtt_marker_identifier
|
||||
{
|
||||
RGP_SQTT_MARKER_IDENTIFIER_EVENT = 0x0,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_CB_START = 0x1,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_CB_END = 0x2,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_BARRIER_START = 0x3,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_BARRIER_END = 0x4,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_USER_EVENT = 0x5,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_GENERAL_API = 0x6,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_SYNC = 0x7,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_PRESENT = 0x8,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_LAYOUT_TRANSITION = 0x9,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_RENDER_PASS = 0xA,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_RESERVED2 = 0xB,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_BIND_PIPELINE = 0xC,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_RESERVED4 = 0xD,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_RESERVED5 = 0xE,
|
||||
RGP_SQTT_MARKER_IDENTIFIER_RESERVED6 = 0xF
|
||||
};
|
||||
|
||||
/**
|
||||
* Command buffer IDs used in RGP SQ thread-tracing markers (only 20 bits).
|
||||
*/
|
||||
union rgp_sqtt_marker_cb_id {
|
||||
struct {
|
||||
uint32_t per_frame : 1; /* Must be 1, frame-based command buffer ID. */
|
||||
uint32_t frame_index : 7;
|
||||
uint32_t cb_index : 12; /* Command buffer index within the frame. */
|
||||
uint32_t reserved : 12;
|
||||
} per_frame_cb_id;
|
||||
|
||||
struct {
|
||||
uint32_t per_frame : 1; /* Must be 0, global command buffer ID. */
|
||||
uint32_t cb_index : 19; /* Global command buffer index. */
|
||||
uint32_t reserved : 12;
|
||||
} global_cb_id;
|
||||
|
||||
uint32_t all;
|
||||
};
|
||||
|
||||
/**
|
||||
* RGP SQ thread-tracing marker for the start of a command buffer. (Table 2)
|
||||
*/
|
||||
struct rgp_sqtt_marker_cb_start {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t queue : 5;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
uint32_t device_id_low;
|
||||
uint32_t dword02;
|
||||
};
|
||||
union {
|
||||
uint32_t device_id_high;
|
||||
uint32_t dword03;
|
||||
};
|
||||
union {
|
||||
uint32_t queue_flags;
|
||||
uint32_t dword04;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* RGP SQ thread-tracing marker for the end of a command buffer. (Table 3)
|
||||
*/
|
||||
struct rgp_sqtt_marker_cb_end {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t reserved : 5;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
uint32_t device_id_low;
|
||||
uint32_t dword02;
|
||||
};
|
||||
union {
|
||||
uint32_t device_id_high;
|
||||
uint32_t dword03;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* API types used in RGP SQ thread-tracing markers for the "General API"
|
||||
* packet.
|
||||
*/
|
||||
enum rgp_sqtt_marker_general_api_type
|
||||
{
|
||||
ApiCmdBindPipeline = 0,
|
||||
ApiCmdBindDescriptorSets = 1,
|
||||
ApiCmdBindIndexBuffer = 2,
|
||||
ApiCmdBindVertexBuffers = 3,
|
||||
ApiCmdDraw = 4,
|
||||
ApiCmdDrawIndexed = 5,
|
||||
ApiCmdDrawIndirect = 6,
|
||||
ApiCmdDrawIndexedIndirect = 7,
|
||||
ApiCmdDrawIndirectCountAMD = 8,
|
||||
ApiCmdDrawIndexedIndirectCountAMD = 9,
|
||||
ApiCmdDispatch = 10,
|
||||
ApiCmdDispatchIndirect = 11,
|
||||
ApiCmdCopyBuffer = 12,
|
||||
ApiCmdCopyImage = 13,
|
||||
ApiCmdBlitImage = 14,
|
||||
ApiCmdCopyBufferToImage = 15,
|
||||
ApiCmdCopyImageToBuffer = 16,
|
||||
ApiCmdUpdateBuffer = 17,
|
||||
ApiCmdFillBuffer = 18,
|
||||
ApiCmdClearColorImage = 19,
|
||||
ApiCmdClearDepthStencilImage = 20,
|
||||
ApiCmdClearAttachments = 21,
|
||||
ApiCmdResolveImage = 22,
|
||||
ApiCmdWaitEvents = 23,
|
||||
ApiCmdPipelineBarrier = 24,
|
||||
ApiCmdBeginQuery = 25,
|
||||
ApiCmdEndQuery = 26,
|
||||
ApiCmdResetQueryPool = 27,
|
||||
ApiCmdWriteTimestamp = 28,
|
||||
ApiCmdCopyQueryPoolResults = 29,
|
||||
ApiCmdPushConstants = 30,
|
||||
ApiCmdBeginRenderPass = 31,
|
||||
ApiCmdNextSubpass = 32,
|
||||
ApiCmdEndRenderPass = 33,
|
||||
ApiCmdExecuteCommands = 34,
|
||||
ApiCmdSetViewport = 35,
|
||||
ApiCmdSetScissor = 36,
|
||||
ApiCmdSetLineWidth = 37,
|
||||
ApiCmdSetDepthBias = 38,
|
||||
ApiCmdSetBlendConstants = 39,
|
||||
ApiCmdSetDepthBounds = 40,
|
||||
ApiCmdSetStencilCompareMask = 41,
|
||||
ApiCmdSetStencilWriteMask = 42,
|
||||
ApiCmdSetStencilReference = 43,
|
||||
ApiCmdDrawIndirectCount = 44,
|
||||
ApiCmdDrawIndexedIndirectCount = 45,
|
||||
/* gap */
|
||||
ApiCmdDrawMeshTasksEXT = 47,
|
||||
ApiCmdDrawMeshTasksIndirectCountEXT = 48,
|
||||
ApiCmdDrawMeshTasksIndirectEXT = 49,
|
||||
|
||||
ApiRayTracingSeparateCompiled = 0x800000,
|
||||
ApiInvalid = 0xffffffff
|
||||
};
|
||||
|
||||
/**
|
||||
* RGP SQ thread-tracing marker for a "General API" instrumentation packet.
|
||||
*/
|
||||
struct rgp_sqtt_marker_general_api {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t api_type : 20;
|
||||
uint32_t is_end : 1;
|
||||
uint32_t reserved : 4;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* API types used in RGP SQ thread-tracing markers (Table 16).
|
||||
*/
|
||||
enum rgp_sqtt_marker_event_type
|
||||
{
|
||||
EventCmdDraw = 0,
|
||||
EventCmdDrawIndexed = 1,
|
||||
EventCmdDrawIndirect = 2,
|
||||
EventCmdDrawIndexedIndirect = 3,
|
||||
EventCmdDrawIndirectCountAMD = 4,
|
||||
EventCmdDrawIndexedIndirectCountAMD = 5,
|
||||
EventCmdDispatch = 6,
|
||||
EventCmdDispatchIndirect = 7,
|
||||
EventCmdCopyBuffer = 8,
|
||||
EventCmdCopyImage = 9,
|
||||
EventCmdBlitImage = 10,
|
||||
EventCmdCopyBufferToImage = 11,
|
||||
EventCmdCopyImageToBuffer = 12,
|
||||
EventCmdUpdateBuffer = 13,
|
||||
EventCmdFillBuffer = 14,
|
||||
EventCmdClearColorImage = 15,
|
||||
EventCmdClearDepthStencilImage = 16,
|
||||
EventCmdClearAttachments = 17,
|
||||
EventCmdResolveImage = 18,
|
||||
EventCmdWaitEvents = 19,
|
||||
EventCmdPipelineBarrier = 20,
|
||||
EventCmdResetQueryPool = 21,
|
||||
EventCmdCopyQueryPoolResults = 22,
|
||||
EventRenderPassColorClear = 23,
|
||||
EventRenderPassDepthStencilClear = 24,
|
||||
EventRenderPassResolve = 25,
|
||||
EventInternalUnknown = 26,
|
||||
EventCmdDrawIndirectCount = 27,
|
||||
EventCmdDrawIndexedIndirectCount = 28,
|
||||
/* gap */
|
||||
EventCmdTraceRaysKHR = 30,
|
||||
EventCmdTraceRaysIndirectKHR = 31,
|
||||
EventCmdBuildAccelerationStructuresKHR = 32,
|
||||
EventCmdBuildAccelerationStructuresIndirectKHR = 33,
|
||||
EventCmdCopyAccelerationStructureKHR = 34,
|
||||
EventCmdCopyAccelerationStructureToMemoryKHR = 35,
|
||||
EventCmdCopyMemoryToAccelerationStructureKHR = 36,
|
||||
/* gap */
|
||||
EventCmdDrawMeshTasksEXT = 41,
|
||||
EventCmdDrawMeshTasksIndirectCountEXT = 42,
|
||||
EventCmdDrawMeshTasksIndirectEXT = 43,
|
||||
EventUnknown = 0x7fff,
|
||||
EventInvalid = 0xffffffff
|
||||
};
|
||||
|
||||
/**
|
||||
* "Event (Per-draw/dispatch)" RGP SQ thread-tracing marker. (Table 4)
|
||||
*/
|
||||
struct rgp_sqtt_marker_event {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t api_type : 24;
|
||||
uint32_t has_thread_dims : 1;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t vertex_offset_reg_idx : 4;
|
||||
uint32_t instance_offset_reg_idx : 4;
|
||||
uint32_t draw_index_reg_idx : 4;
|
||||
};
|
||||
uint32_t dword02;
|
||||
};
|
||||
union {
|
||||
uint32_t cmd_id;
|
||||
uint32_t dword03;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Per-dispatch specific marker where workgroup dims are included.
|
||||
*/
|
||||
struct rgp_sqtt_marker_event_with_dims {
|
||||
struct rgp_sqtt_marker_event event;
|
||||
uint32_t thread_x;
|
||||
uint32_t thread_y;
|
||||
uint32_t thread_z;
|
||||
};
|
||||
|
||||
/**
|
||||
* "Barrier Start" RGP SQTT instrumentation marker (Table 5)
|
||||
*/
|
||||
struct rgp_sqtt_marker_barrier_start {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t reserved : 5;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint32_t driver_reason : 31;
|
||||
uint32_t internal : 1;
|
||||
};
|
||||
uint32_t dword02;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* "Barrier End" RGP SQTT instrumentation marker (Table 6)
|
||||
*/
|
||||
struct rgp_sqtt_marker_barrier_end {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t wait_on_eop_ts : 1;
|
||||
uint32_t vs_partial_flush : 1;
|
||||
uint32_t ps_partial_flush : 1;
|
||||
uint32_t cs_partial_flush : 1;
|
||||
uint32_t pfp_sync_me : 1;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint32_t sync_cp_dma : 1;
|
||||
uint32_t inval_tcp : 1;
|
||||
uint32_t inval_sqI : 1;
|
||||
uint32_t inval_sqK : 1;
|
||||
uint32_t flush_tcc : 1;
|
||||
uint32_t inval_tcc : 1;
|
||||
uint32_t flush_cb : 1;
|
||||
uint32_t inval_cb : 1;
|
||||
uint32_t flush_db : 1;
|
||||
uint32_t inval_db : 1;
|
||||
uint32_t num_layout_transitions : 16;
|
||||
uint32_t inval_gl1 : 1;
|
||||
uint32_t wait_on_ts : 1;
|
||||
uint32_t eop_ts_bottom_of_pipe : 1;
|
||||
uint32_t eos_ts_ps_done : 1;
|
||||
uint32_t eos_ts_cs_done : 1;
|
||||
uint32_t reserved : 1;
|
||||
};
|
||||
uint32_t dword02;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* "Layout Transition" RGP SQTT instrumentation marker (Table 7)
|
||||
*/
|
||||
struct rgp_sqtt_marker_layout_transition {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t depth_stencil_expand : 1;
|
||||
uint32_t htile_hiz_range_expand : 1;
|
||||
uint32_t depth_stencil_resummarize : 1;
|
||||
uint32_t dcc_decompress : 1;
|
||||
uint32_t fmask_decompress : 1;
|
||||
uint32_t fast_clear_eliminate : 1;
|
||||
uint32_t fmask_color_expand : 1;
|
||||
uint32_t init_mask_ram : 1;
|
||||
uint32_t reserved1 : 17;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint32_t reserved2 : 32;
|
||||
};
|
||||
uint32_t dword02;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* "User Event" RGP SQTT instrumentation marker (Table 8)
|
||||
*/
|
||||
struct rgp_sqtt_marker_user_event {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t reserved0 : 8;
|
||||
uint32_t data_type : 8;
|
||||
uint32_t reserved1 : 12;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
};
|
||||
struct rgp_sqtt_marker_user_event_with_length {
|
||||
struct rgp_sqtt_marker_user_event user_event;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
enum rgp_sqtt_marker_user_event_type
|
||||
{
|
||||
UserEventTrigger = 0,
|
||||
UserEventPop,
|
||||
UserEventPush,
|
||||
UserEventObjectName,
|
||||
};
|
||||
|
||||
/**
|
||||
* "Pipeline bind" RGP SQTT instrumentation marker (Table 12)
|
||||
*/
|
||||
struct rgp_sqtt_marker_pipeline_bind {
|
||||
union {
|
||||
struct {
|
||||
uint32_t identifier : 4;
|
||||
uint32_t ext_dwords : 3;
|
||||
uint32_t bind_point : 1;
|
||||
uint32_t cb_id : 20;
|
||||
uint32_t reserved : 4;
|
||||
};
|
||||
uint32_t dword01;
|
||||
};
|
||||
union {
|
||||
uint32_t api_pso_hash[2];
|
||||
struct {
|
||||
uint32_t dword02;
|
||||
uint32_t dword03;
|
||||
};
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user