Use glenng's cargo-aoc with bench --quick
This commit is contained in:
parent
24b343d3f8
commit
fe6716b468
@ -1,7 +1,7 @@
|
||||
FROM rust:latest
|
||||
|
||||
# Install cargo-aoc
|
||||
RUN cargo install cargo-aoc
|
||||
# Install cargo-aoc from specific GitHub repository
|
||||
RUN cargo install --git https://github.com/ggriffiniii/cargo-aoc cargo-aoc
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
94
aocsync.py
94
aocsync.py
@ -584,7 +584,7 @@ class CargoAOCRunner:
|
||||
return commits
|
||||
|
||||
@staticmethod
|
||||
def _run_cargo_aoc_in_container(work_dir: Path, day: int, repo_root: Path, docker_config: dict) -> subprocess.CompletedProcess:
|
||||
def _run_cargo_aoc_in_container(work_dir: Path, day: int, repo_root: Path, docker_config: dict, user: str = "unknown", year: int = 0) -> subprocess.CompletedProcess:
|
||||
"""Run cargo aoc in a Podman container for security
|
||||
|
||||
Args:
|
||||
@ -592,6 +592,8 @@ class CargoAOCRunner:
|
||||
day: Day number to run
|
||||
repo_root: Absolute path to repository root
|
||||
docker_config: Podman configuration dictionary
|
||||
user: User name for build cache directory organization
|
||||
year: Year for build cache directory organization
|
||||
|
||||
Returns:
|
||||
CompletedProcess with stdout, stderr, returncode
|
||||
@ -612,14 +614,16 @@ class CargoAOCRunner:
|
||||
temp_build_dir = None
|
||||
|
||||
if build_cache_dir:
|
||||
# Use persistent build cache directory
|
||||
build_cache_path = Path(build_cache_dir).resolve()
|
||||
# Use persistent build cache directory with user/year subdirectories
|
||||
base_cache_path = Path(build_cache_dir).resolve()
|
||||
# Create user/year specific directory: build_cache_dir/user/year/
|
||||
build_cache_path = base_cache_path / user / str(year)
|
||||
build_cache_path.mkdir(parents=True, exist_ok=True)
|
||||
logger.info(f"Using persistent build cache: {build_cache_path}")
|
||||
logger.info(f"Using persistent build cache: {build_cache_path} (user: {user}, year: {year})")
|
||||
else:
|
||||
# Create a temporary directory for cargo build artifacts (outside repo)
|
||||
import tempfile
|
||||
temp_build_dir = tempfile.mkdtemp(prefix='cargo-aoc-build-')
|
||||
temp_build_dir = tempfile.mkdtemp(prefix=f'cargo-aoc-build-{user}-{year}-')
|
||||
build_cache_path = Path(temp_build_dir)
|
||||
use_temp_build = True
|
||||
logger.info(f"Using temporary build cache: {build_cache_path}")
|
||||
@ -677,13 +681,13 @@ class CargoAOCRunner:
|
||||
# Check if already installed to avoid reinstalling every time
|
||||
podman_cmd.extend([
|
||||
podman_image,
|
||||
'sh', '-c', 'if ! command -v cargo-aoc >/dev/null 2>&1; then cargo install --quiet cargo-aoc 2>/dev/null || true; fi; cargo aoc --day ' + str(day)
|
||||
'sh', '-c', f'if ! command -v cargo-aoc >/dev/null 2>&1; then cargo install --quiet --git https://github.com/ggriffiniii/cargo-aoc cargo-aoc 2>/dev/null || true; fi; cargo aoc bench -d {day} -- --quick'
|
||||
])
|
||||
else:
|
||||
# Use pre-installed cargo-aoc (faster, requires aocsync:latest image)
|
||||
podman_cmd.extend([
|
||||
podman_image,
|
||||
'cargo', 'aoc', '--day', str(day)
|
||||
'cargo', 'aoc', 'bench', '-d', str(day), '--', '--quick'
|
||||
])
|
||||
|
||||
result = subprocess.run(
|
||||
@ -747,7 +751,7 @@ class CargoAOCRunner:
|
||||
|
||||
for day in days:
|
||||
try:
|
||||
logger.info(f"Running cargo aoc for {user} year {year} day {day} in {work_dir} (in Podman container)")
|
||||
logger.info(f"Running cargo aoc bench for {user} year {year} day {day} in {work_dir} (in Podman container)")
|
||||
# Run cargo aoc in a Podman container for security
|
||||
# Use default docker_config if not provided
|
||||
if docker_config is None:
|
||||
@ -758,7 +762,7 @@ class CargoAOCRunner:
|
||||
'cpus': '2',
|
||||
'image': 'aocsync:latest'
|
||||
}
|
||||
result = CargoAOCRunner._run_cargo_aoc_in_container(work_dir, day, repo_root, docker_config)
|
||||
result = CargoAOCRunner._run_cargo_aoc_in_container(work_dir, day, repo_root, docker_config, user, year)
|
||||
|
||||
# Write to log file if provided
|
||||
if log_file:
|
||||
@ -770,7 +774,7 @@ class CargoAOCRunner:
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n{'='*80}\n")
|
||||
f.write(f"[{timestamp}] {user} - Year {year} - Day {day}\n")
|
||||
f.write(f"Command: cargo aoc --day {day} (in Podman container)\n")
|
||||
f.write(f"Command: cargo aoc bench -d {day} -- --quick (in Podman container)\n")
|
||||
f.write(f"Working Directory: {work_dir}\n")
|
||||
f.write(f"Return Code: {result.returncode}\n")
|
||||
f.write(f"{'='*80}\n")
|
||||
@ -785,12 +789,12 @@ class CargoAOCRunner:
|
||||
f.write(f"{'='*80}\n\n")
|
||||
|
||||
if result.returncode != 0:
|
||||
logger.warning(f"cargo aoc failed for day {day} in {work_dir}: {result.stderr}")
|
||||
logger.warning(f"cargo aoc bench failed for day {day} in {work_dir}: {result.stderr}")
|
||||
continue
|
||||
|
||||
# Log output for debugging if no results found
|
||||
if not result.stdout.strip() and not result.stderr.strip():
|
||||
logger.warning(f"No output from cargo aoc for {user} year {year} day {day}")
|
||||
logger.warning(f"No output from cargo aoc bench for {user} year {year} day {day}")
|
||||
|
||||
# Strip ANSI codes before parsing (for cleaner parsing)
|
||||
stdout_clean = CargoAOCRunner._strip_ansi_codes(result.stdout or "")
|
||||
@ -812,14 +816,14 @@ class CargoAOCRunner:
|
||||
results.extend(day_results)
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
error_msg = f"Timeout running cargo aoc for day {day}"
|
||||
error_msg = f"Timeout running cargo aoc bench for day {day}"
|
||||
logger.error(error_msg)
|
||||
if log_file:
|
||||
timestamp = datetime.now().isoformat()
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(f"\n[{timestamp}] ERROR: {error_msg}\n")
|
||||
except Exception as e:
|
||||
error_msg = f"Error running cargo aoc for day {day}: {e}"
|
||||
error_msg = f"Error running cargo aoc bench for day {day}: {e}"
|
||||
logger.error(error_msg)
|
||||
if log_file:
|
||||
timestamp = datetime.now().isoformat()
|
||||
@ -831,9 +835,14 @@ class CargoAOCRunner:
|
||||
@staticmethod
|
||||
def _parse_runtime_output(stdout: str, stderr: str, day: int, year: int,
|
||||
user: str, git_rev: str = "", repo_url: str = "", output_bytes: int = 0) -> List[PerformanceResult]:
|
||||
"""Parse cargo-aoc runtime output
|
||||
"""Parse cargo aoc bench runtime output
|
||||
|
||||
cargo aoc typically outputs timing information like:
|
||||
cargo aoc bench -- --quick outputs timing information in format like:
|
||||
- "Day8 - Part1/(default) time: [15.127 ms 15.168 ms 15.331 ms]"
|
||||
- "Day8 - Part2/(default) time: [15.141 ms 15.160 ms 15.164 ms]"
|
||||
Extracts the middle measurement (second value) from the three measurements.
|
||||
|
||||
Also supports legacy cargo-aoc custom format for backward compatibility:
|
||||
- "Day X - Part Y: XXX.XXX ms"
|
||||
- "Day X - Part Y: XXX.XXX μs"
|
||||
- "Day X - Part Y: XXX.XXX ns"
|
||||
@ -846,6 +855,43 @@ class CargoAOCRunner:
|
||||
# Combine stdout and stderr (timing info might be in either)
|
||||
output = stdout + "\n" + stderr
|
||||
|
||||
# First, try to parse cargo aoc bench output format
|
||||
# Pattern: Day<X> - Part<Y>/(default) time: [<val1> <unit> <val2> <unit> <val3> <unit>]
|
||||
# Example: Day8 - Part1/(default) time: [15.127 ms 15.168 ms 15.331 ms]
|
||||
# Extract the middle measurement (val2)
|
||||
cargo_bench_pattern = r'Day\s*(\d+)\s*-\s*Part\s*(\d+).*?time:\s*\[([\d.]+)\s+(\w+)\s+([\d.]+)\s+(\w+)\s+([\d.]+)\s+(\w+)\]'
|
||||
for match in re.finditer(cargo_bench_pattern, output, re.IGNORECASE | re.MULTILINE):
|
||||
bench_day = int(match.group(1))
|
||||
bench_part = int(match.group(2))
|
||||
# Extract middle value (group 5) and its unit (group 6)
|
||||
time_str = match.group(5)
|
||||
unit = match.group(6).lower()
|
||||
|
||||
try:
|
||||
time_val = float(time_str)
|
||||
time_ns = CargoAOCRunner._convert_to_nanoseconds(time_val, unit)
|
||||
|
||||
# Avoid duplicates
|
||||
if not any(r.day == bench_day and r.part == bench_part
|
||||
for r in results):
|
||||
results.append(PerformanceResult(
|
||||
user=user,
|
||||
year=year,
|
||||
day=bench_day,
|
||||
part=bench_part,
|
||||
time_ns=time_ns,
|
||||
output_bytes=output_bytes,
|
||||
git_rev=git_rev,
|
||||
repo_url=repo_url,
|
||||
timestamp=timestamp
|
||||
))
|
||||
except ValueError:
|
||||
logger.warning(f"Could not parse cargo bench time: {time_str} {unit}")
|
||||
|
||||
# If we found results with cargo bench format, return them
|
||||
if results:
|
||||
return results
|
||||
|
||||
# Patterns to match various cargo-aoc output formats
|
||||
# Common formats:
|
||||
# "Day 1 - Part 1: 123.456 ms"
|
||||
@ -2229,20 +2275,32 @@ class AOCSync:
|
||||
elif repo_type == 'multi-year':
|
||||
# Multiple repositories, one per year
|
||||
years_config = repo_config.get('years', [])
|
||||
if not years_config:
|
||||
logger.warning(f"No years configured for multi-year repository {user_name}")
|
||||
return
|
||||
|
||||
logger.info(f"Processing multi-year repository {user_name} with {len(years_config)} year(s)")
|
||||
for year_config in years_config:
|
||||
year = year_config['year']
|
||||
url = year_config['url']
|
||||
local_path = year_config['local_path']
|
||||
|
||||
if self.force_rerun or self.git_manager.has_changes(url, local_path):
|
||||
logger.debug(f"Checking {user_name} year {year} at {local_path}")
|
||||
has_changes_result = GitManager.has_changes(url, local_path)
|
||||
|
||||
if self.force_rerun or has_changes_result:
|
||||
if self.force_rerun:
|
||||
logger.info(f"Force rerun enabled, processing repository {user_name} year {year}...")
|
||||
else:
|
||||
logger.info(f"Repository {user_name} year {year} has changes, updating...")
|
||||
if self.git_manager.clone_or_update_repo(url, local_path):
|
||||
if GitManager.clone_or_update_repo(url, local_path):
|
||||
repo_path = Path(local_path)
|
||||
self._run_and_store_benchmarks(repo_path, year, user_name,
|
||||
repo_url=url, is_multi_year=True)
|
||||
else:
|
||||
logger.error(f"Failed to clone/update repository {user_name} year {year} at {local_path}")
|
||||
else:
|
||||
logger.info(f"Repository {user_name} year {year} has no changes, skipping...")
|
||||
|
||||
def _check_year_in_repo(self, repo_path: Path, year: int) -> bool:
|
||||
"""Check if a repository contains solutions for a specific year"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user