Transpose table of results
This commit is contained in:
parent
9a76b0496f
commit
d1bdecf5e7
339
aocsync.py
339
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:
|
||||
<h2 class="year-header">Year {year}</h2>
|
||||
"""
|
||||
|
||||
# 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 += "<p>No data available for this year.</p>"
|
||||
html += "</div>"
|
||||
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 += """
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Day/Part</th>
|
||||
"""
|
||||
|
||||
# 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'<br><small><a href="{commit_url}" target="_blank" title="View commit">{git_rev[:7]}</a></small>'
|
||||
elif git_rev:
|
||||
git_rev_html = f'<br><small>{git_rev[:7]}</small>'
|
||||
else:
|
||||
git_rev_html = ''
|
||||
|
||||
html += f' <th>{user}{git_rev_html}</th>\n'
|
||||
|
||||
html += """ </tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
"""
|
||||
|
||||
# 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"""
|
||||
<div class="day-section">
|
||||
<h3 class="day-header">Day {day}</h3>
|
||||
<tr>
|
||||
<td><strong>Day {day} Part {part}</strong></td>
|
||||
"""
|
||||
|
||||
# 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 += ' <td class="no-data">-</td>\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"""
|
||||
<div class="part-section">
|
||||
<h4 class="part-header">Part {part}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Total Time</th>
|
||||
<th>Generator</th>
|
||||
<th>Runner</th>
|
||||
<th>Git Rev</th>
|
||||
<th>Relative Speed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
"""
|
||||
|
||||
# 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"""
|
||||
<tr>
|
||||
<td>{user}</td>
|
||||
<td class="no-data">No data</td>
|
||||
<td class="no-data">-</td>
|
||||
<td class="no-data">-</td>
|
||||
<td class="no-data">-</td>
|
||||
<td class="no-data">-</td>
|
||||
</tr>
|
||||
"""
|
||||
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'<a href="{commit_url}" target="_blank" title="View commit">{git_rev[:7]}</a>'
|
||||
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'<div class="history-item">{hist_date}: {hist_time_str} ({hist_git})</div>')
|
||||
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'<div class="history-item">{hist_date}: {hist_time_str} ({hist_git})</div>')
|
||||
|
||||
history_html = f'''
|
||||
<div class="history-data" id="history-{user}-{year}-{day}-{part}">
|
||||
<strong>History:</strong>
|
||||
{''.join(history_items)}
|
||||
</div>
|
||||
'''
|
||||
history_link = f'<span class="history-link" onclick="toggleHistory(\'{user}\', {year}, {day}, {part})">📊</span>'
|
||||
else:
|
||||
history_link = ""
|
||||
|
||||
html += f"""
|
||||
<tr class="{row_class}">
|
||||
<td>{user}{history_link}</td>
|
||||
<td class="time">{total_str}</td>
|
||||
<td class="time">{gen_str}</td>
|
||||
<td class="time">{run_str}</td>
|
||||
<td>{git_rev_html}</td>
|
||||
<td>{relative_str}</td>
|
||||
</tr>
|
||||
{history_html}
|
||||
"""
|
||||
|
||||
html += """
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
row_history_htmls.append(history_html)
|
||||
history_link = f' <span class="history-link" onclick="toggleHistory(\'{user}\', {year}, {day}, {part})">📊</span>'
|
||||
|
||||
html += f' <td class="time {cell_class}">{total_str}{history_link}</td>\n'
|
||||
|
||||
html += """ </tr>
|
||||
"""
|
||||
|
||||
html += """
|
||||
</div>
|
||||
"""
|
||||
# Add history HTML after the row
|
||||
for hist_html in row_history_htmls:
|
||||
html += hist_html
|
||||
|
||||
html += """
|
||||
html += """ </tbody>
|
||||
</table>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user