Skip to content

Commit

Permalink
Rollup merge of rust-lang#57537 - sinkuu:fmt_perf, r=alexcrichton
Browse files Browse the repository at this point in the history
Small perf improvement for fmt

Added benchmark is based on rust-lang#10761
  • Loading branch information
Centril authored Jan 15, 2019
2 parents 3c0d0c8 + 038d837 commit c5c8e96
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 5 deletions.
110 changes: 110 additions & 0 deletions src/libcore/benches/fmt.rs
Original file line number Diff line number Diff line change
@@ -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();
}
});
}
1 change: 1 addition & 0 deletions src/libcore/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ mod iter;
mod num;
mod ops;
mod slice;
mod fmt;
10 changes: 6 additions & 4 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,28 +997,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)?;
}

Expand Down
9 changes: 9 additions & 0 deletions src/libfmt_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ pub enum Position<'a> {
ArgumentNamed(&'a str),
}

impl Position<'_> {
pub fn index(&self) -> Option<usize> {
match self {
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
_ => None,
}
}
}

/// Enum of alignments which are supported.
#[derive(Copy, Clone, PartialEq)]
pub enum Alignment {
Expand Down
5 changes: 4 additions & 1 deletion src/libsyntax_ext/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit c5c8e96

Please sign in to comment.