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; 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 {{ table {{
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@ -1141,207 +1156,163 @@ class HTMLGenerator:
<h2 class="year-header">Year {year}</h2> <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 day in sorted(data[year].keys()):
html += f"""
<div class="day-section">
<h3 class="day-header">Day {day}</h3>
"""
# Generate content for each part
for part in sorted(data[year][day].keys()): for part in sorted(data[year][day].keys()):
part_data = data[year][day][part] day_part_combos.append((day, part))
if not part_data: if not day_part_combos:
continue html += "<p>No data available for this year.</p>"
html += "</div>"
continue
# Find fastest and slowest (using total time) # Collect user info (git rev, repo_url) for header
times = [] user_info = {}
for user, time_data in part_data.items(): 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 isinstance(time_data, dict):
total_time = time_data.get('total', 0) if not user_info[user]['git_rev']:
else: user_info[user]['git_rev'] = time_data.get('git_rev', '')
# Backward compatibility with old format if not user_info[user]['repo_url']:
total_time = time_data if time_data > 0 else 0 user_info[user]['repo_url'] = time_data.get('repo_url', '')
if total_time > 0:
times.append((user, time_data, total_time))
if not times: # Find fastest times per day/part for highlighting
continue 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)
times.sort(key=lambda x: x[2]) # Sort by total time # Create table with transposed structure
fastest_time = times[0][2] html += """
slowest_time = times[-1][2] <table>
<thead>
# Get git rev and repo_url for historical data link <tr>
first_user_data = times[0][1] if isinstance(times[0][1], dict) else {} <th>Day/Part</th>
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) # Add user columns with git rev in header
user_times = [] for user in sorted(users):
for user in users: git_rev = user_info[user]['git_rev']
time_data = part_data.get(user, 0) repo_url = user_info[user]['repo_url']
if isinstance(time_data, dict):
total_time = time_data.get('total', 0)
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')) 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 = ''
for user, time_data, total_time_ns in sorted_users: html += f' <th>{user}{git_rev_html}</th>\n'
if total_time_ns == 0:
html += f""" html += """ </tr>
<tr> </thead>
<td>{user}</td> <tbody>
<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>
""" """
# 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"""
<tr>
<td><strong>Day {day} Part {part}</strong></td>
"""
# Add timing data for each user
for user in sorted(users):
time_data = part_data.get(user, 0)
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_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: else:
# Extract times and metadata # Backward compatibility
if isinstance(time_data, dict): total_time_ns = time_data
runner_time_ns = time_data.get('runner', 0) runner_time_ns = total_time_ns
generator_time_ns = time_data.get('generator', 0) generator_time_ns = 0
git_rev = time_data.get('git_rev', '') git_rev = ''
repo_url = time_data.get('repo_url', '') repo_url = ''
else:
# Backward compatibility
runner_time_ns = total_time_ns
generator_time_ns = 0
git_rev = ''
repo_url = ''
# Format total time # Format total time
total_ms = total_time_ns / 1_000_000 total_ms = total_time_ns / 1_000_000
total_us = total_time_ns / 1_000 total_us = total_time_ns / 1_000
if total_ms >= 1: if total_ms >= 1:
total_str = f"{total_ms:.2f} ms" total_str = f"{total_ms:.2f} ms"
elif total_us >= 1: elif total_us >= 1:
total_str = f"{total_us:.2f} μs" total_str = f"{total_us:.2f} μs"
else: else:
total_str = f"{total_time_ns} ns" total_str = f"{total_time_ns} ns"
# Format generator time # Determine if fastest
gen_ms = generator_time_ns / 1_000_000 cell_class = ""
gen_us = generator_time_ns / 1_000 if fastest_time > 0 and total_time_ns == fastest_time:
if gen_ms >= 1: cell_class = "fastest"
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 # Get historical data for this user/day/part
run_ms = runner_time_ns / 1_000_000 historical = db.get_historical_results(user, year, day, part)
run_us = runner_time_ns / 1_000 history_link = ""
if run_ms >= 1: if len(historical) > 1:
run_str = f"{run_ms:.2f} ms" history_items = []
elif run_us >= 1: for hist in historical[:10]: # Show last 10 runs
run_str = f"{run_us:.2f} μs" hist_total = hist['time_ns'] + hist.get('generator_time_ns', 0)
else: hist_ms = hist_total / 1_000_000
run_str = f"{runner_time_ns} ns" 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"
# Calculate relative speed (based on total time) hist_git = hist.get('git_rev', '')[:7] if hist.get('git_rev') else '-'
if fastest_time > 0: hist_date = hist.get('timestamp', '')[:16] if hist.get('timestamp') else ''
relative = total_time_ns / fastest_time history_items.append(f'<div class="history-item">{hist_date}: {hist_time_str} ({hist_git})</div>')
relative_str = f"{relative:.2f}x"
else:
relative_str = "-"
# Determine if fastest or slowest history_html = f'''
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>')
history_html = f'''
<div class="history-data" id="history-{user}-{year}-{day}-{part}"> <div class="history-data" id="history-{user}-{year}-{day}-{part}">
<strong>History:</strong> <strong>History:</strong>
{''.join(history_items)} {''.join(history_items)}
</div> </div>
''' '''
history_link = f'<span class="history-link" onclick="toggleHistory(\'{user}\', {year}, {day}, {part})">📊</span>' row_history_htmls.append(history_html)
else: history_link = f' <span class="history-link" onclick="toggleHistory(\'{user}\', {year}, {day}, {part})">📊</span>'
history_link = ""
html += f""" html += f' <td class="time {cell_class}">{total_str}{history_link}</td>\n'
<tr class="{row_class}">
<td>{user}{history_link}</td> html += """ </tr>
<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 += """ # Add history HTML after the row
</tbody> for hist_html in row_history_htmls:
</table> html += hist_html
</div>
"""
html += """ html += """ </tbody>
</div> </table>
"""
html += """
</div> </div>
""" """