|
|
|
@@ -36,10 +36,11 @@ import pandas as pd
|
|
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from math import ceil
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
from dataclasses import dataclass, field, asdict, fields
|
|
|
|
|
from pathlib import Path as path
|
|
|
|
|
from textwrap import dedent
|
|
|
|
|
from utils.utils import error, get_hbm_stack_num, get_version
|
|
|
|
|
from utils.tty import get_table_string
|
|
|
|
|
|
|
|
|
|
VERSION_LOC = [
|
|
|
|
|
"version",
|
|
|
|
@@ -52,129 +53,264 @@ VERSION_LOC = [
|
|
|
|
|
"version-utils",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
def detect_arch(_rocminfo):
|
|
|
|
|
from omniperf_base import SUPPORTED_ARCHS
|
|
|
|
|
|
|
|
|
|
for idx1, linetext in enumerate(_rocminfo):
|
|
|
|
|
gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext)
|
|
|
|
|
if gpu_arch in SUPPORTED_ARCHS.keys():
|
|
|
|
|
break
|
|
|
|
|
if str(gpu_arch) in SUPPORTED_ARCHS.keys():
|
|
|
|
|
gpu_arch = str(gpu_arch)
|
|
|
|
|
break
|
|
|
|
|
if not gpu_arch in SUPPORTED_ARCHS.keys():
|
|
|
|
|
error("[profiling] Cannot find a supported arch in rocminfo")
|
|
|
|
|
else:
|
|
|
|
|
return (gpu_arch, idx1)
|
|
|
|
|
|
|
|
|
|
def generate_machine_specs(args, sysinfo:dict=None):
|
|
|
|
|
if not sysinfo is None:
|
|
|
|
|
sysinfo_ver = str(sysinfo['version'])
|
|
|
|
|
version = get_version(config.omniperf_home)['version']
|
|
|
|
|
if sysinfo_ver != version[:version.find(".")]:
|
|
|
|
|
logging.warning("WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data.")
|
|
|
|
|
return MachineSpecs(**sysinfo)
|
|
|
|
|
# read timestamp info
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
local_now = now.astimezone()
|
|
|
|
|
local_tz = local_now.tzinfo
|
|
|
|
|
local_tzname = local_tz.tzname(local_now)
|
|
|
|
|
timestamp = now.strftime("%c") + " (" + local_tzname + ")"
|
|
|
|
|
hostname = socket.gethostname()
|
|
|
|
|
|
|
|
|
|
# set specs version
|
|
|
|
|
vData = get_version(config.omniperf_home)
|
|
|
|
|
version = vData["version"]
|
|
|
|
|
# NB: Just taking major as specs version. May want to make this more specific in the future
|
|
|
|
|
specs_version = version[:version.find(".")] # version will always follow 'major.minor.patch' format
|
|
|
|
|
|
|
|
|
|
##########################################
|
|
|
|
|
## A. Machine Specs
|
|
|
|
|
##########################################
|
|
|
|
|
cpuinfo = path("/proc/cpuinfo").read_text()
|
|
|
|
|
meminfo = path("/proc/meminfo").read_text()
|
|
|
|
|
version = path("/proc/version").read_text()
|
|
|
|
|
os_release = path("/etc/os-release").read_text()
|
|
|
|
|
cpu_model = search(r"^model name\s*: (.*?)$", cpuinfo)
|
|
|
|
|
sbios = path("/sys/class/dmi/id/bios_vendor").read_text().strip() + \
|
|
|
|
|
path("/sys/class/dmi/id/bios_version").read_text().strip()
|
|
|
|
|
linux_kernel_version = search(r"version (\S*)", version)
|
|
|
|
|
amd_gpu_kernel_version = "" #TODO: Extract amdgpu kernel version
|
|
|
|
|
cpu_memory = search(r"MemTotal:\s*(\S*)", meminfo)
|
|
|
|
|
gpu_memory = "" #TODO: Extract gpu memory
|
|
|
|
|
linux_distro = search(r'PRETTY_NAME="(.*?)"', os_release)
|
|
|
|
|
if linux_distro is None:
|
|
|
|
|
linux_distro = ""
|
|
|
|
|
rocm_version = get_rocm_ver().strip()
|
|
|
|
|
#FIXME: use device
|
|
|
|
|
vbios = search(
|
|
|
|
|
r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True))
|
|
|
|
|
compute_partition = search(
|
|
|
|
|
r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"]))
|
|
|
|
|
if compute_partition is None:
|
|
|
|
|
compute_partition = "NA"
|
|
|
|
|
memory_partition = search(
|
|
|
|
|
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"]))
|
|
|
|
|
if memory_partition is None:
|
|
|
|
|
memory_partition = "NA"
|
|
|
|
|
|
|
|
|
|
##########################################
|
|
|
|
|
## B. SoC Specs
|
|
|
|
|
##########################################
|
|
|
|
|
# read rocminfo
|
|
|
|
|
rocminfo_full = run(["rocminfo"])
|
|
|
|
|
_rocminfo = rocminfo_full.split("\n")
|
|
|
|
|
gpu_arch, idx = detect_arch(_rocminfo)
|
|
|
|
|
_rocminfo = _rocminfo[idx + 1 :] # update rocminfo for target section
|
|
|
|
|
specs = MachineSpecs(version=specs_version,
|
|
|
|
|
timestamp=timestamp,
|
|
|
|
|
_rocminfo=_rocminfo,
|
|
|
|
|
hostname=hostname,
|
|
|
|
|
cpu_model=cpu_model,
|
|
|
|
|
sbios=sbios,
|
|
|
|
|
linux_kernel_version=linux_kernel_version,
|
|
|
|
|
amd_gpu_kernel_version=amd_gpu_kernel_version,
|
|
|
|
|
cpu_memory=cpu_memory,
|
|
|
|
|
gpu_memory=gpu_memory,
|
|
|
|
|
linux_distro=linux_distro,
|
|
|
|
|
rocm_version=rocm_version,
|
|
|
|
|
vbios=vbios,
|
|
|
|
|
compute_partition=compute_partition,
|
|
|
|
|
memory_partition=memory_partition,
|
|
|
|
|
gpu_arch=gpu_arch)
|
|
|
|
|
# Load above SoC specs via module import
|
|
|
|
|
try:
|
|
|
|
|
soc_module = importlib.import_module('omniperf_soc.soc_'+ specs.gpu_arch)
|
|
|
|
|
except ModuleNotFoundError as e:
|
|
|
|
|
error("Arch %s marked as supported, but couldn't find class implementation %s." % (specs.gpu_arch, e))
|
|
|
|
|
soc_class = getattr(soc_module, specs.gpu_arch+'_soc')
|
|
|
|
|
soc_obj = soc_class(args, specs)
|
|
|
|
|
# Update arch specific specs
|
|
|
|
|
specs.total_l2_chan: str = total_l2_banks(
|
|
|
|
|
specs.gpu_model, int(specs._l2_banks), specs.memory_partition
|
|
|
|
|
)
|
|
|
|
|
specs.hbm_bw: str = str(int(specs.max_mclk) / 1000 * 32 * specs.get_hbm_channels())
|
|
|
|
|
return specs
|
|
|
|
|
|
|
|
|
|
@dataclass(kw_only=True)
|
|
|
|
|
class MachineSpecs:
|
|
|
|
|
def __init__(self, args, sysinfo:dict=None):
|
|
|
|
|
if not sysinfo is None:
|
|
|
|
|
sysinfo_ver = str(sysinfo['specs_version'][0])
|
|
|
|
|
version = get_version(config.omniperf_home)['version']
|
|
|
|
|
if sysinfo_ver != version[:version.find(".")]:
|
|
|
|
|
logging.warning("WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data.")
|
|
|
|
|
for key, value in sysinfo.items():
|
|
|
|
|
setattr(self, key, value[0])
|
|
|
|
|
return
|
|
|
|
|
# set specs version
|
|
|
|
|
vData = get_version(config.omniperf_home)
|
|
|
|
|
version = vData["version"]
|
|
|
|
|
# NB: Just taking major as specs version. May want to make this more specific in the future
|
|
|
|
|
self.specs_version = version[:version.find(".")] # version will alway follow 'major.minor.patch' format
|
|
|
|
|
##########################################
|
|
|
|
|
## A. Workload / Spec info
|
|
|
|
|
##########################################
|
|
|
|
|
|
|
|
|
|
# read timestamp info
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
local_now = now.astimezone()
|
|
|
|
|
local_tz = local_now.tzinfo
|
|
|
|
|
local_tzname = local_tz.tzname(local_now)
|
|
|
|
|
self.timestamp = now.strftime("%c") + " (" + local_tzname + ")"
|
|
|
|
|
# these three fields are special in that they're not included
|
|
|
|
|
# when you use (e.g.,) --specs to view the machinespecs, but they
|
|
|
|
|
# _are_ included in profiling/analysis, so we mark them as 'optional'
|
|
|
|
|
# in the metadata to avoid erroring out on missing fields on
|
|
|
|
|
# serialization
|
|
|
|
|
workload_name: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The name of the workload data was collected for.',
|
|
|
|
|
'name': 'Workload Name',
|
|
|
|
|
'optional': True})
|
|
|
|
|
command: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The command the workload was executed with.',
|
|
|
|
|
'name': 'Command',
|
|
|
|
|
'optional': True})
|
|
|
|
|
ip_blocks: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The hardware blocks profiling information was collected for.',
|
|
|
|
|
'name': 'IP Blocks',
|
|
|
|
|
'optional': True
|
|
|
|
|
})
|
|
|
|
|
timestamp: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The time (in local system time) when data was collected',
|
|
|
|
|
'name': 'Timestamp'})
|
|
|
|
|
version: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The version of the machine specification file format.',
|
|
|
|
|
'name': 'MachineSpecs Version'})
|
|
|
|
|
timestamp: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The time (in local system time) when data was collected',
|
|
|
|
|
'name': 'Timestamp'})
|
|
|
|
|
_rocminfo: list = field(default=None)
|
|
|
|
|
##########################################
|
|
|
|
|
## A. Machine Specs
|
|
|
|
|
##########################################
|
|
|
|
|
hostname: str = field(default=None, metadata={'doc': 'The hostname of the machine.',
|
|
|
|
|
'name': 'Hostname'})
|
|
|
|
|
cpu_model: str = field(default=None, metadata={'doc': 'The model name of the CPU used.',
|
|
|
|
|
'name': 'CPU Model'})
|
|
|
|
|
sbios: str = field(default=None, metadata={'doc': 'The system management bios version and vendor.',
|
|
|
|
|
'name': "SBIOS"})
|
|
|
|
|
linux_distro: str = field(default=None, metadata={'doc': 'The Linux distribution installed on the machine.',
|
|
|
|
|
'name': 'Linux Distribution'})
|
|
|
|
|
linux_kernel_version: str = field(default=None,
|
|
|
|
|
metadata={'doc': 'The Linux kernel version running on the machine.',
|
|
|
|
|
'name': 'Linux Kernel Version'})
|
|
|
|
|
amd_gpu_kernel_version: str = field(default=None, metadata={
|
|
|
|
|
'doc': '[RESERVED] The version of the AMDGPU driver installed on the machine. Unimplemented.',
|
|
|
|
|
'name': "AMD GPU Kernel Version"})
|
|
|
|
|
cpu_memory: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The total amount of memory available to the CPU.', 'unit': 'KB',
|
|
|
|
|
'name': 'CPU Memory'})
|
|
|
|
|
gpu_memory: str = field(default=None, metadata={
|
|
|
|
|
'doc': '[RESERVED] The total amount of memory available to accelerators/GPUs in the system. Unimplemented.',
|
|
|
|
|
'unit': 'KB',
|
|
|
|
|
'name': 'GPU Memory'})
|
|
|
|
|
rocm_version: str = field(default=None,
|
|
|
|
|
metadata={'doc': 'The ROCm version used during data-collection.',
|
|
|
|
|
'name': "ROCm Version"})
|
|
|
|
|
vbios: str = field(default=None,
|
|
|
|
|
metadata={'doc': 'The version of the accelerators/GPUs video bios in the system.',
|
|
|
|
|
'name': 'VBIOS'})
|
|
|
|
|
compute_partition: str = field(default=None,
|
|
|
|
|
metadata={'doc': 'The compute partitioning mode active on the accelerators/GPUs in the system (MI300 only).',
|
|
|
|
|
'name': 'Compute Partition'})
|
|
|
|
|
memory_partition: str = field(default=None,
|
|
|
|
|
metadata={'doc': 'The memory partitioning mode active on the accelerators/GPUs in the system (MI300 only).',
|
|
|
|
|
'name': 'Memory Partition'})
|
|
|
|
|
|
|
|
|
|
# read rocminfo
|
|
|
|
|
rocminfo_full = run(["rocminfo"])
|
|
|
|
|
self._rocminfo = rocminfo_full.split("\n")
|
|
|
|
|
##########################################
|
|
|
|
|
## B. SoC Specs
|
|
|
|
|
##########################################
|
|
|
|
|
gpu_model: str = field(
|
|
|
|
|
default=None,
|
|
|
|
|
metadata={
|
|
|
|
|
'doc': 'The product name of the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'GPU Model'})
|
|
|
|
|
gpu_arch: str = field(
|
|
|
|
|
default=None,
|
|
|
|
|
metadata={
|
|
|
|
|
'doc': 'The architecture name of the accelerators/GPUs in the system,\n'
|
|
|
|
|
'as used by (e.g.,) the AMDGPU backed of LLVM.',
|
|
|
|
|
'name': 'GPU Arch'})
|
|
|
|
|
gpu_l1: str = field(default=None, metadata={'doc':
|
|
|
|
|
"The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
|
|
|
|
'name': 'GPU L1'})
|
|
|
|
|
gpu_l2: str = field(default=None, metadata={'doc':
|
|
|
|
|
"The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
|
|
|
|
'name': 'GPU L2'})
|
|
|
|
|
cu_per_gpu: str = field(default=None, metadata={'doc':
|
|
|
|
|
"The total number of compute units per accelerator/GPU in the system. On systems with configurable\n"
|
|
|
|
|
"partitioning, (e.g., MI300) this is the total number of compute units in a partition.",
|
|
|
|
|
'name': 'CU per GPU'})
|
|
|
|
|
simd_per_cu: str = field(default=None, metadata={'doc':
|
|
|
|
|
"The number of SIMD processors in a compute unit for the accelerators/GPUs in the system.",
|
|
|
|
|
'name': 'SIMD per CU'})
|
|
|
|
|
se_per_gpu: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The number of shader engines on the accelerators/GPUs in the system. On systems with configurable\n'
|
|
|
|
|
'partitioning, (e.g., MI300) this is the total number of shader engines in a partition.',
|
|
|
|
|
'name': 'SE per GPU'})
|
|
|
|
|
wave_size: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The number work-items in a wavefront on the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'Wave Size'})
|
|
|
|
|
workgroup_max_size: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The maximum number of work-items in a workgroup on the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'Workgroup Max Size'})
|
|
|
|
|
max_waves_per_cu: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The maximum number of wavefronts that can be resident on a compute unit on the\n'
|
|
|
|
|
'accelerators/GPUs in the system',
|
|
|
|
|
'name': 'Max Waves per CU'})
|
|
|
|
|
max_sclk: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The maximum engine (compute-unit) clock rate of the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'Max SCLK',
|
|
|
|
|
'unit': 'MHz'})
|
|
|
|
|
max_mclk: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The maximum memory clock rate of the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'Max MCLK',
|
|
|
|
|
'unit': 'MHz'})
|
|
|
|
|
cur_sclk: str = field(default=None, metadata={'doc':
|
|
|
|
|
'[RESERVED] The current engine (compute unit) clock rate of the accelerators/GPUs in the system. Unused.',
|
|
|
|
|
'name': 'Max SCLK',
|
|
|
|
|
'unit': 'MHz'})
|
|
|
|
|
cur_mclk: str = field(default=None, metadata={'doc':
|
|
|
|
|
'[RESERVED] The current memory clock rate of the accelerators/GPUs in the system. Unused.',
|
|
|
|
|
'name': 'Max MCLK',
|
|
|
|
|
'unit': 'MHz'})
|
|
|
|
|
_l2_banks: str = None # NB: This only used in flatten_tcc_info_across_hbm_stacks()
|
|
|
|
|
total_l2_chan: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The maximum number of L2 cache channels on the accelerators/GPUs in the system. On systems with\n'
|
|
|
|
|
'configurable partitioning, (e.g., MI300) this is the total number of L2 cache channels in a partition.',
|
|
|
|
|
'name': 'Total L2 Channels'})
|
|
|
|
|
lds_banks_per_cu: str = field(default=None, metadata={'doc':
|
|
|
|
|
'The number of banks in the LDS for a compute unit on the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'LDS Banks per CU'})
|
|
|
|
|
sqc_per_gpu: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The number of L1I/sL1D caches on the accelerators/GPUs in the system. On systems with\n'
|
|
|
|
|
'configurable partitioning, (e.g., MI300) this is the total number of L1I/sL1D caches in a partition.',
|
|
|
|
|
'name': 'SQC per GPU'})
|
|
|
|
|
pipes_per_gpu: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The number of scheduler-pipes on the accelerators/GPUs in the system.',
|
|
|
|
|
'name': 'Pipes per GPU'})
|
|
|
|
|
hbm_bw: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The peak theoretical HBM bandwidth for the accelerators/GPUs in the system. On systems with\n'
|
|
|
|
|
'configurable partitioning, (e.g., MI300) this is the peak theoretical HBM bandwidth for a partition.',
|
|
|
|
|
'name': 'HBM BW',
|
|
|
|
|
'unit': 'MB/s'})
|
|
|
|
|
num_xcd: str = field(default=None, metadata={
|
|
|
|
|
'doc': 'The total number of accelerator complex dies in a compute partition on the accelerators/GPUs in the\n'
|
|
|
|
|
'system. For accelerators without partitioning (i.e., pre-MI300), this is considered to be one.',
|
|
|
|
|
'name': 'Num XCDs',
|
|
|
|
|
'unit': 'MB/s'})
|
|
|
|
|
|
|
|
|
|
##########################################
|
|
|
|
|
## A. Machine Specs
|
|
|
|
|
##########################################
|
|
|
|
|
cpuinfo = path("/proc/cpuinfo").read_text()
|
|
|
|
|
meminfo = path("/proc/meminfo").read_text()
|
|
|
|
|
version = path("/proc/version").read_text()
|
|
|
|
|
os_release = path("/etc/os-release").read_text()
|
|
|
|
|
|
|
|
|
|
self.hostname: str = socket.gethostname()
|
|
|
|
|
self.cpu_model: str = search(r"^model name\s*: (.*?)$", cpuinfo)
|
|
|
|
|
self.sbios: str = (
|
|
|
|
|
path("/sys/class/dmi/id/bios_vendor").read_text().strip()
|
|
|
|
|
+ path("/sys/class/dmi/id/bios_version").read_text().strip()
|
|
|
|
|
)
|
|
|
|
|
self.linux_kernel_version: str = search(r"version (\S*)", version)
|
|
|
|
|
self.amd_gpu_kernel_version: str = None
|
|
|
|
|
if self.amd_gpu_kernel_version is None: #TODO: Extract amdgpu kernel version
|
|
|
|
|
self.amd_gpu_kernel_version = ""
|
|
|
|
|
self.cpu_memory: str = search(r"MemTotal:\s*(\S*)", meminfo)
|
|
|
|
|
self.gpu_memory: str = None #TODO: Extract total gpu memory
|
|
|
|
|
if self.gpu_memory is None:
|
|
|
|
|
self.gpu_memory = ""
|
|
|
|
|
self.linux_distro: str = search(r'PRETTY_NAME="(.*?)"', os_release)
|
|
|
|
|
if self.linux_distro is None:
|
|
|
|
|
self.linux_distro = ""
|
|
|
|
|
self.rocm_version: str = get_rocm_ver().strip()
|
|
|
|
|
#FIXME: use device
|
|
|
|
|
self.vbios: str = search(
|
|
|
|
|
r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True)
|
|
|
|
|
)
|
|
|
|
|
self.compute_partition: str = search(
|
|
|
|
|
r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"])
|
|
|
|
|
)
|
|
|
|
|
if self.compute_partition is None:
|
|
|
|
|
self.compute_partition = "NA"
|
|
|
|
|
self.memory_partition: str = search(
|
|
|
|
|
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"])
|
|
|
|
|
)
|
|
|
|
|
if self.memory_partition is None:
|
|
|
|
|
self.memory_partition = "NA"
|
|
|
|
|
|
|
|
|
|
##########################################
|
|
|
|
|
## B. SoC Specs
|
|
|
|
|
##########################################
|
|
|
|
|
self.gpu_arch: str = self.detect_arch()[0]
|
|
|
|
|
self.gpu_l1: str = None
|
|
|
|
|
self.gpu_l2: str = None
|
|
|
|
|
self.cu_per_gpu: str = None
|
|
|
|
|
self.simd_per_cu: str = None
|
|
|
|
|
self.se_per_gpu: str = None
|
|
|
|
|
self.wave_size: str = None
|
|
|
|
|
self.workgroup_max_size: str = None
|
|
|
|
|
self.max_sclk: str = None
|
|
|
|
|
self.max_mclk: str = None
|
|
|
|
|
self.cur_sclk: str = None
|
|
|
|
|
self.cur_mclk: str = None
|
|
|
|
|
self.max_waves_per_cu: str = None
|
|
|
|
|
self.gpu_model: str = None
|
|
|
|
|
self._l2_banks: str = None #NB: This only used in flatten_tcc_info_across_hbm_stacks()
|
|
|
|
|
self.lds_banks_per_cu: str = None
|
|
|
|
|
self.sqc_per_gpu: str = None
|
|
|
|
|
self.pipes_per_gpu: str = None
|
|
|
|
|
self.total_l2_chan: str = None
|
|
|
|
|
self.hbm_bw: str = None
|
|
|
|
|
self.num_xcd: str = None
|
|
|
|
|
# Load above SoC specs via module import
|
|
|
|
|
try:
|
|
|
|
|
soc_module = importlib.import_module('omniperf_soc.soc_'+ self.gpu_arch)
|
|
|
|
|
except ModuleNotFoundError as e:
|
|
|
|
|
error("Arch %s marked as supported, but couldn't find class implementation %s." % (self.gpu_arch, e))
|
|
|
|
|
soc_class = getattr(soc_module, self.gpu_arch+'_soc')
|
|
|
|
|
self._rocminfo = self._rocminfo[self.detect_arch()[1] + 1 :] # update rocminfo for target section
|
|
|
|
|
soc_obj = soc_class(args, self)
|
|
|
|
|
# Update arch specific specs
|
|
|
|
|
self.total_l2_chan: str = total_l2_banks(
|
|
|
|
|
self.gpu_model, int(self._l2_banks), self.memory_partition
|
|
|
|
|
)
|
|
|
|
|
self.hbm_bw: str = str(int(self.max_mclk) / 1000 * 32 * self.get_hbm_channels())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def detect_arch(self):
|
|
|
|
|
from omniperf_base import SUPPORTED_ARCHS
|
|
|
|
|
|
|
|
|
|
for idx1, linetext in enumerate(self._rocminfo):
|
|
|
|
|
gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext)
|
|
|
|
|
if gpu_arch in SUPPORTED_ARCHS.keys():
|
|
|
|
|
break
|
|
|
|
|
if str(gpu_arch) in SUPPORTED_ARCHS.keys():
|
|
|
|
|
gpu_arch = str(gpu_arch)
|
|
|
|
|
break
|
|
|
|
|
if not gpu_arch in SUPPORTED_ARCHS.keys():
|
|
|
|
|
error("[profiling] Cannot find a supported arch in rocminfo")
|
|
|
|
|
else:
|
|
|
|
|
return (gpu_arch, idx1)
|
|
|
|
|
|
|
|
|
|
def get_hbm_channels(self):
|
|
|
|
|
hbmchannels = int(self.total_l2_chan)
|
|
|
|
|
if (
|
|
|
|
@@ -189,60 +325,55 @@ class MachineSpecs:
|
|
|
|
|
all_populated = True
|
|
|
|
|
data = {}
|
|
|
|
|
# dataclass uses an OrderedDict for member variables, ensuring order consistency
|
|
|
|
|
for attr_name in self.__dict__.keys():
|
|
|
|
|
if not attr_name.startswith("_"):
|
|
|
|
|
attr_value = getattr(self, attr_name)
|
|
|
|
|
if attr_value is None:
|
|
|
|
|
#TODO: use proper logging function when that's merged
|
|
|
|
|
logging.warning(f"WARNING: Incomplete class definition for {self.gpu_arch}. Expecting populated {attr_name} but detected None.")
|
|
|
|
|
all_populated = False
|
|
|
|
|
data[attr_name] = attr_value
|
|
|
|
|
for field in fields(self):
|
|
|
|
|
name = field.name
|
|
|
|
|
if not name.startswith("_"):
|
|
|
|
|
value = getattr(self, name)
|
|
|
|
|
if value is None:
|
|
|
|
|
# check if we've marked it optional
|
|
|
|
|
if field.metadata and 'optional' in field.metadata and field.metadata['optional']:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
#TODO: use proper logging function when that's merged
|
|
|
|
|
logging.warning(
|
|
|
|
|
f"WARNING: Incomplete class definition for {self.gpu_arch}. "
|
|
|
|
|
f"Expecting populated {name} but detected None.")
|
|
|
|
|
all_populated = False
|
|
|
|
|
data[name] = value
|
|
|
|
|
|
|
|
|
|
if not all_populated:
|
|
|
|
|
error("Missing specs fields for %s" % self.gpu_arch)
|
|
|
|
|
return pd.DataFrame(data, index=[0])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return dedent(
|
|
|
|
|
f"""\
|
|
|
|
|
Specs version: v{self.specs_version}
|
|
|
|
|
Host info:
|
|
|
|
|
Hostname: {self.hostname}
|
|
|
|
|
CPU Model: {self.cpu_model}
|
|
|
|
|
sbios: {self.sbios}
|
|
|
|
|
CPU Memory: {self.cpu_memory}
|
|
|
|
|
GPU Memory: {self.gpu_memory}
|
|
|
|
|
Linux Distro: {self.linux_distro}
|
|
|
|
|
Linux Kernel Version: {self.linux_kernel_version}
|
|
|
|
|
AMD GPU Kernel Version: {self.amd_gpu_kernel_version}
|
|
|
|
|
ROCm Version: {self.rocm_version}
|
|
|
|
|
Device info:
|
|
|
|
|
GPU Model: {self.gpu_model}
|
|
|
|
|
GPU Arch: {self.gpu_arch}
|
|
|
|
|
vbios: {self.vbios}
|
|
|
|
|
GPU L1: {self.gpu_l1} KB
|
|
|
|
|
GPU L2: {self.gpu_l2} KB
|
|
|
|
|
Max SCLK: {self.max_sclk} MHz
|
|
|
|
|
Max MCLK: {self.max_mclk} MHz
|
|
|
|
|
Cur SCLK: {self.cur_sclk} MHz
|
|
|
|
|
Cur MCLK: {self.cur_mclk} MHz
|
|
|
|
|
CU per GPU: {self.cu_per_gpu}
|
|
|
|
|
SIMD per CU: {self.simd_per_cu}
|
|
|
|
|
SE per GPU: {self.se_per_gpu}
|
|
|
|
|
Wave Size: {self.wave_size}
|
|
|
|
|
Workgroup Max Size: {self.workgroup_max_size}
|
|
|
|
|
Max Waves per CU: {self.max_waves_per_cu}
|
|
|
|
|
Total L2 Channels: {self.total_l2_chan}
|
|
|
|
|
LDS Banks per CU: {self.lds_banks_per_cu}
|
|
|
|
|
SQC per GPU: {self.sqc_per_gpu}
|
|
|
|
|
Pipes per GPU: {self.pipes_per_gpu}
|
|
|
|
|
HBM BW: {self.hbm_bw} MB/s
|
|
|
|
|
Compute Partition: {self.compute_partition}
|
|
|
|
|
Memory Partition: {self.memory_partition}
|
|
|
|
|
Num XCDs: {self.num_xcd}
|
|
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
data = []
|
|
|
|
|
for field in fields(self):
|
|
|
|
|
name = field.name
|
|
|
|
|
if not name.startswith("_"):
|
|
|
|
|
_data = {}
|
|
|
|
|
value = getattr(self, name)
|
|
|
|
|
if field.metadata:
|
|
|
|
|
if 'name' in field.metadata:
|
|
|
|
|
name = field.metadata['name']
|
|
|
|
|
if 'unit' in field.metadata:
|
|
|
|
|
_data['Unit'] = field.metadata['unit']
|
|
|
|
|
if 'doc' in field.metadata:
|
|
|
|
|
_data['Description'] = field.metadata['doc']
|
|
|
|
|
_data['Spec'] = name
|
|
|
|
|
_data['Value'] = value
|
|
|
|
|
data.append(_data)
|
|
|
|
|
df = pd.DataFrame(data)
|
|
|
|
|
columns = ['Spec', 'Value']
|
|
|
|
|
if 'Description' in df.columns:
|
|
|
|
|
columns += ['Description']
|
|
|
|
|
if 'Unit' in df.columns:
|
|
|
|
|
columns += ['Unit']
|
|
|
|
|
df = df[columns]
|
|
|
|
|
df = df.fillna('')
|
|
|
|
|
return (
|
|
|
|
|
"Machine Specifications: describing the state of the machine that Omniperf data was collected on." +
|
|
|
|
|
"\n" +
|
|
|
|
|
get_table_string(df, transpose=False, decimal=2))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_rocm_ver():
|
|
|
|
@@ -350,4 +481,4 @@ def total_xcds(archname, compute_partition):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
print(MachineSpecs())
|
|
|
|
|
print(generate_machine_specs())
|
|
|
|
|