2019-02-20 13:50:10 +03:00
extern crate proxmox_backup ;
// also see https://www.johndcook.com/blog/standard_deviation/
2022-04-10 18:44:34 +03:00
use anyhow ::Error ;
2019-02-20 13:50:10 +03:00
use std ::io ::{ Read , Write } ;
2024-04-19 16:34:54 +03:00
use pbs_datastore ::{ Chunker , ChunkerImpl } ;
2019-02-20 13:50:10 +03:00
struct ChunkWriter {
2024-04-19 16:34:54 +03:00
chunker : ChunkerImpl ,
2019-02-20 13:50:10 +03:00
last_chunk : usize ,
chunk_offset : usize ,
chunk_count : usize ,
2019-02-20 14:05:28 +03:00
m_old : f64 ,
m_new : f64 ,
s_old : f64 ,
s_new : f64 ,
2019-02-20 13:50:10 +03:00
}
impl ChunkWriter {
fn new ( chunk_size : usize ) -> Self {
ChunkWriter {
2024-04-19 16:34:54 +03:00
chunker : ChunkerImpl ::new ( chunk_size ) ,
2019-02-20 13:50:10 +03:00
last_chunk : 0 ,
chunk_offset : 0 ,
chunk_count : 0 ,
2019-02-20 14:05:28 +03:00
m_old : 0.0 ,
m_new : 0.0 ,
s_old : 0.0 ,
s_new : 0.0 ,
2019-02-20 13:50:10 +03:00
}
}
fn record_stat ( & mut self , chunk_size : f64 ) {
self . chunk_count + = 1 ;
if self . chunk_count = = 1 {
2019-02-20 14:05:28 +03:00
self . m_old = chunk_size ;
self . m_new = chunk_size ;
self . s_old = 0.0 ;
2019-02-20 13:50:10 +03:00
} else {
2022-04-10 18:44:34 +03: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 13:50:10 +03:00
// set up for next iteration
2019-02-20 14:05:28 +03:00
self . m_old = self . m_new ;
self . s_old = self . s_new ;
2019-02-20 13:50:10 +03:00
}
let variance = if self . chunk_count > 1 {
2022-04-10 18:44:34 +03:00
self . s_new / ( ( self . chunk_count - 1 ) as f64 )
} else {
0.0
} ;
2019-02-20 13:50:10 +03:00
let std_deviation = variance . sqrt ( ) ;
2022-04-10 18:44:34 +03: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 13:50:10 +03:00
}
}
impl Write for ChunkWriter {
fn write ( & mut self , data : & [ u8 ] ) -> std ::result ::Result < usize , std ::io ::Error > {
let chunker = & mut self . chunker ;
2024-04-19 16:34:54 +03:00
let ctx = pbs_datastore ::chunker ::Context ::default ( ) ;
let pos = chunker . scan ( data , & ctx ) ;
2019-02-20 13:50:10 +03:00
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 ;
2022-04-10 18:44:34 +03:00
let mut buffer = [ 0 u8 ; 64 * 1024 ] ;
2019-02-20 13:50:10 +03:00
2022-04-10 18:44:34 +03:00
let mut writer = ChunkWriter ::new ( 4096 * 1024 ) ;
2019-02-20 13:50:10 +03:00
loop {
file . read_exact ( & mut buffer ) ? ;
bytes + = buffer . len ( ) ;
writer . write_all ( & buffer ) ? ;
2022-04-10 18:44:34 +03:00
if bytes > 1024 * 1024 * 1024 {
break ;
}
2019-02-20 13:50:10 +03:00
}
Ok ( ( ) )
}