Files
rocm-systems/projects/rocprofiler-compute/tools/split_config.py
T
2025-10-22 15:17:43 -04:00

308 خطوط
12 KiB
Python

##############################################################################
# MIT License
#
# Copyright (c) 2025 Advanced Micro Devices, Inc. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
##############################################################################
# NOTES
#
# Read tools/unified_config.yaml and split it into per gfx architecture per panel
# config files. WARNING: This script will overwrite existing files under per gfx
# architecture folders under src/rocprof_compute_soc/analysis_configs.
#
# Read tools/unified_config.yaml and split it into metric tables per documentation
# section.
# WARNING: This script will overwrite existing docs/data/metrics_description.yaml.
import copy
import hashlib
import re
from pathlib import Path
import yaml
# Get root directory of the project
ROOT_DIR = Path(__file__).parent.parent
SOURCE_DIR = ROOT_DIR / "tools"
TARGET_DIR = ROOT_DIR / "src" / "rocprof_compute_soc" / "analysis_configs"
SETS_TARGET_DIR = ROOT_DIR / "src" / "rocprof_compute_soc" / "profile_configs" / "sets"
DOC_TARGET_DIR = ROOT_DIR / "docs" / "data"
AUTOGEN_TEXT = (
"# AUTOGENERATED FILE. Only edit for testing purposes, not for development. "
"Generated from tools/unified_config.yaml. Generated by tools/split_config.py\n"
)
HASH_FILE = ROOT_DIR / "tools" / "autogen_hash.yaml"
HASH_FILE_MAP = {}
GFX_VERSIONS = ["gfx908", "gfx90a", "gfx940", "gfx941", "gfx942", "gfx950"]
METRIC_ID_TO_NAME_MAP = {gfx_version: {} for gfx_version in GFX_VERSIONS}
def str_representer(dumper, data):
if "\n" in data:
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
yaml.add_representer(str, str_representer)
def get_autogen_text(config_file="tools/unified_config.yaml"):
return (
f"# AUTOGENERATED FILE. Only edit for testing purposes, "
f"not for development. Generated from {config_file}. "
f"Generated by tools/split_config.py\n"
)
def update_analysis_config():
global METRIC_ID_TO_NAME_MAP
# Read the unified config file
with open(SOURCE_DIR / "unified_config.yaml") as file:
unified_config = yaml.safe_load(file)
# Create per panel config file
for panel_config in unified_config["panels"]:
new_panel_config = {"Panel Config": {}}
new_panel_config["Panel Config"]["id"] = panel_config["id"]
new_panel_config["Panel Config"]["title"] = panel_config["title"]
panel_id_int = panel_config["id"]
# Convert int into str with 4 digits
panel_id = str(panel_config["id"]).zfill(4)
# Replace parentehsis, hyphen, slash and space with underscore
# Remove duplicate underscore
# Convert to lower case
panel_title = re.sub(r"[()\-/ ]+", "_", panel_config["title"])
panel_title = "_".join(filter(None, panel_title.split("_")))
panel_title = panel_title.lower()
for gfx_version in GFX_VERSIONS:
# Create per gfx architecture folder
gfx_dir = TARGET_DIR / gfx_version
# Create directory if it doesn't exist
if not gfx_dir.exists():
gfx_dir.mkdir()
print(f"Created directory: {gfx_dir}")
# Collect metrics for this gfx_version
gfx_metrics = []
# Select metrics from current gfx arch
new_panel_config["Panel Config"]["data source"] = []
for data_source_index, data_source_config in enumerate(
panel_config["data source"]
):
data_source_config = copy.deepcopy(data_source_config)
if "metric_table" in data_source_config:
data_source_config["metric_table"]["metric"] = data_source_config[
"metric_table"
]["metric"][gfx_version]
# Collect metric names for this gfx version (preserve order)
for metric_name in data_source_config["metric_table"][
"metric"
].keys():
if metric_name not in gfx_metrics:
gfx_metrics.append(metric_name)
build_metric_id_mapping(
panel_id_int,
data_source_index,
data_source_config["metric_table"]["metric"],
gfx_version,
)
new_panel_config["Panel Config"]["data source"].append(
data_source_config
)
# Only include metric descriptions for metrics that exist in this gfx
new_panel_config["Panel Config"]["metrics_description"] = {
key: value["plain"].strip()
for key, value in panel_config.get("metrics_description", {}).items()
if key in gfx_metrics
}
# Write panel config to file
filename = TARGET_DIR / gfx_version / f"{panel_id}_{panel_title}.yaml"
with open(filename, "w") as file:
file.write(get_autogen_text())
yaml.dump(new_panel_config, file, sort_keys=False)
print(f"File write: {filename}")
# Calculate hash of filename
HASH_FILE_MAP[str(filename.relative_to(ROOT_DIR))] = hashlib.sha256(
filename.read_bytes()
).hexdigest()
def build_metric_id_mapping(panel_id, data_source_index, metrics, gfx_version):
# Build metric id to metric name mapping
global METRIC_ID_TO_NAME_MAP
for metric_index, metric_name in enumerate(metrics.keys()):
metric_id = f"{panel_id // 100}.{data_source_index + 1}.{metric_index}"
METRIC_ID_TO_NAME_MAP[gfx_version][str(metric_id)] = metric_name
def update_sets_config():
# Create directory if it doesn't exist
if not SETS_TARGET_DIR.exists():
SETS_TARGET_DIR.mkdir()
print(f"Created directory: {SETS_TARGET_DIR}")
# Read the unified config file
with open(SOURCE_DIR / "unified_sets.yaml") as file:
unified_sets = yaml.safe_load(file)
# Create per gfx version file
for gfx_version in GFX_VERSIONS:
new_sets = {"sets": []}
for sets in unified_sets["sets"]:
# Create new set object for each set
current_set = {
"title": sets["title"],
"set_option": sets["set_option"],
"description": sets["description"],
"metric": [],
}
for metric_id in sets["metric"][gfx_version]:
current_set["metric"].append({
metric_id: METRIC_ID_TO_NAME_MAP[gfx_version][str(metric_id)]
})
new_sets["sets"].append(current_set)
# Write gfx version sets to file
filename = SETS_TARGET_DIR / f"{gfx_version}_sets.yaml"
with open(filename, "w") as file:
file.write(get_autogen_text("tools/unified_sets.yaml"))
yaml.dump(new_sets, file, sort_keys=False)
print(f"File write: {filename}")
# Calculate hash of filename
HASH_FILE_MAP[str(filename.relative_to(ROOT_DIR))] = hashlib.sha256(
filename.read_bytes()
).hexdigest()
def update_documentation():
# Documentation sections
section_panel_map = {
"Wavefront launch stats": 701,
"Wavefront runtime stats": 702,
"Overall instruction mix": 1001,
"VALU arithmetic instruction mix": 1002,
"MFMA instruction mix": 1004,
"Compute Speed-of-Light": 1101,
"Pipeline statistics": 1102,
"Arithmetic operations": 1103,
"LDS Speed-of-Light": 1201,
"LDS Statistics": 1202,
"vL1D Speed-of-Light": 1601,
"Busy / stall metrics": 1501,
"Instruction counts": 1502,
"Spill / stack metrics": 1503,
"L1 Unified Translation Cache (UTCL1)": 1605,
"vL1D cache stall metrics": 1602,
"vL1D cache access metrics": 1603,
"Vector L1 data-return path or Texture Data (TD)": 1504,
"L2 Speed-of-Light": 1701,
"L2 cache accesses": 1703,
"L2-Fabric interface metrics": 1702,
"L2 - Fabric interface detailed metrics": 1706,
"L2 - Fabric Interface stalls": 1705,
"Scalar L1D Speed-of-Light": 1401,
"Scalar L1D cache accesses": 1402,
"Scalar L1D Cache - L2 Interface": 1403,
"L1I Speed-of-Light": 1301,
"L1I cache accesses": 1302,
"L1I <-> L2 interface": 1303,
"Workgroup manager utilizations": 601,
"Workgroup Manager - Resource Allocation": 602,
"Command processor fetcher (CPF)": 501,
"Command processor packet processor (CPC)": 502,
"System Speed-of-Light": 201,
}
# Read the unified config file
with open(SOURCE_DIR / "unified_config.yaml") as file:
unified_config = yaml.safe_load(file)
panel_metric_map = {}
for panel_config in unified_config["panels"]:
for data_source in panel_config["data source"]:
if "metric_table" in data_source:
metrics_info = {}
# Metric names from data source
metric_names = {
metric
for _, gfx_data in data_source["metric_table"]["metric"].items()
for metric in gfx_data
}
# Select metrics with descriptions available
metric_names = metric_names.intersection(
panel_config["metrics_description"].keys()
)
# Add metrics info
for metric_name in sorted(list(metric_names)):
metrics_info[metric_name] = {
"rst": panel_config["metrics_description"][metric_name][
"rst"
].strip(),
"unit": panel_config["metrics_description"][metric_name][
"unit"
],
}
panel_metric_map[data_source["metric_table"]["id"]] = metrics_info
# Merge panel_metric_map with section_panel_map
section_metric_map = {}
for section, panel_id in section_panel_map.items():
if panel_id in panel_metric_map:
section_metric_map[section] = panel_metric_map[panel_id]
# Write documentation metrics description file
filename = DOC_TARGET_DIR / "metrics_description.yaml"
with open(filename, "w") as file:
file.write(get_autogen_text())
yaml.dump(section_metric_map, file, sort_keys=False)
print(f"File write: {filename}")
# Calculate hash of filename
HASH_FILE_MAP[str(filename.relative_to(ROOT_DIR))] = hashlib.sha256(
filename.read_bytes()
).hexdigest()
def update_hash():
# Write hash file
with open(HASH_FILE, "w") as file:
file.write(get_autogen_text())
yaml.dump(HASH_FILE_MAP, file, sort_keys=False)
print(f"File write: {HASH_FILE}")
if __name__ == "__main__":
update_analysis_config()
update_sets_config()
update_documentation()
update_hash()