diff --git a/flamegraphs/01-Naive-Implementation/flamegraph.svg b/flamegraphs/01-Naive-Implementation/flamegraph.svg new file mode 100644 index 0000000..ee8868a --- /dev/null +++ b/flamegraphs/01-Naive-Implementation/flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch core::num::<impl usize>::repeat_u8 (142 samples, 0.11%)core::ptr::const_ptr::<impl *const T>::align_offset (279 samples, 0.22%)core::ptr::align_offset (279 samples, 0.22%)core::slice::memchr::contains_zero_byte (570 samples, 0.45%)core::num::<impl usize>::wrapping_sub (84 samples, 0.07%)core::str::iter::SplitInternal<P>::next_inclusive (12,827 samples, 10.18%)core::str::iter..<core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match (12,552 samples, 9.96%)<core::str::pa..core::slice::memchr::memchr (11,825 samples, 9.38%)core::slice::..core::slice::memchr::memchr_aligned (11,550 samples, 9.16%)core::slice::..core::slice::memchr::memchr_naive (5,079 samples, 4.03%)core..<core::str::iter::SplitInclusive<P> as core::iter::traits::iterator::Iterator>::next (12,849 samples, 10.19%)<core::str::ite..rust_1brc::main (22 samples, 0.02%)<core::str::LinesMap as core::ops::function::Fn<(&str,)>>::call (978 samples, 0.78%)core::str::<impl str>::strip_suffix (53 samples, 0.04%)<char as core::str::pattern::Pattern>::strip_suffix_of (53 samples, 0.04%)<&str as core::str::pattern::Pattern>::strip_suffix_of (53 samples, 0.04%)<&str as core::str::pattern::Pattern>::is_suffix_of (53 samples, 0.04%)core::slice::<impl [T]>::ends_with (53 samples, 0.04%)<core::str::iter::Lines as core::iter::traits::iterator::Iterator>::next (14,277 samples, 11.33%)<core::str::iter:..<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next (14,277 samples, 11.33%)<core::iter::adap..core::option::Option<T>::map (1,428 samples, 1.13%)core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once (1,428 samples, 1.13%)<core::str::LinesMap as core::ops::function::FnMut<(&str,)>>::call_mut (1,428 samples, 1.13%)rust_1brc::main (450 samples, 0.36%)__rdl_alloc (262 samples, 0.21%)__rust_alloc (504 samples, 0.40%)alloc::vec::Vec<T,A>::with_capacity_in (9,430 samples, 7.48%)alloc::vec..alloc::raw_vec::RawVec<T,A>::with_capacity_in (9,430 samples, 7.48%)alloc::raw..alloc::raw_vec::RawVec<T,A>::allocate_in (9,430 samples, 7.48%)alloc::raw..<alloc::alloc::Global as core::alloc::Allocator>::allocate (7,963 samples, 6.32%)<alloc::..alloc::alloc::Global::alloc_impl (7,963 samples, 6.32%)alloc::a..alloc::alloc::alloc (7,963 samples, 6.32%)alloc::a..malloc (6,729 samples, 5.34%)malloc[libc.so.6] (1,172 samples, 0.93%)<str as alloc::string::ToString>::to_string (10,614 samples, 8.42%)<str as allo..<alloc::string::String as core::convert::From<&str>>::from (10,614 samples, 8.42%)<alloc::stri..alloc::str::<impl alloc::borrow::ToOwned for str>::to_owned (10,614 samples, 8.42%)alloc::str::..alloc::slice::<impl alloc::borrow::ToOwned for [T]>::to_owned (10,614 samples, 8.42%)alloc::slice..alloc::slice::<impl [T]>::to_vec (10,614 samples, 8.42%)alloc::slice..alloc::slice::<impl [T]>::to_vec_in (10,614 samples, 8.42%)alloc::slice..alloc::slice::hack::to_vec (10,614 samples, 8.42%)alloc::slice..<T as alloc::slice::hack::ConvertVec>::to_vec (10,614 samples, 8.42%)<T as alloc:..core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping (1,184 samples, 0.94%)core::intrinsics::copy_nonoverlapping (1,184 samples, 0.94%)<F as core::str::pattern::MultiCharEq>::matches (453 samples, 0.36%)core::str::_<impl str>::trim::_{{closure}} (453 samples, 0.36%)core::char::methods::<impl char>::is_whitespace (453 samples, 0.36%)<core::str::pattern::MultiCharEqSearcher<C> as core::str::pattern::ReverseSearcher>::next_back (1,358 samples, 1.08%)<core::str::iter::CharIndices as core::iter::traits::double_ended::DoubleEndedIterator>::next_back (905 samples, 0.72%)<core::str::iter::Chars as core::iter::traits::double_ended::DoubleEndedIterator>::next_back (905 samples, 0.72%)core::str::validations::next_code_point_reverse (903 samples, 0.72%)<core::slice::iter::Iter<T> as core::iter::traits::double_ended::DoubleEndedIterator>::next_back (60 samples, 0.05%)<core::ptr::non_null::NonNull<T> as core::cmp::PartialEq>::eq (25 samples, 0.02%)<core::str::pattern::CharPredicateSearcher<F> as core::str::pattern::ReverseSearcher>::next_reject_back (1,418 samples, 1.12%)core::str::pattern::ReverseSearcher::next_reject_back (1,418 samples, 1.12%)core::str::<impl str>::trim_matches (60 samples, 0.05%)<F as core::str::pattern::MultiCharEq>::matches (219 samples, 0.17%)core::str::_<impl str>::trim::_{{closure}} (219 samples, 0.17%)core::char::methods::<impl char>::is_whitespace (219 samples, 0.17%)<core::str::pattern::MultiCharEqSearcher<C> as core::str::pattern::Searcher>::next (564 samples, 0.45%)<core::str::iter::CharIndices as core::iter::traits::iterator::Iterator>::next (338 samples, 0.27%)<core::str::iter::Chars as core::iter::traits::iterator::Iterator>::next (96 samples, 0.08%)core::str::validations::next_code_point (90 samples, 0.07%)core::str::validations::utf8_first_byte (29 samples, 0.02%)<core::str::pattern::CharPredicateSearcher<F> as core::str::pattern::Searcher>::next_reject (815 samples, 0.65%)core::str::pattern::Searcher::next_reject (815 samples, 0.65%)core::str::<impl str>::trim_matches (251 samples, 0.20%)core::str::<impl str>::trim (3,000 samples, 2.38%)co..core::str::<impl str>::trim_matches (2,996 samples, 2.38%)co..rust_1brc::main (158 samples, 0.13%)<alloc::vec::Vec<T,A> as core::ops::deref::Deref>::deref (127 samples, 0.10%)<alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index (750 samples, 0.59%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (623 samples, 0.49%)<usize as core::slice::index::SliceIndex<[T]>>::index (623 samples, 0.49%)__rdl_alloc (262 samples, 0.21%)__rust_alloc (501 samples, 0.40%)alloc::vec::Vec<T,A>::with_capacity_in (3,888 samples, 3.08%)all..alloc::raw_vec::RawVec<T,A>::with_capacity_in (3,888 samples, 3.08%)all..alloc::raw_vec::RawVec<T,A>::allocate_in (3,888 samples, 3.08%)all..<alloc::alloc::Global as core::alloc::Allocator>::allocate (2,860 samples, 2.27%)<..alloc::alloc::Global::alloc_impl (2,860 samples, 2.27%)a..alloc::alloc::alloc (2,860 samples, 2.27%)a..malloc (2,083 samples, 1.65%)<str as alloc::string::ToString>::to_string (4,952 samples, 3.93%)<str..<alloc::string::String as core::convert::From<&str>>::from (4,952 samples, 3.93%)<all..alloc::str::<impl alloc::borrow::ToOwned for str>::to_owned (4,952 samples, 3.93%)allo..alloc::slice::<impl alloc::borrow::ToOwned for [T]>::to_owned (4,952 samples, 3.93%)allo..alloc::slice::<impl [T]>::to_vec (4,952 samples, 3.93%)allo..alloc::slice::<impl [T]>::to_vec_in (4,952 samples, 3.93%)allo..alloc::slice::hack::to_vec (4,952 samples, 3.93%)allo..<T as alloc::slice::hack::ConvertVec>::to_vec (4,952 samples, 3.93%)<T a..core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping (1,064 samples, 0.84%)core::intrinsics::copy_nonoverlapping (1,064 samples, 0.84%)[libc.so.6] (1,049 samples, 0.83%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (42 samples, 0.03%)_ZN90_$LT$core..str..iter..Split$LT$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17hd5f458329bed3afeE.llvm.16165884326432275876 (373 samples, 0.30%)core::array::_<impl core::ops::index::Index<I> for [T: N]>::index (17 samples, 0.01%)core::slice::index::<impl core::ops::index::Index<I> for [T]>::index (17 samples, 0.01%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index (17 samples, 0.01%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get (268 samples, 0.21%)core::slice::<impl [T]>::get (273 samples, 0.22%)<core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match (3,124 samples, 2.48%)<c..core::slice::memchr::memchr (2,130 samples, 1.69%)core::slice::memchr::memchr_naive (1,196 samples, 0.95%)_ZN90_$LT$core..str..iter..Split$LT$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17hd5f458329bed3afeE.llvm.16165884326432275876 (328 samples, 0.26%)<core::str::iter::Split<P> as core::iter::traits::iterator::Iterator>::next (6,647 samples, 5.27%)<core:..core::str::iter::SplitInternal<P>::next (4,925 samples, 3.91%)core..core::str::iter::SplitInternal<P>::get_end (422 samples, 0.33%)core::str::<impl str>::get_unchecked (20 samples, 0.02%)core::str::traits::<impl core::slice::index::SliceIndex<str> for core::ops::range::Range<usize>>::get_unchecked (18 samples, 0.01%)core::ptr::const_ptr::<impl *const T>::add (15 samples, 0.01%)_ZN90_$LT$core..str..iter..Split$LT$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17hd5f458329bed3afeE.llvm.16165884326432275876 (39 samples, 0.03%)<alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<T,I>>::spec_extend (7,266 samples, 5.76%)<alloc:..alloc::vec::Vec<T,A>::extend_desugared (7,266 samples, 5.76%)alloc::..core::ptr::write (228 samples, 0.18%)_ZN90_$LT$core..str..iter..Split$LT$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17hd5f458329bed3afeE.llvm.16165884326432275876 (261 samples, 0.21%)core::cmp::impls::<impl core::cmp::PartialEq<&B> for &A>::eq (2,591 samples, 2.06%)c..core::slice::cmp::<impl core::cmp::PartialEq<[B]> for [A]>::eq (2,591 samples, 2.06%)c..<[A] as core::slice::cmp::SlicePartialEq<B>>::equal (2,591 samples, 2.06%)<..[libc.so.6] (1,269 samples, 1.01%)<core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get (57 samples, 0.05%)core::slice::<impl [T]>::get (87 samples, 0.07%)_ZN90_$LT$core..str..iter..Split$LT$P$GT$$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17hd5f458329bed3afeE.llvm.16165884326432275876 (30 samples, 0.02%)core::num::<impl usize>::repeat_u8 (38 samples, 0.03%)core::ptr::const_ptr::<impl *const T>::align_offset (99 samples, 0.08%)core::ptr::align_offset (99 samples, 0.08%)core::slice::memchr::contains_zero_byte (82 samples, 0.07%)core::slice::memchr::memchr_aligned (1,600 samples, 1.27%)core::slice::memchr::memchr_naive (873 samples, 0.69%)<core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match (8,946 samples, 7.10%)<core::str..core::slice::memchr::memchr (4,329 samples, 3.43%)cor..core::slice::memchr::memchr_naive (2,720 samples, 2.16%)c..<core::str::iter::Split<P> as core::iter::traits::iterator::Iterator>::next (12,167 samples, 9.65%)<core::str::it..core::str::iter::SplitInternal<P>::next (10,903 samples, 8.65%)core::str::i..__rdl_alloc (238 samples, 0.19%)__rust_alloc (740 samples, 0.59%)core::ptr::read_volatile (90 samples, 0.07%)alloc::vec::Vec<T>::with_capacity (6,597 samples, 5.23%)alloc:..alloc::vec::Vec<T,A>::with_capacity_in (6,597 samples, 5.23%)alloc:..alloc::raw_vec::RawVec<T,A>::with_capacity_in (6,597 samples, 5.23%)alloc:..alloc::raw_vec::RawVec<T,A>::allocate_in (6,597 samples, 5.23%)alloc:..<alloc::alloc::Global as core::alloc::Allocator>::allocate (5,748 samples, 4.56%)<allo..alloc::alloc::Global::alloc_impl (5,748 samples, 4.56%)alloc..alloc::alloc::alloc (5,748 samples, 4.56%)alloc..malloc (4,516 samples, 3.58%)mall..core::ptr::write (31 samples, 0.02%)core::iter::traits::iterator::Iterator::collect (28,119 samples, 22.31%)core::iter::traits::iterator::Itera..<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (28,119 samples, 22.31%)<alloc::vec::Vec<T> as core::iter::..<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (28,101 samples, 22.29%)<alloc::vec::Vec<T> as alloc::vec::..<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (27,054 samples, 21.46%)<alloc::vec::Vec<T> as alloc::vec:..__rdl_dealloc (253 samples, 0.20%)__rust_dealloc (252 samples, 0.20%)core::ptr::drop_in_place<alloc::string::String> (4,797 samples, 3.81%)core..core::ptr::drop_in_place<alloc::vec::Vec<u8>> (4,797 samples, 3.81%)core..core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (4,797 samples, 3.81%)core..<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (4,797 samples, 3.81%)<all..<alloc::alloc::Global as core::alloc::Allocator>::deallocate (4,797 samples, 3.81%)<all..alloc::alloc::dealloc (4,797 samples, 3.81%)allo..cfree (4,042 samples, 3.21%)cfr..[libc.so.6] (2,936 samples, 2.33%)[..__rdl_dealloc (274 samples, 0.22%)__rust_dealloc (248 samples, 0.20%)core::ptr::drop_in_place<alloc::vec::Vec<&str>> (3,145 samples, 2.49%)co..core::ptr::drop_in_place<alloc::raw_vec::RawVec<&str>> (3,145 samples, 2.49%)co..<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (3,145 samples, 2.49%)<a..<alloc::alloc::Global as core::alloc::Allocator>::deallocate (3,145 samples, 2.49%)<a..alloc::alloc::dealloc (3,145 samples, 2.49%)al..cfree (2,623 samples, 2.08%)c..[libc.so.6] (1,838 samples, 1.46%)core::result::Result<T,E>::expect (264 samples, 0.21%)core::num::dec2flt::<impl core::str::traits::FromStr for f32>::from_str (247 samples, 0.20%)<f32 as core::num::dec2flt::float::RawFloat>::from_u64 (185 samples, 0.15%)<f32 as core::num::dec2flt::float::RawFloat>::pow10_fast_path (16 samples, 0.01%)<f32 as core::ops::arith::Div>::div (3,237 samples, 2.57%)<f..core::num::dec2flt::number::Number::try_fast_path (3,822 samples, 3.03%)cor..core::num::dec2flt::number::Number::is_fast_path (79 samples, 0.06%)core::num::dec2flt::parse::parse_number (32 samples, 0.03%)core::num::<impl u8>::wrapping_sub (172 samples, 0.14%)<[u8] as core::num::dec2flt::common::ByteSlice>::parse_digits (1,839 samples, 1.46%)core::num::dec2flt::parse::try_parse_digits::_{{closure}} (100 samples, 0.08%)core::num::dec2flt::parse::try_parse_digits (3,020 samples, 2.40%)co..core::num::dec2flt::parse::parse_number (119 samples, 0.09%)core::num::dec2flt::parse::parse_number (4,700 samples, 3.73%)core..core::num::dec2flt::parse::parse_partial_number (3,649 samples, 2.89%)co..core::str::<impl str>::parse (11,663 samples, 9.25%)core::str::<i..core::num::dec2flt::<impl core::str::traits::FromStr for f32>::from_str (11,663 samples, 9.25%)core::num::de..core::num::dec2flt::dec2flt (10,678 samples, 8.47%)core::num::d..core::slice::<impl [T]>::first (243 samples, 0.19%)rust_1brc::read_line (56,898 samples, 45.14%)rust_1brc::read_linecore::str::<impl str>::split (471 samples, 0.37%)std::collections::hash::map::Entry<K,V>::and_modify (600 samples, 0.48%)rust_1brc::calculate_station_values::_{{closure}} (600 samples, 0.48%)__rdl_dealloc (297 samples, 0.24%)__rust_dealloc (521 samples, 0.41%)[libc.so.6] (2,142 samples, 1.70%)alloc::alloc::dealloc (3,820 samples, 3.03%)all..cfree (2,996 samples, 2.38%)cf..std::collections::hash::map::Entry<K,V>::or_insert (3,877 samples, 3.08%)std..std::collections::hash::map::OccupiedEntry<K,V>::into_mut (3,877 samples, 3.08%)std..hashbrown::rustc_entry::RustcOccupiedEntry<K,V,A>::into_mut (3,877 samples, 3.08%)has..core::ptr::drop_in_place<hashbrown::rustc_entry::RustcOccupiedEntry<alloc::string::String,rust_1brc::StationValues>> (3,877 samples, 3.08%)cor..core::ptr::drop_in_place<core::option::Option<alloc::string::String>> (3,877 samples, 3.08%)cor..core::ptr::drop_in_place<alloc::string::String> (3,824 samples, 3.03%)cor..core::ptr::drop_in_place<alloc::vec::Vec<u8>> (3,824 samples, 3.03%)cor..core::ptr::drop_in_place<alloc::raw_vec::RawVec<u8>> (3,824 samples, 3.03%)cor..<alloc::raw_vec::RawVec<T,A> as core::ops::drop::Drop>::drop (3,824 samples, 3.03%)<al..<alloc::alloc::Global as core::alloc::Allocator>::deallocate (3,824 samples, 3.03%)<al..core::num::<impl u64>::rotate_left (568 samples, 0.45%)<core::hash::sip::Sip13Rounds as core::hash::sip::Sip>::c_rounds (1,305 samples, 1.04%)core::num::<impl u64>::wrapping_add (228 samples, 0.18%)core::num::<impl u64>::rotate_left (2,906 samples, 2.31%)c..<core::hash::sip::Hasher<S> as core::hash::Hasher>::finish (6,397 samples, 5.07%)<core:..<core::hash::sip::Sip13Rounds as core::hash::sip::Sip>::d_rounds (3,928 samples, 3.12%)<co..core::num::<impl u64>::wrapping_add (528 samples, 0.42%)<std::hash::random::DefaultHasher as core::hash::Hasher>::finish (7,771 samples, 6.16%)<std::ha..<core::hash::sip::SipHasher13 as core::hash::Hasher>::finish (7,771 samples, 6.16%)<core::h..core::hash::BuildHasher::hash_one (1,374 samples, 1.09%)<std::hash::random::RandomState as core::hash::BuildHasher>::build_hasher (723 samples, 0.57%)core::hash::sip::SipHasher13::new_with_keys (454 samples, 0.36%)core::hash::sip::Hasher<S>::new_with_keys (454 samples, 0.36%)core::hash::sip::Hasher<S>::reset (454 samples, 0.36%)core::hash::BuildHasher::hash_one (170 samples, 0.13%)core::num::<impl u64>::rotate_left (402 samples, 0.32%)<core::hash::sip::Sip13Rounds as core::hash::sip::Sip>::c_rounds (673 samples, 0.53%)core::num::<impl u64>::wrapping_add (165 samples, 0.13%)<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (79 samples, 0.06%)core::hash::sip::u8to64_le (770 samples, 0.61%)core::intrinsics::copy_nonoverlapping (80 samples, 0.06%)<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (3,526 samples, 2.80%)<c..<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (19 samples, 0.02%)core::num::<impl u64>::rotate_left (100 samples, 0.08%)<core::hash::sip::Sip13Rounds as core::hash::sip::Sip>::c_rounds (273 samples, 0.22%)core::num::<impl u64>::wrapping_add (108 samples, 0.09%)core::cmp::min (132 samples, 0.10%)core::cmp::Ord::min (132 samples, 0.10%)<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (132 samples, 0.10%)hashbrown::map::make_hash (15,739 samples, 12.49%)hashbrown::map::mak..core::hash::BuildHasher::hash_one (15,649 samples, 12.41%)core::hash::BuildHa..core::hash::impls::<impl core::hash::Hash for &T>::hash (6,519 samples, 5.17%)core::..<alloc::string::String as core::hash::Hash>::hash (6,459 samples, 5.12%)<alloc..core::hash::impls::<impl core::hash::Hash for str>::hash (6,459 samples, 5.12%)core::..<std::hash::random::DefaultHasher as core::hash::Hasher>::write_str (6,459 samples, 5.12%)<std::..<core::hash::sip::SipHasher13 as core::hash::Hasher>::write_str (6,459 samples, 5.12%)<core:..<core::hash::sip::Hasher<S> as core::hash::Hasher>::write_str (6,459 samples, 5.12%)<core:..core::hash::Hasher::write_u8 (2,896 samples, 2.30%)c..<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (2,686 samples, 2.13%)<..core::hash::sip::u8to64_le (807 samples, 0.64%)core::num::nonzero::NonZero<u16>::new (82 samples, 0.07%)<hashbrown::raw::bitmask::BitMaskIter as core::iter::traits::iterator::Iterator>::next (88 samples, 0.07%)hashbrown::raw::bitmask::BitMask::lowest_set_bit (88 samples, 0.07%)hashbrown::raw::RawTable<T,A>::bucket (511 samples, 0.41%)hashbrown::raw::Bucket<T>::from_base_index (511 samples, 0.41%)core::ptr::mut_ptr::<impl *mut T>::sub (511 samples, 0.41%)core::ptr::mut_ptr::<impl *mut T>::offset (264 samples, 0.21%)hashbrown::raw::RawTable<T,A>::find::_{{closure}} (9,294 samples, 7.37%)hashbrown:..hashbrown::rustc_entry::_<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry::_{{closure}} (8,776 samples, 6.96%)hashbrown..<alloc::string::String as core::cmp::PartialEq>::eq (8,776 samples, 6.96%)<alloc::s..alloc::vec::partial_eq::<impl core::cmp::PartialEq<alloc::vec::Vec<U,A2>> for alloc::vec::Vec<T,A1>>::eq (8,776 samples, 6.96%)alloc::ve..core::slice::cmp::<impl core::cmp::PartialEq<[B]> for [A]>::eq (8,776 samples, 6.96%)core::sli..<[A] as core::slice::cmp::SlicePartialEq<B>>::equal (8,776 samples, 6.96%)<[A] as c..[libc.so.6] (5,804 samples, 4.60%)[libc..hashbrown::raw::h2 (1,909 samples, 1.51%)hashbrown::raw::sse2::Group::load (93 samples, 0.07%)core::core_arch::x86::sse2::_mm_loadu_si128 (93 samples, 0.07%)hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (92 samples, 0.07%)hashbrown::raw::sse2::Group::match_byte (2,324 samples, 1.84%)h..core::core_arch::x86::sse2::_mm_movemask_epi8 (2,324 samples, 1.84%)c..hashbrown::raw::sse2::Group::match_empty (138 samples, 0.11%)hashbrown::raw::sse2::Group::match_byte (138 samples, 0.11%)core::core_arch::x86::sse2::_mm_movemask_epi8 (138 samples, 0.11%)hashbrown::raw::RawTableInner::find_inner (16,007 samples, 12.70%)hashbrown::raw::Raw..hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (392 samples, 0.31%)hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (33,411 samples, 26.51%)hashbrown::rustc_entry::<impl hashbrown::m..hashbrown::raw::RawTable<T,A>::find (16,025 samples, 12.71%)hashbrown::raw::Raw..hashbrown::rustc_entry::<impl hashbrown::map::HashMap<K,V,S,A>>::rustc_entry (14 samples, 0.01%)rust_1brc::main (546 samples, 0.43%)rust_1brc::calculate_station_values (123,810 samples, 98.22%)rust_1brc::calculate_station_valuesstd::collections::hash::map::HashMap<K,V,S>::entry (34,084 samples, 27.04%)std::collections::hash::map::HashMap<K,V,S>..rust_1brc::main (290 samples, 0.23%)core::str::converts::from_utf8 (1,923 samples, 1.53%)core::str::validations::run_utf8_validation (1,923 samples, 1.53%)core::str::validations::utf8_char_width (73 samples, 0.06%)all (126,054 samples, 100%)rust-1brc (126,054 samples, 100.00%)rust-1brc_start (126,047 samples, 99.99%)_start__libc_start_main (126,047 samples, 99.99%)__libc_start_main[libc.so.6] (126,047 samples, 99.99%)[libc.so.6]main (126,047 samples, 99.99%)mainstd::rt::lang_start_internal (126,047 samples, 99.99%)std::rt::lang_start_internalstd::rt::lang_start::_{{closure}} (126,047 samples, 99.99%)std::rt::lang_start::_{{closure}}std::sys_common::backtrace::__rust_begin_short_backtrace (126,047 samples, 99.99%)std::sys_common::backtrace::__rust_begin_short_backtracecore::ops::function::FnOnce::call_once (126,047 samples, 99.99%)core::ops::function::FnOnce::call_oncerust_1brc::main (126,047 samples, 99.99%)rust_1brc::mainstd::fs::read_to_string (1,947 samples, 1.54%)std::fs::read_to_string::inner (1,947 samples, 1.54%)std::io::default_read_to_end (23 samples, 0.02%) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e7a11a9..90cc7a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,179 @@ +use clap::Parser; +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::time::Instant; + +#[derive(Parser, Debug)] +#[command( + name = "rs-1brc", + version = "1.0", + about = "confusedHooman's version of 1BRC challenge" +)] +struct Args { + #[arg(short = 'f', long, help = "Path to the measurement file")] + file: String, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +struct StationValues { + min: f32, + max: f32, + mean: f32, + count: u32, +} + +fn read_line(data: String) -> (String, f32) { + let parts: Vec<&str> = data.split(';').collect(); + let station_name = parts[0].to_string(); + let value = parts[1].parse::().expect("Failed to parse value"); + (station_name, value) +} + +// Calculate the station values +fn calculate_station_values(data: String) -> HashMap { + let mut result: HashMap = HashMap::new(); + for line in data.lines() { + let line = line.trim(); + let (station_name, value) = read_line(line.to_string()); + result + .entry(station_name) + .and_modify(|e| { + if value < e.min { + e.min = value; + } + if value > e.max { + e.max = value; + } + e.mean = e.mean + value; + e.count += 1; + }) + .or_insert(StationValues { + min: value, + max: value, + mean: value, + count: 1, + }); + } + + // Calculate the mean for all entries and round off to 1 decimal place + for (_, station_values) in result.iter_mut() { + station_values.mean = round_off(station_values.mean / station_values.count as f32); + station_values.min = round_off(station_values.min); + station_values.max = round_off(station_values.max); + } + + result +} + +fn round_off(value: f32) -> f32 { + (value * 10.0).round() / 10.0 +} + +fn write_result_stdout(result: HashMap) -> () { + let mut ordered_result = BTreeMap::new(); + for (station_name, station_values) in result { + ordered_result.insert(station_name, station_values); + } + let mut iterator = ordered_result.iter().peekable(); + print!("{{"); + while let Some((station_name, station_values)) = iterator.next() { + if iterator.peek().is_none() { + print!( + "{}={:.1}/{:.1}/{:.1}}}", + station_name, station_values.min, station_values.mean, station_values.max + ); + } else { + print!( + "{}={:.1}/{:.1}/{:.1}, ", + station_name, station_values.min, station_values.mean, station_values.max + ); + } + } +} + fn main() { - println!("Hello, world!"); + let start = Instant::now(); + let args = Args::parse(); + let data = std::fs::read_to_string(args.file).expect("Failed to read file"); + let result = calculate_station_values(data); + write_result_stdout(result); + let duration = start.elapsed(); + println!("\nTime taken is: {:?}", duration); + +} + +#[cfg(test)] +mod tests { + use crate::{calculate_station_values, StationValues}; + use std::{collections::HashMap, fs, path::PathBuf}; + #[test] + fn test_measurement_data() { + let test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); + let files = fs::read_dir(test_dir).unwrap(); + + for file in files { + let test_file_name = file.unwrap().path().to_str().unwrap().to_string(); + if test_file_name.ends_with(".out") { + continue; + } + let output_file_name = test_file_name.replace(".txt", ".out"); + print!("\nTest file: {}\n", test_file_name); + let test_output = read_test_output_file(output_file_name); + let data = fs::read_to_string(test_file_name.clone()).expect("Failed to read file"); + let mut result = calculate_station_values(data); + let mut test_output_map_copy = test_output.clone(); + + // compare two hashmaps + for (station_name, station_values) in test_output.into_iter() { + let result_station_values = result.remove(&station_name).expect( + ("Station not found: ".to_string() + &station_name + " in result hashmap") + .as_str(), + ); + assert_eq!(station_values.min, result_station_values.min); + assert_eq!(station_values.max, result_station_values.max); + assert_eq!(station_values.mean, result_station_values.mean); + test_output_map_copy.remove(&station_name); + } + + assert_eq!(result.len(), 0); + assert_eq!(test_output_map_copy.len(), 0); + + print!("Test passed\n"); + print!("-----------------------------------\n"); + } + } + + fn read_test_output_file(file_name: String) -> HashMap { + let data = std::fs::read_to_string(file_name).expect("Failed to read file"); + // remove whitespace and braces + // {Adelaide=15.0/15.0/15.0, Cabo San Lucas=14.9/14.9/14.9} => Adelaide=15.0/15.0/15.0, Cabo San Lucas=14.9/14.9/14.9 + let data_without_braces = data + .trim_start() + .trim_end() + .trim_matches(['{', '}'].as_ref()); + + // split the data by comma + // Adelaide=15.0/15.0/15.0, Cabo San Lucas=14.9/14.9/14.9 => [Adelaide=15.0/15.0/15.0, Cabo San Lucas=14.9/14.9/14.9] + let stations_data: Vec<&str> = data_without_braces.split(",").collect(); + let mut result: HashMap = HashMap::new(); + // split the data by "=" and "/" to get the station name and values + for station_data in stations_data { + let parts: Vec<&str> = station_data.split("=").collect(); + let station_name = parts[0].trim_start().trim_end().to_string(); + let values: Vec<&str> = parts[1].split("/").collect(); + let min = values[0].parse::().expect("Failed to parse min"); + let mean = values[1].parse::().expect("Failed to parse max"); + let max = values[2].parse::().expect("Failed to parse mean"); + result.insert( + station_name, + StationValues { + min, + max, + mean, + count: 0, + }, + ); + } + result + } }