1+ use std:: {
2+ fs,
3+ io,
4+ path:: Path ,
5+ sync:: { Arc , Mutex } ,
6+ } ;
7+
8+ use colored:: Colorize ;
9+
10+ use crate :: { RankMethod , index_directory, model:: { InMemoryModel , Model } } ;
11+
12+ // Benchmark function logic
13+ pub fn calculate_dir_size ( dir_path : & Path ) -> io:: Result < u64 > {
14+ let mut total_size = 0 ;
15+ if dir_path. is_dir ( ) {
16+ for entry in fs:: read_dir ( dir_path) ? {
17+ let entry = entry?;
18+ let path = entry. path ( ) ;
19+ if path. is_dir ( ) {
20+ total_size += calculate_dir_size ( & path) ?;
21+ } else {
22+ total_size += entry. metadata ( ) ?. len ( ) ;
23+ }
24+ }
25+ }
26+ Ok ( total_size)
27+ }
28+
29+ pub fn run_benchmark ( dir_path : & Path ) -> Result < ( ) , ( ) > {
30+ println ! ( "\n {}: Starting benchmarks on '{}'" , "INFO" . cyan( ) , dir_path. display( ) ) ;
31+
32+ // 1. Storage Efficiency
33+ let raw_size = calculate_dir_size ( dir_path) . unwrap_or ( 0 ) ;
34+ println ! ( "Raw Corpus Size: {:.2} MB" , raw_size as f64 / 1_048_576.0 ) ;
35+
36+ // 2. Indexing Throughput
37+ let model = Arc :: new ( Mutex :: < InMemoryModel > :: new ( Default :: default ( ) ) ) ;
38+ println ! ( "{}: Indexing directory (this may take a while)..." , "INFO" . cyan( ) ) ;
39+ let start_time = std:: time:: Instant :: now ( ) ;
40+
41+ let mut index_path = dir_path. to_path_buf ( ) ;
42+ index_path. push ( ".docsense.benchmark.json" ) ;
43+ let index_str = index_path. to_str ( ) . unwrap ( ) . to_string ( ) ;
44+
45+ index_directory ( dir_path, Arc :: clone ( & model) , Some ( & index_str) ) ?;
46+
47+ let indexing_duration = start_time. elapsed ( ) ;
48+ let index_size = fs:: metadata ( & index_path) . map ( |m| m. len ( ) ) . unwrap_or ( 0 ) ;
49+
50+ println ! ( "Indexing Time: {:?}" , indexing_duration) ;
51+ println ! ( "Index File Size: {:.2} MB" , index_size as f64 / 1_048_576.0 ) ;
52+ println ! ( "Space Reduction Ratio: {:.2}x\n " , raw_size as f64 / index_size. max( 1 ) as f64 ) ;
53+
54+ // 3. Query Latency
55+ println ! ( "{}: Running query latency tests..." , "INFO" . cyan( ) ) ;
56+
57+ let queries = vec ! [
58+ "opengl" ,
59+ "texture array shader" ,
60+ "missingkeywordthatdoesnotexist" ,
61+ ] ;
62+
63+ let model_lock = model. lock ( ) . unwrap ( ) ;
64+
65+ for rank_method in vec ! [ RankMethod :: Tfidf , RankMethod :: Bm25 ] {
66+ println ! ( "\n Ranking Method: {:?}" , rank_method) ;
67+ println ! ( "{:<30} | {:<15} | {:<15}" , "Query" , "Avg Latency" , "Top Result Score" ) ;
68+ println ! ( "{:-<66}" , "" ) ;
69+
70+ for query_str in & queries {
71+ let query = query_str. chars ( ) . collect :: < Vec < char > > ( ) ;
72+
73+ // Warm up
74+ let _ = model_lock. search_query ( & query, & model_lock, rank_method. clone ( ) ) ;
75+
76+ let iters = 10 ;
77+ let mut total_duration = std:: time:: Duration :: new ( 0 , 0 ) ;
78+ let mut top_score = 0.0 ;
79+
80+ for _ in 0 ..iters {
81+ let start_query = std:: time:: Instant :: now ( ) ;
82+ let results = model_lock. search_query ( & query, & model_lock, rank_method. clone ( ) ) . unwrap_or_default ( ) ;
83+ total_duration += start_query. elapsed ( ) ;
84+
85+ if let Some ( ( _, score) ) = results. first ( ) {
86+ top_score = * score;
87+ }
88+ }
89+
90+ let avg_duration = total_duration / iters;
91+ println ! ( "{:<30} | {:<15?} | {:.4}" , query_str, avg_duration, top_score) ;
92+ }
93+ }
94+
95+ println ! ( "\n {}: Benchmark complete." , "INFO" . cyan( ) ) ;
96+ Ok ( ( ) )
97+ }
0 commit comments