1 use std
::path
::PathBuf
;
6 use chrono
::{TimeZone, Utc}
;
9 use proxmox
::api
::{ApiMethod, RpcEnvironment}
;
16 format_and_print_result_full
,
17 default_table_format_options
,
21 use proxmox_backup
::backup
::{
27 use proxmox_backup
::client
::*;
30 KEYFILE_SCHEMA
, REPO_URL_SCHEMA
,
31 extract_repository_from_value
,
37 #[derive(Copy, Clone, Serialize)]
40 /// The meassured speed in Bytes/second
41 #[serde(skip_serializing_if="Option::is_none")]
43 /// Top result we want to compare with
66 #[derive(Copy, Clone, Serialize)]
68 struct BenchmarkResult
{
71 /// SHA256 checksum comptation speed
73 /// ZStd level 1 compression speed
75 /// ZStd level 1 decompression speed
77 /// AES256 GCM encryption speed
82 static BENCHMARK_RESULT_2020_TOP
: BenchmarkResult
= BenchmarkResult
{
85 top
: 1_000_000.0 * 590.0, // TLS to localhost, AMD Ryzen 7 2700X
89 top
: 1_000_000.0 * 2120.0, // AMD Ryzen 7 2700X
93 top
: 1_000_000.0 * 2158.0, // AMD Ryzen 7 2700X
97 top
: 1_000_000.0 * 8062.0, // AMD Ryzen 7 2700X
101 top
: 1_000_000.0 * 3803.0, // AMD Ryzen 7 2700X
109 schema
: REPO_URL_SCHEMA
,
113 description
: "Verbose output.",
118 schema
: KEYFILE_SCHEMA
,
122 schema
: OUTPUT_FORMAT
,
128 /// Run benchmark tests
129 pub async
fn benchmark(
132 _rpcenv
: &mut dyn RpcEnvironment
,
133 ) -> Result
<(), Error
> {
135 let repo
= extract_repository_from_value(¶m
).ok();
137 let keyfile
= param
["keyfile"].as_str().map(PathBuf
::from
);
139 let verbose
= param
["verbose"].as_bool().unwrap_or(false);
141 let output_format
= get_output_format(¶m
);
143 let crypt_config
= match keyfile
{
146 let (key
, _
) = load_and_decrypt_key(&path
, &crate::key
::get_encryption_key_password
)?
;
147 let crypt_config
= CryptConfig
::new(key
)?
;
148 Some(Arc
::new(crypt_config
))
152 let mut benchmark_result
= BENCHMARK_RESULT_2020_TOP
;
154 // do repo tests first, because this may prompt for a password
155 if let Some(repo
) = repo
{
156 test_upload_speed(&mut benchmark_result
, repo
, crypt_config
.clone(), verbose
).await?
;
159 test_crypt_speed(&mut benchmark_result
, verbose
)?
;
161 render_result(&output_format
, &benchmark_result
)?
;
166 // print comparison table
169 benchmark_result
: &BenchmarkResult
,
170 ) -> Result
<(), Error
> {
172 let mut data
= serde_json
::to_value(benchmark_result
)?
;
173 let schema
= BenchmarkResult
::API_SCHEMA
;
175 let render_speed
= |value
: &Value
, _record
: &Value
| -> Result
<String
, Error
> {
176 match value
["speed"].as_f64() {
177 None
=> Ok(String
::from("not tested")),
179 let top
= value
["top"].as_f64().unwrap();
180 Ok(format
!("{:.2} MB/s ({:.0}%)", speed
/1_000_000.0, (speed
*100.0)/top
))
185 let options
= default_table_format_options()
186 .column(ColumnConfig
::new("tls")
187 .header("TLS (maximal backup upload speed)")
188 .right_align(false).renderer(render_speed
))
189 .column(ColumnConfig
::new("sha256")
190 .header("SHA256 checksum comptation speed")
191 .right_align(false).renderer(render_speed
))
192 .column(ColumnConfig
::new("compress")
193 .header("ZStd level 1 compression speed")
194 .right_align(false).renderer(render_speed
))
195 .column(ColumnConfig
::new("decompress")
196 .header("ZStd level 1 decompression speed")
197 .right_align(false).renderer(render_speed
))
198 .column(ColumnConfig
::new("aes256_gcm")
199 .header("AES256 GCM encryption speed")
200 .right_align(false).renderer(render_speed
));
203 format_and_print_result_full(&mut data
, schema
, output_format
, &options
);
208 async
fn test_upload_speed(
209 benchmark_result
: &mut BenchmarkResult
,
210 repo
: BackupRepository
,
211 crypt_config
: Option
<Arc
<CryptConfig
>>,
213 ) -> Result
<(), Error
> {
215 let backup_time
= Utc
.timestamp(Utc
::now().timestamp(), 0);
217 let client
= connect(repo
.host(), repo
.user())?
;
218 record_repository(&repo
);
220 if verbose { eprintln!("Connecting to backup server"); }
221 let client
= BackupWriter
::start(
223 crypt_config
.clone(),
231 if verbose { eprintln!("Start TLS speed test"); }
232 let speed
= client
.upload_speedtest(verbose
).await?
;
234 eprintln
!("TLS speed: {:.2} MB/s", speed
/1_000_000.0);
236 benchmark_result
.tls
.speed
= Some(speed
);
241 // test hash/crypt/compress speed
243 benchmark_result
: &mut BenchmarkResult
,
245 ) -> Result
<(), Error
> {
249 let kdf
= KeyDerivationConfig
::Scrypt
{
256 let testkey
= kdf
.derive_key(pw
)?
;
258 let crypt_config
= CryptConfig
::new(testkey
)?
;
260 let random_data
= proxmox
::sys
::linux
::random_data(1024*1024)?
;
262 let start_time
= std
::time
::Instant
::now();
266 openssl
::sha
::sha256(&random_data
);
267 bytes
+= random_data
.len();
268 if start_time
.elapsed().as_micros() > 1_000_000 { break; }
270 let speed
= (bytes
as f64)/start_time
.elapsed().as_secs_f64();
271 benchmark_result
.sha256
.speed
= Some(speed
);
273 eprintln
!("SHA256 speed: {:.2} MB/s", speed
/1_000_000_.0);
276 let start_time
= std
::time
::Instant
::now();
280 let mut reader
= &random_data
[..];
281 zstd
::stream
::encode_all(&mut reader
, 1)?
;
282 bytes
+= random_data
.len();
283 if start_time
.elapsed().as_micros() > 3_000_000 { break; }
285 let speed
= (bytes
as f64)/start_time
.elapsed().as_secs_f64();
286 benchmark_result
.compress
.speed
= Some(speed
);
288 eprintln
!("Compression speed: {:.2} MB/s", speed
/1_000_000_.0);
291 let start_time
= std
::time
::Instant
::now();
293 let compressed_data
= {
294 let mut reader
= &random_data
[..];
295 zstd
::stream
::encode_all(&mut reader
, 1)?
300 let mut reader
= &compressed_data
[..];
301 let data
= zstd
::stream
::decode_all(&mut reader
)?
;
303 if start_time
.elapsed().as_micros() > 1_000_000 { break; }
305 let speed
= (bytes
as f64)/start_time
.elapsed().as_secs_f64();
306 benchmark_result
.decompress
.speed
= Some(speed
);
308 eprintln
!("Decompress speed: {:.2} MB/s", speed
/1_000_000_.0);
311 let start_time
= std
::time
::Instant
::now();
315 let mut out
= Vec
::new();
316 crypt_config
.encrypt_to(&random_data
, &mut out
)?
;
317 bytes
+= random_data
.len();
318 if start_time
.elapsed().as_micros() > 1_000_000 { break; }
320 let speed
= (bytes
as f64)/start_time
.elapsed().as_secs_f64();
321 benchmark_result
.aes256_gcm
.speed
= Some(speed
);
323 eprintln
!("AES256/GCM speed: {:.2} MB/s", speed
/1_000_000_.0);