1 #![feature(test)]
2 
3 extern crate test;
4 
5 use std::io;
6 
7 use serde::{de::DeserializeOwned, Deserialize, Serialize};
8 use test::Bencher;
9 
10 use csv::{
11     ByteRecord, Reader, ReaderBuilder, StringRecord, Trim, Writer,
12     WriterBuilder,
13 };
14 
15 static NFL: &'static str = include_str!("../examples/data/bench/nfl.csv");
16 static GAME: &'static str = include_str!("../examples/data/bench/game.csv");
17 static POP: &'static str =
18     include_str!("../examples/data/bench/worldcitiespop.csv");
19 static MBTA: &'static str =
20     include_str!("../examples/data/bench/gtfs-mbta-stop-times.csv");
21 
22 #[derive(Debug, Serialize, Deserialize, PartialEq)]
23 struct NFLRowOwned {
24     gameid: String,
25     qtr: i32,
26     min: Option<i32>,
27     sec: Option<i32>,
28     off: String,
29     def: String,
30     down: Option<i32>,
31     togo: Option<i32>,
32     ydline: Option<i32>,
33     description: String,
34     offscore: i32,
35     defscore: i32,
36     season: i32,
37 }
38 
39 #[derive(Debug, Serialize, Deserialize, PartialEq)]
40 struct NFLRowBorrowed<'a> {
41     gameid: &'a str,
42     qtr: i32,
43     min: Option<i32>,
44     sec: Option<i32>,
45     off: &'a str,
46     def: &'a str,
47     down: Option<i32>,
48     togo: Option<i32>,
49     ydline: Option<i32>,
50     description: &'a str,
51     offscore: i32,
52     defscore: i32,
53     season: i32,
54 }
55 
56 #[derive(Debug, Serialize, Deserialize, PartialEq)]
57 struct GAMERowOwned(String, String, String, String, i32, String);
58 
59 #[derive(Debug, Serialize, Deserialize, PartialEq)]
60 struct GAMERowBorrowed<'a>(&'a str, &'a str, &'a str, &'a str, i32, &'a str);
61 
62 #[derive(Debug, Serialize, Deserialize, PartialEq)]
63 #[serde(rename_all = "PascalCase")]
64 struct POPRowOwned {
65     country: String,
66     city: String,
67     accent_city: String,
68     region: String,
69     population: Option<i32>,
70     latitude: f64,
71     longitude: f64,
72 }
73 
74 #[derive(Debug, Serialize, Deserialize, PartialEq)]
75 #[serde(rename_all = "PascalCase")]
76 struct POPRowBorrowed<'a> {
77     country: &'a str,
78     city: &'a str,
79     accent_city: &'a str,
80     region: &'a str,
81     population: Option<i32>,
82     latitude: f64,
83     longitude: f64,
84 }
85 
86 #[derive(Debug, Serialize, Deserialize, PartialEq)]
87 struct MBTARowOwned {
88     trip_id: String,
89     arrival_time: String,
90     departure_time: String,
91     stop_id: String,
92     stop_sequence: i32,
93     stop_headsign: String,
94     pickup_type: i32,
95     drop_off_type: i32,
96     timepoint: i32,
97 }
98 
99 #[derive(Debug, Serialize, Deserialize, PartialEq)]
100 struct MBTARowBorrowed<'a> {
101     trip_id: &'a str,
102     arrival_time: &'a str,
103     departure_time: &'a str,
104     stop_id: &'a str,
105     stop_sequence: i32,
106     stop_headsign: &'a str,
107     pickup_type: i32,
108     drop_off_type: i32,
109     timepoint: i32,
110 }
111 
112 #[derive(Default)]
113 struct ByteCounter {
114     count: usize,
115 }
116 impl io::Write for ByteCounter {
write(&mut self, data: &[u8]) -> io::Result<usize>117     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
118         self.count += data.len();
119         Ok(data.len())
120     }
flush(&mut self) -> io::Result<()>121     fn flush(&mut self) -> io::Result<()> {
122         Ok(())
123     }
124 }
125 
126 macro_rules! bench {
127     ($name:ident, $data:ident, $counter:ident, $result:expr) => {
128         #[bench]
129         fn $name(b: &mut Bencher) {
130             let data = $data.as_bytes();
131             b.bytes = data.len() as u64;
132             b.iter(|| {
133                 let mut rdr =
134                     ReaderBuilder::new().has_headers(false).from_reader(data);
135                 assert_eq!($counter(&mut rdr), $result);
136             })
137         }
138     };
139 }
140 
141 macro_rules! bench_trimmed {
142     ($name:ident, $data:ident, $counter:ident, $result:expr) => {
143         #[bench]
144         fn $name(b: &mut Bencher) {
145             let data = $data.as_bytes();
146             b.bytes = data.len() as u64;
147             b.iter(|| {
148                 let mut rdr = ReaderBuilder::new()
149                     .has_headers(false)
150                     .trim(Trim::All)
151                     .from_reader(data);
152                 assert_eq!($counter(&mut rdr), $result);
153             })
154         }
155     };
156 }
157 
158 macro_rules! bench_serde {
159     (no_headers,
160      $name_de:ident, $name_ser:ident, $data:ident, $counter:ident, $type:ty, $result:expr) => {
161         #[bench]
162         fn $name_de(b: &mut Bencher) {
163             let data = $data.as_bytes();
164             b.bytes = data.len() as u64;
165             b.iter(|| {
166                 let mut rdr =
167                     ReaderBuilder::new().has_headers(false).from_reader(data);
168                 assert_eq!($counter::<_, $type>(&mut rdr), $result);
169             })
170         }
171         #[bench]
172         fn $name_ser(b: &mut Bencher) {
173             let data = $data.as_bytes();
174             let values = ReaderBuilder::new()
175                 .has_headers(false)
176                 .from_reader(data)
177                 .deserialize()
178                 .collect::<Result<Vec<$type>, _>>()
179                 .unwrap();
180 
181             let do_it = || {
182                 let mut counter = ByteCounter::default();
183                 {
184                     let mut wtr = WriterBuilder::new()
185                         .has_headers(false)
186                         .from_writer(&mut counter);
187                     for val in &values {
188                         wtr.serialize(val).unwrap();
189                     }
190                 }
191                 counter.count
192             };
193             b.bytes = do_it() as u64;
194             b.iter(do_it)
195         }
196     };
197     ($name_de:ident, $name_ser:ident, $data:ident, $counter:ident, $type:ty, $result:expr) => {
198         #[bench]
199         fn $name_de(b: &mut Bencher) {
200             let data = $data.as_bytes();
201             b.bytes = data.len() as u64;
202             b.iter(|| {
203                 let mut rdr =
204                     ReaderBuilder::new().has_headers(true).from_reader(data);
205                 assert_eq!($counter::<_, $type>(&mut rdr), $result);
206             })
207         }
208         #[bench]
209         fn $name_ser(b: &mut Bencher) {
210             let data = $data.as_bytes();
211             let values = ReaderBuilder::new()
212                 .has_headers(true)
213                 .from_reader(data)
214                 .deserialize()
215                 .collect::<Result<Vec<$type>, _>>()
216                 .unwrap();
217 
218             let do_it = || {
219                 let mut counter = ByteCounter::default();
220                 {
221                     let mut wtr = WriterBuilder::new()
222                         .has_headers(true)
223                         .from_writer(&mut counter);
224                     for val in &values {
225                         wtr.serialize(val).unwrap();
226                     }
227                 }
228                 counter.count
229             };
230             b.bytes = do_it() as u64;
231             b.iter(do_it)
232         }
233     };
234 }
235 
236 macro_rules! bench_serde_borrowed_bytes {
237     ($name:ident, $data:ident, $type:ty, $headers:expr, $result:expr) => {
238         #[bench]
239         fn $name(b: &mut Bencher) {
240             let data = $data.as_bytes();
241             b.bytes = data.len() as u64;
242             b.iter(|| {
243                 let mut rdr = ReaderBuilder::new()
244                     .has_headers($headers)
245                     .from_reader(data);
246                 let mut count = 0;
247                 let mut rec = ByteRecord::new();
248                 while rdr.read_byte_record(&mut rec).unwrap() {
249                     let _: $type = rec.deserialize(None).unwrap();
250                     count += 1;
251                 }
252                 count
253             })
254         }
255     };
256 }
257 
258 macro_rules! bench_serde_borrowed_str {
259     ($name:ident, $data:ident, $type:ty, $headers:expr, $result:expr) => {
260         #[bench]
261         fn $name(b: &mut Bencher) {
262             let data = $data.as_bytes();
263             b.bytes = data.len() as u64;
264             b.iter(|| {
265                 let mut rdr = ReaderBuilder::new()
266                     .has_headers($headers)
267                     .from_reader(data);
268                 let mut count = 0;
269                 let mut rec = StringRecord::new();
270                 while rdr.read_record(&mut rec).unwrap() {
271                     let _: $type = rec.deserialize(None).unwrap();
272                     count += 1;
273                 }
274                 count
275             })
276         }
277     };
278 }
279 
280 bench_serde!(
281     count_nfl_deserialize_owned_bytes,
282     count_nfl_serialize_owned_bytes,
283     NFL,
284     count_deserialize_owned_bytes,
285     NFLRowOwned,
286     9999
287 );
288 bench_serde!(
289     count_nfl_deserialize_owned_str,
290     count_nfl_serialize_owned_str,
291     NFL,
292     count_deserialize_owned_str,
293     NFLRowOwned,
294     9999
295 );
296 bench_serde_borrowed_bytes!(
297     count_nfl_deserialize_borrowed_bytes,
298     NFL,
299     NFLRowBorrowed,
300     true,
301     9999
302 );
303 bench_serde_borrowed_str!(
304     count_nfl_deserialize_borrowed_str,
305     NFL,
306     NFLRowBorrowed,
307     true,
308     9999
309 );
310 bench!(count_nfl_iter_bytes, NFL, count_iter_bytes, 130000);
311 bench_trimmed!(count_nfl_iter_bytes_trimmed, NFL, count_iter_bytes, 130000);
312 bench!(count_nfl_iter_str, NFL, count_iter_str, 130000);
313 bench_trimmed!(count_nfl_iter_str_trimmed, NFL, count_iter_str, 130000);
314 bench!(count_nfl_read_bytes, NFL, count_read_bytes, 130000);
315 bench!(count_nfl_read_str, NFL, count_read_str, 130000);
316 bench_serde!(
317     no_headers,
318     count_game_deserialize_owned_bytes,
319     count_game_serialize_owned_bytes,
320     GAME,
321     count_deserialize_owned_bytes,
322     GAMERowOwned,
323     100000
324 );
325 bench_serde!(
326     no_headers,
327     count_game_deserialize_owned_str,
328     count_game_serialize_owned_str,
329     GAME,
330     count_deserialize_owned_str,
331     GAMERowOwned,
332     100000
333 );
334 bench_serde_borrowed_bytes!(
335     count_game_deserialize_borrowed_bytes,
336     GAME,
337     GAMERowBorrowed,
338     true,
339     100000
340 );
341 bench_serde_borrowed_str!(
342     count_game_deserialize_borrowed_str,
343     GAME,
344     GAMERowBorrowed,
345     true,
346     100000
347 );
348 bench!(count_game_iter_bytes, GAME, count_iter_bytes, 600000);
349 bench!(count_game_iter_str, GAME, count_iter_str, 600000);
350 bench!(count_game_read_bytes, GAME, count_read_bytes, 600000);
351 bench!(count_game_read_str, GAME, count_read_str, 600000);
352 bench_serde!(
353     count_pop_deserialize_owned_bytes,
354     count_pop_serialize_owned_bytes,
355     POP,
356     count_deserialize_owned_bytes,
357     POPRowOwned,
358     20000
359 );
360 bench_serde!(
361     count_pop_deserialize_owned_str,
362     count_pop_serialize_owned_str,
363     POP,
364     count_deserialize_owned_str,
365     POPRowOwned,
366     20000
367 );
368 bench_serde_borrowed_bytes!(
369     count_pop_deserialize_borrowed_bytes,
370     POP,
371     POPRowBorrowed,
372     true,
373     20000
374 );
375 bench_serde_borrowed_str!(
376     count_pop_deserialize_borrowed_str,
377     POP,
378     POPRowBorrowed,
379     true,
380     20000
381 );
382 bench!(count_pop_iter_bytes, POP, count_iter_bytes, 140007);
383 bench!(count_pop_iter_str, POP, count_iter_str, 140007);
384 bench!(count_pop_read_bytes, POP, count_read_bytes, 140007);
385 bench!(count_pop_read_str, POP, count_read_str, 140007);
386 bench_serde!(
387     count_mbta_deserialize_owned_bytes,
388     count_mbta_serialize_owned_bytes,
389     MBTA,
390     count_deserialize_owned_bytes,
391     MBTARowOwned,
392     9999
393 );
394 bench_serde!(
395     count_mbta_deserialize_owned_str,
396     count_mbta_serialize_owned_str,
397     MBTA,
398     count_deserialize_owned_str,
399     MBTARowOwned,
400     9999
401 );
402 bench_serde_borrowed_bytes!(
403     count_mbta_deserialize_borrowed_bytes,
404     MBTA,
405     MBTARowBorrowed,
406     true,
407     9999
408 );
409 bench_serde_borrowed_str!(
410     count_mbta_deserialize_borrowed_str,
411     MBTA,
412     MBTARowBorrowed,
413     true,
414     9999
415 );
416 bench!(count_mbta_iter_bytes, MBTA, count_iter_bytes, 90000);
417 bench!(count_mbta_iter_str, MBTA, count_iter_str, 90000);
418 bench!(count_mbta_read_bytes, MBTA, count_read_bytes, 90000);
419 bench!(count_mbta_read_str, MBTA, count_read_str, 90000);
420 
421 macro_rules! bench_write {
422     ($name:ident, $data:ident) => {
423         #[bench]
424         fn $name(b: &mut Bencher) {
425             let data = $data.as_bytes();
426             b.bytes = data.len() as u64;
427             let records = collect_records(data);
428 
429             b.iter(|| {
430                 let mut wtr = Writer::from_writer(vec![]);
431                 for r in &records {
432                     wtr.write_record(r).unwrap();
433                 }
434                 assert!(wtr.flush().is_ok());
435             })
436         }
437     };
438 }
439 
440 macro_rules! bench_write_bytes {
441     ($name:ident, $data:ident) => {
442         #[bench]
443         fn $name(b: &mut Bencher) {
444             let data = $data.as_bytes();
445             b.bytes = data.len() as u64;
446             let records = collect_records(data);
447 
448             b.iter(|| {
449                 let mut wtr = Writer::from_writer(vec![]);
450                 for r in &records {
451                     wtr.write_byte_record(r).unwrap();
452                 }
453                 assert!(wtr.flush().is_ok());
454             })
455         }
456     };
457 }
458 
459 bench_write!(write_nfl_record, NFL);
460 bench_write_bytes!(write_nfl_bytes, NFL);
461 
count_deserialize_owned_bytes<R, D>(rdr: &mut Reader<R>) -> u64 where R: io::Read, D: DeserializeOwned,462 fn count_deserialize_owned_bytes<R, D>(rdr: &mut Reader<R>) -> u64
463 where
464     R: io::Read,
465     D: DeserializeOwned,
466 {
467     let mut count = 0;
468     let mut rec = ByteRecord::new();
469     while rdr.read_byte_record(&mut rec).unwrap() {
470         let _: D = rec.deserialize(None).unwrap();
471         count += 1;
472     }
473     count
474 }
475 
count_deserialize_owned_str<R, D>(rdr: &mut Reader<R>) -> u64 where R: io::Read, D: DeserializeOwned,476 fn count_deserialize_owned_str<R, D>(rdr: &mut Reader<R>) -> u64
477 where
478     R: io::Read,
479     D: DeserializeOwned,
480 {
481     let mut count = 0;
482     for rec in rdr.deserialize::<D>() {
483         let _ = rec.unwrap();
484         count += 1;
485     }
486     count
487 }
488 
count_iter_bytes<R: io::Read>(rdr: &mut Reader<R>) -> u64489 fn count_iter_bytes<R: io::Read>(rdr: &mut Reader<R>) -> u64 {
490     let mut count = 0;
491     for rec in rdr.byte_records() {
492         count += rec.unwrap().len() as u64;
493     }
494     count
495 }
496 
count_iter_str<R: io::Read>(rdr: &mut Reader<R>) -> u64497 fn count_iter_str<R: io::Read>(rdr: &mut Reader<R>) -> u64 {
498     let mut count = 0;
499     for rec in rdr.records() {
500         count += rec.unwrap().len() as u64;
501     }
502     count
503 }
504 
count_read_bytes<R: io::Read>(rdr: &mut Reader<R>) -> u64505 fn count_read_bytes<R: io::Read>(rdr: &mut Reader<R>) -> u64 {
506     let mut count = 0;
507     let mut rec = ByteRecord::new();
508     while rdr.read_byte_record(&mut rec).unwrap() {
509         count += rec.len() as u64;
510     }
511     count
512 }
513 
count_read_str<R: io::Read>(rdr: &mut Reader<R>) -> u64514 fn count_read_str<R: io::Read>(rdr: &mut Reader<R>) -> u64 {
515     let mut count = 0;
516     let mut rec = StringRecord::new();
517     while rdr.read_record(&mut rec).unwrap() {
518         count += rec.len() as u64;
519     }
520     count
521 }
522 
collect_records(data: &[u8]) -> Vec<ByteRecord>523 fn collect_records(data: &[u8]) -> Vec<ByteRecord> {
524     let mut rdr = ReaderBuilder::new().has_headers(false).from_reader(data);
525     rdr.byte_records().collect::<Result<Vec<_>, _>>().unwrap()
526 }
527