2023-03-19 19:20:42 +01:00
|
|
|
// Copyright 2023 Protocol Labs.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
//! Implementation of the [libp2p perf protocol](https://github.com/libp2p/specs/pull/478/).
|
|
|
|
//!
|
|
|
|
//! Do not use in untrusted environments.
|
|
|
|
|
|
|
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
|
|
|
|
2023-05-28 07:51:53 +02:00
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
|
|
use instant::Duration;
|
2023-05-04 05:47:11 +01:00
|
|
|
use libp2p_swarm::StreamProtocol;
|
|
|
|
|
2023-03-19 19:20:42 +01:00
|
|
|
pub mod client;
|
|
|
|
mod protocol;
|
|
|
|
pub mod server;
|
|
|
|
|
2023-05-04 05:47:11 +01:00
|
|
|
pub const PROTOCOL_NAME: StreamProtocol = StreamProtocol::new("/perf/1.0.0");
|
2023-05-28 07:51:53 +02:00
|
|
|
|
|
|
|
/// Parameters for a single run, i.e. one stream, sending and receiving data.
|
|
|
|
///
|
|
|
|
/// Property names are from the perspective of the actor. E.g. `to_send` is the amount of data to
|
|
|
|
/// send, both as the client and the server.
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct RunParams {
|
|
|
|
pub to_send: usize,
|
|
|
|
pub to_receive: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Duration for a single run, i.e. one stream, sending and receiving data.
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct RunDuration {
|
|
|
|
pub upload: Duration,
|
|
|
|
pub download: Duration,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Run {
|
|
|
|
pub params: RunParams,
|
|
|
|
pub duration: RunDuration,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Run {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
const KILO: f64 = 1024.0;
|
|
|
|
const MEGA: f64 = KILO * 1024.0;
|
|
|
|
const GIGA: f64 = MEGA * 1024.0;
|
|
|
|
|
|
|
|
fn format_bytes(bytes: usize) -> String {
|
|
|
|
let bytes = bytes as f64;
|
|
|
|
if bytes >= GIGA {
|
|
|
|
format!("{:.2} GiB", bytes / GIGA)
|
|
|
|
} else if bytes >= MEGA {
|
|
|
|
format!("{:.2} MiB", bytes / MEGA)
|
|
|
|
} else if bytes >= KILO {
|
|
|
|
format!("{:.2} KiB", bytes / KILO)
|
|
|
|
} else {
|
|
|
|
format!("{} B", bytes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn format_bandwidth(duration: Duration, bytes: usize) -> String {
|
|
|
|
const KILO: f64 = 1024.0;
|
|
|
|
const MEGA: f64 = KILO * 1024.0;
|
|
|
|
const GIGA: f64 = MEGA * 1024.0;
|
|
|
|
|
|
|
|
let bandwidth = (bytes as f64 * 8.0) / duration.as_secs_f64();
|
|
|
|
|
|
|
|
if bandwidth >= GIGA {
|
|
|
|
format!("{:.2} Gbit/s", bandwidth / GIGA)
|
|
|
|
} else if bandwidth >= MEGA {
|
|
|
|
format!("{:.2} Mbit/s", bandwidth / MEGA)
|
|
|
|
} else if bandwidth >= KILO {
|
|
|
|
format!("{:.2} Kbit/s", bandwidth / KILO)
|
|
|
|
} else {
|
|
|
|
format!("{:.2} bit/s", bandwidth)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let Run {
|
|
|
|
params: RunParams {
|
|
|
|
to_send,
|
|
|
|
to_receive,
|
|
|
|
},
|
|
|
|
duration: RunDuration { upload, download },
|
|
|
|
} = self;
|
|
|
|
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"uploaded {} in {:.4} s ({}), downloaded {} in {:.4} s ({})",
|
|
|
|
format_bytes(*to_send),
|
|
|
|
upload.as_secs_f64(),
|
|
|
|
format_bandwidth(*upload, *to_send),
|
|
|
|
format_bytes(*to_receive),
|
|
|
|
download.as_secs_f64(),
|
|
|
|
format_bandwidth(*download, *to_receive),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|