diff --git a/Cargo.toml b/Cargo.toml index 0f642d3..564c3af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ clap = { version = "4.4.13", features = ["derive"] } rust_decimal = "1.34" rust_decimal_macros = "1.34" fast-float = "0.2" +rustc-hash = { version = "1.0"} diff --git a/flamegraphs/05-use-Fxhashmap/flamegraph.svg b/flamegraphs/05-use-Fxhashmap/flamegraph.svg new file mode 100644 index 0000000..aaa3960 --- /dev/null +++ b/flamegraphs/05-use-Fxhashmap/flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch [unknown] (13 samples, 0.01%)<alloc::string::String as core::ops::deref::Deref>::deref (125 samples, 0.14%)<alloc::vec::Vec<T,A> as core::ops::deref::Deref>::deref (125 samples, 0.14%)alloc::string::String::new (265 samples, 0.29%)core::str::<impl str>::ends_with (25 samples, 0.03%)<char as core::str::pattern::Pattern>::is_suffix_of (25 samples, 0.03%)<&str as core::str::pattern::Pattern>::is_suffix_of (25 samples, 0.03%)core::slice::<impl [T]>::ends_with (25 samples, 0.03%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index (770 samples, 0.84%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked (531 samples, 0.58%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked (531 samples, 0.58%)core::ptr::const_ptr::<impl *const T>::add (531 samples, 0.58%)<alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index (774 samples, 0.85%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (774 samples, 0.85%)alloc::string::String::len (253 samples, 0.28%)alloc::vec::Vec<T,A>::len (253 samples, 0.28%)core::ptr::drop_in_place<std::io::Guard> (33 samples, 0.04%)<std::io::Guard as core::ops::drop::Drop>::drop (33 samples, 0.04%)alloc::vec::Vec<T,A>::set_len (33 samples, 0.04%)core::result::Result<T,E>::is_err (201 samples, 0.22%)core::result::Result<T,E>::is_ok (201 samples, 0.22%)core::num::<impl usize>::wrapping_sub (27 samples, 0.03%)core::str::converts::from_utf8 (9,129 samples, 10.01%)core::str::con..core::str::validations::run_utf8_validation (5,648 samples, 6.20%)core::st..core::str::validations::utf8_char_width (74 samples, 0.08%)std::io::append_to_string (235 samples, 0.26%)<std::io::buffered::bufreader::BufReader<R> as std::io::BufRead>::consume (332 samples, 0.36%)std::io::buffered::bufreader::buffer::Buffer::consume (332 samples, 0.36%)core::cmp::min (258 samples, 0.28%)core::cmp::Ord::min (258 samples, 0.28%)std::io::append_to_string (258 samples, 0.28%)<std::io::buffered::bufreader::BufReader<R> as std::io::BufRead>::fill_buf (506 samples, 0.56%)std::io::buffered::bufreader::buffer::Buffer::fill_buf (506 samples, 0.56%)std::io::impls::<impl std::io::Read for &mut R>::read_buf (500 samples, 0.55%)<std::fs::File as std::io::Read>::read_buf (500 samples, 0.55%)read (486 samples, 0.53%)[unknown] (486 samples, 0.53%)[unknown] (415 samples, 0.46%)[unknown] (376 samples, 0.41%)[unknown] (375 samples, 0.41%)[unknown] (365 samples, 0.40%)[unknown] (292 samples, 0.32%)[unknown] (244 samples, 0.27%)[unknown] (191 samples, 0.21%)[unknown] (118 samples, 0.13%)[unknown] (85 samples, 0.09%)[unknown] (69 samples, 0.08%)[unknown] (36 samples, 0.04%)alloc::vec::Vec<T,A>::len (98 samples, 0.11%)alloc::raw_vec::RawVec<T,A>::needs_to_grow (26 samples, 0.03%)<core::result::Result<T,E> as core::ops::try_trait::Try>::branch (130 samples, 0.14%)__rdl_alloc (252 samples, 0.28%)__rust_alloc (532 samples, 0.58%)_ZN5alloc7raw_vec11finish_grow17h69ddc77eabc41a76E.llvm.11994866762887591369 (3,023 samples, 3.32%)_ZN..malloc (2,221 samples, 2.44%)ma..alloc::raw_vec::RawVec<T,A>::set_ptr_and_cap (99 samples, 0.11%)_ZN5alloc7raw_vec11finish_grow17h69ddc77eabc41a76E.llvm.11994866762887591369 (99 samples, 0.11%)alloc::raw_vec::finish_grow (958 samples, 1.05%)core::result::Result<T,E>::map_err (148 samples, 0.16%)core::alloc::layout::Layout::array (280 samples, 0.31%)core::alloc::layout::Layout::array::inner (280 samples, 0.31%)core::cmp::max (25 samples, 0.03%)core::cmp::Ord::max (25 samples, 0.03%)alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle (25 samples, 0.03%)alloc::raw_vec::RawVec<T,A>::grow_amortized (4,816 samples, 5.28%)alloc:..core::num::<impl usize>::checked_add (33 samples, 0.04%)core::num::<impl usize>::overflowing_add (33 samples, 0.04%)alloc::vec::Vec<T,A>::reserve (5,229 samples, 5.74%)alloc::..alloc::raw_vec::RawVec<T,A>::reserve (5,229 samples, 5.74%)alloc::..alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle (4,965 samples, 5.45%)alloc::..alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle (16 samples, 0.02%)core::intrinsics::copy_nonoverlapping (2,201 samples, 2.41%)co..[libc.so.6] (1,951 samples, 2.14%)[..alloc::vec::Vec<T,A>::append_elements (8,529 samples, 9.36%)alloc::vec::V..core::ptr::mut_ptr::<impl *mut T>::add (963 samples, 1.06%)alloc::vec::Vec<T,A>::extend_from_slice (8,595 samples, 9.43%)alloc::vec::V..<alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<&T,core::slice::iter::Iter<T>>>::spec_extend (8,595 samples, 9.43%)<alloc::vec::..std::io::append_to_string (66 samples, 0.07%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (17 samples, 0.02%)<core::ops::range::RangeToInclusive<usize> as core::slice::index::SliceIndex<[T]>>::index (17 samples, 0.02%)<core::ops::range::RangeInclusive<usize> as core::slice::index::SliceIndex<[T]>>::index (17 samples, 0.02%)<std::io::Lines<B> as core::iter::traits::iterator::Iterator>::next (28,639 samples, 31.41%)<std::io::Lines<B> as core::iter::traits::iterator:..std::io::BufRead::read_line (25,829 samples, 28.33%)std::io::BufRead::read_linestd::io::append_to_string (25,828 samples, 28.33%)std::io::append_to_stringstd::io::BufRead::read_line::_{{closure}} (11,998 samples, 13.16%)std::io::BufRead::re..std::io::read_until (11,763 samples, 12.90%)std::io::read_untilstd::sys_common::memchr::memchr (1,906 samples, 2.09%)s..std::sys::pal::unix::memchr::memchr (1,630 samples, 1.79%)s..[libc.so.6] (840 samples, 0.92%)core::result::Result<T,E>::expect (1,407 samples, 1.54%)core::cmp::impls::<impl core::cmp::PartialEq<&B> for &A>::eq (1,668 samples, 1.83%)c..core::slice::cmp::<impl core::cmp::PartialEq<[B]> for [A]>::eq (1,668 samples, 1.83%)c..<[A] as core::slice::cmp::SlicePartialEq<B>>::equal (1,668 samples, 1.83%)<..[libc.so.6] (1,074 samples, 1.18%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get (25 samples, 0.03%)core::slice::<impl [T]>::get (37 samples, 0.04%)core::str::iter::SplitInternal<P>::next (12 samples, 0.01%)core::num::<impl usize>::repeat_u8 (40 samples, 0.04%)core::ptr::const_ptr::<impl *const T>::align_offset (92 samples, 0.10%)core::ptr::align_offset (92 samples, 0.10%)core::slice::memchr::contains_zero_byte (102 samples, 0.11%)core::num::<impl usize>::wrapping_sub (26 samples, 0.03%)core::slice::memchr::memchr_aligned (847 samples, 0.93%)core::slice::memchr::memchr_naive (418 samples, 0.46%)<core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match (8,896 samples, 9.76%)<core::str::pa..core::slice::memchr::memchr (4,305 samples, 4.72%)core::..core::slice::memchr::memchr_naive (3,367 samples, 3.69%)core..core::str::<impl str>::get_unchecked (17 samples, 0.02%)core::str::traits::<impl core::slice::index::SliceIndex<str> for core::ops::range::Range<usize>>::get_unchecked (17 samples, 0.02%)<core::str::iter::Split<P> as core::iter::traits::iterator::Iterator>::next (14,765 samples, 16.20%)<core::str::iter::Split<P..core::str::iter::SplitInternal<P>::next (14,119 samples, 15.49%)core::str::iter::SplitIn..core::str::iter::SplitInternal<P>::get_end (830 samples, 0.91%)core::str::<impl str>::get_unchecked (218 samples, 0.24%)core::str::traits::<impl core::slice::index::SliceIndex<str> for core::ops::range::Range<usize>>::get_unchecked (218 samples, 0.24%)core::ptr::const_ptr::<impl *const T>::add (50 samples, 0.05%)__rdl_alloc (241 samples, 0.26%)__rust_alloc (265 samples, 0.29%)core::ptr::read_volatile (244 samples, 0.27%)alloc::vec::Vec<T,A>::with_capacity_in (2,481 samples, 2.72%)al..alloc::raw_vec::RawVec<T,A>::with_capacity_in (2,481 samples, 2.72%)al..alloc::raw_vec::RawVec<T,A>::allocate_in (2,481 samples, 2.72%)al..<alloc::alloc::Global as core::alloc::Allocator>::allocate (2,447 samples, 2.68%)<a..alloc::alloc::Global::alloc_impl (2,447 samples, 2.68%)al..alloc::alloc::alloc (2,447 samples, 2.68%)al..malloc (1,472 samples, 1.61%)alloc::str::<impl alloc::borrow::ToOwned for str>::to_owned (3,800 samples, 4.17%)alloc..alloc::slice::<impl alloc::borrow::ToOwned for [T]>::to_owned (3,800 samples, 4.17%)alloc..alloc::slice::<impl [T]>::to_vec (3,800 samples, 4.17%)alloc..alloc::slice::<impl [T]>::to_vec_in (3,800 samples, 4.17%)alloc..alloc::slice::hack::to_vec (3,800 samples, 4.17%)alloc..<T as alloc::slice::hack::ConvertVec>::to_vec (3,800 samples, 4.17%)<T as..core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping (1,319 samples, 1.45%)core::intrinsics::copy_nonoverlapping (1,319 samples, 1.45%)[libc.so.6] (1,309 samples, 1.44%)core::option::Option<T>::expect (1,015 samples, 1.11%)__rdl_dealloc (243 samples, 0.27%)__rust_dealloc (508 samples, 0.56%)<alloc::alloc::Global as core::alloc::Allocator>::deallocate (7,419 samples, 8.14%)<alloc::all..alloc::alloc::dealloc (7,419 samples, 8.14%)alloc::allo..cfree (6,668 samples, 7.31%)cfree[libc.so.6] (4,501 samples, 4.94%)[libc...core::ptr::drop_in_place<alloc::string::String> (7,425 samples, 8.14%)core::ptr::..core::ptr::drop_in_place<alloc::vec::Vec<u8>> (7,425 samples, 8.14%)core::ptr::..core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (7,425 samples, 8.14%)core::ptr::..<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (7,425 samples, 8.14%)<alloc::raw..core::str::<impl str>::split (296 samples, 0.32%)<f32 as fast_float::float::Float>::from_u64 (141 samples, 0.15%)fast_float::number::Number::try_fast_path (993 samples, 1.09%)fast_float::number::Number::is_fast_path (92 samples, 0.10%)fast_float::common::AsciiStr::check_first (38 samples, 0.04%)fast_float::common::AsciiStr::is_empty (34 samples, 0.04%)fast_float::common::AsciiStr::check_first_either (38 samples, 0.04%)fast_float::common::AsciiStr::is_empty (31 samples, 0.03%)fast_float::common::AsciiStr::first (264 samples, 0.29%)fast_float::number::try_parse_8digits_le (209 samples, 0.23%)fast_float::common::AsciiStr::try_read_u64 (209 samples, 0.23%)fast_float::common::AsciiStr::check_len (185 samples, 0.20%)core::num::<impl u8>::is_ascii_digit (349 samples, 0.38%)fast_float::common::AsciiStr::is_empty (259 samples, 0.28%)fast_float::common::AsciiStr::step (183 samples, 0.20%)fast_float::common::AsciiStr::step_by (183 samples, 0.20%)core::ptr::const_ptr::<impl *const T>::add (183 samples, 0.20%)fast_float::common::AsciiStr::parse_digits (1,254 samples, 1.38%)fast_float::number::try_parse_digits::_{{closure}} (205 samples, 0.22%)core::num::<impl u64>::wrapping_add (12 samples, 0.01%)fast_float::number::parse_number (6,225 samples, 6.83%)fast_floa..fast_float::number::try_parse_digits (1,459 samples, 1.60%)rust_1brc::main (205 samples, 0.22%)rust_1brc::read_line (35,798 samples, 39.27%)rust_1brc::read_linefast_float::parse (8,488 samples, 9.31%)fast_float::p..fast_float::FastFloat::parse_float (8,488 samples, 9.31%)fast_float::F..fast_float::FastFloat::parse_float_partial (8,488 samples, 9.31%)fast_float::F..fast_float::parse::parse_float (8,488 samples, 9.31%)fast_float::p..rust_1brc::main (22 samples, 0.02%)std::collections::hash::map::Entry<K,V>::and_modify (527 samples, 0.58%)rust_1brc::calculate_station_values::_{{closure}} (527 samples, 0.58%)__rdl_dealloc (274 samples, 0.30%)__rust_dealloc (260 samples, 0.29%)[libc.so.6] (1,858 samples, 2.04%)[..alloc::alloc::dealloc (3,488 samples, 3.83%)allo..cfree (2,688 samples, 2.95%)cf..std::collections::hash::map::Entry<K,V>::or_insert (3,497 samples, 3.84%)std:..std::collections::hash::map::OccupiedEntry<K,V>::into_mut (3,497 samples, 3.84%)std:..hashbrown::rustc_entry::RustcOccupiedEntry<K,V,A>::into_mut (3,497 samples, 3.84%)hash..core::ptr::drop_in_place<hashbrown::rustc_entry::RustcOccupiedEntry<alloc::string::String,rust_1brc::StationValues>> (3,497 samples, 3.84%)core..core::ptr::drop_in_place<core::option::Option<alloc::string::String>> (3,497 samples, 3.84%)core..core::ptr::drop_in_place<alloc::string::String> (3,494 samples, 3.83%)core..core::ptr::drop_in_place<alloc::vec::Vec<u8>> (3,494 samples, 3.83%)core..core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (3,494 samples, 3.83%)core..<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (3,494 samples, 3.83%)<all..<alloc::alloc::Global as core::alloc::Allocator>::deallocate (3,494 samples, 3.83%)<all..core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (267 samples, 0.29%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index (267 samples, 0.29%)<core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked (267 samples, 0.29%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked (267 samples, 0.29%)<usize as core::ops::bit::BitXor>::bitxor (317 samples, 0.35%)core::num::<impl usize>::rotate_left (164 samples, 0.18%)<rustc_hash::FxHasher as core::hash::Hasher>::write (2,191 samples, 2.40%)<r..rustc_hash::FxHasher::add_to_hash (700 samples, 0.77%)core::num::<impl usize>::wrapping_mul (219 samples, 0.24%)<usize as core::ops::bit::BitXor>::bitxor (516 samples, 0.57%)core::num::<impl usize>::rotate_left (28 samples, 0.03%)<rustc_hash::FxHasher as core::hash::Hasher>::write_u8 (758 samples, 0.83%)rustc_hash::FxHasher::add_to_hash (758 samples, 0.83%)core::num::<impl usize>::wrapping_mul (214 samples, 0.23%)hashbrown::map::make_hash (3,174 samples, 3.48%)has..core::hash::BuildHasher::hash_one (3,174 samples, 3.48%)cor..core::hash::impls::<impl core::hash::Hash for &T>::hash (3,174 samples, 3.48%)cor..<alloc::string::String as core::hash::Hash>::hash (3,149 samples, 3.45%)<al..core::hash::impls::<impl core::hash::Hash for str>::hash (3,149 samples, 3.45%)cor..core::hash::Hasher::write_str (3,149 samples, 3.45%)cor..hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (200 samples, 0.22%)<hashbrown::raw::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next (21 samples, 0.02%)hashbrown::raw::bitmask::BitMask::lowest_set_bit (21 samples, 0.02%)core::num::nonzero::NonZero<u16>::new (21 samples, 0.02%)hashbrown::raw::RawTable<T,A>::bucket (509 samples, 0.56%)hashbrown::raw::Bucket<T>::from_base_index (509 samples, 0.56%)core::ptr::mut_ptr::<impl *mut T>::sub (509 samples, 0.56%)core::ptr::mut_ptr::<impl *mut T>::offset (251 samples, 0.28%)[libc.so.6] (5,108 samples, 5.60%)[libc.s..<[A] as core::slice::cmp::SlicePartialEq<B>>::equal (8,203 samples, 9.00%)<[A] as core:..hashbrown::raw::RawTable<T,A>::find::_{{closure}} (8,813 samples, 9.67%)hashbrown::raw..hashbrown::rustc_entry::_<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry::_{{closure}} (8,204 samples, 9.00%)hashbrown::ru..<alloc::string::String as core::cmp::PartialEq>::eq (8,204 samples, 9.00%)<alloc::strin..alloc::vec::partial_eq::<impl core::cmp::PartialEq<alloc::vec::Vec<U,A2>> for alloc::vec::Vec<T,A1>>::eq (8,204 samples, 9.00%)alloc::vec::p..core::slice::cmp::<impl core::cmp::PartialEq<[B]> for [A]>::eq (8,204 samples, 9.00%)core::slice::..hashbrown::raw::h2 (2,336 samples, 2.56%)ha..hashbrown::raw::sse2::Group::load (205 samples, 0.22%)core::core_arch::x86::sse2::_mm_loadu_si128 (205 samples, 0.22%)hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (205 samples, 0.22%)hashbrown::raw::sse2::Group::match_byte (2,591 samples, 2.84%)ha..core::core_arch::x86::sse2::_mm_movemask_epi8 (2,591 samples, 2.84%)co..hashbrown::raw::RawTableInner::find_inner (15,739 samples, 17.26%)hashbrown::raw::RawTableInn..hashbrown::raw::sse2::Group::match_empty (122 samples, 0.13%)hashbrown::raw::sse2::Group::match_byte (122 samples, 0.13%)core::core_arch::x86::sse2::_mm_movemask_epi8 (122 samples, 0.13%)hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (20,502 samples, 22.49%)hashbrown::rustc_entry::<impl hashbr..hashbrown::raw::RawTable<T,A>::find (16,000 samples, 17.55%)hashbrown::raw::RawTable<T,..rust_1brc::calculate_station_values (91,143 samples, 99.97%)rust_1brc::calculate_station_valuesstd::collections::hash::map::HashMap<K,V,S>::entry (20,755 samples, 22.77%)std::collections::hash::map::HashMap..[libc.so.6] (91,144 samples, 99.97%)[libc.so.6]main (91,144 samples, 99.97%)mainstd::rt::lang_start_internal (91,144 samples, 99.97%)std::rt::lang_start_internalstd::rt::lang_start::_{{closure}} (91,144 samples, 99.97%)std::rt::lang_start::_{{closure}}std::sys_common::backtrace::__rust_begin_short_backtrace (91,144 samples, 99.97%)std::sys_common::backtrace::__rust_begin_short_backtracecore::ops::function::FnOnce::call_once (91,144 samples, 99.97%)core::ops::function::FnOnce::call_oncerust_1brc::main (91,144 samples, 99.97%)rust_1brc::mainall (91,167 samples, 100%)rust-1brc (91,167 samples, 100.00%)rust-1brc_start (91,145 samples, 99.98%)_start__libc_start_main (91,145 samples, 99.98%)__libc_start_main \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 13d01cf..c04149d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ use clap::Parser; use std::collections::BTreeMap; -use std::collections::HashMap; use std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::time::Instant; use fast_float; +use rustc_hash::FxHashMap; #[derive(Parser, Debug)] #[command( @@ -35,8 +35,8 @@ fn read_line(data: String) -> (String, f32) { } // Calculate the station values -fn calculate_station_values(data: BufReader) -> HashMap { - let mut result: HashMap = HashMap::new(); +fn calculate_station_values(data: BufReader) -> FxHashMap { + let mut result: FxHashMap = FxHashMap::default(); for line in data.lines() { let line = line.expect("Failed to read line"); let (station_name, value) = read_line(line); @@ -74,7 +74,7 @@ fn round_off(value: f32) -> f32 { (value * 10.0).round() / 10.0 } -fn write_result_stdout(result: HashMap) -> () { +fn write_result_stdout(result: FxHashMap) -> () { let mut ordered_result = BTreeMap::new(); for (station_name, station_values) in result { ordered_result.insert(station_name, station_values);