-
Notifications
You must be signed in to change notification settings - Fork 949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(perf): implement libp2p perf protocol #3508
Conversation
Flow user -> client -> server -> client -> user is implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short drive-by review. Thanks for starting this!
protocols/perf/Cargo.toml
Outdated
name = "libp2p-perf" | ||
edition = "2021" | ||
rust-version = "1.62.0" | ||
description = "Direct connection upgrade through relay" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it? :)
server_address: Multiaddr, | ||
} | ||
|
||
fn main() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these examples and not proper crate binaries? I think the fact that we ship them in a Docker container makes them binary worth instead of just "examples".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My flawed thought process, moving everything to examples/
after starting with src/bin/
, was the hope to prevent circular dependencies in Cargo.toml/[dependencies]
.
Thinking about it some more, as long as I don't depend on libp2p
directly, I should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My flawed thought process, moving everything to
examples/
after starting withsrc/bin/
, was the hope to prevent circular dependencies inCargo.toml/[dependencies]
.Thinking about it some more, as long as I don't depend on
libp2p
directly, I should be fine.
The other option would be to create an entirely separate crate, like interop-tests
instead of building binaries within libp2p-perf
.
I don't mind either way. With latter, you can easily depend on libp2p
. With the former, you need to depend on select crates that you want to use.
// TODO: What if we are already connected? | ||
self.queued_events | ||
.push_back(NetworkBehaviourAction::Dial { opts }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've developed the opinion that protocols should not manage connections unless their sole purpose is to do so (like dcutr or kad).
Instead, I'd state it as a prerequisite that we are connected and use NotifyHandler::Any
.
You can then establish the connection within the binary through Swarm::dial
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I share the same opinion. Changed with 39694af.
protocols/perf/src/client/handler.rs
Outdated
#[derive(Debug)] | ||
pub enum Event { | ||
Finished { stats: RunStats }, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum Command { | ||
Start { params: RunParams }, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should they be enums if they don't have to be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once I have proper error handling, I expect more variants to be needed, at least for Event
.
protocols/perf/src/client/handler.rs
Outdated
>, | ||
) { | ||
match event { | ||
ConnectionEvent::FullyNegotiatedInbound(_) => todo!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Use void::unreachable
.
Great review. Thanks for the help @thomaseizinger! I will leave this open a bit longer as I posted some follow-up questions to your comments. |
The I am leaning towards flagging this as a non-wasm crate for now. In case anyone wants to use it with wasm we can introduce a more advanced feature gating with the Any objections? |
The user doesn't need to know the implementation details of `Handler`. The can refer to the type via `Behaviour::Handler` if they want and the only API they should care about is that it implements `ConnectionHandler`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple more comments, plus I pushed a commit to reduce the API surface. Let me know if you disagree.
protocols/perf/Cargo.toml
Outdated
libp2p-core = { version = "0.39.0", path = "../../core" } | ||
libp2p-dns = { version = "0.39.0", path = "../../transports/dns", features = ["async-std"] } | ||
libp2p-noise = { version = "0.42.0", path = "../../transports/noise" } | ||
libp2p-quic = { version = "0.7.0-alpha.2", path = "../../transports/quic", features = ["async-std"] } | ||
libp2p-swarm = { version = "0.42.0", path = "../../swarm", features = ["macros", "async-std"] } | ||
libp2p-tcp = { version = "0.39.0", path = "../../transports/tcp", features = ["async-io"] } | ||
libp2p-yamux = { version = "0.43.0", path = "../../muxers/yamux" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only need most these for the binaries right? How about we introduce a separate crate that implements the server and client binaries, similarly to interop-tests
? That would allow this protocol to be WASM-friendly. Plus, in the spirit of #3111, it would be consistent with not introduce binaries in our protocol crates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which folder should these binaries go into?
That would allow this protocol to be WASM-friendly.
I don't think we should introduce any complexity for the sake of supporting WASM at this point. It is not a critical protocol. I don't see it used in WASM any time soon.
Plus, in the spirit of #3111, it would be consistent with not introduce binaries in our protocol crates.
Consistency is a good argument in my eyes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which folder should these binaries go into?
You'd have to make another crate, like interop-tests
. Perhaps perf-utils
, perf-cs
(for perf-client-server) or perf-bins
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And perf-bins/
would be a top level folder? Is that worth the noise it is introducing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could put them into misc/
too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thomaseizinger do you feel strongly about this? Thinking about it some more, I don't think the split into two folders is worth the effort at this point. I expect this crate to change quite a bit after this pull request merges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
This pull request has merge conflicts. Could you please resolve them @mxinden? 🙏 |
protocols/perf/Cargo.toml
Outdated
libp2p-core = { version = "0.39.0", path = "../../core" } | ||
libp2p-dns = { version = "0.39.0", path = "../../transports/dns", features = ["async-std"] } | ||
libp2p-noise = { version = "0.42.0", path = "../../transports/noise" } | ||
libp2p-quic = { version = "0.7.0-alpha.2", path = "../../transports/quic", features = ["async-std"] } | ||
libp2p-swarm = { version = "0.42.0", path = "../../swarm", features = ["macros", "async-std"] } | ||
libp2p-tcp = { version = "0.39.0", path = "../../transports/tcp", features = ["async-io"] } | ||
libp2p-yamux = { version = "0.43.0", path = "../../muxers/yamux" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which folder should these binaries go into?
You'd have to make another crate, like interop-tests
. Perhaps perf-utils
, perf-cs
(for perf-client-server) or perf-bins
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All comments, apart from new location for the binaries addressed. @thomaseizinger mind taking another look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking very nice. Some non-blocking comments :)
protocols/perf/tests/lib.rs
Outdated
#[test] | ||
fn perf() { | ||
let _ = env_logger::try_init(); | ||
let mut pool = LocalPool::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not make it an async_std::test
? I find .await
nicer than function-calls to LocalPool
.
protocols/perf/tests/lib.rs
Outdated
loop { | ||
match client.select_next_some().await { | ||
SwarmEvent::IncomingConnection { .. } => panic!(), | ||
SwarmEvent::ConnectionEstablished { .. } => {} | ||
SwarmEvent::Dialing(_) => {} | ||
SwarmEvent::Behaviour(client::Event { result: Ok(_), .. }) => break, | ||
e => panic!("{e:?}"), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want to use client.wait
here as it incorporates a timeout whereas select_next_some
will wait forever, potentially making your test hang.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably return the result
and then either assert!(result.is_ok)
or unwrap
/expect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat. Saves a bunch of lines of code.
Feel free to merge whenever. |
Recommendations:
|
|
As we do with all other protocols, make sure to expose `libp2p-perf` as well. See also discussion libp2p#3508 (comment)
As we do with all other protocols, make sure to expose `libp2p-perf` as well. See also discussion libp2p#3508 (comment)
As we do with all other protocols, make sure to expose `libp2p-perf` as well. Related: #3508 (comment). Pull-Request: #3693.
Description
Implementation of the libp2p perf protocol according to libp2p/specs#478.
//CC @MarcoPolo as the author of the specification.
Don't (yet) expect this to produce reliable performance metrics.
Notes
Server implementation is deployed at
/dns4/libp2p-perf.max-inden.de/tcp/4001
.Easiest way to test from your machine:
For server machine metrics, see https://libp2p-perf.max-inden.de/d/rYdddlPWk/node-exporter-full
Links to any relevant issues
Open Questions
Change checklist