diff --git a/common/generate_combined_report.py b/common/generate_combined_report.py
index 1328f64..9722bde 100755
--- a/common/generate_combined_report.py
+++ b/common/generate_combined_report.py
@@ -7,6 +7,7 @@
from plotly.subplots import make_subplots
from datetime import datetime
import json
+import html
def read_system_info(info_file):
"""Read and parse system information file."""
@@ -52,13 +53,10 @@ def read_system_info(info_file):
def generate_gpu_graph(csv_file):
"""Generate GPU performance graph from GPU data."""
try:
- # Read GPU CSV data
df = pd.read_csv(csv_file)
-
if df.empty or 'gpu_load' not in df.columns:
return None, 0
- # Create GPU load trace with frequency in hover
gpu_hover = []
for _, row in df.iterrows():
text = f"GPU Load: {row['gpu_load']:.0f}% "
@@ -77,15 +75,41 @@ def generate_gpu_graph(csv_file):
text=gpu_hover
)
- # Calculate test duration
duration = df['seconds'].iloc[-1] / 60 if len(df) > 0 else 1
-
return trace, duration
except Exception as e:
print(f"Error processing GPU data: {e}")
return None, 0
+def generate_network_graph(csv_file):
+ """Generate Network Latency graph from test metrics."""
+ try:
+ df = pd.read_csv(csv_file)
+ if df.empty or 'Latency_ms' not in df.columns:
+ return None
+
+ network_hover = []
+ for _, row in df.iterrows():
+ text = f"Status: {row['Interface_Status']} "
+ text += f"Time: {row['seconds']}s "
+ text += f"Latency: {row['Latency_ms']:.2f} ms "
+ network_hover.append(text)
+
+ trace = go.Scatter(
+ x=df['seconds'],
+ y=df['Latency_ms'],
+ mode='lines+markers',
+ name='Network Latency (ms)',
+ line=dict(color='#00A8FF', width=2),
+ hovertemplate='%{text}',
+ text=network_hover
+ )
+ return trace
+ except Exception as e:
+ print(f"Error processing network data: {e}")
+ return None
+
def generate_temperature_graph(csv_file):
"""Generate temperature graph for backward compatibility."""
if not os.path.exists(csv_file):
@@ -127,51 +151,28 @@ def generate_temperature_graph(csv_file):
def generate_system_graphs(csv_file):
"""Generate system monitoring graphs with temperature, CPU load, and CPU frequency."""
-
if not os.path.exists(csv_file):
return [], None
try:
- # Read CSV, skipping metadata line if present
- with open(csv_file, 'r') as f:
- first_line = f.readline()
- metadata = {}
- if first_line.startswith('# METADATA:'):
- import json
- metadata_str = first_line.replace('# METADATA:', '').strip()
- metadata = json.loads(metadata_str)
-
- # Read the actual data
df = pd.read_csv(csv_file, comment='#')
-
- if df.empty:
- return [], None
-
- # Use seconds column for time axis
- if 'seconds' in df.columns:
- df['time'] = df['seconds']
- time_column = 'time'
- else:
+ if df.empty or 'seconds' not in df.columns:
return [], None
+ time_column = 'seconds'
traces = []
- # 1. Temperature trace (average with hover details)
+ # 1. Temperature trace
temp_columns = [col for col in df.columns if col.startswith('temp_')]
if temp_columns:
- # Convert to numeric
for col in temp_columns:
df[col] = pd.to_numeric(df[col], errors='coerce')
-
- # Calculate average
df['avg_temp'] = df[temp_columns].mean(axis=1)
- # Create hover text
temp_hover = []
for idx, row in df.iterrows():
text = f"Avg Temperature: {row['avg_temp']:.1f}°C "
- text += f"Time: {row[time_column]:.1f}s "
- text += " Sensors: "
+ text += f"Time: {row[time_column]:.1f}s
Sensors: "
for col in temp_columns:
sensor_name = col.replace('temp_', '').replace('_', ' ').title()
if pd.notna(row[col]):
@@ -179,33 +180,22 @@ def generate_system_graphs(csv_file):
temp_hover.append(text)
traces.append(go.Scatter(
- x=df[time_column],
- y=df['avg_temp'],
- mode='lines',
- name='Temperature (°C)',
- line=dict(color='#FF6B6B', width=2),
- hovertemplate='%{text}',
- text=temp_hover,
- visible=True,
- yaxis='y'
+ x=df[time_column], y=df['avg_temp'], mode='lines',
+ name='Temperature (°C)', line=dict(color='#FF6B6B', width=2),
+ hovertemplate='%{text}', text=temp_hover, yaxis='y'
))
- # 2. CPU Load trace (average with hover details)
+ # 2. CPU Load trace
load_columns = [col for col in df.columns if col.startswith('load_')]
if load_columns:
- # Convert to numeric
for col in load_columns:
df[col] = pd.to_numeric(df[col], errors='coerce')
-
- # Calculate average
df['avg_load'] = df[load_columns].mean(axis=1)
- # Create hover text
load_hover = []
for idx, row in df.iterrows():
text = f"Avg CPU Load: {row['avg_load']:.1f}% "
- text += f"Time: {row[time_column]:.1f}s "
- text += " Per Core: "
+ text += f"Time: {row[time_column]:.1f}s
Per Core: "
for col in sorted(load_columns):
core_num = col.replace('load_cpu', '')
if pd.notna(row[col]):
@@ -213,34 +203,23 @@ def generate_system_graphs(csv_file):
load_hover.append(text)
traces.append(go.Scatter(
- x=df[time_column],
- y=df['avg_load'],
- mode='lines',
- name='CPU Load (%)',
- line=dict(color='#4ECDC4', width=2),
- hovertemplate='%{text}',
- text=load_hover,
- visible=True,
- yaxis='y2'
+ x=df[time_column], y=df['avg_load'], mode='lines',
+ name='CPU Load (%)', line=dict(color='#4ECDC4', width=2),
+ hovertemplate='%{text}', text=load_hover, yaxis='y2'
))
- # 3. CPU Frequency trace (average with hover details)
+ # 3. CPU Frequency trace
freq_columns = [col for col in df.columns if col.startswith('freq_')]
if freq_columns:
- # Convert to numeric
for col in freq_columns:
df[col] = pd.to_numeric(df[col], errors='coerce')
-
- # Calculate average
df['avg_freq'] = df[freq_columns].mean(axis=1)
- # Create hover text
freq_hover = []
for idx, row in df.iterrows():
text = f"Avg CPU Freq: {row['avg_freq']:.0f} MHz "
- text += f"Time: {row[time_column]:.1f}s "
- text += " Per Core: "
- for i, col in enumerate(sorted(freq_columns)):
+ text += f"Time: {row[time_column]:.1f}s
Per Core: "
+ for col in sorted(freq_columns):
core_num = col.replace('freq_cpu', '')
if pd.notna(row[col]):
core_type = "LITTLE" if int(core_num) < 4 else "BIG"
@@ -248,36 +227,23 @@ def generate_system_graphs(csv_file):
freq_hover.append(text)
traces.append(go.Scatter(
- x=df[time_column],
- y=df['avg_freq'],
- mode='lines',
- name='CPU Frequency (MHz)',
- line=dict(color='#95E77E', width=2),
- hovertemplate='%{text}',
- text=freq_hover,
- visible=True,
- yaxis='y3'
+ x=df[time_column], y=df['avg_freq'], mode='lines',
+ name='CPU Frequency (MHz)', line=dict(color='#95E77E', width=2),
+ hovertemplate='%{text}', text=freq_hover, yaxis='y3'
))
-
- # Calculate test duration
- duration = df[time_column].iloc[-1] / 60 # Convert seconds to minutes
-
+ duration = df[time_column].iloc[-1] / 60
return traces, max(0.1, duration)
except Exception as e:
print(f"Error processing system data: {e}")
- import traceback
- traceback.print_exc()
return [], None
def generate_combined_report(results_dir):
"""Generate a combined HTML report for all tests."""
-
- # Read system information
system_info = read_system_info(os.path.join(results_dir, 'system_info.txt'))
- # Check for CPU stress test marker
+ # Check for CPU stress markers and log
cpu_stress_status = None
cpu_stress_log_content = ""
cpu_stress_marker_file = os.path.join(results_dir, 'cpu_stress_marker.txt')
@@ -285,18 +251,16 @@ def generate_combined_report(results_dir):
with open(cpu_stress_marker_file, 'r') as f:
marker_content = f.read()
if 'CPU_STRESS=RUNNING' in marker_content or 'PID=' in marker_content:
- cpu_stress_status = 'success' # Assume success if marker exists
+ cpu_stress_status = 'success'
elif 'STATUS=FAILED' in marker_content:
cpu_stress_status = 'failed'
-
- # Read CPU stress log content
+
cpu_stress_log_file = os.path.join(results_dir, 'cpu_stress.log')
if os.path.exists(cpu_stress_log_file):
with open(cpu_stress_log_file, 'r') as f:
- import html
cpu_stress_log_content = html.escape(f.read())
- # Check for GPU stress test marker and read log
+ # Check for GPU stress markers and log
gpu_stress_status = None
gpu_stress_log_content = ""
gpu_info_content = ""
@@ -305,19 +269,15 @@ def generate_combined_report(results_dir):
with open(gpu_stress_marker_file, 'r') as f:
marker_content = f.read()
if 'GPU_STRESS=RUNNING' in marker_content or 'PID=' in marker_content:
- gpu_stress_status = 'success' # Assume success if marker exists
+ gpu_stress_status = 'success'
elif 'STATUS=FAILED' in marker_content:
gpu_stress_status = 'failed'
-
- # Read GPU stress log content
+
gpu_stress_log_file = os.path.join(results_dir, 'gpu_stress.log')
if os.path.exists(gpu_stress_log_file):
with open(gpu_stress_log_file, 'r') as f:
- import html
full_log = f.read()
gpu_stress_log_content = html.escape(full_log)
-
- # Extract GPU info from glmark2 header
if 'OpenGL Information' in full_log:
lines = full_log.split('\n')
in_header = False
@@ -333,149 +293,75 @@ def generate_combined_report(results_dir):
gpu_info_lines.append(line.strip())
gpu_info_content = html.escape('\n'.join(gpu_info_lines))
- # Read full system info for debug section
system_info_text = ""
system_info_file = os.path.join(results_dir, 'system_info.txt')
if os.path.exists(system_info_file):
with open(system_info_file, 'r') as f:
- import html
system_info_text = html.escape(f.read())
-
- # Try new system data format first, fall back to old temperature format
+
traces = []
test_duration = None
- # Check for new system_data.csv
if os.path.exists(os.path.join(results_dir, 'system_data.csv')):
traces, test_duration = generate_system_graphs(os.path.join(results_dir, 'system_data.csv'))
- # Fall back to old temperature_data.csv
elif os.path.exists(os.path.join(results_dir, 'temperature_data.csv')):
- # Use old temperature-only graph for backward compatibility
temp_trace, test_duration = generate_temperature_graph(os.path.join(results_dir, 'temperature_data.csv'))
- if temp_trace:
- traces = [temp_trace]
-
- # Generate separate GPU graph if available
+ if temp_trace: traces = [temp_trace]
+
gpu_graph_html = ""
if os.path.exists(os.path.join(results_dir, 'gpu_data.csv')):
gpu_trace, gpu_duration = generate_gpu_graph(os.path.join(results_dir, 'gpu_data.csv'))
if gpu_trace:
- # Create separate GPU figure
- gpu_fig = go.Figure()
- gpu_fig.add_trace(gpu_trace)
+ gpu_fig = go.Figure(data=[gpu_trace])
gpu_fig.update_layout(
- title={
- 'text': 'GPU Performance',
- 'x': 0.5,
- 'xanchor': 'center',
- 'font': {'size': 18, 'family': 'Arial, sans-serif'}
- },
+ title={'text': 'GPU Performance', 'x': 0.5, 'xanchor': 'center', 'font': {'size': 18}},
xaxis=dict(title="Time (seconds)"),
- yaxis=dict(
- title="GPU Load (%)",
- range=[0, 100],
- titlefont=dict(color="#FF9800"),
- tickfont=dict(color="#FF9800")
- ),
- height=400,
- margin=dict(l=60, r=60, t=60, b=60),
- plot_bgcolor='#f8f9fa',
- paper_bgcolor='white',
- hovermode='x'
+ yaxis=dict(title="GPU Load (%)", range=[0, 100], titlefont=dict(color="#FF9800"), tickfont=dict(color="#FF9800")),
+ height=400, margin=dict(l=60, r=60, t=60, b=60), plot_bgcolor='#f8f9fa', paper_bgcolor='white', hovermode='x'
)
gpu_graph_html = gpu_fig.to_html(include_plotlyjs=False).replace('