Skip to content

Commit 1c2f2b0

Browse files
committed
style: apply rustfmt code formatting
Applied automatic code formatting across multiple files to improve consistency and readability, including proper indentation, line breaks, and spacing according to Rust style guidelines.
1 parent 3551d9c commit 1c2f2b0

File tree

2 files changed

+106
-45
lines changed

2 files changed

+106
-45
lines changed

src/engine.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::template::TemplateEngine;
88
use crate::ui::LiveUI;
99
use anyhow::Result;
1010
use rand::Rng;
11+
use std::sync::atomic::{AtomicBool, Ordering};
1112
use std::sync::Arc;
1213
use std::time::{Duration, Instant};
1314
use tokio::sync::mpsc;
@@ -91,7 +92,6 @@ pub async fn run_benchmark(args: Args) -> Result<()> {
9192
final_stats.print_summary(args.latency);
9293
} else {
9394
// Print final summary after UI exits
94-
println!("\n=== Final Results ===");
9595
final_stats.print_summary(args.latency);
9696
}
9797

@@ -287,15 +287,28 @@ async fn run_benchmark_with_ui(
287287
let shared_stats = create_shared_stats();
288288
let shared_stats_for_ui = shared_stats.clone();
289289

290+
// Create stop flag for early termination (Ctrl+C)
291+
let stop_flag = Arc::new(AtomicBool::new(false));
292+
let stop_flag_for_ui = stop_flag.clone();
293+
290294
// Create channel for UI updates (send cloned stats snapshot)
291295
let (ui_tx, ui_rx) = mpsc::channel(100);
292296

293297
// Spawn UI task
294298
let ui_handle = tokio::spawn(async move {
295299
let mut ui = LiveUI::new(ui_rx, duration);
296-
if let Err(e) = ui.run().await {
297-
eprintln!("UI error: {}", e);
298-
}
300+
let result = match ui.run().await {
301+
Ok(interrupted) => interrupted,
302+
Err(e) => {
303+
eprintln!("UI error: {}", e);
304+
false
305+
}
306+
};
307+
308+
// Set stop flag when UI exits (either interrupted or completed)
309+
stop_flag_for_ui.store(true, Ordering::Release);
310+
311+
result
299312
});
300313

301314
// Spawn stats updater task
@@ -339,6 +352,7 @@ async fn run_benchmark_with_ui(
339352
template_engine,
340353
enable_http2,
341354
shared_stats,
355+
stop_flag,
342356
)
343357
})
344358
.await??;
@@ -353,8 +367,15 @@ async fn run_benchmark_with_ui(
353367
// Wait a bit for UI to render final update
354368
tokio::time::sleep(Duration::from_millis(200)).await;
355369

356-
// Wait for UI to finish
357-
let _ = ui_handle.await;
370+
// Wait for UI to finish and get interrupted status
371+
let interrupted = ui_handle.await.unwrap_or(false);
372+
373+
// Print message based on whether test was interrupted
374+
if interrupted {
375+
println!("\n=== Test Interrupted (Ctrl+C) ===");
376+
} else {
377+
println!("\n=== Test Completed ===");
378+
}
358379

359380
Ok(final_stats)
360381
}
@@ -370,6 +391,7 @@ fn run_workers_with_ui_updates(
370391
template_engine: Arc<TemplateEngine>,
371392
enable_http2: bool,
372393
shared_stats: SharedStats,
394+
stop_flag: Arc<AtomicBool>,
373395
) -> Result<Statistics> {
374396
let commands = Arc::new(commands);
375397
let end_time = Instant::now() + duration;
@@ -404,6 +426,7 @@ fn run_workers_with_ui_updates(
404426
let load_strategy = load_strategy.clone();
405427
let template_engine = template_engine.clone();
406428
let pool = pool.clone();
429+
let stop_flag = stop_flag.clone();
407430

408431
// 为每个线程创建独立的 tokio 运行时
409432
std::thread::spawn(move || {
@@ -421,13 +444,14 @@ fn run_workers_with_ui_updates(
421444
let load_strategy = load_strategy.clone();
422445
let template_engine = template_engine.clone();
423446
let client = pool.get_client().clone();
447+
let stop_flag = stop_flag.clone();
424448

425449
local.spawn_local(async move {
426450
// 创建客户端状态用于连接复用
427451
let mut client_state = ClientState::new();
428452
let mut request_count = 0u64;
429453

430-
while Instant::now() < end_time {
454+
while Instant::now() < end_time && !stop_flag.load(Ordering::Acquire) {
431455
// Select command based on load strategy
432456
let cmd = match load_strategy.as_str() {
433457
"round-robin" => &commands[request_count as usize % commands.len()],

src/ui.rs

Lines changed: 75 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ impl LiveUI {
236236
}
237237

238238
/// Run the Live-UI main loop
239-
pub async fn run(&mut self) -> Result<()> {
239+
/// Returns true if interrupted by user (Ctrl+C), false if completed normally
240+
pub async fn run(&mut self) -> Result<bool> {
240241
// Setup terminal
241242
enable_raw_mode()?;
242243
let mut stdout = std::io::stdout();
@@ -259,9 +260,13 @@ impl LiveUI {
259260
let mut last_request_count = 0u64;
260261
let mut last_rps_update = Instant::now();
261262

263+
// Track if interrupted by user
264+
let mut interrupted = false;
265+
262266
loop {
263267
// Check if we should stop
264268
if self.should_stop {
269+
interrupted = true;
265270
break;
266271
}
267272

@@ -335,7 +340,7 @@ impl LiveUI {
335340
disable_raw_mode()?;
336341
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
337342

338-
Ok(())
343+
Ok(interrupted)
339344
}
340345

341346
/// Render the UI
@@ -594,36 +599,20 @@ impl LiveUI {
594599

595600
let max_value = history.iter().copied().fold(0.0f64, f64::max).max(1.0);
596601

597-
// Build title with max value indicator
598-
let formatted_max = if max_value >= 1_000_000.0 {
599-
format!("{:.1}M", max_value / 1_000_000.0)
600-
} else if max_value >= 1_000.0 {
601-
format!("{:.1}K", max_value / 1_000.0)
602-
} else {
603-
format!("{:.1}", max_value)
604-
};
602+
// Build title with max value indicator using formatNumber rules
603+
let formatted_max = format_number_f64(max_value);
605604
let title = format!("Request Rate (Last 10s) - Max: {} req/s", formatted_max);
606605

607-
// Create bar chart data - use actual TPS values, not normalized percentages
606+
// Create bar chart data - label only shows time (1s, 2s, etc.)
608607
let bar_data: Vec<(String, u64)> = history
609608
.iter()
610609
.enumerate()
611610
.map(|(i, &value)| {
612-
// Format TPS value with K/M suffix
613-
let tps_str = if value >= 1_000_000.0 {
614-
format!("{:.0}M", value / 1_000_000.0)
615-
} else if value >= 1_000.0 {
616-
format!("{:.0}K", value / 1_000.0)
617-
} else {
618-
format!("{:.0}", value)
619-
};
620-
621-
// Label with time and formatted TPS: "1s\n92K"
622-
let label = format!("{}s\n{}", i + 1, tps_str);
611+
// Label only shows time
612+
let label = format!("{}s", i + 1);
623613

624-
// Use actual TPS value (as integer) for bar height
625-
let tps_value = value as u64;
626-
(label, tps_value)
614+
// Use actual TPS value for bar height
615+
(label, value as u64)
627616
})
628617
.collect();
629618

@@ -641,17 +630,56 @@ impl LiveUI {
641630
.title(title),
642631
)
643632
.data(&bar_data_refs)
644-
.bar_width(3)
633+
.bar_width(6)
645634
.bar_gap(1)
646635
.bar_style(Style::default().fg(self.theme.highlight_color()))
647-
.value_style(
648-
Style::default()
649-
.fg(self.theme.text_color())
650-
.add_modifier(Modifier::BOLD),
651-
)
652-
.label_style(Style::default().fg(self.theme.text_color()));
636+
.label_style(Style::default().fg(self.theme.text_color()))
637+
.value_style(Style::default().fg(Color::Black).bg(Color::Black)); // Hide raw values
653638

654639
f.render_widget(bar_chart, area);
640+
641+
// Manually render formatted numbers on top of bars
642+
let bar_width = 6u16;
643+
let bar_gap = 1u16;
644+
let total_bar_unit = bar_width + bar_gap;
645+
646+
// Calculate starting position for bars
647+
let inner_area = Rect {
648+
x: area.x + 1,
649+
y: area.y + 1,
650+
width: area.width.saturating_sub(2),
651+
height: area.height.saturating_sub(2),
652+
};
653+
654+
// Render formatted numbers above each bar
655+
for (i, &value) in history.iter().enumerate() {
656+
let formatted = format_number_f64(value);
657+
let bar_x = inner_area.x + 2 + (i as u16 * total_bar_unit);
658+
659+
// Calculate bar height as percentage of available height
660+
let chart_height = inner_area.height.saturating_sub(2); // Leave space for labels
661+
let bar_height_ratio = (value / max_value).min(1.0);
662+
let bar_height = (chart_height as f64 * bar_height_ratio) as u16;
663+
664+
// Position text on top of bar
665+
let text_y = inner_area.y + chart_height.saturating_sub(bar_height).saturating_sub(1);
666+
667+
if bar_x < inner_area.x + inner_area.width && text_y < inner_area.y + inner_area.height
668+
{
669+
let text_area = Rect {
670+
x: bar_x,
671+
y: text_y,
672+
width: bar_width,
673+
height: 1,
674+
};
675+
676+
let text = Paragraph::new(formatted)
677+
.style(Style::default().fg(self.theme.text_color()))
678+
.alignment(Alignment::Center);
679+
680+
f.render_widget(text, text_area);
681+
}
682+
}
655683
}
656684

657685
/// Render latency histogram (percentiles)
@@ -816,14 +844,23 @@ impl LiveUI {
816844
}
817845
}
818846

819-
/// Format large numbers with K/M suffix
847+
/// Format large numbers with K/M suffix (for u64)
820848
fn format_number(n: u64) -> String {
821-
if n >= 1_000_000 {
822-
format!("{:.1}M", n as f64 / 1_000_000.0)
823-
} else if n >= 1_000 {
824-
format!("{:.1}K", n as f64 / 1_000.0)
849+
format_number_f64(n as f64)
850+
}
851+
852+
/// Format large numbers with K/M suffix (for f64)
853+
/// Follows the formatting rules:
854+
/// - >= 1M: show with 1 decimal place (e.g., "1.5M")
855+
/// - >= 1K: show with no decimal places (e.g., "24K")
856+
/// - < 1K: show as integer (e.g., "500")
857+
fn format_number_f64(n: f64) -> String {
858+
if n >= 1_000_000.0 {
859+
format!("{:.1}M", n / 1_000_000.0)
860+
} else if n >= 1_000.0 {
861+
format!("{:.0}K", n / 1_000.0)
825862
} else {
826-
n.to_string()
863+
format!("{:.0}", n)
827864
}
828865
}
829866

0 commit comments

Comments
 (0)