global: perf + resource imprv

This commit is contained in:
nym21
2025-07-12 15:07:02 +02:00
parent 0167a2ae59
commit b24a29895f
18 changed files with 274 additions and 417 deletions

5
.gitignore vendored
View File

@@ -18,3 +18,8 @@ _*
# Logs # Logs
.log .log
# Profiling
profile.json.gz
flamegraph.svg
*.trace

View File

@@ -1,2 +0,0 @@
profile.json.gz
flamegraph.svg

View File

@@ -13,7 +13,8 @@ pub fn main() -> color_eyre::Result<()> {
brk_logger::init(Some(Path::new(".log"))); brk_logger::init(Some(Path::new(".log")));
let bitcoin_dir = default_bitcoin_path(); // let bitcoin_dir = default_bitcoin_path();
let bitcoin_dir = Path::new("/Volumes/WD_BLACK/bitcoin");
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new( let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
"http://localhost:8332", "http://localhost:8332",
@@ -23,11 +24,11 @@ pub fn main() -> color_eyre::Result<()> {
// Can't increase main thread's stack programatically, thus we need to use another thread // Can't increase main thread's stack programatically, thus we need to use another thread
thread::Builder::new() thread::Builder::new()
.stack_size(32 * 1024 * 1024) .stack_size(256 * 1024 * 1024)
.spawn(move || -> color_eyre::Result<()> { .spawn(move || -> color_eyre::Result<()> {
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc); let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
let _outputs_dir = default_brk_path().join("outputs"); let _outputs_dir = Path::new("/Volumes/WD_BLACK/brk").join("outputs");
let outputs_dir = _outputs_dir.as_path(); let outputs_dir = _outputs_dir.as_path();
// let outputs_dir = Path::new("../../_outputs"); // let outputs_dir = Path::new("../../_outputs");

View File

@@ -0,0 +1,2 @@
cargo build --profile profiling
flamegraph -- ../../target/profiling/examples/main

2
crates/brk_computer/samply.sh Executable file
View File

@@ -0,0 +1,2 @@
cargo build --example main --profile profiling
samply record ../../target/profiling/examples/main

View File

@@ -1,30 +1,6 @@
use std::mem;
use derive_deref::{Deref, DerefMut}; use derive_deref::{Deref, DerefMut};
use super::ByAddressType; use super::ByAddressType;
#[derive(Debug, Default, Deref, DerefMut)] #[derive(Debug, Default, Deref, DerefMut)]
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>); pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
impl<T> AddressTypeToVec<T> {
pub fn merge(&mut self, mut other: Self) {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
Self::merge_(&mut self.p2sh, &mut other.p2sh);
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
}
fn merge_(own: &mut Vec<T>, other: &mut Vec<T>) {
if own.len() >= other.len() {
own.append(other);
} else {
other.append(own);
mem::swap(own, other);
}
}
}

View File

@@ -1,4 +1,4 @@
use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread}; use std::{cmp::Ordering, collections::BTreeMap, mem, ops::ControlFlow, path::Path, thread};
use brk_core::{ use brk_core::{
AddressData, ByAddressType, CheckedSub, DateIndex, Dollars, EmptyAddressData, Height, AddressData, ByAddressType, CheckedSub, DateIndex, Dollars, EmptyAddressData, Height,
@@ -8,7 +8,7 @@ use brk_exit::Exit;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_vec::{ use brk_vec::{
AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec, AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec,
StoredIndex, StoredVec, UnsafeSlice, VecIterator, StoredIndex, StoredVec, VecIterator,
}; };
use either::Either; use either::Either;
use log::info; use log::info;
@@ -57,7 +57,7 @@ use range_map::*;
use r#trait::CohortVecs; use r#trait::CohortVecs;
pub use withaddressdatasource::WithAddressDataSource; pub use withaddressdatasource::WithAddressDataSource;
const VERSION: Version = Version::new(12); const VERSION: Version = Version::new(18);
#[derive(Clone)] #[derive(Clone)]
pub struct Vecs { pub struct Vecs {
@@ -497,11 +497,11 @@ impl Vecs {
let dateindex_to_first_height = &indexes.dateindex_to_first_height; let dateindex_to_first_height = &indexes.dateindex_to_first_height;
let dateindex_to_height_count = &indexes.dateindex_to_height_count; let dateindex_to_height_count = &indexes.dateindex_to_height_count;
let inputindex_to_outputindex_mmap = inputindex_to_outputindex.mmap().load();
let outputindex_to_value_mmap = outputindex_to_value.mmap().load(); let outputindex_to_value_mmap = outputindex_to_value.mmap().load();
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load(); let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load();
let outputindex_to_typeindex_mmap = outputindex_to_typeindex.mmap().load(); let outputindex_to_typeindex_mmap = outputindex_to_typeindex.mmap().load();
let mut inputindex_to_outputindex_iter = inputindex_to_outputindex.into_iter();
let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter(); let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter();
let mut height_to_first_inputindex_iter = height_to_first_inputindex.into_iter(); let mut height_to_first_inputindex_iter = height_to_first_inputindex.into_iter();
let mut height_to_first_p2aaddressindex_iter = height_to_first_p2aaddressindex.into_iter(); let mut height_to_first_p2aaddressindex_iter = height_to_first_p2aaddressindex.into_iter();
@@ -701,6 +701,8 @@ impl Vecs {
.try_for_each(|_height| -> color_eyre::Result<()> { .try_for_each(|_height| -> color_eyre::Result<()> {
height = _height; height = _height;
info!("Processing chain at {height}...");
self.utxo_vecs self.utxo_vecs
.as_mut_separate_vecs() .as_mut_separate_vecs()
.iter_mut() .iter_mut()
@@ -711,8 +713,6 @@ impl Vecs {
.iter_mut() .iter_mut()
.for_each(|(_, v)| v.state.reset_single_iteration_values()); .for_each(|(_, v)| v.state.reset_single_iteration_values());
info!("Processing chain at {height}...");
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height); let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
let price = height_to_close_iter let price = height_to_close_iter
.as_mut() .as_mut()
@@ -754,193 +754,40 @@ impl Vecs {
}; };
let ( let (
(mut height_to_sent, addresstype_to_typedindex_to_sent_data), mut transacted,
(mut transacted, addresstype_to_typedindex_to_received_data), addresstype_to_typedindex_to_received_data,
) = thread::scope(|s| { mut height_to_sent,
if chain_state_starting_height <= height { addresstype_to_typedindex_to_sent_data,
s.spawn(|| { ) = thread::scope(|scope| {
scope.spawn(|| {
self.utxo_vecs.tick_tock_next_block(&chain_state, timestamp); self.utxo_vecs.tick_tock_next_block(&chain_state, timestamp);
}); });
}
let sent_handle = s.spawn(|| { let received = scope.spawn(|| {
// Skip coinbase let mut transacted = Transacted::default();
(first_inputindex + 1..first_inputindex + *input_count)
.into_par_iter()
.map(InputIndex::from)
.map(|inputindex| {
let outputindex = inputindex_to_outputindex
.get_or_read(
inputindex,
&inputindex_to_outputindex_mmap,
)
.unwrap()
.unwrap()
.into_owned();
let value = outputindex_to_value let mut addresstype_to_typedindex_to_received_data = AddressTypeToVec::<
.get_or_read(outputindex, &outputindex_to_value_mmap) (TypeIndex, Sats, Option<WithAddressDataSource<AddressData>>),
.unwrap() >::default(
.unwrap()
.into_owned();
let input_type = outputindex_to_outputtype
.get_or_read(
outputindex,
&outputindex_to_outputtype_mmap,
)
.unwrap()
.unwrap()
.into_owned();
let prev_height =
*outputindex_range_to_height.get(outputindex).unwrap();
if input_type.is_unspendable() {
unreachable!()
} else if input_type.is_not_address() {
return (
prev_height,
value,
input_type,
None,
); );
}
let typeindex = outputindex_to_typeindex let _ = (first_outputindex..first_outputindex + *output_count)
.get_or_read(
outputindex,
&outputindex_to_typeindex_mmap,
)
.unwrap()
.unwrap()
.into_owned();
let addressdata_opt = if input_type.is_address()
&& *first_addressindexes.get(input_type).unwrap()
> typeindex
&& !addresstype_to_typeindex_to_addressdata
.get(input_type)
.unwrap()
.contains_key(&typeindex)
&& let Some(address_data) = stores
.get_addressdata(input_type, typeindex)
.unwrap()
// Otherwise it was empty and got funds in the same block before sending them
{
Some(WithAddressDataSource::FromAddressDataStore(
address_data,
))
} else {
None
};
(
prev_height,
value,
input_type,
Some((typeindex, addressdata_opt)),
)
})
.fold(
|| {
(
BTreeMap::<Height, Transacted>::default(),
HeightToAddressTypeToVec::<(
TypeIndex,
Sats,
Option<WithAddressDataSource<AddressData>>,
)>::default(
),
)
},
|(mut tree, mut tree2),
(
height,
value,
input_type,
address_data_opt,
)| {
tree.entry(height)
.or_default()
.iterate(value, input_type);
if let Some((typeindex, addressdata_opt)) =
address_data_opt
{
tree2
.entry(height)
.or_default()
.get_mut(input_type)
.unwrap()
.push((typeindex, value, addressdata_opt));
}
(tree, tree2)
},
)
.reduce(
|| {
(
BTreeMap::<Height, Transacted>::default(),
HeightToAddressTypeToVec::<(
TypeIndex,
Sats,
Option<WithAddressDataSource<AddressData>>,
)>::default(
),
)
},
|(first_tree, first_tree2), (second_tree, second_tree2)| {
let (mut tree_source, tree_to_consume) =
if first_tree.len() > second_tree.len() {
(first_tree, second_tree)
} else {
(second_tree, first_tree)
};
tree_to_consume.into_iter().for_each(|(k, v)| {
*tree_source.entry(k).or_default() += v;
});
let (mut tree_source2, tree_to_consume2) =
if first_tree2.len() > second_tree2.len() {
(first_tree2, second_tree2)
} else {
(second_tree2, first_tree2)
};
tree_to_consume2.0.into_iter().for_each(|(k, v)| {
tree_source2.entry(k).or_default().merge(v);
});
(tree_source, tree_source2)
},
)
});
let received_output = (first_outputindex
..first_outputindex + *output_count)
.into_par_iter()
.map(OutputIndex::from) .map(OutputIndex::from)
.map(|outputindex| { .try_for_each(|outputindex| -> ControlFlow<()> {
let value = outputindex_to_value let value = outputindex_to_value
.get_or_read(outputindex, &outputindex_to_value_mmap) .unwrap_read(outputindex, &outputindex_to_value_mmap);
.unwrap()
.unwrap()
.into_owned();
let output_type = outputindex_to_outputtype let output_type = outputindex_to_outputtype
.get_or_read(outputindex, &outputindex_to_outputtype_mmap) .unwrap_read(outputindex, &outputindex_to_outputtype_mmap);
.unwrap()
.unwrap() transacted.iterate(value, output_type);
.into_owned();
if output_type.is_not_address() { if output_type.is_not_address() {
return (value, output_type, None); return ControlFlow::Continue(());
} }
let typeindex = outputindex_to_typeindex let typeindex = outputindex_to_typeindex
.get_or_read(outputindex, &outputindex_to_typeindex_mmap) .unwrap_read(outputindex, &outputindex_to_typeindex_mmap);
.unwrap()
.unwrap()
.into_owned();
let addressdata_opt = if *first_addressindexes let addressdata_opt = if *first_addressindexes
.get(output_type) .get(output_type)
@@ -958,10 +805,13 @@ impl Vecs {
.contains_key(&typeindex) .contains_key(&typeindex)
{ {
Some( Some(
if let Some(addressdata) = if let Some(addressdata) = stores
stores.get_addressdata(output_type, typeindex).unwrap() .get_addressdata(output_type, typeindex)
.unwrap()
{ {
WithAddressDataSource::FromAddressDataStore(addressdata) WithAddressDataSource::FromAddressDataStore(
addressdata,
)
} else if let Some(emptyaddressdata) = stores } else if let Some(emptyaddressdata) = stores
.get_emptyaddressdata(output_type, typeindex) .get_emptyaddressdata(output_type, typeindex)
.unwrap() .unwrap()
@@ -970,65 +820,122 @@ impl Vecs {
emptyaddressdata.into(), emptyaddressdata.into(),
) )
} else { } else {
WithAddressDataSource::New(AddressData::default()) unreachable!("I think ?")
}, },
) )
} else { } else {
None None
}; };
( addresstype_to_typedindex_to_received_data
value, .get_mut(output_type)
output_type, .unwrap()
Some((typeindex, addressdata_opt)), .push((typeindex, value, addressdata_opt));
)
})
.fold(
|| {
(
Transacted::default(),
AddressTypeToVec::<(
TypeIndex,
Sats,
Option<WithAddressDataSource<AddressData>>,
)>::default(),
)
},
|(mut transacted, mut vecs),
(
value,
output_type,
typeindex_with_addressdata_opt,
)| {
transacted.iterate(value, output_type);
if let Some(vec) = vecs.get_mut(output_type) {
let (typeindex, addressdata_opt) =
typeindex_with_addressdata_opt.unwrap();
vec.push((typeindex, value, addressdata_opt));
}
(transacted, vecs) ControlFlow::Continue(())
}, });
)
.reduce(
|| {
(
Transacted::default(),
AddressTypeToVec::<(
TypeIndex,
Sats,
Option<WithAddressDataSource<AddressData>>,
)>::default(),
)
},
|(transacted, mut vecs), (other_transacted, other_vecs)| {
vecs.merge(other_vecs);
(transacted + other_transacted, vecs) (transacted, addresstype_to_typedindex_to_received_data)
}, });
let mut height_to_sent = BTreeMap::<Height, Transacted>::default();
let mut addresstype_to_typedindex_to_sent_data = HeightToAddressTypeToVec::<
(TypeIndex, Sats, Option<WithAddressDataSource<AddressData>>),
>::default(
); );
(sent_handle.join().unwrap(), received_output) // Skip coinbase
let _ = (first_inputindex + 1..first_inputindex + *input_count)
.map(InputIndex::from)
.try_for_each(|inputindex| -> ControlFlow<()> {
let outputindex =
inputindex_to_outputindex_iter.unwrap_get_inner(inputindex);
let value = outputindex_to_value
.unwrap_read(outputindex, &outputindex_to_value_mmap);
let input_type = outputindex_to_outputtype
.unwrap_read(outputindex, &outputindex_to_outputtype_mmap);
let prev_height =
*outputindex_range_to_height.get(outputindex).unwrap();
height_to_sent
.entry(prev_height)
.or_default()
.iterate(value, input_type);
if input_type.is_not_address() {
return ControlFlow::Continue(());
}
let typeindex = outputindex_to_typeindex
.unwrap_read(outputindex, &outputindex_to_typeindex_mmap);
let addressdata_opt = if *first_addressindexes
.get(input_type)
.unwrap()
> typeindex
&& !addresstype_to_typeindex_to_addressdata
.get(input_type)
.unwrap()
.contains_key(&typeindex)
&& let Some(address_data) =
stores.get_addressdata(input_type, typeindex).unwrap()
// Otherwise it was empty and got funds in the same block before sending them
{
Some(WithAddressDataSource::FromAddressDataStore(address_data))
} else {
None
};
addresstype_to_typedindex_to_sent_data
.entry(prev_height)
.or_default()
.get_mut(input_type)
.unwrap()
.push((typeindex, value, addressdata_opt));
ControlFlow::Continue(())
});
let (transacted, addresstype_to_typedindex_to_received_data) =
received.join().unwrap();
(
transacted,
addresstype_to_typedindex_to_received_data,
height_to_sent,
addresstype_to_typedindex_to_sent_data,
)
});
thread::scope(|scope| {
scope.spawn(|| {
addresstype_to_typedindex_to_received_data.process_received(
&mut self.address_vecs,
&mut addresstype_to_typeindex_to_addressdata,
&mut addresstype_to_typeindex_to_emptyaddressdata,
price,
&mut addresstype_to_address_count,
&mut addresstype_to_empty_address_count,
);
addresstype_to_typedindex_to_sent_data
.process_sent(
&mut self.address_vecs,
&mut addresstype_to_typeindex_to_addressdata,
&mut addresstype_to_typeindex_to_emptyaddressdata,
price,
&mut addresstype_to_address_count,
&mut addresstype_to_empty_address_count,
height_to_close_vec.as_ref(),
&height_to_timestamp_fixed_vec,
height,
timestamp,
)
.unwrap();
}); });
if chain_state_starting_height > height { if chain_state_starting_height > height {
@@ -1059,9 +966,6 @@ impl Vecs {
} }
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65); .iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
}; };
thread::scope(|scope| -> Result<()> {
scope.spawn(|| {
// Push current block state before processing sends and receives // Push current block state before processing sends and receives
chain_state.push(BlockState { chain_state.push(BlockState {
supply: transacted.spendable_supply.clone(), supply: transacted.spendable_supply.clone(),
@@ -1071,41 +975,9 @@ impl Vecs {
self.utxo_vecs.receive(transacted, height, price); self.utxo_vecs.receive(transacted, height, price);
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state); self.utxo_vecs.send(height_to_sent, &mut chain_state);
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
&sent.spendable_supply;
}); });
self.utxo_vecs.send(height_to_sent, chain_state.as_slice());
});
addresstype_to_typedindex_to_received_data.process_received(
&mut self.address_vecs,
&mut addresstype_to_typeindex_to_addressdata,
&mut addresstype_to_typeindex_to_emptyaddressdata,
price,
&mut addresstype_to_address_count,
&mut addresstype_to_empty_address_count,
);
addresstype_to_typedindex_to_sent_data.process_sent(
&mut self.address_vecs,
&mut addresstype_to_typeindex_to_addressdata,
&mut addresstype_to_typeindex_to_emptyaddressdata,
price,
&mut addresstype_to_address_count,
&mut addresstype_to_empty_address_count,
height_to_close_vec.as_ref(),
&height_to_timestamp_fixed_vec,
height,
timestamp,
)?;
Ok(())
})?;
let mut separate_utxo_vecs = self.utxo_vecs.as_mut_separate_vecs(); let mut separate_utxo_vecs = self.utxo_vecs.as_mut_separate_vecs();
separate_utxo_vecs separate_utxo_vecs
@@ -1168,10 +1040,17 @@ impl Vecs {
info!("Flushing..."); info!("Flushing...");
exit.block(); exit.block();
self.flush_states(height, &chain_state, exit)?; self.flush_states(height, &chain_state, exit)?;
// Maybe keep some from the end for both
let addresstype_to_typeindex_to_addressdata_to_consume =
mem::take(&mut addresstype_to_typeindex_to_addressdata);
let addresstype_to_typeindex_to_emptyaddressdata_to_consume =
mem::take(&mut addresstype_to_typeindex_to_emptyaddressdata);
stores.commit( stores.commit(
height, height,
mem::take(&mut addresstype_to_typeindex_to_addressdata), addresstype_to_typeindex_to_addressdata_to_consume,
mem::take(&mut addresstype_to_typeindex_to_emptyaddressdata), addresstype_to_typeindex_to_emptyaddressdata_to_consume,
)?; )?;
exit.release(); exit.release();
} }
@@ -1565,7 +1444,7 @@ impl HeightToAddressTypeToVec<(TypeIndex, Sats, Option<WithAddressDataSource<Add
let blocks_old = height.unwrap_to_usize() - prev_height.unwrap_to_usize(); let blocks_old = height.unwrap_to_usize() - prev_height.unwrap_to_usize();
let days_old = prev_timestamp.difference_in_days_between_float(timestamp); let days_old = timestamp.difference_in_days_between_float(prev_timestamp);
let older_than_hour = timestamp let older_than_hour = timestamp
.checked_sub(prev_timestamp) .checked_sub(prev_timestamp)

View File

@@ -1342,17 +1342,15 @@ impl Vecs {
self.age_range self.age_range
.as_mut_vec() .as_mut_vec()
.into_par_iter() .into_iter()
.for_each(|(filter, v)| { .map(|(filter, v)| (filter, &mut v.state))
let state = &mut v.state; .for_each(|(filter, state)| {
let _ = chain_state let _ = chain_state
.iter() .iter()
.try_for_each(|block_state| -> ControlFlow<()> { .try_for_each(|block_state| -> ControlFlow<()> {
let prev_days_old = block_state let prev_days_old =
.timestamp prev_timestamp.difference_in_days_between(block_state.timestamp);
.difference_in_days_between(prev_timestamp); let days_old = timestamp.difference_in_days_between(block_state.timestamp);
let days_old = block_state.timestamp.difference_in_days_between(timestamp);
if prev_days_old == days_old { if prev_days_old == days_old {
return ControlFlow::Continue(()); return ControlFlow::Continue(());
@@ -1375,7 +1373,7 @@ impl Vecs {
pub fn send( pub fn send(
&mut self, &mut self,
height_to_sent: BTreeMap<Height, Transacted>, height_to_sent: BTreeMap<Height, Transacted>,
chain_state: &[BlockState], chain_state: &mut [BlockState],
) { ) {
let mut time_based_vecs = self let mut time_based_vecs = self
.0 .0
@@ -1388,21 +1386,17 @@ impl Vecs {
let last_timestamp = chain_state.last().unwrap().timestamp; let last_timestamp = chain_state.last().unwrap().timestamp;
let current_price = chain_state.last().unwrap().price; let current_price = chain_state.last().unwrap().price;
// dbg!(&height_to_sent);
height_to_sent.into_iter().for_each(|(height, sent)| { height_to_sent.into_iter().for_each(|(height, sent)| {
chain_state[height.unwrap_to_usize()].supply -= &sent.spendable_supply;
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap(); let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
let prev_price = block_state.price; let prev_price = block_state.price;
let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize(); let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize();
let days_old = block_state let days_old = last_timestamp.difference_in_days_between(block_state.timestamp);
.timestamp let days_old_float =
.difference_in_days_between(last_timestamp); last_timestamp.difference_in_days_between_float(block_state.timestamp);
let days_old_float = block_state
.timestamp
.difference_in_days_between_float(last_timestamp);
let older_than_hour = last_timestamp let older_than_hour = last_timestamp
.checked_sub(block_state.timestamp) .checked_sub(block_state.timestamp)

View File

@@ -21,12 +21,12 @@ impl AddressData {
(self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits() (self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits()
} }
#[inline(always)] #[inline]
pub fn has_0_sats(&self) -> bool { pub fn has_0_sats(&self) -> bool {
self.amount() == Sats::ZERO self.amount() == Sats::ZERO
} }
#[inline(always)] #[inline]
pub fn has_0_utxos(&self) -> bool { pub fn has_0_utxos(&self) -> bool {
self.outputs_len == 0 self.outputs_len == 0
} }

View File

@@ -243,7 +243,7 @@ impl Mul<Sats> for Dollars {
self self
} else { } else {
Self::from(Cents::from( Self::from(Cents::from(
u128::from(rhs) * u128::from(Cents::from(self)) / u128::from(Sats::ONE_BTC), u128::from(rhs) * u128::from(Cents::from(self)) / Sats::ONE_BTC_U128,
)) ))
} }
} }

View File

@@ -53,6 +53,7 @@ impl Sats {
pub const ONE_BTC: Self = Self(1_00_000_000); pub const ONE_BTC: Self = Self(1_00_000_000);
pub const MAX: Self = Self(u64::MAX); pub const MAX: Self = Self(u64::MAX);
pub const FIFTY_BTC: Self = Self(50_00_000_000); pub const FIFTY_BTC: Self = Self(50_00_000_000);
pub const ONE_BTC_U128: u128 = 1_00_000_000;
pub fn new(sats: u64) -> Self { pub fn new(sats: u64) -> Self {
Self(sats) Self(sats)

View File

@@ -1,7 +1,4 @@
use std::{ use std::ops::{Add, AddAssign, Div};
cmp::Ordering,
ops::{Add, AddAssign, Div},
};
use derive_deref::Deref; use derive_deref::Deref;
use jiff::{civil::date, tz::TimeZone}; use jiff::{civil::date, tz::TimeZone};
@@ -29,7 +26,9 @@ use super::Date;
)] )]
pub struct Timestamp(u32); pub struct Timestamp(u32);
const ONE_DAY_IN_SEC: i64 = 24 * 60 * 60; const ONE_HOUR_IN_SEC: u32 = 60 * 60;
const ONE_DAY_IN_SEC: u32 = 24 * 60 * 60;
const ONE_DAY_IN_SEC_F64: f64 = ONE_DAY_IN_SEC as f64;
impl Timestamp { impl Timestamp {
pub const ZERO: Self = Self(0); pub const ZERO: Self = Self(0);
@@ -50,34 +49,25 @@ impl Timestamp {
Self::from(trunc_date_time.to_zoned(TimeZone::UTC).unwrap().timestamp()) Self::from(trunc_date_time.to_zoned(TimeZone::UTC).unwrap().timestamp())
} }
pub fn difference_in_days_between(&self, other: Self) -> usize { #[inline]
match self.cmp(&other) { pub fn difference_in_days_between(&self, older: Self) -> usize {
Ordering::Equal => 0, // if self.0 < older.0 {
Ordering::Greater => other.difference_in_days_between(*self), // unreachable!()
Ordering::Less => { // }
(jiff::Timestamp::from(*self) ((self.0 - older.0) / ONE_DAY_IN_SEC) as usize
.duration_until(jiff::Timestamp::from(other))
.as_secs()
/ ONE_DAY_IN_SEC) as usize
}
}
} }
pub fn difference_in_days_between_float(&self, other: Self) -> f64 { #[inline]
match self.cmp(&other) { pub fn difference_in_days_between_float(&self, older: Self) -> f64 {
Ordering::Equal => 0.0, // if self.0 < older.0 {
Ordering::Greater => other.difference_in_days_between_float(*self), // unreachable!()
Ordering::Less => { // }
jiff::Timestamp::from(*self) (self.0 - older.0) as f64 / ONE_DAY_IN_SEC_F64
.duration_until(jiff::Timestamp::from(other))
.as_secs() as f64
/ ONE_DAY_IN_SEC as f64
}
}
} }
#[inline]
pub fn is_more_than_hour(&self) -> bool { pub fn is_more_than_hour(&self) -> bool {
jiff::Timestamp::from(*self).as_second() >= 60 * 60 self.0 >= ONE_HOUR_IN_SEC
} }
} }

View File

@@ -14,7 +14,7 @@ use color_eyre::owo_colors::OwoColorize;
use env_logger::{Builder, Env}; use env_logger::{Builder, Env};
use jiff::{Timestamp, tz}; use jiff::{Timestamp, tz};
#[inline(always)] #[inline]
pub fn init(path: Option<&Path>) { pub fn init(path: Option<&Path>) {
let file = path.map(|path| { let file = path.map(|path| {
let _ = fs::remove_file(path); let _ = fs::remove_file(path);

View File

@@ -17,14 +17,14 @@ impl XORIndex {
bytes bytes
} }
#[inline(always)] #[inline]
pub fn byte(&mut self, mut byte: u8, xor_bytes: &XORBytes) -> u8 { pub fn byte(&mut self, mut byte: u8, xor_bytes: &XORBytes) -> u8 {
byte ^= xor_bytes[self.0]; byte ^= xor_bytes[self.0];
self.increment(); self.increment();
byte byte
} }
#[inline(always)] #[inline]
pub fn increment(&mut self) { pub fn increment(&mut self) {
self.0 += 1; self.0 += 1;
if self.0 == XOR_LEN { if self.0 == XOR_LEN {
@@ -32,7 +32,7 @@ impl XORIndex {
} }
} }
#[inline(always)] #[inline]
pub fn add_assign(&mut self, i: usize) { pub fn add_assign(&mut self, i: usize) {
self.0 = (self.0 + i) % XOR_LEN; self.0 = (self.0 + i) % XOR_LEN;
} }

View File

@@ -22,6 +22,10 @@ where
{ {
const SIZE_OF_T: usize = size_of::<T>(); const SIZE_OF_T: usize = size_of::<T>();
#[inline]
fn unwrap_read(&self, index: I, mmap: &Mmap) -> T {
self.read(index, mmap).unwrap().unwrap()
}
#[inline] #[inline]
fn read(&self, index: I, mmap: &Mmap) -> Result<Option<T>> { fn read(&self, index: I, mmap: &Mmap) -> Result<Option<T>> {
self.read_(index.to_usize()?, mmap) self.read_(index.to_usize()?, mmap)

View File

@@ -120,12 +120,12 @@ where
zstd::encode_all(bytes.as_slice(), DEFAULT_COMPRESSION_LEVEL).unwrap() zstd::encode_all(bytes.as_slice(), DEFAULT_COMPRESSION_LEVEL).unwrap()
} }
#[inline(always)] #[inline]
fn index_to_page_index(index: usize) -> usize { fn index_to_page_index(index: usize) -> usize {
index / Self::PER_PAGE index / Self::PER_PAGE
} }
#[inline(always)] #[inline]
fn page_index_to_index(page_index: usize) -> usize { fn page_index_to_index(page_index: usize) -> usize {
page_index * Self::PER_PAGE page_index * Self::PER_PAGE
} }

View File

@@ -24,7 +24,7 @@ use crate::{
const ONE_KIB: usize = 1024; const ONE_KIB: usize = 1024;
const ONE_MIB: usize = ONE_KIB * ONE_KIB; const ONE_MIB: usize = ONE_KIB * ONE_KIB;
const MAX_CACHE_SIZE: usize = 210 * ONE_MIB; const MAX_CACHE_SIZE: usize = 256 * ONE_MIB;
const DCA_AMOUNT: Dollars = Dollars::mint(100.0); const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@@ -29,6 +29,11 @@ where
)) ))
} }
#[inline]
pub fn unwrap_read(&self, index: I, mmap: &Mmap) -> T {
self.0.unwrap_read(index, mmap)
}
#[inline] #[inline]
pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result<Option<Cow<T>>> { pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result<Option<Cow<T>>> {
self.0.get_or_read(index, mmap) self.0.get_or_read(index, mmap)