#![cfg(all(target_os = "linux", not(any(feature = "blocking", feature = "wal"))))]
use btree_ondisk::{MemoryBlockLoader, NullNodeCache};
use hyperfile::config::{HyperFileConfigBuilder, HyperFileMetaConfig, HyperFileRuntimeConfig};
use hyperfile::file::file::HyperFile;
use hyperfile::file::flags::{FileFlags, HyperFileFlags};
use hyperfile::file::mode::{FileMode, HyperFileMode};
use hyperfile::file::HyperTrait;
use hyperfile::meta_format::BlockPtrFormat;
use hyperfile::staging::config::StagingConfig;
use hyperfile::staging::memory::MemoryStaging;
use hyperfile::staging::Staging;
use std::sync::Arc;
type MemFile<'a> = HyperFile<'a, MemoryStaging, MemoryBlockLoader<hyperfile::BlockPtr>, NullNodeCache>;
const BS: usize = 4096;
const MIB: usize = 1 << 20;
const TOTAL: usize = 512 * MIB;
fn thread_cpu() -> std::time::Duration {
let mut t = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(libc::CLOCK_THREAD_CPUTIME_ID, &mut t) };
std::time::Duration::new(t.tv_sec as u64, t.tv_nsec as u32)
}
struct Src(Vec<u8>);
impl hyperfile::block_source::BlockSource for Src {
fn read_at(&self, off: u64, buf: &mut [u8]) -> std::io::Result<()> {
buf.copy_from_slice(&self.0[off as usize..off as usize + buf.len()]);
Ok(())
}
}
async fn writer_cpu(fmt: BlockPtrFormat, by_ref: bool, src: &Arc<Src>, chunk: &[u8]) -> std::time::Duration {
let mut rt = HyperFileRuntimeConfig::default();
rt.data_cache_dirty_max_bytes_threshold = 1 << 40;
rt.data_cache_dirty_max_blocks_threshold = (1 << 40) / BS;
rt.segment_buffer_size = 1 << 40;
rt.segment_mpu_max_concurrency = 8;
let mut meta = HyperFileMetaConfig::default();
meta.block_ptr_format = fmt;
let s = MemoryStaging::new(StagingConfig::new_memory("cpu"), rt.clone());
let cfg = HyperFileConfigBuilder::new().with_staging_config(s.config()).with_meta_config(&meta).with_runtime_config(&rt).build();
let mut f = MemFile::new(s.clone(), s.to_block_loader(), NullNodeCache, cfg, HyperFileFlags::from_flags(FileFlags::rdwr()),
HyperFileMode::from_mode(FileMode::default_file())).await.expect("create");
if by_ref {
f.set_block_source(Some(src.clone())).unwrap();
}
let mut spent = std::time::Duration::ZERO;
let mut off = 0;
while off < TOTAL {
let t = thread_cpu();
if by_ref { f.write_ref(off, chunk.len()).await.unwrap(); } else { f.write(off, chunk).await.unwrap(); }
spent += thread_cpu() - t;
off += chunk.len();
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
}
f.flush().await.expect("flush");
spent
}
async fn best_of_three(fmt: BlockPtrFormat, by_ref: bool, src: &Arc<Src>, chunk: &[u8]) -> std::time::Duration {
let mut best = std::time::Duration::MAX;
for _ in 0..3 {
best = best.min(writer_cpu(fmt, by_ref, src, chunk).await);
}
best
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn sending_ahead_costs_the_writer_about_what_it_does() {
let chunk: Vec<u8> = (0..16 * MIB).map(|i| (i.wrapping_mul(2654435761) >> 13) as u8).collect();
let src = Arc::new(Src((0..TOTAL).map(|i| (i.wrapping_mul(2654435761) >> 13) as u8).collect()));
let _ = writer_cpu(BlockPtrFormat::PartedSegment, false, &src, &chunk).await;
let value_parted = best_of_three(BlockPtrFormat::PartedSegment, false, &src, &chunk).await;
let value_stream = best_of_three(BlockPtrFormat::StreamSegment, false, &src, &chunk).await;
let ref_parted = best_of_three(BlockPtrFormat::PartedSegment, true, &src, &chunk).await;
let ref_stream = best_of_three(BlockPtrFormat::StreamSegment, true, &src, &chunk).await;
let gib = TOTAL as f64 / (1u64 << 30) as f64;
let per = |d: std::time::Duration| d.as_secs_f64() / gib;
println!("writer CPU, s/GiB: by value {:.2} parted, {:.2} stream; by reference {:.2} parted, {:.2} stream",
per(value_parted), per(value_stream), per(ref_parted), per(ref_stream));
assert!(value_stream.as_secs_f64() <= 3.0 * value_parted.as_secs_f64(),
"by value, sending ahead cost the writer {:.2} s/GiB against {:.2}", per(value_stream), per(value_parted));
assert!(per(ref_stream) <= per(ref_parted) + 0.25,
"by reference, sending ahead cost the writer {:.2} s/GiB against {:.2}", per(ref_stream), per(ref_parted));
}