Skip to content

Commit 1b6060e

Browse files
committed
some
1 parent 745efba commit 1b6060e

26 files changed

+5466
-9
lines changed

module/core/strs_tools/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ default = [
3333
"string_parse_number",
3434
"string_split",
3535
"simd",
36+
"compile_time_optimizations",
3637
]
3738
full = [
3839
"enabled",
@@ -42,10 +43,12 @@ full = [
4243
"string_parse_number",
4344
"string_split",
4445
"simd",
46+
"compile_time_optimizations",
4547
]
4648

4749
# Performance optimization features - enabled by default, disable with --no-default-features
4850
simd = ["memchr", "aho-corasick", "bytecount", "lazy_static"]
51+
compile_time_optimizations = ["strs_tools_meta"]
4952

5053
no_std = []
5154
use_alloc = [ "no_std" ]
@@ -70,6 +73,9 @@ string_split = [ "split" ]
7073
lexical = { workspace = true, optional = true }
7174
component_model_types = { workspace = true, features = ["enabled"] }
7275

76+
# Compile-time optimization macros
77+
strs_tools_meta = { path = "strs_tools_meta", optional = true }
78+
7379
# SIMD optimization dependencies (optional)
7480
memchr = { workspace = true, optional = true }
7581
aho-corasick = { workspace = true, optional = true }
@@ -80,13 +86,24 @@ lazy_static = { version = "1.4", optional = true }
8086
[dev-dependencies]
8187
test_tools = { workspace = true }
8288
criterion = { version = "0.5", features = ["html_reports"] }
89+
ctor = { version = "0.2" }
8390

8491
# Disabled due to infinite loop issues
8592
[[bench]]
8693
name = "bottlenecks"
8794
harness = false
8895
path = "benchmarks/bottlenecks.rs"
8996

97+
[[bench]]
98+
name = "zero_copy_comparison"
99+
harness = false
100+
path = "benchmarks/zero_copy_comparison.rs"
101+
102+
[[bench]]
103+
name = "compile_time_optimization_benchmark"
104+
harness = false
105+
path = "benchmarks/compile_time_optimization_benchmark.rs"
106+
90107
[[bin]]
91108
name = "simd_test"
92109
required-features = ["simd"]
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
//! Benchmark comparing compile-time optimizations vs runtime optimizations
2+
//!
3+
//! This benchmark measures the performance impact of compile-time pattern analysis
4+
//! and optimization compared to runtime decision-making.
5+
6+
#![ allow( missing_docs ) ]
7+
8+
use criterion::{ black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput };
9+
use std::time::Instant;
10+
11+
use strs_tools::string::split;
12+
use strs_tools::string::zero_copy::ZeroCopyStringExt;
13+
14+
#[ cfg( feature = "compile_time_optimizations" ) ]
15+
use strs_tools::{ optimize_split, optimize_match };
16+
17+
/// Generate test data for benchmarking
18+
fn generate_benchmark_data( size: usize, pattern: &str ) -> String {
19+
match pattern {
20+
"csv" => "field1,field2,field3,field4,field5,field6,field7,field8".repeat( size / 50 + 1 ),
21+
"structured" => "key1:value1;key2:value2,key3:value3|key4:value4".repeat( size / 60 + 1 ),
22+
"urls" => "https://example.com,http://test.org,ftp://files.net".repeat( size / 50 + 1 ),
23+
_ => "a,b,c".repeat( size / 5 + 1 ),
24+
}
25+
}
26+
27+
/// Benchmark single delimiter splitting
28+
fn bench_single_delimiter_split( c: &mut Criterion ) {
29+
let mut group = c.benchmark_group( "single_delimiter_split" );
30+
31+
let test_cases = [
32+
( "small_1kb", 1024 ),
33+
( "medium_10kb", 10240 ),
34+
( "large_100kb", 102400 ),
35+
];
36+
37+
for ( name, size ) in test_cases {
38+
let csv_data = generate_benchmark_data( size, "csv" );
39+
group.throughput( Throughput::Bytes( csv_data.len() as u64 ) );
40+
41+
// Runtime optimization (standard library split)
42+
group.bench_with_input(
43+
BenchmarkId::new( "stdlib_split", name ),
44+
&csv_data,
45+
|b, data| {
46+
b.iter( || {
47+
let result: Vec< &str > = data.split( ',' ).collect();
48+
black_box( result )
49+
} );
50+
},
51+
);
52+
53+
// Runtime optimization (zero-copy)
54+
group.bench_with_input(
55+
BenchmarkId::new( "zero_copy_runtime", name ),
56+
&csv_data,
57+
|b, data| {
58+
b.iter( || {
59+
let result: Vec< _ > = data.zero_copy_split( &[","] ).collect();
60+
black_box( result )
61+
} );
62+
},
63+
);
64+
65+
// Compile-time optimization
66+
#[ cfg( feature = "compile_time_optimizations" ) ]
67+
group.bench_with_input(
68+
BenchmarkId::new( "compile_time_optimized", name ),
69+
&csv_data,
70+
|b, data| {
71+
b.iter( || {
72+
let result: Vec< _ > = optimize_split!( black_box( data ), "," ).collect();
73+
black_box( result )
74+
} );
75+
},
76+
);
77+
}
78+
79+
group.finish();
80+
}
81+
82+
/// Benchmark multiple delimiter splitting
83+
fn bench_multiple_delimiter_split( c: &mut Criterion ) {
84+
let mut group = c.benchmark_group( "multiple_delimiter_split" );
85+
86+
let test_cases = [
87+
( "small_1kb", 1024 ),
88+
( "medium_10kb", 10240 ),
89+
( "large_100kb", 102400 ),
90+
];
91+
92+
for ( name, size ) in test_cases {
93+
let structured_data = generate_benchmark_data( size, "structured" );
94+
group.throughput( Throughput::Bytes( structured_data.len() as u64 ) );
95+
96+
// Runtime optimization (traditional)
97+
group.bench_with_input(
98+
BenchmarkId::new( "traditional_runtime", name ),
99+
&structured_data,
100+
|b, data| {
101+
b.iter( || {
102+
let result: Vec< String > = split()
103+
.src( black_box( data ) )
104+
.delimeter( vec![ ":", ";", ",", "|" ] )
105+
.perform()
106+
.map( |split| split.string.into_owned() )
107+
.collect();
108+
black_box( result )
109+
} );
110+
},
111+
);
112+
113+
// Runtime optimization (zero-copy)
114+
group.bench_with_input(
115+
BenchmarkId::new( "zero_copy_runtime", name ),
116+
&structured_data,
117+
|b, data| {
118+
b.iter( || {
119+
let result: Vec< _ > = data.zero_copy_split( &[":", ";", ",", "|"] ).collect();
120+
black_box( result )
121+
} );
122+
},
123+
);
124+
125+
// Compile-time optimization
126+
#[ cfg( feature = "compile_time_optimizations" ) ]
127+
group.bench_with_input(
128+
BenchmarkId::new( "compile_time_optimized", name ),
129+
&structured_data,
130+
|b, data| {
131+
b.iter( || {
132+
let result: Vec< _ > = optimize_split!(
133+
black_box( data ),
134+
[":", ";", ",", "|"]
135+
).collect();
136+
black_box( result )
137+
} );
138+
},
139+
);
140+
}
141+
142+
group.finish();
143+
}
144+
145+
/// Benchmark pattern matching
146+
fn bench_pattern_matching( c: &mut Criterion ) {
147+
let mut group = c.benchmark_group( "pattern_matching" );
148+
149+
let url_data = generate_benchmark_data( 50000, "urls" );
150+
group.throughput( Throughput::Bytes( url_data.len() as u64 ) );
151+
152+
// Runtime pattern matching
153+
group.bench_function( "runtime_pattern_matching", |b| {
154+
b.iter( || {
155+
let mut matches = Vec::new();
156+
let data = black_box( &url_data );
157+
158+
if let Some( pos ) = data.find( "https://" ) {
159+
matches.push( pos );
160+
}
161+
if let Some( pos ) = data.find( "http://" ) {
162+
matches.push( pos );
163+
}
164+
if let Some( pos ) = data.find( "ftp://" ) {
165+
matches.push( pos );
166+
}
167+
168+
black_box( matches )
169+
} );
170+
} );
171+
172+
// Compile-time optimized pattern matching
173+
#[ cfg( feature = "compile_time_optimizations" ) ]
174+
group.bench_function( "compile_time_pattern_matching", |b| {
175+
b.iter( || {
176+
let result = optimize_match!(
177+
black_box( &url_data ),
178+
["https://", "http://", "ftp://"],
179+
strategy = "first_match"
180+
);
181+
black_box( result )
182+
} );
183+
} );
184+
185+
group.finish();
186+
}
187+
188+
/// Benchmark delimiter preservation
189+
fn bench_delimiter_preservation( c: &mut Criterion ) {
190+
let mut group = c.benchmark_group( "delimiter_preservation" );
191+
192+
let test_data = "key1:value1;key2:value2,key3:value3".repeat( 500 );
193+
group.throughput( Throughput::Bytes( test_data.len() as u64 ) );
194+
195+
// Runtime delimiter preservation
196+
group.bench_function( "runtime_preserve_delimiters", |b| {
197+
b.iter( || {
198+
let result: Vec< _ > = test_data.zero_copy_split_preserve( &[":", ";", ","] ).collect();
199+
black_box( result )
200+
} );
201+
} );
202+
203+
// Compile-time optimized delimiter preservation
204+
#[ cfg( feature = "compile_time_optimizations" ) ]
205+
group.bench_function( "compile_time_preserve_delimiters", |b| {
206+
b.iter( || {
207+
let result: Vec< _ > = optimize_split!(
208+
&test_data,
209+
[":", ";", ","],
210+
preserve_delimiters = true
211+
).collect();
212+
black_box( result )
213+
} );
214+
} );
215+
216+
group.finish();
217+
}
218+
219+
/// Benchmark counting operations (no allocation)
220+
fn bench_counting_operations( c: &mut Criterion ) {
221+
let mut group = c.benchmark_group( "counting_operations" );
222+
223+
let large_data = "item1,item2,item3,item4,item5".repeat( 10000 );
224+
group.throughput( Throughput::Bytes( large_data.len() as u64 ) );
225+
226+
// Runtime counting
227+
group.bench_function( "runtime_count", |b| {
228+
b.iter( || {
229+
let count = large_data.count_segments( &[","] );
230+
black_box( count )
231+
} );
232+
} );
233+
234+
// Compile-time optimized counting
235+
#[ cfg( feature = "compile_time_optimizations" ) ]
236+
group.bench_function( "compile_time_count", |b| {
237+
b.iter( || {
238+
let count = optimize_split!( &large_data, "," ).count();
239+
black_box( count )
240+
} );
241+
} );
242+
243+
group.finish();
244+
}
245+
246+
/// Memory usage comparison benchmark
247+
fn bench_memory_usage_patterns( c: &mut Criterion ) {
248+
let mut group = c.benchmark_group( "memory_usage_patterns" );
249+
group.sample_size( 20 );
250+
251+
let test_data = generate_benchmark_data( 100000, "csv" );
252+
group.throughput( Throughput::Bytes( test_data.len() as u64 ) );
253+
254+
// Runtime memory pattern
255+
group.bench_function( "runtime_memory_pattern", |b| {
256+
b.iter_custom( |iters| {
257+
let start_time = Instant::now();
258+
259+
for _ in 0..iters {
260+
let result: Vec< _ > = test_data.zero_copy_split( &[","] ).collect();
261+
black_box( result );
262+
}
263+
264+
start_time.elapsed()
265+
} );
266+
} );
267+
268+
// Compile-time optimized memory pattern
269+
#[ cfg( feature = "compile_time_optimizations" ) ]
270+
group.bench_function( "compile_time_memory_pattern", |b| {
271+
b.iter_custom( |iters| {
272+
let start_time = Instant::now();
273+
274+
for _ in 0..iters {
275+
let result: Vec< _ > = optimize_split!( &test_data, "," ).collect();
276+
black_box( result );
277+
}
278+
279+
start_time.elapsed()
280+
} );
281+
} );
282+
283+
group.finish();
284+
}
285+
286+
/// Complex pattern optimization benchmark
287+
#[ cfg( feature = "compile_time_optimizations" ) ]
288+
fn bench_complex_pattern_optimization( c: &mut Criterion ) {
289+
let mut group = c.benchmark_group( "complex_pattern_optimization" );
290+
291+
let complex_data = "prefix1::item1->value1|prefix2::item2->value2|prefix3::item3->value3".repeat( 1000 );
292+
group.throughput( Throughput::Bytes( complex_data.len() as u64 ) );
293+
294+
// Runtime complex pattern handling
295+
group.bench_function( "runtime_complex_patterns", |b| {
296+
b.iter( || {
297+
let result: Vec< _ > = complex_data.zero_copy_split( &["::", "->", "|"] ).collect();
298+
black_box( result )
299+
} );
300+
} );
301+
302+
// Compile-time optimized complex patterns
303+
group.bench_function( "compile_time_complex_patterns", |b| {
304+
b.iter( || {
305+
let result: Vec< _ > = optimize_split!(
306+
&complex_data,
307+
["::", "->", "|"],
308+
use_simd = true
309+
).collect();
310+
black_box( result )
311+
} );
312+
} );
313+
314+
group.finish();
315+
}
316+
317+
criterion_group!(
318+
compile_time_benches,
319+
bench_single_delimiter_split,
320+
bench_multiple_delimiter_split,
321+
bench_pattern_matching,
322+
bench_delimiter_preservation,
323+
bench_counting_operations,
324+
bench_memory_usage_patterns,
325+
);
326+
327+
#[ cfg( feature = "compile_time_optimizations" ) ]
328+
criterion_group!(
329+
compile_time_advanced_benches,
330+
bench_complex_pattern_optimization,
331+
);
332+
333+
#[ cfg( feature = "compile_time_optimizations" ) ]
334+
criterion_main!( compile_time_benches, compile_time_advanced_benches );
335+
336+
#[ cfg( not( feature = "compile_time_optimizations" ) ) ]
337+
criterion_main!( compile_time_benches );

0 commit comments

Comments
 (0)