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:
"""
- # 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 += """
+
+
+
+ | Day/Part |
+"""
+
+ # 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' {user}{git_rev_html} | \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} Part {part} |
"""
- # 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"""
-
-
-
-
-
- | User |
- Total Time |
- Generator |
- Runner |
- Git Rev |
- Relative Speed |
-
-
-
-"""
-
- # 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"""
-
- | {user} |
- No data |
- - |
- - |
- - |
- - |
-
-"""
- 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"""
-
- | {user}{history_link} |
- {total_str} |
- {gen_str} |
- {run_str} |
- {git_rev_html} |
- {relative_str} |
-
-{history_html}
-"""
-
- html += """
-
-
-
+ 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 += """
+
"""