perf(headers): switch from fmt to itoa when writing content-length header
This commit is contained in:
		| @@ -26,6 +26,7 @@ http = "0.1.5" | |||||||
| httparse = "1.0" | httparse = "1.0" | ||||||
| h2 = "0.1.5" | h2 = "0.1.5" | ||||||
| iovec = "0.1" | iovec = "0.1" | ||||||
|  | itoa = "0.4.1" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| net2 = { version = "0.2.32", optional = true } | net2 = { version = "0.2.32", optional = true } | ||||||
| time = "0.1" | time = "0.1" | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use std::fmt::Write; |  | ||||||
|  |  | ||||||
| use bytes::BytesMut; | use bytes::BytesMut; | ||||||
| use http::HeaderMap; | use http::HeaderMap; | ||||||
| use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; | use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING}; | ||||||
| @@ -70,7 +68,7 @@ pub fn content_length_parse_all_values(values: ValueIter<HeaderValue>) -> Option | |||||||
|  |  | ||||||
| pub fn content_length_value(len: u64) -> HeaderValue { | pub fn content_length_value(len: u64) -> HeaderValue { | ||||||
|     let mut len_buf = BytesMut::with_capacity(MAX_DECIMAL_U64_BYTES); |     let mut len_buf = BytesMut::with_capacity(MAX_DECIMAL_U64_BYTES); | ||||||
|     write!(len_buf, "{}", len) |     ::itoa::fmt(&mut len_buf, len) | ||||||
|         .expect("BytesMut can hold a decimal u64"); |         .expect("BytesMut can hold a decimal u64"); | ||||||
|     // safe because u64 Display is ascii numerals |     // safe because u64 Display is ascii numerals | ||||||
|     unsafe { |     unsafe { | ||||||
| @@ -141,6 +139,10 @@ fn eq_ascii(left: &str, right: &str) -> bool { | |||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|  |  | ||||||
|  |     #[cfg(feature = "nightly")] | ||||||
|  |     use test::Bencher; | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn assert_max_decimal_u64_bytes() { |     fn assert_max_decimal_u64_bytes() { | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
| @@ -148,4 +150,32 @@ mod tests { | |||||||
|             ::std::u64::MAX.to_string().len() |             ::std::u64::MAX.to_string().len() | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[cfg(feature = "nightly")] | ||||||
|  |     #[bench] | ||||||
|  |     fn bench_content_length_fmt_small(b: &mut Bencher) { | ||||||
|  |         let n = 13; | ||||||
|  |         let s = n.to_string(); | ||||||
|  |         b.bytes = s.len() as u64; | ||||||
|  |  | ||||||
|  |         b.iter(|| { | ||||||
|  |             let val = super::content_length_value(n); | ||||||
|  |             debug_assert_eq!(val, s); | ||||||
|  |             ::test::black_box(&val); | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[cfg(feature = "nightly")] | ||||||
|  |     #[bench] | ||||||
|  |     fn bench_content_length_fmt_big(b: &mut Bencher) { | ||||||
|  |         let n = 326_893_010; | ||||||
|  |         let s = n.to_string(); | ||||||
|  |         b.bytes = s.len() as u64; | ||||||
|  |  | ||||||
|  |         b.iter(|| { | ||||||
|  |             let val = super::content_length_value(n); | ||||||
|  |             debug_assert_eq!(val, s); | ||||||
|  |             ::test::black_box(&val); | ||||||
|  |         }) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ extern crate h2; | |||||||
| extern crate http; | extern crate http; | ||||||
| extern crate httparse; | extern crate httparse; | ||||||
| extern crate iovec; | extern crate iovec; | ||||||
|  | extern crate itoa; | ||||||
| #[macro_use] extern crate log; | #[macro_use] extern crate log; | ||||||
| #[cfg(feature = "runtime")] extern crate net2; | #[cfg(feature = "runtime")] extern crate net2; | ||||||
| extern crate time; | extern crate time; | ||||||
|   | |||||||
| @@ -190,7 +190,7 @@ impl Http1Transaction for Server { | |||||||
|         })) |         })) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn encode(mut msg: Encode<Self::Outgoing>, dst: &mut Vec<u8>) -> ::Result<Encoder> { |     fn encode(mut msg: Encode<Self::Outgoing>, mut dst: &mut Vec<u8>) -> ::Result<Encoder> { | ||||||
|         trace!( |         trace!( | ||||||
|             "Server::encode status={:?}, body={:?}, req_method={:?}", |             "Server::encode status={:?}, body={:?}, req_method={:?}", | ||||||
|             msg.head.subject, |             msg.head.subject, | ||||||
| @@ -439,7 +439,9 @@ impl Http1Transaction for Server { | |||||||
|                     Encoder::length(0) |                     Encoder::length(0) | ||||||
|                 }, |                 }, | ||||||
|                 Some(BodyLength::Known(len)) => { |                 Some(BodyLength::Known(len)) => { | ||||||
|                     let _ = write!(FastWrite(dst), "content-length: {}\r\n", len); |                     extend(dst, b"content-length: "); | ||||||
|  |                     let _ = ::itoa::write(&mut dst, len); | ||||||
|  |                     extend(dst, b"\r\n"); | ||||||
|                     Encoder::length(len) |                     Encoder::length(len) | ||||||
|                 }, |                 }, | ||||||
|             }; |             }; | ||||||
| @@ -1444,9 +1446,9 @@ mod tests { | |||||||
|         b.bytes = len as u64; |         b.bytes = len as u64; | ||||||
|  |  | ||||||
|         let mut head = MessageHead::default(); |         let mut head = MessageHead::default(); | ||||||
|  |         let mut vec = Vec::with_capacity(128); | ||||||
|  |  | ||||||
|         b.iter(|| { |         b.iter(|| { | ||||||
|             let mut vec = Vec::new(); |  | ||||||
|             Server::encode(Encode { |             Server::encode(Encode { | ||||||
|                 head: &mut head, |                 head: &mut head, | ||||||
|                 body: Some(BodyLength::Known(10)), |                 body: Some(BodyLength::Known(10)), | ||||||
| @@ -1455,7 +1457,12 @@ mod tests { | |||||||
|                 title_case_headers: false, |                 title_case_headers: false, | ||||||
|             }, &mut vec).unwrap(); |             }, &mut vec).unwrap(); | ||||||
|             assert_eq!(vec.len(), len); |             assert_eq!(vec.len(), len); | ||||||
|             ::test::black_box(vec); |             ::test::black_box(&vec); | ||||||
|  |  | ||||||
|  |             // reset Vec<u8> to 0 (always safe) | ||||||
|  |             unsafe { | ||||||
|  |                 vec.set_len(0); | ||||||
|  |             } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user