1/*
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use bencher::{benchmark_group, Bencher};
18use flatbuffers;
19
20#[allow(dead_code, unused_imports)]
21#[path = "../../monster_test/mod.rs"]
22mod monster_test_generated;
23pub use monster_test_generated::my_game;
24
25fn traverse_canonical_buffer(bench: &mut Bencher) {
26 let owned_data = {
27 let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
28 create_serialized_example_with_generated_code(&mut builder, true);
29 builder.finished_data().to_vec()
30 };
31 let data = &owned_data[..];
32 let n = data.len() as u64;
33 bench.iter(|| {
34 traverse_serialized_example_with_generated_code(data);
35 });
36 bench.bytes = n;
37}
38
39fn create_canonical_buffer_then_reset(bench: &mut Bencher) {
40 let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
41 // warmup
42 create_serialized_example_with_generated_code(&mut builder, true);
43 let n = builder.finished_data().len() as u64;
44 builder.reset();
45
46 bench.iter(|| {
47 let _ = create_serialized_example_with_generated_code(&mut builder, true);
48 builder.reset();
49 });
50
51 bench.bytes = n;
52}
53
54#[inline(always)]
55fn create_serialized_example_with_generated_code(
56 builder: &mut flatbuffers::FlatBufferBuilder,
57 finish: bool,
58) -> usize {
59 let s0 = builder.create_string("test1");
60 let s1 = builder.create_string("test2");
61 let t0_name = builder.create_string("Barney");
62 let t1_name = builder.create_string("Fred");
63 let t2_name = builder.create_string("Wilma");
64 let t0 = my_game::example::Monster::create(
65 builder,
66 &my_game::example::MonsterArgs {
67 hp: 1000,
68 name: Some(t0_name),
69 ..Default::default()
70 },
71 );
72 let t1 = my_game::example::Monster::create(
73 builder,
74 &my_game::example::MonsterArgs {
75 name: Some(t1_name),
76 ..Default::default()
77 },
78 );
79 let t2 = my_game::example::Monster::create(
80 builder,
81 &my_game::example::MonsterArgs {
82 name: Some(t2_name),
83 ..Default::default()
84 },
85 );
86 let mon = {
87 let name = builder.create_string("MyMonster");
88 let fred_name = builder.create_string("Fred");
89 let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4]);
90 let test4 = builder.create_vector(&[
91 my_game::example::Test::new(10, 20),
92 my_game::example::Test::new(30, 40),
93 ]);
94 let pos = my_game::example::Vec3::new(
95 1.0,
96 2.0,
97 3.0,
98 3.0,
99 my_game::example::Color::Green,
100 &my_game::example::Test::new(5i16, 6i8),
101 );
102 let args = my_game::example::MonsterArgs {
103 hp: 80,
104 mana: 150,
105 name: Some(name),
106 pos: Some(&pos),
107 test_type: my_game::example::Any::Monster,
108 test: Some(
109 my_game::example::Monster::create(
110 builder,
111 &my_game::example::MonsterArgs {
112 name: Some(fred_name),
113 ..Default::default()
114 },
115 )
116 .as_union_value(),
117 ),
118 inventory: Some(inventory),
119 test4: Some(test4),
120 testarrayofstring: Some(builder.create_vector(&[s0, s1])),
121 testarrayoftables: Some(builder.create_vector(&[t0, t1, t2])),
122 ..Default::default()
123 };
124 my_game::example::Monster::create(builder, &args)
125 };
126 if finish {
127 my_game::example::finish_monster_buffer(builder, mon);
128 }
129
130 builder.finished_data().len()
131
132 // make it do some work
133 // if builder.finished_data().len() == 0 { panic!("bad benchmark"); }
134}
135
136#[inline(always)]
137fn blackbox<T>(t: T) -> T {
138 // encapsulate this in case we need to turn it into a noop
139 bencher::black_box(t)
140}
141
142#[inline(always)]
143fn traverse_serialized_example_with_generated_code(bytes: &[u8]) {
144 let m = unsafe { my_game::example::root_as_monster_unchecked(bytes) };
145 blackbox(m.hp());
146 blackbox(m.mana());
147 blackbox(m.name());
148 let pos = m.pos().unwrap();
149 blackbox(pos.x());
150 blackbox(pos.y());
151 blackbox(pos.z());
152 blackbox(pos.test1());
153 blackbox(pos.test2());
154 let pos_test3 = pos.test3();
155 blackbox(pos_test3.a());
156 blackbox(pos_test3.b());
157 blackbox(m.test_type());
158 let table2 = m.test().unwrap();
159 let monster2 = unsafe { my_game::example::Monster::init_from_table(table2) };
160 blackbox(monster2.name());
161 blackbox(m.inventory());
162 blackbox(m.test4());
163 let testarrayoftables = m.testarrayoftables().unwrap();
164 blackbox(testarrayoftables.get(0).hp());
165 blackbox(testarrayoftables.get(0).name());
166 blackbox(testarrayoftables.get(1).name());
167 blackbox(testarrayoftables.get(2).name());
168 let testarrayofstring = m.testarrayofstring().unwrap();
169 blackbox(testarrayofstring.get(0));
170 blackbox(testarrayofstring.get(1));
171}
172
173fn create_string_10(bench: &mut Bencher) {
174 let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20);
175 let mut i = 0;
176 bench.iter(|| {
177 builder.create_string("foobarbaz"); // zero-terminated -> 10 bytes
178 i += 1;
179 if i == 10000 {
180 builder.reset();
181 i = 0;
182 }
183 });
184
185 bench.bytes = 10;
186}
187
188fn create_string_100(bench: &mut Bencher) {
189 let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20);
190 let s_owned = (0..99).map(|_| "x").collect::<String>();
191 let s: &str = &s_owned;
192
193 let mut i = 0;
194 bench.iter(|| {
195 builder.create_string(s); // zero-terminated -> 100 bytes
196 i += 1;
197 if i == 1000 {
198 builder.reset();
199 i = 0;
200 }
201 });
202
203 bench.bytes = s.len() as u64;
204}
205
206fn create_byte_vector_100_naive(bench: &mut Bencher) {
207 let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20);
208 let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
209 let v: &[u8] = &v_owned;
210
211 let mut i = 0;
212 bench.iter(|| {
213 builder.create_vector(v); // zero-terminated -> 100 bytes
214 i += 1;
215 if i == 10000 {
216 builder.reset();
217 i = 0;
218 }
219 });
220
221 bench.bytes = v.len() as u64;
222}
223
224fn create_byte_vector_100_optimal(bench: &mut Bencher) {
225 let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20);
226 let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
227 let v: &[u8] = &v_owned;
228
229 let mut i = 0;
230 bench.iter(|| {
231 builder.create_vector(v);
232 i += 1;
233 if i == 10000 {
234 builder.reset();
235 i = 0;
236 }
237 });
238
239 bench.bytes = v.len() as u64;
240}
241
242fn create_many_tables(bench: &mut Bencher) {
243 let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20);
244 // We test vtable overhead by making many unique tables of up to 16 fields of u8s.
245 bench.iter(|| {
246 for i in 0..(1u16 << 10) {
247 let t = builder.start_table();
248 for j in 0..15 {
249 if i & (1 << j) == 1 {
250 builder.push_slot_always(i * 2, 42u8);
251 }
252 }
253 builder.end_table(t);
254 }
255 builder.reset();
256 });
257 bench.bytes = 1 << 15;
258}
259
260benchmark_group!(
261 benches,
262 create_byte_vector_100_naive,
263 create_byte_vector_100_optimal,
264 traverse_canonical_buffer,
265 create_canonical_buffer_then_reset,
266 create_string_10,
267 create_string_100,
268 create_many_tables,
269);
View as plain text