Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ seaborn>=0.12.0

# For GEMM analysis (scripts/gemm_analysis/)
git+https://github.com/AMD-AGI/TraceLens.git
jinja2>=3.0.0

# For hw_queue_eval (optional - install with: pip install -e ".[hw-queue]")
# click>=8.0.0
Expand Down
147 changes: 52 additions & 95 deletions scripts/gemm_analysis/create_embeded_html_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
Create a self-contained HTML report comparing two experiment sweeps.
Embeds all images as base64 for easy sharing.

Uses the report_generator framework with ComparisonReportBuilder.

TODO: Future enhancement - support multiple sweep comparisons using comma-separated
input (e.g., --sweeps sweep1,sweep2,sweep3) for N-way comparisons.
Current implementation focuses on pairwise comparison which covers the most
common use case of A/B testing.
"""

import base64
import sys
import argparse
from pathlib import Path
from html_template import get_comparison_template

def image_to_base64(image_path):
"""Convert an image file to base64 string"""
try:
with open(image_path, 'rb') as img_file:
return base64.b64encode(img_file.read()).decode('utf-8')
except FileNotFoundError:
print(f"Warning: Image not found: {image_path}")
return None
# Add scripts directory to path for report_generator imports
sys.path.insert(0, str(Path(__file__).parent.parent))
from report_generator.comparison_builder import ComparisonReportBuilder


def get_default_config_path() -> Path:
"""Return the default path to the config JSON file."""
return Path(__file__).parent.parent / "utils" / "gemm_comparison_config.json"


def parse_args():
"""Parse command line arguments"""
Expand All @@ -43,105 +45,59 @@ def parse_args():
--label1 "Base ROCm" \\
--label2 "ROCm 7.0" \\
--output comparison_report.html
"""
""",
)

parser.add_argument(
'--sweep1',
type=Path,
required=True,
help='Path to first sweep directory'
)
parser.add_argument("--sweep1", type=Path, required=True, help="Path to first sweep directory")

parser.add_argument("--sweep2", type=Path, required=True, help="Path to second sweep directory")

parser.add_argument(
'--sweep2',
type=Path,
required=True,
help='Path to second sweep directory'
"--label1", type=str, default=None, help="Label for first sweep (default: directory name)"
)

parser.add_argument(
'--label1',
type=str,
default=None,
help='Label for first sweep (default: directory name)'
"--label2", type=str, default=None, help="Label for second sweep (default: directory name)"
)

parser.add_argument(
'--label2',
type=str,
"--output",
type=Path,
default=None,
help='Label for second sweep (default: directory name)'
help="Output HTML file path (default: sweep_comparison_report.html in current directory)",
)

parser.add_argument(
'--output',
"--config",
type=Path,
default=None,
help='Output HTML file path (default: sweep_comparison_report.html in current directory)'
help="Path to JSON config file (default: utils/gemm_comparison_config.json)",
)

return parser.parse_args()

def get_plot_images(sweep_path):
"""Get paths to all plot images for a sweep"""
plots_dir = sweep_path / "tracelens_analysis" / "plots"

return {
'threads': plots_dir / 'variance_by_threads_boxplot.png',
'channels': plots_dir / 'variance_by_channels_boxplot.png',
'ranks': plots_dir / 'variance_by_ranks_boxplot.png',
'violin': plots_dir / 'variance_violin_combined.png',
'interaction': plots_dir / 'variance_thread_channel_interaction.png',
}

def create_html_report(sweep1_path, sweep2_path, label1, label2, output_path):
"""Create HTML report comparing two sweeps"""

# Get sweep names from paths if labels not provided
if label1 is None:
label1 = sweep1_path.name
if label2 is None:
label2 = sweep2_path.name

# Get image paths for both sweeps
images_sweep1 = get_plot_images(sweep1_path)
images_sweep2 = get_plot_images(sweep2_path)

# Convert images to base64
print("Converting images to base64...")
print(f"\nSweep 1: {label1}")
image_data = {}
for key, path in images_sweep1.items():
print(f" Processing: {key}")
b64 = image_to_base64(path)
if b64:
image_data[f'{key}_sweep1'] = f"data:image/png;base64,{b64}"
print(f" [OK]")
else:
image_data[f'{key}_sweep1'] = ""
print(f" [MISSING] {path}")

print(f"\nSweep 2: {label2}")
for key, path in images_sweep2.items():
print(f" Processing: {key}")
b64 = image_to_base64(path)
if b64:
image_data[f'{key}_sweep2'] = f"data:image/png;base64,{b64}"
print(f" [OK]")
else:
image_data[f'{key}_sweep2'] = ""
print(f" [MISSING] {path}")

# Create HTML with embedded images
html_content = get_comparison_template(label1, label2, sweep1_path, sweep2_path, image_data)

# Write the HTML file
with open(output_path, 'w', encoding='utf-8') as f:
f.write(html_content)

print(f"\n[OK] HTML report created: {output_path}")
print(f" File size: {output_path.stat().st_size / 1024 / 1024:.2f} MB")

def create_comparison_report(
sweep1_path: Path,
sweep2_path: Path,
output_path: Path,
config_path: Path | None = None,
label1: str | None = None,
label2: str | None = None,
) -> Path:
"""Create HTML report comparing two sweeps using ComparisonReportBuilder."""
if config_path is None:
config_path = get_default_config_path()

builder = ComparisonReportBuilder(
sweep1_path=sweep1_path,
sweep2_path=sweep2_path,
output_path=output_path,
config_path=config_path,
label1=label1,
label2=label2,
)
builder.save()
return output_path


Expand Down Expand Up @@ -171,12 +127,13 @@ def main():
print()

# Create the report
create_html_report(
args.sweep1,
args.sweep2,
args.label1,
args.label2,
args.output
create_comparison_report(
sweep1_path=args.sweep1,
sweep2_path=args.sweep2,
output_path=args.output,
config_path=args.config,
label1=args.label1,
label2=args.label2,
)

return 0
Expand Down
Loading
Loading