1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use bencher::{benchmark_group, benchmark_main, Bencher};
16use flexbuffers::*;
17
18fn push_vec_u64_to_map(b: &mut Bencher) {
19 let va = vec![u64::max_value() - 10; 512];
20 let vb = vec![u64::max_value() - 20; 512];
21 let vc = vec![u64::max_value() - 30; 512];
22 let mut n = 0;
23
24 b.iter(|| {
25 let mut fxb = Builder::default();
26 let mut m = fxb.start_map();
27 let mut ma = m.start_vector("a");
28 for &a in va.iter() {
29 ma.push(a);
30 }
31 ma.end_vector();
32 let mut mb = m.start_vector("b");
33 for &b in vb.iter() {
34 mb.push(b);
35 }
36 mb.end_vector();
37 let mut mc = m.start_vector("c");
38 for &c in vc.iter() {
39 mc.push(c);
40 }
41 mc.end_vector();
42 m.end_map();
43 n = fxb.view().len();
44 });
45 b.bytes = n as u64;
46}
47fn push_vec_u64_to_map_reused(b: &mut Bencher) {
48 let va = vec![u64::max_value() - 10; 512];
49 let vb = vec![u64::max_value() - 20; 512];
50 let vc = vec![u64::max_value() - 30; 512];
51 let mut fxb = Builder::default();
52 let mut n = 0;
53 let mut go = || {
54 let mut m = fxb.start_map();
55 let mut ma = m.start_vector("a");
56 for &a in va.iter() {
57 ma.push(a);
58 }
59 ma.end_vector();
60 let mut mb = m.start_vector("b");
61 for &b in vb.iter() {
62 mb.push(b);
63 }
64 mb.end_vector();
65 let mut mc = m.start_vector("c");
66 for &c in vc.iter() {
67 mc.push(c);
68 }
69 mc.end_vector();
70 m.end_map();
71 n = fxb.view().len();
72 };
73 go(); // warm up allocations.
74 b.iter(go);
75 b.bytes = n as u64;
76}
77fn push_vec_u64_to_map_direct(b: &mut Bencher) {
78 let va = vec![u64::max_value() - 10; 512];
79 let vb = vec![u64::max_value() - 20; 512];
80 let vc = vec![u64::max_value() - 30; 512];
81 let mut n = 0;
82
83 b.iter(|| {
84 let mut fxb = Builder::default();
85 let mut m = fxb.start_map();
86 m.push("a", &va);
87 m.push("b", &vb);
88 m.push("c", &vc);
89 m.end_map();
90 n = fxb.view().len();
91 });
92 b.bytes = n as u64;
93}
94fn push_vec_u64_to_map_direct_reused(b: &mut Bencher) {
95 let va = vec![u64::max_value() - 10; 512];
96 let vb = vec![u64::max_value() - 20; 512];
97 let vc = vec![u64::max_value() - 30; 512];
98 let mut n = 0;
99 let mut fxb = Builder::default();
100 let mut go = || {
101 let mut m = fxb.start_map();
102 m.push("a", &va);
103 m.push("b", &vb);
104 m.push("c", &vc);
105 m.end_map();
106 n = fxb.view().len();
107 };
108 go(); // warm up allocations.
109 b.iter(go);
110 b.bytes = n as u64;
111}
112
113fn push_vec_without_indirect(b: &mut Bencher) {
114 let mut builder = Builder::default();
115 let mut n = 0;
116 let mut go = || {
117 let mut b = builder.start_vector();
118 for i in 0..1024u16 {
119 b.push(i);
120 }
121 b.push(i64::max_value());
122 b.end_vector();
123 n = builder.view().len();
124 };
125 go(); // warm up allocations.
126 b.iter(go);
127 b.bytes = n as u64;
128}
129// This isn't actually faster than the alternative but it is a lot smaller.
130// Based on the above benchmarks a lot of time is stuck in the `values` stack.
131fn push_vec_with_indirect(b: &mut Bencher) {
132 let mut builder = Builder::default();
133 let mut n = 0;
134 let mut go = || {
135 let mut b = builder.start_vector();
136 for i in 0..1024u16 {
137 b.push(i);
138 }
139 b.push(IndirectInt(i64::max_value()));
140 b.end_vector();
141 n = builder.view().len();
142 };
143 go(); // warm up allocations.
144 b.iter(go);
145 b.bytes = n as u64;
146}
147
148fn example_map<'a>(m: &mut MapBuilder<'a>) {
149 m.push("some_ints", &[256; 5]);
150 m.push("some_uints", &[256u16; 5]);
151 m.push("some_floats", &[256f32; 5]);
152 m.push("some_strings", "muahahahahaha");
153}
154fn hundred_maps(b: &mut Bencher) {
155 let mut builder = Builder::default();
156 let mut n = 0;
157 let mut go = || {
158 let mut v = builder.start_vector();
159 for _ in 0..100 {
160 example_map(&mut v.start_map());
161 }
162 v.end_vector();
163 n = builder.view().len();
164 };
165 go(); // Warm up allocations.
166 b.iter(go);
167 b.bytes = n as u64;
168}
169fn hundred_maps_pooled(b: &mut Bencher) {
170 let mut builder = Builder::default();
171 let mut n = 0;
172 let mut go = || {
173 let mut v = builder.start_vector();
174 for _ in 0..100 {
175 example_map(&mut v.start_map());
176 }
177 v.end_vector();
178 n = builder.view().len();
179 };
180 go(); // Warm up allocations.
181 b.iter(go);
182 b.bytes = n as u64;
183}
184fn make_monster(mut monster: MapBuilder) {
185 monster.push("type", "great orc");
186 monster.push("age", 100u8);
187 monster.push("name", "Mr. Orc");
188 monster.push("coins", &[1, 25, 50, 100, 250]);
189 monster.push("color", &[255u8, 0, 0, 0]);
190 {
191 let mut weapons = monster.start_vector("weapons");
192 {
193 let mut hammer = weapons.start_map();
194 hammer.push("name", "hammer");
195 hammer.push("damage type", "crush");
196 hammer.push("damage", 20);
197 }
198 {
199 let mut axe = weapons.start_map();
200 axe.push("name", "Great Axe");
201 axe.push("damage type", "slash");
202 axe.push("damage", 30);
203 }
204 }
205 {
206 let mut sounds = monster.start_vector("sounds");
207 sounds.push("grr");
208 sounds.push("rawr");
209 sounds.push("muahaha");
210 }
211}
212fn serialize_monsters(b: &mut Bencher) {
213 let mut builder = Builder::default();
214 let mut n = 0;
215 let mut go = || {
216 let mut monsters = builder.start_vector();
217 for _ in 0..100 {
218 make_monster(monsters.start_map())
219 }
220 monsters.end_vector();
221 n = builder.view().len();
222 };
223 go(); // Warm up allocations.
224 b.iter(go);
225 b.bytes = n as u64;
226}
227fn validate_monster(r: MapReader<&[u8]>) {
228 assert_eq!(r.idx("type").as_str(), "great orc");
229 assert_eq!(r.idx("age").as_u8(), 100);
230 assert_eq!(r.idx("name").as_str(), "Mr. Orc");
231 assert!(r
232 .idx("coins")
233 .as_vector()
234 .iter()
235 .map(|c| c.as_i16())
236 .eq([1, 25, 50, 100, 250].iter().cloned()));
237 assert!(r
238 .idx("color")
239 .as_vector()
240 .iter()
241 .map(|c| c.as_u8())
242 .eq([255, 0, 0, 0].iter().cloned()));
243
244 let weapons = r.idx("weapons").as_vector();
245 assert_eq!(weapons.len(), 2);
246
247 let hammer = weapons.idx(0).as_map();
248 assert_eq!(hammer.idx("name").as_str(), "hammer");
249 assert_eq!(hammer.idx("damage type").as_str(), "crush");
250 assert_eq!(hammer.idx("damage").as_u64(), 20);
251
252 let axe = weapons.idx(1).as_map();
253 assert_eq!(axe.idx("name").as_str(), "Great Axe");
254 assert_eq!(axe.idx("damage type").as_str(), "slash");
255 assert_eq!(axe.idx("damage").as_u64(), 30);
256
257 assert!(r
258 .idx("sounds")
259 .as_vector()
260 .iter()
261 .map(|s| s.as_str())
262 .eq(["grr", "rawr", "muahaha"].iter().cloned()));
263}
264fn read_monsters(b: &mut Bencher) {
265 let mut builder = Builder::default();
266 let mut monsters = builder.start_vector();
267 for _ in 0..100 {
268 make_monster(monsters.start_map());
269 }
270 monsters.end_vector();
271 b.bytes = builder.view().len() as u64;
272 let go = || {
273 let r = Reader::get_root(builder.view()).unwrap().as_vector();
274 assert_eq!(r.len(), 100);
275 for i in 0..100 {
276 validate_monster(r.idx(i).as_map());
277 }
278 };
279 b.iter(go);
280}
281
282benchmark_group!(
283 benches,
284 push_vec_u64_to_map,
285 push_vec_u64_to_map_reused,
286 push_vec_u64_to_map_direct,
287 push_vec_u64_to_map_direct_reused,
288 push_vec_without_indirect,
289 push_vec_with_indirect,
290 hundred_maps,
291 hundred_maps_pooled,
292 serialize_monsters,
293 read_monsters,
294);
295benchmark_main!(benches);
View as plain text