]>
Commit | Line | Data |
---|---|---|
1604ec26 DM |
1 | extern crate proxmox_backup; |
2 | ||
3 | // also see https://www.johndcook.com/blog/standard_deviation/ | |
4 | ||
f7d4e4b5 | 5 | use anyhow::{Error}; |
1604ec26 DM |
6 | use std::io::{Read, Write}; |
7 | ||
8 | use proxmox_backup::backup::*; | |
9 | ||
10 | struct ChunkWriter { | |
11 | chunker: Chunker, | |
12 | last_chunk: usize, | |
13 | chunk_offset: usize, | |
14 | ||
15 | chunk_count: usize, | |
16 | ||
14691fc1 DM |
17 | m_old: f64, |
18 | m_new: f64, | |
19 | s_old: f64, | |
20 | s_new: f64, | |
1604ec26 DM |
21 | } |
22 | ||
23 | impl ChunkWriter { | |
24 | ||
25 | fn new(chunk_size: usize) -> Self { | |
26 | ChunkWriter { | |
27 | chunker: Chunker::new(chunk_size), | |
28 | last_chunk: 0, | |
29 | chunk_offset: 0, | |
30 | chunk_count: 0, | |
31 | ||
14691fc1 DM |
32 | m_old: 0.0, |
33 | m_new: 0.0, | |
34 | s_old: 0.0, | |
35 | s_new: 0.0, | |
1604ec26 DM |
36 | } |
37 | } | |
38 | ||
39 | fn record_stat(&mut self, chunk_size: f64) { | |
40 | ||
41 | self.chunk_count += 1; | |
42 | ||
43 | if self.chunk_count == 1 { | |
14691fc1 DM |
44 | self.m_old = chunk_size; |
45 | self.m_new = chunk_size; | |
46 | self.s_old = 0.0; | |
1604ec26 | 47 | } else { |
14691fc1 DM |
48 | self.m_new = self.m_old + (chunk_size - self.m_old)/(self.chunk_count as f64); |
49 | self.s_new = self.s_old + | |
50 | (chunk_size - self.m_old)*(chunk_size - self.m_new); | |
1604ec26 | 51 | // set up for next iteration |
14691fc1 DM |
52 | self.m_old = self.m_new; |
53 | self.s_old = self.s_new; | |
1604ec26 DM |
54 | } |
55 | ||
56 | let variance = if self.chunk_count > 1 { | |
14691fc1 | 57 | self.s_new/((self.chunk_count -1)as f64) |
1604ec26 DM |
58 | } else { 0.0 }; |
59 | ||
60 | let std_deviation = variance.sqrt(); | |
14691fc1 DM |
61 | let deviation_per = (std_deviation*100.0)/self.m_new; |
62 | println!("COUNT {:10} SIZE {:10} MEAN {:10} DEVIATION {:3}%", self.chunk_count, chunk_size, self.m_new as usize, deviation_per as usize); | |
1604ec26 DM |
63 | } |
64 | } | |
65 | ||
66 | impl Write for ChunkWriter { | |
67 | ||
68 | fn write(&mut self, data: &[u8]) -> std::result::Result<usize, std::io::Error> { | |
69 | ||
70 | let chunker = &mut self.chunker; | |
71 | ||
72 | let pos = chunker.scan(data); | |
73 | ||
74 | if pos > 0 { | |
75 | self.chunk_offset += pos; | |
76 | ||
77 | let chunk_size = self.chunk_offset - self.last_chunk; | |
78 | ||
79 | self.record_stat(chunk_size as f64); | |
80 | ||
81 | self.last_chunk = self.chunk_offset; | |
82 | Ok(pos) | |
83 | ||
84 | } else { | |
85 | self.chunk_offset += data.len(); | |
86 | Ok(data.len()) | |
87 | } | |
88 | } | |
89 | ||
90 | fn flush(&mut self) -> std::result::Result<(), std::io::Error> { | |
91 | Ok(()) | |
92 | } | |
93 | } | |
94 | ||
95 | fn main() -> Result<(), Error> { | |
96 | ||
97 | let mut file = std::fs::File::open("/dev/urandom")?; | |
98 | ||
99 | let mut bytes = 0; | |
100 | ||
101 | let mut buffer = [0u8; 64*1024]; | |
102 | ||
103 | let mut writer = ChunkWriter::new(4096*1024); | |
104 | ||
105 | loop { | |
106 | ||
107 | file.read_exact(&mut buffer)?; | |
108 | bytes += buffer.len(); | |
109 | ||
110 | writer.write_all(&buffer)?; | |
111 | ||
14691fc1 | 112 | if bytes > 1024*1024*1024 { break; } |
1604ec26 DM |
113 | } |
114 | ||
115 | Ok(()) | |
116 | } |