From 80ac15f667c32b1e441cffaa3237cae2990cc152 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 16 May 2021 21:31:18 -0400 Subject: [PATCH 1/2] Optimize default ToString impl This avoids a zero-length write_str call, which boils down to a zero-length memmove and ultimately costs quite a few instructions on some workloads. This is approximately a 0.33% instruction count win on diesel-check. --- library/alloc/src/string.rs | 5 +++-- library/core/src/fmt/mod.rs | 32 +++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e625245247086..ec09595e357a6 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2323,9 +2323,10 @@ impl ToString for T { // to try to remove it. #[inline] default fn to_string(&self) -> String { - use fmt::Write; let mut buf = String::new(); - buf.write_fmt(format_args!("{}", self)) + let mut formatter = core::fmt::Formatter::new(&mut buf); + // Bypass format_args!() to avoid write_str with zero-length strs + fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); buf } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 87042d95fbef0..5cb3c9062fe73 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -221,6 +221,28 @@ pub struct Formatter<'a> { buf: &'a mut (dyn Write + 'a), } +impl<'a> Formatter<'a> { + /// Creates a new formatter with default settings. + /// + /// This can be used as a micro-optimization in cases where a full `Arguments` + /// structure (as created by `format_args!`) is not necessary; `Arguments` + /// is a little more expensive to use in simple formatting scenarios. + /// + /// Currently not intended for use outside of the standard library. + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + #[doc(hidden)] + pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + Formatter { + flags: 0, + fill: ' ', + align: rt::v1::Alignment::Unknown, + width: None, + precision: None, + buf, + } + } +} + // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. @@ -1075,15 +1097,7 @@ pub trait UpperExp { /// [`write!`]: crate::write! #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { - let mut formatter = Formatter { - flags: 0, - width: None, - precision: None, - buf: output, - align: rt::v1::Alignment::Unknown, - fill: ' ', - }; - + let mut formatter = Formatter::new(output); let mut idx = 0; match args.fmt { From c7c93364697615edefccf281fa69b3f3af3dc67b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 17 May 2021 09:30:58 -0400 Subject: [PATCH 2/2] Avoid zero-length write_str in fmt::write --- library/core/src/fmt/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 5cb3c9062fe73..afef790ca64ea 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1104,7 +1104,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { None => { // We can use default formatting parameters for all arguments. for (arg, piece) in iter::zip(args.args, args.pieces) { - formatter.buf.write_str(*piece)?; + if !piece.is_empty() { + formatter.buf.write_str(*piece)?; + } (arg.formatter)(arg.value, &mut formatter)?; idx += 1; } @@ -1113,7 +1115,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { // Every spec has a corresponding argument that is preceded by // a string piece. for (arg, piece) in iter::zip(fmt, args.pieces) { - formatter.buf.write_str(*piece)?; + if !piece.is_empty() { + formatter.buf.write_str(*piece)?; + } // SAFETY: arg and args.args come from the same Arguments, // which guarantees the indexes are always within bounds. unsafe { run(&mut formatter, arg, &args.args) }?;