Files
rocm-systems/projects/rocprofiler-compute/src/rocprof_compute_tui/widgets/collapsibles.py
T
jamessiddeley-amd 5deeea71df [rocprof-compute] Update Formatting (#671)
* updated rocprof-compute formatting

* fixed ammolite peak variables in parser.py

* format parser.py

* update formatting rocprof_compute_base
2025-08-22 12:22:17 -04:00

158 lines
5.8 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.
##############################################################################
from typing import Any, Dict, List
import pandas as pd
import yaml
from textual.widgets import Collapsible, DataTable, Label
from rocprof_compute_tui.widgets.charts import (
MemoryChart,
SimpleBar,
SimpleBox,
SimpleMultiBar,
)
def create_table(df: pd.DataFrame) -> DataTable:
table = DataTable(zebra_stripes=True)
df = df.reset_index()
df = df[~df.apply(lambda row: row.astype(str).str.strip().eq("").any(), axis=1)]
str_columns = [str(col) for col in df.columns]
table.add_columns(*str_columns)
table.add_rows([tuple(str(x) for x in row) for row in df.itertuples(index=False)])
return table
def create_widget_from_data(df: pd.DataFrame, tui_style: str = None, context: str = ""):
if df is None or df.empty:
return Label(
f"Data not available{f' for {context}' if context else ''}",
classes="warning",
)
match tui_style:
# TODO: implement tui_style == "roofline"
# case "roofline":
# return Roofline(df)
case None:
return create_table(df)
case "mem_chart":
return MemoryChart(df)
case "simple_bar":
return SimpleBar(df)
case "simple_box":
return SimpleBox(df)
case "simple_multiple_bar":
return SimpleMultiBar(df)
case _:
return Label(f"Unknown display type: {tui_style}")
def load_config(config_path) -> Dict[str, Any]:
try:
with open(config_path, "r") as file:
return yaml.safe_load(file)
except FileNotFoundError:
raise FileNotFoundError(
(
f"Configuration file {config_path} not found, \n"
"please populate the analysis_config.yaml file."
)
)
except yaml.YAMLError as e:
raise ValueError(f"Error parsing YAML configuration: {e}")
def build_section_from_config(
dfs: Dict[str, Any], section_config: Dict[str, Any]
) -> Collapsible:
title = section_config["title"]
collapsed = section_config.get("collapsed", True)
children = []
for subsection_config in section_config["subsections"]:
# Handle arch_config_data
if subsection_config.get("arch_config_data", False):
if isinstance(dfs, dict):
exclude_keys = subsection_config.get("exclude_keys", [])
for section_name, subsections in dfs.items():
if section_name not in exclude_keys and isinstance(
subsections, dict
):
kernel_children = []
for subsection_name, data in subsections.items():
if isinstance(data, dict) and "df" in data:
widget = create_widget_from_data(
data["df"], data.get("tui_style"), subsection_name
)
kernel_children.append(
Collapsible(
widget, title=subsection_name, collapsed=True
)
)
if kernel_children:
children.append(
Collapsible(
*kernel_children, title=section_name, collapsed=True
)
)
else:
# Handle data_path
tui_style = subsection_config.get("tui_style")
data_path = subsection_config["data_path"]
df = dfs.get(data_path[0], {}).get(data_path[1], {})
df = df.get("df") if isinstance(df, dict) else None
if df is not None and isinstance(df, dict) and tui_style is None:
tui_style = df.get("tui_style")
widgets = [
create_widget_from_data(df, tui_style, f"path {' -> '.join(data_path)}")
]
children.append(
Collapsible(
*widgets,
title=subsection_config.get("title", "Untitled"),
collapsed=subsection_config.get("collapsed", True),
)
)
return Collapsible(*children, title=title, collapsed=collapsed)
def build_all_sections(dfs: Dict[str, Any], config_path) -> List[Collapsible]:
config = load_config(config_path)
sections = []
for section_config in config["sections"]:
section = build_section_from_config(dfs, section_config)
sections.append(section)
return sections