diff options
author | Balaji Sivaraman <balaji@balajisivaraman.com> | 2018-02-12 22:47:22 +0530 |
---|---|---|
committer | Andrew Gallant <jamslam@gmail.com> | 2018-03-10 10:59:00 -0500 |
commit | 00520b30f5f38e543e17b1a4cc5e8417bc488ea4 (patch) | |
tree | 154aee40835b6a0d2fe945ccc065ff3ee0b8d8c0 /src/main.rs | |
parent | 11a8f0eaf0f661c5b20c20fa2399314905d84fc1 (diff) |
output: add --stats flag
This commit provides basic support for a --stats flag, which will print
various aggregate statistics about a search after all of the results
have been printed. This is mostly intended to support a similar feature
found in the Silver Searcher. Note though that we don't emit the total
bytes searched; this is a first pass at an implementation and we can
improve upon it later.
Closes #411, Closes #799
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs index bc064816..f0be94c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc; use std::thread; +use std::time::{Duration, Instant}; use args::Args; use worker::Work; @@ -85,16 +86,19 @@ fn run(args: Arc<Args>) -> Result<u64> { } fn run_parallel(args: &Arc<Args>) -> Result<u64> { + let start_time = Instant::now(); let bufwtr = Arc::new(args.buffer_writer()); let quiet_matched = args.quiet_matched(); let paths_searched = Arc::new(AtomicUsize::new(0)); let match_line_count = Arc::new(AtomicUsize::new(0)); + let paths_matched = Arc::new(AtomicUsize::new(0)); args.walker_parallel().run(|| { let args = Arc::clone(args); let quiet_matched = quiet_matched.clone(); let paths_searched = paths_searched.clone(); let match_line_count = match_line_count.clone(); + let paths_matched = paths_matched.clone(); let bufwtr = Arc::clone(&bufwtr); let mut buf = bufwtr.buffer(); let mut worker = args.worker(); @@ -129,6 +133,9 @@ fn run_parallel(args: &Arc<Args>) -> Result<u64> { if quiet_matched.set_match(count > 0) { return Quit; } + if args.stats() && count > 0 { + paths_matched.fetch_add(1, Ordering::SeqCst); + } } // BUG(burntsushi): We should handle this error instead of ignoring // it. See: https://github.com/BurntSushi/ripgrep/issues/200 @@ -141,15 +148,28 @@ fn run_parallel(args: &Arc<Args>) -> Result<u64> { eprint_nothing_searched(); } } - Ok(match_line_count.load(Ordering::SeqCst) as u64) + let match_line_count = match_line_count.load(Ordering::SeqCst) as u64; + let paths_searched = paths_searched.load(Ordering::SeqCst) as u64; + let paths_matched = paths_matched.load(Ordering::SeqCst) as u64; + if args.stats() { + print_stats( + match_line_count, + paths_searched, + paths_matched, + start_time.elapsed(), + ); + } + Ok(match_line_count) } fn run_one_thread(args: &Arc<Args>) -> Result<u64> { + let start_time = Instant::now(); let stdout = args.stdout(); let mut stdout = stdout.lock(); let mut worker = args.worker(); let mut paths_searched: u64 = 0; let mut match_line_count = 0; + let mut paths_matched: u64 = 0; for result in args.walker() { let dent = match get_or_log_dir_entry( result, @@ -170,18 +190,30 @@ fn run_one_thread(args: &Arc<Args>) -> Result<u64> { } } paths_searched += 1; - match_line_count += + let count = if dent.is_stdin() { worker.run(&mut printer, Work::Stdin) } else { worker.run(&mut printer, Work::DirEntry(dent)) }; + match_line_count += count; + if args.stats() && count > 0 { + paths_matched += 1; + } } if !args.paths().is_empty() && paths_searched == 0 { if !args.no_messages() { eprint_nothing_searched(); } } + if args.stats() { + print_stats( + match_line_count, + paths_searched, + paths_matched, + start_time.elapsed(), + ); + } Ok(match_line_count) } @@ -373,6 +405,22 @@ fn eprint_nothing_searched() { Try running again with --debug."); } +fn print_stats( + match_count: u64, + paths_searched: u64, + paths_matched: u64, + time_elapsed: Duration, +) { + let time_elapsed = + time_elapsed.as_secs() as f64 + + (time_elapsed.subsec_nanos() as f64 * 1e-9); + println!("\n{} matched lines\n\ + {} files contained matches\n\ + {} files searched\n\ + {:.3} seconds", match_count, paths_matched, + paths_searched, time_elapsed); +} + // The Rust standard library suppresses the default SIGPIPE behavior, so that // writing to a closed pipe doesn't kill the process. The goal is to instead // handle errors through the normal result mechanism. Ripgrep needs some |