1 // Copyright 2014 The Servo Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
12 A cautionary note about these benchmarks:
14 Many of the operations we're attempting to measure take less than one
15 nanosecond. That's why we run them thousands of times in a loop just to get a
16 single iteration that Rust's statistical benchmarking can work with. At that
17 scale, any change anywhere in the library can produce durable performance
18 regressions on the order of half a nanosecond, i.e. "500 ns" in the output for
19 a test like eq_x_1000.
21 We can't get anything done if we rachet on these numbers! They are more useful
22 for selecting between alternatives, and for noticing large regressions or
25 Furthermore, a large part of the point of interning is to make strings small
26 and cheap to move around, which isn't reflected in these tests.
30 use atom
::tests
::TestAtom
;
31 use test
::{Bencher, black_box}
;
34 fn mk(x
: &str) -> TestAtom
{
38 macro_rules
! check_type (($name
:ident
, $x
:expr
, $p
:pat
) => (
39 // NB: "cargo bench" does not run these!
42 match unsafe { $x.unpack() }
{
44 _
=> panic
!("atom has wrong type"),
49 macro_rules
! bench_tiny_op (($name
:ident
, $op
:ident
, $ctor_x
:expr
, $ctor_y
:expr
) => (
51 fn $
name(b
: &mut Bencher
) {
52 const n
: usize = 1000;
53 let xs
: Vec
<_
> = repeat($ctor_x
).take(n
).collect();
54 let ys
: Vec
<_
> = repeat($ctor_y
).take(n
).collect();
57 for (x
, y
) in xs
.iter().zip(ys
.iter()) {
64 macro_rules
! bench_one (
65 (x_static $x
:expr
, $y
:expr
) => (check_type
!(check_type_x
, $x
, Static(..)););
66 (x_inline $x
:expr
, $y
:expr
) => (check_type
!(check_type_x
, $x
, Inline(..)););
67 (x_dynamic $x
:expr
, $y
:expr
) => (check_type
!(check_type_x
, $x
, Dynamic(..)););
68 (y_static $x
:expr
, $y
:expr
) => (check_type
!(check_type_y
, $y
, Static(..)););
69 (y_inline $x
:expr
, $y
:expr
) => (check_type
!(check_type_y
, $y
, Inline(..)););
70 (y_dynamic $x
:expr
, $y
:expr
) => (check_type
!(check_type_y
, $y
, Dynamic(..)););
71 (is_static $x
:expr
, $y
:expr
) => (bench_one
!(x_static $x
, $y
); bench_one
!(y_static $x
, $y
););
72 (is_inline $x
:expr
, $y
:expr
) => (bench_one
!(x_inline $x
, $y
); bench_one
!(y_inline $x
, $y
););
73 (is_dynamic $x
:expr
, $y
:expr
) => (bench_one
!(x_dynamic $x
, $y
); bench_one
!(y_dynamic $x
, $y
););
75 (eq $x
:expr
, $_y
:expr
) => (bench_tiny_op
!(eq_x_1000
, eq
, $x
, $x
););
76 (ne $x
:expr
, $y
:expr
) => (bench_tiny_op
!(ne_x_1000
, ne
, $x
, $y
););
77 (lt $x
:expr
, $y
:expr
) => (bench_tiny_op
!(lt_x_1000
, lt
, $x
, $y
););
79 (intern $x
:expr
, $_y
:expr
) => (
81 fn intern(b
: &mut Bencher
) {
82 let x
= $x
.to_string();
84 black_box(TestAtom
::from(&*x
));
89 (as_ref $x
:expr
, $_y
:expr
) => (
91 fn as_ref_x_1000(b
: &mut Bencher
) {
95 black_box(x
.as_ref());
101 (clone $x
:expr
, $_y
:expr
) => (
103 fn clone_x_1000(b
: &mut Bencher
) {
107 black_box(x
.clone());
113 (clone_string $x
:expr
, $_y
:expr
) => (
115 fn clone_x_1000(b
: &mut Bencher
) {
116 let x
= $x
.to_string();
119 black_box(x
.clone());
126 macro_rules
! bench_all (
127 ([ $
($which
:ident
)+ ] for $name
:ident
= $x
:expr
, $y
:expr
) => (
128 // FIXME: This module works around rust-lang/rust#12249 so we don't
129 // have to repeat the names for eq and neq.
131 #![allow(unused_imports)]
133 use test
::{Bencher, black_box}
;
134 use std
::string
::ToString
;
135 use std
::iter
::repeat
;
137 use atom
::tests
::TestAtom
;
138 use atom
::UnpackedAtom
::{Static, Inline, Dynamic}
;
143 bench_one
!($which $x
, $y
);
149 pub const longer_dynamic_a
: &'
static str
150 = "Thee Silver Mt. Zion Memorial Orchestra & Tra-La-La Band";
151 pub const longer_dynamic_b
: &'
static str
152 = "Thee Silver Mt. Zion Memorial Orchestra & Tra-La-La Ban!";
154 bench_all
!([eq ne lt clone_string
] for short_string
= "e", "f");
155 bench_all
!([eq ne lt clone_string
] for medium_string
= "xyzzy01", "xyzzy02");
156 bench_all
!([eq ne lt clone_string
]
157 for longer_string
= super::longer_dynamic_a
, super::longer_dynamic_b
);
159 bench_all
!([eq ne intern as_ref clone is_static lt
]
160 for static_atom
= test_atom
!("a"), test_atom
!("b"));
162 bench_all
!([intern as_ref clone is_inline
]
163 for short_inline_atom
= mk("e"), mk("f"));
165 bench_all
!([eq ne intern as_ref clone is_inline lt
]
166 for medium_inline_atom
= mk("xyzzy01"), mk("xyzzy02"));
168 bench_all
!([intern as_ref clone is_dynamic
]
169 for min_dynamic_atom
= mk("xyzzy001"), mk("xyzzy002"));
171 bench_all
!([eq ne intern as_ref clone is_dynamic lt
]
172 for longer_dynamic_atom
= mk(super::longer_dynamic_a
), mk(super::longer_dynamic_b
));
174 bench_all
!([intern as_ref clone is_static
]
175 for static_at_runtime
= mk("a"), mk("b"));
177 bench_all
!([ne lt x_static y_inline
]
178 for static_vs_inline
= test_atom
!("a"), mk("f"));
180 bench_all
!([ne lt x_static y_dynamic
]
181 for static_vs_dynamic
= test_atom
!("a"), mk(super::longer_dynamic_b
));
183 bench_all
!([ne lt x_inline y_dynamic
]
184 for inline_vs_dynamic
= mk("e"), mk(super::longer_dynamic_b
));
186 macro_rules
! bench_rand ( ($name
:ident
, $len
:expr
) => (
188 fn $
name(b
: &mut Bencher
) {
193 let mut gen
= rand
::weak_rng();
195 // We have to generate new atoms on every iter, because
196 // the dynamic atom table isn't reset.
198 // I measured the overhead of random string generation
199 // as about 3-12% at one point.
201 let mut buf
: [u8; $len
] = [0; $len
];
202 gen
.fill_bytes(&mut buf
);
203 for n
in buf
.iter_mut() {
204 // shift into printable ASCII
205 *n
= (*n
% 0x40) + 0x20;
207 let s
= str::from_utf8(&buf
[..]).unwrap();
208 black_box(TestAtom
::from(s
));
213 bench_rand
!(intern_rand_008
, 8);
214 bench_rand
!(intern_rand_032
, 32);
215 bench_rand
!(intern_rand_128
, 128);
216 bench_rand
!(intern_rand_512
, 512);