Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
53 changes: 32 additions & 21 deletions cvs/input/config_file/aorta/aorta_benchmark.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
# Aorta Benchmark Configuration
#
# This configuration controls the CVS benchmark runner for Aorta distributed training.
# Aorta Benchmark Test Configuration
# Parsing runs on the host (your venv) from torch_profiler artifacts. Container TraceLens
# analysis is optional; when enabled and available in the image, Excel reports are used
# first, otherwise host parses raw traces (TraceLens in venv or basic JSON parsing).

# Path to Aorta repository on host (will be bind-mounted into container)
aorta_path: <changeme>
# Path to Aorta repository on shared filesystem (placeholder resolved from cluster config).
# If the directory does not exist, set aorta_auto_clone: true and aorta_clone_url to clone it.
aorta_path: /scratch/users/{user-id}/aorta
# aorta_auto_clone: false
# aorta_clone_url: "https://github.com/your-org/aorta.git" # set when using auto-clone

# Container mount point for aorta_path
container_mount_path: /mnt

# Aorta base config file (relative to aorta_path)
base_config: config/distributed.yaml
# profile_overlap_2gpu.yaml has profiling enabled with compile disabled (works on ROCm)
base_config: config/profile_overlap_2gpu.yaml

# Docker container settings
docker:
Expand All @@ -34,32 +39,38 @@ environment:
OMP_NUM_THREADS: 1
RCCL_MSCCL_ENABLE: 0

# Aorta training config overrides (passed via --override)
# Short test run (profile_overlap_2gpu.yaml already uses a short profile window)
training_overrides:
training.max_steps: 100
profiling.active: 10
training.max_steps: 15
profiling.active: 6

# Scripts to execute (relative to container_mount_path)
build_script: scripts/build_rccl.sh
experiment_script: scripts/rccl_exp.sh
# Scripts to execute (using existing Aorta scripts)
# build_script is skipped when skip_rccl_build is true
build_script: scripts/launch_rocm.sh
experiment_script: scripts/launch_rocm.sh

# Hardware configuration
# Hardware
gpus_per_node: 8

# Execution settings
timeout_seconds: 10800
skip_rccl_build: false
# Timeout
timeout_seconds: 3600

# Post-benchmark analysis
# Skip RCCL build for benchmark runs with container-native RCCL
skip_rccl_build: true

# Post-benchmark analysis (optional; host parsing is primary)
# When true, runner tries to generate Excel reports inside the container. If TraceLens
# is not installed in the image, analysis is skipped and host parses raw traces.
analysis:
enable_tracelens: false
enable_gemm_analysis: false
tracelens_script: scripts/tracelens_single_config/run_tracelens_single_config.sh
gemm_script: scripts/gemm_analysis/run_tracelens_analysis.sh
skip_if_exists: false

# Expected results for validation
# Expected results (tuned for host raw-trace parsing on MI300; use stricter values with TraceLens Excel reports)
expected_results:
max_avg_iteration_ms: 7000
min_compute_ratio: 0.8
max_avg_iteration_ms: 12000
min_compute_ratio: 0.01 # host parsing often 1–10%; use 0.5+ for TraceLens/Excel metrics
min_overlap_ratio: 0.0
max_time_variance_ratio: 0.2
max_time_variance_ratio: 0.5
45 changes: 43 additions & 2 deletions cvs/parsers/aorta_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,51 @@ def parse_analysis_directory(self, analysis_dir: Path) -> ParseResult[AortaTrace
report_files = sorted(individual_dir.glob("perf_*ch_rank*.xlsx"))

if not report_files:
return ParseResult(
status=ParseStatus.FAILED, errors=[f"No perf_rank*.xlsx files found in {individual_dir}"]
# Check if raw traces exist - if so, TraceLens likely couldn't generate reports
# (e.g., chrome_trace: false in config to avoid ROCm crashes)
parent_dir = analysis_dir.parent
torch_profiler_dir = parent_dir / "torch_profiler"

# Check for trace files (handles both .json and .pt.trace.json patterns)
raw_traces_exist = False
if torch_profiler_dir.exists():
# Try multiple patterns since trace file naming varies
for pattern in ["rank*/*.json", "rank*/*.pt.trace.json", "**/*.json"]:
if any(torch_profiler_dir.glob(pattern)):
raw_traces_exist = True
break

# Also check if torch_profiler dir exists with rank subdirs (even if empty)
# This indicates profiling was attempted but may have failed or chrome_trace was disabled
has_profiler_structure = torch_profiler_dir.exists() and any(
d.is_dir() and d.name.startswith("rank") for d in torch_profiler_dir.iterdir()
)

if raw_traces_exist:
# Raw traces exist but no Excel reports - this is expected when chrome_trace is disabled
return ParseResult(
status=ParseStatus.NO_DATA,
warnings=[
f"No Excel reports in {individual_dir}. "
"Raw .pt.trace.json files exist and can be viewed in Perfetto (ui.perfetto.dev). "
"To generate Excel reports, enable chrome_trace in the Aorta config."
],
)
elif has_profiler_structure:
# Profiler structure exists but no trace files - likely crashed or config issue
return ParseResult(
status=ParseStatus.NO_DATA,
warnings=[
f"No Excel reports in {individual_dir}. "
"Profiler directories exist but contain no trace files. "
"This may indicate a crashed run or profiling was disabled."
],
)
else:
return ParseResult(
status=ParseStatus.FAILED, errors=[f"No perf_rank*.xlsx files found in {individual_dir}"]
)

log.info(f"Found {len(report_files)} individual reports to parse")

for report_file in report_files:
Expand Down
11 changes: 10 additions & 1 deletion cvs/parsers/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ParseStatus(Enum):
SUCCESS = "success"
PARTIAL = "partial" # Some results parsed, some failed
FAILED = "failed"
NO_DATA = "no_data" # No data to parse (e.g., TraceLens skipped, Chrome traces disabled)


T = TypeVar('T', bound=BaseModel)
Expand Down Expand Up @@ -389,9 +390,13 @@ class AortaBenchmarkConfigFile(BaseModel):

model_config = ConfigDict(extra="forbid") # Catch typos in top-level keys

# Required: Path to aorta repository
# Path to Aorta repository on host (will be bind-mounted). If missing and aorta_auto_clone is true, it is cloned.
aorta_path: str = Field(description="Path to Aorta repository on host (will be bind-mounted)")

# Optional: clone Aorta repo when aorta_path does not exist
aorta_auto_clone: bool = Field(default=False, description="If true and aorta_path missing, clone from aorta_clone_url")
aorta_clone_url: Optional[str] = Field(default=None, description="Git URL to clone when aorta_auto_clone is true")

# Container settings
container_mount_path: str = Field(default="/mnt", description="Mount point inside container for aorta_path")

Expand Down Expand Up @@ -458,6 +463,9 @@ def validate_paths_exist(self) -> List[str]:

aorta = Path(self.aorta_path)
if not aorta.exists():
if self.aorta_auto_clone and self.aorta_clone_url:
# Runner will clone in setup(); skip path checks here
return errors
errors.append(f"aorta_path does not exist: {self.aorta_path}")
else:
# Check internal paths
Expand Down Expand Up @@ -781,3 +789,4 @@ def validate_config_file(
except Exception as e:
# Re-raise with file context
raise ValueError(f"Invalid configuration in {config_path}:\n{e}") from e

Loading
Loading