]> git.lizzy.rs Git - rust.git/blob - src/libregex/test/bench.rs
Doc says to avoid mixing allocator instead of forbiding it
[rust.git] / src / libregex / test / bench.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 #![allow(non_snake_case)]
11
12 use std::rand::{Rng, task_rng};
13 use stdtest::Bencher;
14
15 use regex::{Regex, NoExpand};
16
17 fn bench_assert_match(b: &mut Bencher, re: Regex, text: &str) {
18     b.iter(|| if !re.is_match(text) { fail!("no match") });
19 }
20
21 #[bench]
22 fn no_exponential(b: &mut Bencher) {
23     let n = 100;
24     let re = Regex::new(format!("{}{}",
25                                 "a?".repeat(n),
26                                 "a".repeat(n)).as_slice()).unwrap();
27     let text = "a".repeat(n);
28     bench_assert_match(b, re, text.as_slice());
29 }
30
31 #[bench]
32 fn literal(b: &mut Bencher) {
33     let re = regex!("y");
34     let text = format!("{}y", "x".repeat(50));
35     bench_assert_match(b, re, text.as_slice());
36 }
37
38 #[bench]
39 fn not_literal(b: &mut Bencher) {
40     let re = regex!(".y");
41     let text = format!("{}y", "x".repeat(50));
42     bench_assert_match(b, re, text.as_slice());
43 }
44
45 #[bench]
46 fn match_class(b: &mut Bencher) {
47     let re = regex!("[abcdw]");
48     let text = format!("{}w", "xxxx".repeat(20));
49     bench_assert_match(b, re, text.as_slice());
50 }
51
52 #[bench]
53 fn match_class_in_range(b: &mut Bencher) {
54     // 'b' is between 'a' and 'c', so the class range checking doesn't help.
55     let re = regex!("[ac]");
56     let text = format!("{}c", "bbbb".repeat(20));
57     bench_assert_match(b, re, text.as_slice());
58 }
59
60 #[bench]
61 fn replace_all(b: &mut Bencher) {
62     let re = regex!("[cjrw]");
63     let text = "abcdefghijklmnopqrstuvwxyz";
64     // FIXME: This isn't using the $name expand stuff.
65     // It's possible RE2/Go is using it, but currently, the expand in this
66     // crate is actually compiling a regex, so it's incredibly slow.
67     b.iter(|| re.replace_all(text, NoExpand("")));
68 }
69
70 #[bench]
71 fn anchored_literal_short_non_match(b: &mut Bencher) {
72     let re = regex!("^zbc(d|e)");
73     let text = "abcdefghijklmnopqrstuvwxyz";
74     b.iter(|| re.is_match(text));
75 }
76
77 #[bench]
78 fn anchored_literal_long_non_match(b: &mut Bencher) {
79     let re = regex!("^zbc(d|e)");
80     let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
81     b.iter(|| re.is_match(text.as_slice()));
82 }
83
84 #[bench]
85 fn anchored_literal_short_match(b: &mut Bencher) {
86     let re = regex!("^.bc(d|e)");
87     let text = "abcdefghijklmnopqrstuvwxyz";
88     b.iter(|| re.is_match(text));
89 }
90
91 #[bench]
92 fn anchored_literal_long_match(b: &mut Bencher) {
93     let re = regex!("^.bc(d|e)");
94     let text = "abcdefghijklmnopqrstuvwxyz".repeat(15);
95     b.iter(|| re.is_match(text.as_slice()));
96 }
97
98 #[bench]
99 fn one_pass_short_a(b: &mut Bencher) {
100     let re = regex!("^.bc(d|e)*$");
101     let text = "abcddddddeeeededd";
102     b.iter(|| re.is_match(text));
103 }
104
105 #[bench]
106 fn one_pass_short_a_not(b: &mut Bencher) {
107     let re = regex!(".bc(d|e)*$");
108     let text = "abcddddddeeeededd";
109     b.iter(|| re.is_match(text));
110 }
111
112 #[bench]
113 fn one_pass_short_b(b: &mut Bencher) {
114     let re = regex!("^.bc(?:d|e)*$");
115     let text = "abcddddddeeeededd";
116     b.iter(|| re.is_match(text));
117 }
118
119 #[bench]
120 fn one_pass_short_b_not(b: &mut Bencher) {
121     let re = regex!(".bc(?:d|e)*$");
122     let text = "abcddddddeeeededd";
123     b.iter(|| re.is_match(text));
124 }
125
126 #[bench]
127 fn one_pass_long_prefix(b: &mut Bencher) {
128     let re = regex!("^abcdefghijklmnopqrstuvwxyz.*$");
129     let text = "abcdefghijklmnopqrstuvwxyz";
130     b.iter(|| re.is_match(text));
131 }
132
133 #[bench]
134 fn one_pass_long_prefix_not(b: &mut Bencher) {
135     let re = regex!("^.bcdefghijklmnopqrstuvwxyz.*$");
136     let text = "abcdefghijklmnopqrstuvwxyz";
137     b.iter(|| re.is_match(text));
138 }
139
140 macro_rules! throughput(
141     ($name:ident, $regex:expr, $size:expr) => (
142         #[bench]
143         fn $name(b: &mut Bencher) {
144             let text = gen_text($size);
145             b.bytes = $size;
146             b.iter(|| if $regex.is_match(text.as_slice()) { fail!("match") });
147         }
148     );
149 )
150
151 fn easy0() -> Regex { regex!("ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
152 fn easy1() -> Regex { regex!("A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$") }
153 fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
154 fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
155
156 fn gen_text(n: uint) -> String {
157     let mut rng = task_rng();
158     let mut bytes = rng.gen_ascii_chars().map(|n| n as u8).take(n)
159                        .collect::<Vec<u8>>();
160     for (i, b) in bytes.mut_iter().enumerate() {
161         if i % 20 == 0 {
162             *b = b'\n'
163         }
164     }
165     String::from_utf8(bytes).unwrap()
166 }
167
168 throughput!(easy0_32, easy0(), 32)
169 throughput!(easy0_1K, easy0(), 1<<10)
170 throughput!(easy0_32K, easy0(), 32<<10)
171
172 throughput!(easy1_32, easy1(), 32)
173 throughput!(easy1_1K, easy1(), 1<<10)
174 throughput!(easy1_32K, easy1(), 32<<10)
175
176 throughput!(medium_32, medium(), 32)
177 throughput!(medium_1K, medium(), 1<<10)
178 throughput!(medium_32K,medium(), 32<<10)
179
180 throughput!(hard_32, hard(), 32)
181 throughput!(hard_1K, hard(), 1<<10)
182 throughput!(hard_32K,hard(), 32<<10)