Skip to content

Commit c5c8e96

Browse files
authored
Rollup merge of rust-lang#57537 - sinkuu:fmt_perf, r=alexcrichton
Small perf improvement for fmt Added benchmark is based on rust-lang#10761
2 parents 3c0d0c8 + 038d837 commit c5c8e96

File tree

5 files changed

+130
-5
lines changed

5 files changed

+130
-5
lines changed

src/libcore/benches/fmt.rs

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use std::io::{self, Write as IoWrite};
2+
use std::fmt::{self, Write as FmtWrite};
3+
use test::Bencher;
4+
5+
#[bench]
6+
fn write_vec_value(bh: &mut Bencher) {
7+
bh.iter(|| {
8+
let mut mem = Vec::new();
9+
for _ in 0..1000 {
10+
mem.write_all("abc".as_bytes()).unwrap();
11+
}
12+
});
13+
}
14+
15+
#[bench]
16+
fn write_vec_ref(bh: &mut Bencher) {
17+
bh.iter(|| {
18+
let mut mem = Vec::new();
19+
let wr = &mut mem as &mut dyn io::Write;
20+
for _ in 0..1000 {
21+
wr.write_all("abc".as_bytes()).unwrap();
22+
}
23+
});
24+
}
25+
26+
#[bench]
27+
fn write_vec_macro1(bh: &mut Bencher) {
28+
bh.iter(|| {
29+
let mut mem = Vec::new();
30+
let wr = &mut mem as &mut dyn io::Write;
31+
for _ in 0..1000 {
32+
write!(wr, "abc").unwrap();
33+
}
34+
});
35+
}
36+
37+
#[bench]
38+
fn write_vec_macro2(bh: &mut Bencher) {
39+
bh.iter(|| {
40+
let mut mem = Vec::new();
41+
let wr = &mut mem as &mut dyn io::Write;
42+
for _ in 0..1000 {
43+
write!(wr, "{}", "abc").unwrap();
44+
}
45+
});
46+
}
47+
48+
#[bench]
49+
fn write_vec_macro_debug(bh: &mut Bencher) {
50+
bh.iter(|| {
51+
let mut mem = Vec::new();
52+
let wr = &mut mem as &mut dyn io::Write;
53+
for _ in 0..1000 {
54+
write!(wr, "{:?}", "☃").unwrap();
55+
}
56+
});
57+
}
58+
59+
#[bench]
60+
fn write_str_value(bh: &mut Bencher) {
61+
bh.iter(|| {
62+
let mut mem = String::new();
63+
for _ in 0..1000 {
64+
mem.write_str("abc").unwrap();
65+
}
66+
});
67+
}
68+
69+
#[bench]
70+
fn write_str_ref(bh: &mut Bencher) {
71+
bh.iter(|| {
72+
let mut mem = String::new();
73+
let wr = &mut mem as &mut dyn fmt::Write;
74+
for _ in 0..1000 {
75+
wr.write_str("abc").unwrap();
76+
}
77+
});
78+
}
79+
80+
#[bench]
81+
fn write_str_macro1(bh: &mut Bencher) {
82+
bh.iter(|| {
83+
let mut mem = String::new();
84+
for _ in 0..1000 {
85+
write!(mem, "abc").unwrap();
86+
}
87+
});
88+
}
89+
90+
#[bench]
91+
fn write_str_macro2(bh: &mut Bencher) {
92+
bh.iter(|| {
93+
let mut mem = String::new();
94+
let wr = &mut mem as &mut dyn fmt::Write;
95+
for _ in 0..1000 {
96+
write!(wr, "{}", "abc").unwrap();
97+
}
98+
});
99+
}
100+
101+
#[bench]
102+
fn write_str_macro_debug(bh: &mut Bencher) {
103+
bh.iter(|| {
104+
let mut mem = String::new();
105+
let wr = &mut mem as &mut dyn fmt::Write;
106+
for _ in 0..1000 {
107+
write!(wr, "{:?}", "☃").unwrap();
108+
}
109+
});
110+
}

src/libcore/benches/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ mod iter;
1111
mod num;
1212
mod ops;
1313
mod slice;
14+
mod fmt;

src/libcore/fmt/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -997,28 +997,30 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result {
997997
curarg: args.args.iter(),
998998
};
999999

1000-
let mut pieces = args.pieces.iter();
1000+
let mut idx = 0;
10011001

10021002
match args.fmt {
10031003
None => {
10041004
// We can use default formatting parameters for all arguments.
1005-
for (arg, piece) in args.args.iter().zip(pieces.by_ref()) {
1005+
for (arg, piece) in args.args.iter().zip(args.pieces.iter()) {
10061006
formatter.buf.write_str(*piece)?;
10071007
(arg.formatter)(arg.value, &mut formatter)?;
1008+
idx += 1;
10081009
}
10091010
}
10101011
Some(fmt) => {
10111012
// Every spec has a corresponding argument that is preceded by
10121013
// a string piece.
1013-
for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
1014+
for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
10141015
formatter.buf.write_str(*piece)?;
10151016
formatter.run(arg)?;
1017+
idx += 1;
10161018
}
10171019
}
10181020
}
10191021

10201022
// There can be only one trailing string piece left.
1021-
if let Some(piece) = pieces.next() {
1023+
if let Some(piece) = args.pieces.get(idx) {
10221024
formatter.buf.write_str(*piece)?;
10231025
}
10241026

src/libfmt_macros/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ pub enum Position<'a> {
7272
ArgumentNamed(&'a str),
7373
}
7474

75+
impl Position<'_> {
76+
pub fn index(&self) -> Option<usize> {
77+
match self {
78+
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
79+
_ => None,
80+
}
81+
}
82+
}
83+
7584
/// Enum of alignments which are supported.
7685
#[derive(Copy, Clone, PartialEq)]
7786
pub enum Alignment {

src/libsyntax_ext/format.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,10 @@ impl<'a, 'b> Context<'a, 'b> {
493493

494494
let fill = arg.format.fill.unwrap_or(' ');
495495

496-
if *arg != simple_arg || fill != ' ' {
496+
let pos_simple =
497+
arg.position.index() == simple_arg.position.index();
498+
499+
if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
497500
self.all_pieces_simple = false;
498501
}
499502

0 commit comments

Comments
 (0)