Transpose table of results

This commit is contained in:
Bill Thiede 2025-12-03 10:29:52 -08:00
parent 9a76b0496f
commit d1bdecf5e7

View File

@ -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>
"""