diff --git a/aocsync.py b/aocsync.py index 0703658..e287076 100755 --- a/aocsync.py +++ b/aocsync.py @@ -968,6 +968,21 @@ class HTMLGenerator: font-weight: 600; }} + th small {{ + font-weight: normal; + font-size: 0.7em; + }} + + th small a {{ + color: #fff; + opacity: 0.8; + }} + + th small a:hover {{ + opacity: 1; + text-decoration: underline; + }} + table {{ width: 100%; border-collapse: collapse; @@ -1141,207 +1156,163 @@ class HTMLGenerator:

Year {year}

""" - # Generate content for each day + # Collect all day/part combinations for this year + day_part_combos = [] for day in sorted(data[year].keys()): + for part in sorted(data[year][day].keys()): + day_part_combos.append((day, part)) + + if not day_part_combos: + html += "

No data available for this year.

" + html += "" + continue + + # Collect user info (git rev, repo_url) for header + user_info = {} + for day, part in day_part_combos: + part_data = data[year][day][part] + for user in users: + if user not in user_info: + user_info[user] = {'git_rev': '', 'repo_url': ''} + if user in part_data: + time_data = part_data[user] + if isinstance(time_data, dict): + if not user_info[user]['git_rev']: + user_info[user]['git_rev'] = time_data.get('git_rev', '') + if not user_info[user]['repo_url']: + user_info[user]['repo_url'] = time_data.get('repo_url', '') + + # Find fastest times per day/part for highlighting + fastest_times = {} + for day, part in day_part_combos: + part_data = data[year][day][part] + times = [] + for user, time_data in part_data.items(): + if isinstance(time_data, dict): + total_time = time_data.get('total', 0) + else: + total_time = time_data if time_data > 0 else 0 + if total_time > 0: + times.append(total_time) + if times: + fastest_times[(day, part)] = min(times) + + # Create table with transposed structure + html += """ + + + + +""" + + # Add user columns with git rev in header + for user in sorted(users): + git_rev = user_info[user]['git_rev'] + repo_url = user_info[user]['repo_url'] + + if git_rev and repo_url: + commit_url = repo_url.rstrip('/') + '/commit/' + git_rev + git_rev_html = f'
{git_rev[:7]}' + elif git_rev: + git_rev_html = f'
{git_rev[:7]}' + else: + git_rev_html = '' + + html += f' \n' + + html += """ + + +""" + + # Add rows for each day/part combination + for day, part in day_part_combos: + part_data = data[year][day][part] + fastest_time = fastest_times.get((day, part), 0) + row_history_htmls = [] + html += f""" -
-

Day {day}

+
+ """ - # Generate content for each part - for part in sorted(data[year][day].keys()): - part_data = data[year][day][part] + # Add timing data for each user + for user in sorted(users): + time_data = part_data.get(user, 0) - if not part_data: - continue - - # Find fastest and slowest (using total time) - times = [] - for user, time_data in part_data.items(): + if time_data == 0 or (isinstance(time_data, dict) and time_data.get('total', 0) == 0): + html += ' \n' + else: + # Extract times if isinstance(time_data, dict): - total_time = time_data.get('total', 0) + total_time_ns = time_data.get('total', 0) + runner_time_ns = time_data.get('runner', 0) + generator_time_ns = time_data.get('generator', 0) + git_rev = time_data.get('git_rev', '') + repo_url = time_data.get('repo_url', '') else: - # Backward compatibility with old format - total_time = time_data if time_data > 0 else 0 - if total_time > 0: - times.append((user, time_data, total_time)) - - if not times: - continue - - times.sort(key=lambda x: x[2]) # Sort by total time - fastest_time = times[0][2] - slowest_time = times[-1][2] - - # Get git rev and repo_url for historical data link - first_user_data = times[0][1] if isinstance(times[0][1], dict) else {} - sample_git_rev = first_user_data.get('git_rev', '') - sample_repo_url = first_user_data.get('repo_url', '') - - html += f""" -
-

Part {part}

-
Day/Part{user}{git_rev_html}
Day {day} Part {part}-
- - - - - - - - - - - -""" - - # Sort users by total time (include all users, even if no data) - user_times = [] - for user in users: - time_data = part_data.get(user, 0) - if isinstance(time_data, dict): - total_time = time_data.get('total', 0) + # Backward compatibility + total_time_ns = time_data + runner_time_ns = total_time_ns + generator_time_ns = 0 + git_rev = '' + repo_url = '' + + # Format total time + total_ms = total_time_ns / 1_000_000 + total_us = total_time_ns / 1_000 + if total_ms >= 1: + total_str = f"{total_ms:.2f} ms" + elif total_us >= 1: + total_str = f"{total_us:.2f} μs" else: - total_time = time_data if time_data > 0 else 0 - user_times.append((user, time_data, total_time)) - - sorted_users = sorted(user_times, key=lambda x: x[2] if x[2] > 0 else float('inf')) - - for user, time_data, total_time_ns in sorted_users: - if total_time_ns == 0: - html += f""" - - - - - - - - -""" - else: - # Extract times and metadata - if isinstance(time_data, dict): - runner_time_ns = time_data.get('runner', 0) - generator_time_ns = time_data.get('generator', 0) - git_rev = time_data.get('git_rev', '') - repo_url = time_data.get('repo_url', '') - else: - # Backward compatibility - runner_time_ns = total_time_ns - generator_time_ns = 0 - git_rev = '' - repo_url = '' - - # Format total time - total_ms = total_time_ns / 1_000_000 - total_us = total_time_ns / 1_000 - if total_ms >= 1: - total_str = f"{total_ms:.2f} ms" - elif total_us >= 1: - total_str = f"{total_us:.2f} μs" - else: - total_str = f"{total_time_ns} ns" - - # Format generator time - gen_ms = generator_time_ns / 1_000_000 - gen_us = generator_time_ns / 1_000 - if gen_ms >= 1: - gen_str = f"{gen_ms:.2f} ms" - elif gen_us >= 1: - gen_str = f"{gen_us:.2f} μs" - elif generator_time_ns > 0: - gen_str = f"{generator_time_ns} ns" - else: - gen_str = "-" - - # Format runner time - run_ms = runner_time_ns / 1_000_000 - run_us = runner_time_ns / 1_000 - if run_ms >= 1: - run_str = f"{run_ms:.2f} ms" - elif run_us >= 1: - run_str = f"{run_us:.2f} μs" - else: - run_str = f"{runner_time_ns} ns" - - # Calculate relative speed (based on total time) - if fastest_time > 0: - relative = total_time_ns / fastest_time - relative_str = f"{relative:.2f}x" - else: - relative_str = "-" - - # Determine if fastest or slowest - row_class = "" - if total_time_ns == fastest_time: - row_class = "fastest" - elif total_time_ns == slowest_time and len(times) > 1: - row_class = "slowest" - - # Format git rev with link if available - if git_rev and repo_url: - # Create link to commit - commit_url = repo_url.rstrip('/') + '/commit/' + git_rev - git_rev_html = f'{git_rev[:7]}' - elif git_rev: - git_rev_html = git_rev[:7] - else: - git_rev_html = '-' - - # Get historical data for this user/day/part - historical = db.get_historical_results(user, year, day, part) - history_html = "" - if len(historical) > 1: - history_items = [] - for hist in historical[:10]: # Show last 10 runs - hist_total = hist['time_ns'] + hist.get('generator_time_ns', 0) - hist_ms = hist_total / 1_000_000 - hist_us = hist_total / 1_000 - if hist_ms >= 1: - hist_time_str = f"{hist_ms:.2f} ms" - elif hist_us >= 1: - hist_time_str = f"{hist_us:.2f} μs" - else: - hist_time_str = f"{hist_total} ns" - - hist_git = hist.get('git_rev', '')[:7] if hist.get('git_rev') else '-' - hist_date = hist.get('timestamp', '')[:16] if hist.get('timestamp') else '' - history_items.append(f'
{hist_date}: {hist_time_str} ({hist_git})
') + total_str = f"{total_time_ns} ns" + + # Determine if fastest + cell_class = "" + if fastest_time > 0 and total_time_ns == fastest_time: + cell_class = "fastest" + + # Get historical data for this user/day/part + historical = db.get_historical_results(user, year, day, part) + history_link = "" + if len(historical) > 1: + history_items = [] + for hist in historical[:10]: # Show last 10 runs + hist_total = hist['time_ns'] + hist.get('generator_time_ns', 0) + hist_ms = hist_total / 1_000_000 + hist_us = hist_total / 1_000 + if hist_ms >= 1: + hist_time_str = f"{hist_ms:.2f} ms" + elif hist_us >= 1: + hist_time_str = f"{hist_us:.2f} μs" + else: + hist_time_str = f"{hist_total} ns" - history_html = f''' + hist_git = hist.get('git_rev', '')[:7] if hist.get('git_rev') else '-' + hist_date = hist.get('timestamp', '')[:16] if hist.get('timestamp') else '' + history_items.append(f'
{hist_date}: {hist_time_str} ({hist_git})
') + + history_html = f'''
History: {''.join(history_items)}
''' - history_link = f'📊' - else: - history_link = "" - - html += f""" - - - - - - - - -{history_html} -""" - - html += """ - -
UserTotal TimeGeneratorRunnerGit RevRelative Speed
{user}No data----
{user}{history_link}{total_str}{gen_str}{run_str}{git_rev_html}{relative_str}
- + row_history_htmls.append(history_html) + history_link = f' 📊' + + html += f' {total_str}{history_link}\n' + + html += """ """ - html += """ - -""" + # Add history HTML after the row + for hist_html in row_history_htmls: + html += hist_html - html += """ + html += """ + """