From 0f34e0dabb1251de6769576105a0cd34d6a1db44 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sat, 12 Jan 2019 01:53:47 +0900 Subject: [PATCH 1/3] Add fmt benchmarks --- src/libcore/benches/fmt.rs | 110 +++++++++++++++++++++++++++++++++++++ src/libcore/benches/lib.rs | 1 + 2 files changed, 111 insertions(+) create mode 100644 src/libcore/benches/fmt.rs diff --git a/src/libcore/benches/fmt.rs b/src/libcore/benches/fmt.rs new file mode 100644 index 0000000000000..92f10c760c6d2 --- /dev/null +++ b/src/libcore/benches/fmt.rs @@ -0,0 +1,110 @@ +use std::io::{self, Write as IoWrite}; +use std::fmt::{self, Write as FmtWrite}; +use test::Bencher; + +#[bench] +fn write_vec_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + for _ in 0..1000 { + mem.write_all("abc".as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + wr.write_all("abc".as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "abc").unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{}", "abc").unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{:?}", "☃").unwrap(); + } + }); +} + +#[bench] +fn write_str_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + mem.write_str("abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + wr.write_str("abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + write!(mem, "abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{}", "abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{:?}", "☃").unwrap(); + } + }); +} diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 5b4971c81dd92..48572af611a5b 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -11,3 +11,4 @@ mod iter; mod num; mod ops; mod slice; +mod fmt; From d7a7ce9edd487dc151426dcb6d89911cc741e605 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sat, 12 Jan 2019 01:53:59 +0900 Subject: [PATCH 2/3] Utilize specialized zip iterator impl name old ns/iter new ns/iter diff ns/iter diff % speedup fmt::write_str_macro1 13,927 12,489 -1,438 -10.33% x 1.12 fmt::write_str_macro2 24,633 23,418 -1,215 -4.93% x 1.05 fmt::write_str_macro_debug 234,633 233,092 -1,541 -0.66% x 1.01 fmt::write_str_ref 5,819 5,823 4 0.07% x 1.00 fmt::write_str_value 6,012 5,828 -184 -3.06% x 1.03 fmt::write_vec_macro1 18,550 17,143 -1,407 -7.58% x 1.08 fmt::write_vec_macro2 30,369 28,920 -1,449 -4.77% x 1.05 fmt::write_vec_macro_debug 244,338 244,901 563 0.23% x 1.00 fmt::write_vec_ref 5,952 5,885 -67 -1.13% x 1.01 fmt::write_vec_value 5,944 5,894 -50 -0.84% x 1.01 --- src/libcore/fmt/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index ec1aeb8a7d1e9..306a715f02d6e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1026,28 +1026,30 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result { curarg: args.args.iter(), }; - let mut pieces = args.pieces.iter(); + let mut idx = 0; match args.fmt { None => { // We can use default formatting parameters for all arguments. - for (arg, piece) in args.args.iter().zip(pieces.by_ref()) { + for (arg, piece) in args.args.iter().zip(args.pieces.iter()) { formatter.buf.write_str(*piece)?; (arg.formatter)(arg.value, &mut formatter)?; + idx += 1; } } Some(fmt) => { // Every spec has a corresponding argument that is preceded by // a string piece. - for (arg, piece) in fmt.iter().zip(pieces.by_ref()) { + for (arg, piece) in fmt.iter().zip(args.pieces.iter()) { formatter.buf.write_str(*piece)?; formatter.run(arg)?; + idx += 1; } } } // There can be only one trailing string piece left. - if let Some(piece) = pieces.next() { + if let Some(piece) = args.pieces.get(idx) { formatter.buf.write_str(*piece)?; } From 038d8372244ab088ea186e10704e2bfc4e83f477 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sat, 12 Jan 2019 13:30:03 +0900 Subject: [PATCH 3/3] Fix simple formatting optimization name old2 ns/iter new2 ns/iter diff ns/iter diff % speedup fmt::write_str_macro1 12,295 12,308 13 0.11% x 1.00 fmt::write_str_macro2 24,079 21,451 -2,628 -10.91% x 1.12 fmt::write_str_macro_debug 238,363 230,807 -7,556 -3.17% x 1.03 fmt::write_str_ref 6,203 6,064 -139 -2.24% x 1.02 fmt::write_str_value 6,225 6,075 -150 -2.41% x 1.02 fmt::write_vec_macro1 17,144 17,121 -23 -0.13% x 1.00 fmt::write_vec_macro2 29,845 26,703 -3,142 -10.53% x 1.12 fmt::write_vec_macro_debug 248,840 242,117 -6,723 -2.70% x 1.03 fmt::write_vec_ref 5,954 6,438 484 8.13% x 0.92 fmt::write_vec_value 5,959 6,439 480 8.06% x 0.93 --- src/libfmt_macros/lib.rs | 9 +++++++++ src/libsyntax_ext/format.rs | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 32ae878909f30..da440cdd72f80 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -72,6 +72,15 @@ pub enum Position<'a> { ArgumentNamed(&'a str), } +impl Position<'_> { + pub fn index(&self) -> Option { + match self { + ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), + _ => None, + } + } +} + /// Enum of alignments which are supported. #[derive(Copy, Clone, PartialEq)] pub enum Alignment { diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 61722ba551653..0613c78e49590 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -493,7 +493,10 @@ impl<'a, 'b> Context<'a, 'b> { let fill = arg.format.fill.unwrap_or(' '); - if *arg != simple_arg || fill != ' ' { + let pos_simple = + arg.position.index() == simple_arg.position.index(); + + if !pos_simple || arg.format != simple_arg.format || fill != ' ' { self.all_pieces_simple = false; }