2019-02-20 10:50:10 +00:00
|
|
|
extern crate proxmox_backup;
|
|
|
|
|
|
|
|
// also see https://www.johndcook.com/blog/standard_deviation/
|
|
|
|
|
2020-04-17 12:11:25 +00:00
|
|
|
use anyhow::{Error};
|
2019-02-20 10:50:10 +00:00
|
|
|
use std::io::{Read, Write};
|
|
|
|
|
|
|
|
use proxmox_backup::backup::*;
|
|
|
|
|
|
|
|
struct ChunkWriter {
|
|
|
|
chunker: Chunker,
|
|
|
|
last_chunk: usize,
|
|
|
|
chunk_offset: usize,
|
|
|
|
|
|
|
|
chunk_count: usize,
|
|
|
|
|
2019-02-20 11:05:28 +00:00
|
|
|
m_old: f64,
|
|
|
|
m_new: f64,
|
|
|
|
s_old: f64,
|
|
|
|
s_new: f64,
|
2019-02-20 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ChunkWriter {
|
|
|
|
|
|
|
|
fn new(chunk_size: usize) -> Self {
|
|
|
|
ChunkWriter {
|
|
|
|
chunker: Chunker::new(chunk_size),
|
|
|
|
last_chunk: 0,
|
|
|
|
chunk_offset: 0,
|
|
|
|
chunk_count: 0,
|
|
|
|
|
2019-02-20 11:05:28 +00:00
|
|
|
m_old: 0.0,
|
|
|
|
m_new: 0.0,
|
|
|
|
s_old: 0.0,
|
|
|
|
s_new: 0.0,
|
2019-02-20 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_stat(&mut self, chunk_size: f64) {
|
|
|
|
|
|
|
|
self.chunk_count += 1;
|
|
|
|
|
|
|
|
if self.chunk_count == 1 {
|
2019-02-20 11:05:28 +00:00
|
|
|
self.m_old = chunk_size;
|
|
|
|
self.m_new = chunk_size;
|
|
|
|
self.s_old = 0.0;
|
2019-02-20 10:50:10 +00:00
|
|
|
} else {
|
2019-02-20 11:05:28 +00:00
|
|
|
self.m_new = self.m_old + (chunk_size - self.m_old)/(self.chunk_count as f64);
|
|
|
|
self.s_new = self.s_old +
|
|
|
|
(chunk_size - self.m_old)*(chunk_size - self.m_new);
|
2019-02-20 10:50:10 +00:00
|
|
|
// set up for next iteration
|
2019-02-20 11:05:28 +00:00
|
|
|
self.m_old = self.m_new;
|
|
|
|
self.s_old = self.s_new;
|
2019-02-20 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let variance = if self.chunk_count > 1 {
|
2019-02-20 11:05:28 +00:00
|
|
|
self.s_new/((self.chunk_count -1)as f64)
|
2019-02-20 10:50:10 +00:00
|
|
|
} else { 0.0 };
|
|
|
|
|
|
|
|
let std_deviation = variance.sqrt();
|
2019-02-20 11:05:28 +00:00
|
|
|
let deviation_per = (std_deviation*100.0)/self.m_new;
|
|
|
|
println!("COUNT {:10} SIZE {:10} MEAN {:10} DEVIATION {:3}%", self.chunk_count, chunk_size, self.m_new as usize, deviation_per as usize);
|
2019-02-20 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Write for ChunkWriter {
|
|
|
|
|
|
|
|
fn write(&mut self, data: &[u8]) -> std::result::Result<usize, std::io::Error> {
|
|
|
|
|
|
|
|
let chunker = &mut self.chunker;
|
|
|
|
|
|
|
|
let pos = chunker.scan(data);
|
|
|
|
|
|
|
|
if pos > 0 {
|
|
|
|
self.chunk_offset += pos;
|
|
|
|
|
|
|
|
let chunk_size = self.chunk_offset - self.last_chunk;
|
|
|
|
|
|
|
|
self.record_stat(chunk_size as f64);
|
|
|
|
|
|
|
|
self.last_chunk = self.chunk_offset;
|
|
|
|
Ok(pos)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
self.chunk_offset += data.len();
|
|
|
|
Ok(data.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> Result<(), Error> {
|
|
|
|
|
|
|
|
let mut file = std::fs::File::open("/dev/urandom")?;
|
|
|
|
|
|
|
|
let mut bytes = 0;
|
|
|
|
|
|
|
|
let mut buffer = [0u8; 64*1024];
|
|
|
|
|
|
|
|
let mut writer = ChunkWriter::new(4096*1024);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
|
|
file.read_exact(&mut buffer)?;
|
|
|
|
bytes += buffer.len();
|
|
|
|
|
|
|
|
writer.write_all(&buffer)?;
|
|
|
|
|
2019-02-20 11:05:28 +00:00
|
|
|
if bytes > 1024*1024*1024 { break; }
|
2019-02-20 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|