fixes for better stats

This commit is contained in:
Bob 2025-12-15 08:18:24 -08:00
parent b86bb81110
commit d290589888
3 changed files with 45 additions and 27 deletions

View File

@ -27,7 +27,7 @@ static EventGroupHandle_t s_iperf_event_group = NULL;
#define IPERF_IP_READY_BIT (1 << 0) #define IPERF_IP_READY_BIT (1 << 0)
#define IPERF_STOP_REQ_BIT (1 << 1) #define IPERF_STOP_REQ_BIT (1 << 1)
#define RATE_CHECK_INTERVAL_US 500000 #define MIN_RATE_CHECK_INTERVAL_US 250000
#define MIN_PACING_INTERVAL_US 100 #define MIN_PACING_INTERVAL_US 100
typedef struct { typedef struct {
@ -105,32 +105,36 @@ void iperf_print_status(void) {
} }
// 3. Compute Session Bandwidth // 3. Compute Session Bandwidth
// Logic: If running, use current time. If stopped, use stored end time.
float avg_bw_mbps = 0.0f; float avg_bw_mbps = 0.0f;
if (s_session_start_time > 0) { if (s_session_start_time > 0) {
int64_t end_t = (s_stats.running) ? esp_timer_get_time() : s_session_end_time; int64_t end_t = (s_stats.running) ? esp_timer_get_time() : s_session_end_time;
if (end_t > s_session_start_time) { if (end_t > s_session_start_time) {
double duration_sec = (double)(end_t - s_session_start_time) / 1000000.0; double duration_sec = (double)(end_t - s_session_start_time) / 1000000.0;
// Only calc if duration is significant to avoid divide-by-tiny-number
if (duration_sec > 0.001) { if (duration_sec > 0.001) {
// Total bits = packets * packet_size * 8
double total_bits = (double)s_session_packets * (double)s_iperf_ctrl.cfg.send_len * 8.0; double total_bits = (double)s_session_packets * (double)s_iperf_ctrl.cfg.send_len * 8.0;
avg_bw_mbps = (float)(total_bits / duration_sec / 1000000.0); avg_bw_mbps = (float)(total_bits / duration_sec / 1000000.0);
} }
} }
} }
// New Format: Standard Stats // 4. Calculate State Percentages
double total_us = (double)(s_time_tx_us + s_time_slow_us + s_time_stalled_us);
if (total_us < 1.0) total_us = 1.0; // Prevent div/0
double pct_tx = ((double)s_time_tx_us / total_us) * 100.0;
double pct_slow = ((double)s_time_slow_us / total_us) * 100.0;
double pct_stalled = ((double)s_time_stalled_us / total_us) * 100.0;
// Standard Stats
printf("IPERF_STATUS: Src=%s, Dst=%s, Running=%d, Config=%" PRIu32 ", Actual=%" PRIu32 ", Err=%.1f%%, Pkts=%" PRIu64 ", AvgBW=%.2f Mbps\n", printf("IPERF_STATUS: Src=%s, Dst=%s, Running=%d, Config=%" PRIu32 ", Actual=%" PRIu32 ", Err=%.1f%%, Pkts=%" PRIu64 ", AvgBW=%.2f Mbps\n",
src_ip, dst_ip, s_stats.running, s_stats.config_pps, s_stats.actual_pps, err, s_session_packets, avg_bw_mbps); src_ip, dst_ip, s_stats.running, s_stats.config_pps, s_stats.actual_pps, err, s_session_packets, avg_bw_mbps);
// New Format: State Durations & Edges // New Format: Time + Percentage + Edges
printf("IPERF_STATES: TX=%.2fs (%lu), SLOW=%.2fs (%lu), STALLED=%.2fs (%lu)\n", // Example: TX=15.15s/28.5% (15)
(double)s_time_tx_us/1000000.0, (unsigned long)s_edge_tx, printf("IPERF_STATES: TX=%.2fs/%.1f%% (%lu), SLOW=%.2fs/%.1f%% (%lu), STALLED=%.2fs/%.1f%% (%lu)\n",
(double)s_time_slow_us/1000000.0, (unsigned long)s_edge_slow, (double)s_time_tx_us/1000000.0, pct_tx, (unsigned long)s_edge_tx,
(double)s_time_stalled_us/1000000.0, (unsigned long)s_edge_stalled); (double)s_time_slow_us/1000000.0, pct_slow, (unsigned long)s_edge_slow,
(double)s_time_stalled_us/1000000.0, pct_stalled, (unsigned long)s_edge_stalled);
} }
// --- Network Events --- // --- Network Events ---

View File

@ -59,23 +59,26 @@ class SerialController(asyncio.Protocol):
} }
elif "IPERF_STATES" in line: elif "IPERF_STATES" in line:
m = re.search(r'TX=([\d\.]+)s \((\d+)\), SLOW=([\d\.]+)s \((\d+)\), STALLED=([\d\.]+)s \((\d+)\)', line) # NEW REGEX: Matches "TX=15.15s/28.5% (15)"
# Groups: 1=Time, 2=Pct, 3=Count (Repeated for SLOW and STALLED)
m = re.search(r'TX=([\d\.]+)s/([\d\.]+)% \((\d+)\), SLOW=([\d\.]+)s/([\d\.]+)% \((\d+)\), STALLED=([\d\.]+)s/([\d\.]+)% \((\d+)\)', line)
if m: if m:
self.status_data['states'] = { self.status_data['states'] = {
'tx_t': m.group(1), 'tx_c': m.group(2), 'tx_t': m.group(1), 'tx_p': m.group(2), 'tx_c': m.group(3),
'sl_t': m.group(3), 'sl_c': m.group(4), 'sl_t': m.group(4), 'sl_p': m.group(5), 'sl_c': m.group(6),
'st_t': m.group(5), 'st_c': m.group(6) 'st_t': m.group(7), 'st_p': m.group(8), 'st_c': m.group(9)
} }
if 'main' in self.status_data and 'states' in self.status_data: if 'main' in self.status_data and 'states' in self.status_data:
if not self.completion_future.done(): if not self.completion_future.done():
d = self.status_data['main'] d = self.status_data['main']
s = self.status_data['states'] s = self.status_data['states']
# Updated Output Format
output = (f"{d['src']} -> {d['dst']} | {d['run']}, " output = (f"{d['src']} -> {d['dst']} | {d['run']}, "
f"Cfg:{d['cfg']}, Act:{d['act']}, Err:{d['err']}%, Pkts:{d['pkts']}, BW:{d['bw']}M | " f"Cfg:{d['cfg']}, Act:{d['act']}, Err:{d['err']}%, Pkts:{d['pkts']}, BW:{d['bw']}M | "
f"TX:{s['tx_t']}s({s['tx_c']}) " f"TX:{s['tx_t']}s/{s['tx_p']}%({s['tx_c']}) "
f"SL:{s['sl_t']}s({s['sl_c']}) " f"SL:{s['sl_t']}s/{s['sl_p']}%({s['sl_c']}) "
f"ST:{s['st_t']}s({s['st_c']})") f"ST:{s['st_t']}s/{s['st_p']}%({s['st_c']})")
self.completion_future.set_result(output) self.completion_future.set_result(output)
self.transport.close() self.transport.close()
return return

View File

@ -588,19 +588,30 @@ async def run_deployment(args):
max_c = args.max_concurrent if args.max_concurrent else (1 if args.devices and not args.config_only else DEFAULT_MAX_CONCURRENT_FLASH) max_c = args.max_concurrent if args.max_concurrent else (1 if args.devices and not args.config_only else DEFAULT_MAX_CONCURRENT_FLASH)
flash_sem = asyncio.Semaphore(max_c) flash_sem = asyncio.Semaphore(max_c)
tasks = [] tasks = []
for i, dev in enumerate(devs): for i, dev in enumerate(devs):
# --- ROBUST IP CALCULATION LOGIC --- # --- ROBUST IP CALCULATION LOGIC ---
if args.ip_device_based: if args.ip_device_based:
# Mode A: Offset based on physical port number (e.g. 14 for ttyUSB14) # Mode A: Offset based on physical port number (e.g. 14 for esp_port_14)
offset = extract_device_number(dev.device) raw_port_number = extract_device_number(dev.device)
print(f" [{dev.device}] Using device-based IP offset: +{offset}")
else: # FIX: Subtract 1 from the raw port number to make the offset zero-based.
# Mode B: Sequential offset based on loop index # This ensures esp_port_1 gets the exact --start-ip (offset 0).
offset = i offset = raw_port_number - 1
print(f" [{dev.device}] Using sequential IP offset: +{offset}")
target_ip = str(start_ip + offset) target_ip = str(start_ip + offset)
# Display the result using the clear 'DEVICE IP' label
print(f" [{dev.device}] Using device-based IP offset: +{offset} (Raw Port: {raw_port_number}). DEVICE IP: {target_ip}")
else:
# Mode B: Sequential offset based on loop index (zero-based)
offset = i
target_ip = str(start_ip + offset)
# Display the result using the clear 'DEVICE IP' label
print(f" [{dev.device}] Using sequential IP offset: +{offset}. DEVICE IP: {target_ip}")
tasks.append(UnifiedDeployWorker(dev.device, target_ip, args, project_dir, flash_sem).run()) tasks.append(UnifiedDeployWorker(dev.device, target_ip, args, project_dir, flash_sem).run())
results = await asyncio.gather(*tasks) results = await asyncio.gather(*tasks)