-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Improve new message-rpc API #11159
Comments
- Refactor Channel API to enable sending of any Javscript object over channels instead of having to receive a writeBuffer and write encoding the object into a binary format. This means we essentially move the binary encoding a level - Combine old message encoder/decoders into a common BinaryMessageCodec interface. - Adapt dependent components and services to new API Part of eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor Channel API to enable sending of any Javscript object over channels instead of having to receive a writeBuffer and write encoding the object into a binary format. This means we essentially move the binary encoding a level - Combine old message encoder/decoders into a common BinaryMessageCodec interface. - Adapt dependent components and services to new API Part of eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor Channel API to enable sending of any Javscript object over channels instead of having to receive a writeBuffer and write encoding the object into a binary format. This means we essentially move the binary encoding a level - Combine old message encoder/decoders into a common BinaryMessageCodec interface. - Adapt dependent components and services to new API Part of eclipse-theia#11159 Contributed on behalf of STMicroelectronics
Point 1 (object-based-channel) is addressed with this PR: #11328 |
For Point 2 I also did a little evaluation/benchmarking of different msgpack implementations: IntroductionCurrently we are using a custom binary codec for encoding RPC messages that are sent between the Theia frontend and backend processes.Compared to plain JSON-RPC this codec offers efficient encoding of binary data (buffers). However, it turns out the performance for large (buffer-free) objects is considerably worse with the new message codec.
Nice to have features:
Potential Candidates ( as listed on the offical Msgpack website:Evaluation:@msgpack/msgpack ✔️Weekly NPM Downloads: 52992 More or less the offical mspack implementation for JS. msgpack-lite ❌Weekly NPM Downloads: 583 Seems to be no longer activley maintained. Last release was in 2017. msgpackr ✔️Weekly NPM Downloads: 547747 Claims to be faster than the official msgpack js implementation. @ygoe/msgpack.js ❌Github stars: 119 Small project that only seems to implement the base msgpack specifiation. what-the-pack ❌Deprecated and no longer active. ConclusionIf we switch to BenchmarksCodecs:
BaselineCodec: BinaryMessageCodec TestData: 4 BenchmarkRuns: 5 Testobject
Benchmark for
|
MessageCodec | Encode Success | Encoding Time (ET) | ET-Baseline | Encoded Size (ES) | ES-Baseline | Decode Success | Decode Time (DT) | DT-Baseline | Match (Input-Decoded) |
---|---|---|---|---|---|---|---|---|---|
BinaryMessageCodec | true | 0.09 ms | 0.00 ms (Factor: 1.00) | 82 Bytes | 0 Bytes (Factors: 1.00) | true | 0.14 ms | 0.00 ms (Factor: 1.00) | false |
MsgPack | true | 0.07 ms | -0.02 ms (Factor: 0.78) | 47 Bytes | -35 Bytes (Factors: 0.57) | true | 0.09 ms | -0.05 ms (Factor: 0.64) | true |
MsgPackR | true | 0.04 ms | -0.05 ms (Factor: 0.44) | 53 Bytes | -29 Bytes (Factors: 0.65) | true | 0.04 ms | -0.10 ms (Factor: 0.29) | true |
MsgPackRCircular | true | 0.05 ms | -0.04 ms (Factor: 0.56) | 53 Bytes | -29 Bytes (Factors: 0.65) | true | 0.04 ms | -0.10 ms (Factor: 0.29) | true |
Benchmark for StringArray10000
MessageCodec | Encode Success | Encoding Time (ET) | ET-Baseline | Encoded Size (ES) | ES-Baseline | Decode Success | Decode Time (DT) | DT-Baseline | Match (Input-Decoded) |
---|---|---|---|---|---|---|---|---|---|
BinaryMessageCodec | true | 5.91 ms | 0.00 ms (Factor: 1.00) | 88893 Bytes | 0 Bytes (Factors: 1.00) | true | 16.21 ms | 0.00 ms (Factor: 1.00) | true |
MsgPack | true | 0.67 ms | -5.24 ms (Factor: 0.11) | 48893 Bytes | -40000 Bytes (Factors: 0.55) | true | 1.08 ms | -15.13 ms (Factor: 0.07) | true |
MsgPackR | true | 0.56 ms | -5.35 ms (Factor: 0.09) | 48893 Bytes | -40000 Bytes (Factors: 0.55) | true | 0.94 ms | -15.27 ms (Factor: 0.06) | true |
MsgPackRCircular | true | 0.68 ms | -5.23 ms (Factor: 0.12) | 48893 Bytes | -40000 Bytes (Factors: 0.55) | true | 0.48 ms | -15.73 ms (Factor: 0.03) | true |
Benchmark for BinaryBuffer8MB
MessageCodec | Encode Success | Encoding Time (ET) | ET-Baseline | Encoded Size (ES) | ES-Baseline | Decode Success | Decode Time (DT) | DT-Baseline | Match (Input-Decoded) |
---|---|---|---|---|---|---|---|---|---|
BinaryMessageCodec | true | 6.33 ms | 0.00 ms (Factor: 1.00) | 7755890 Bytes | 0 Bytes (Factors: 1.00) | true | 3.93 ms | 0.00 ms (Factor: 1.00) | false |
MsgPack | true | 2.14 ms | -4.19 ms (Factor: 0.34) | 7755890 Bytes | 0 Bytes (Factors: 1.00) | true | 0.03 ms | -3.90 ms (Factor: 0.01) | false |
MsgPackR | true | 2.96 ms | -3.37 ms (Factor: 0.47) | 7755890 Bytes | 0 Bytes (Factors: 1.00) | true | 0.01 ms | -3.92 ms (Factor: 0.00) | true |
MsgPackRCircular | true | 4.57 ms | -1.76 ms (Factor: 0.72) | 7755890 Bytes | 0 Bytes (Factors: 1.00) | true | 0.02 ms | -3.91 ms (Factor: 0.01) | true |
Benchmark for DeployedPluginsArgs
MessageCodec | Encode Success | Encoding Time (ET) | ET-Baseline | Encoded Size (ES) | ES-Baseline | Decode Success | Decode Time (DT) | DT-Baseline | Match (Input-Decoded) |
---|---|---|---|---|---|---|---|---|---|
BinaryMessageCodec | true | 72.00 ms | 0.00 ms (Factor: 1.00) | 4159142 Bytes | 0 Bytes (Factors: 1.00) | true | 350.89 ms | 0.00 ms (Factor: 1.00) | false |
MsgPack | true | 25.84 ms | -46.16 ms (Factor: 0.36) | 3615603 Bytes | -543539 Bytes (Factors: 0.87) | true | 51.10 ms | -299.79 ms (Factor: 0.15) | true |
MsgPackR | true | 18.52 ms | -53.48 ms (Factor: 0.26) | 3043098 Bytes | -1116044 Bytes (Factors: 0.73) | true | 20.30 ms | -330.59 ms (Factor: 0.06) | true |
MsgPackRCircular | true | 26.91 ms | -45.09 ms (Factor: 0.37) | 3010310 Bytes | -1148832 Bytes (Factors: 0.72) | true | 16.08 ms | -334.81 ms (Factor: 0.05) | true |
Benchmark for CircularParentChild
MessageCodec | Encode Success | Encoding Time (ET) | ET-Baseline | Encoded Size (ES) | ES-Baseline | Decode Success | Decode Time (DT) | DT-Baseline | Match (Input-Decoded) |
---|---|---|---|---|---|---|---|---|---|
BinaryMessageCodec | false | 0.07 ms | 0.00 ms (Factor: 1.00) | -1 Bytes | - | false | -1.00 ms | - | false |
MsgPack | false | 0.17 ms | 0.10 ms (Factor: 2.43) | -1 Bytes | - | false | -1.00 ms | - | false |
MsgPackR | false | 1.15 ms | 1.08 ms (Factor: 16.43) | -1 Bytes | - | false | -1.00 ms | - | false |
MsgPackRCircular | true | 0.03 ms | -0.04 ms (Factor: 0.43) | 37 Bytes | - | true | 0.02 ms | - | true |
Conclusion
Both msgpack
libraries are significantly faster than our custom protocol. Even for small objects or buffers the encoding/decoding duration is at least halved. This becomes especially prominent when looking at the encoding/decoding times for the DeployedPluginArgs
object. This performance improvement alone would be reason enough to switch to msgpack. Both libraries can be easily extended with custom codecs and also support streamed object encoding which means we could also get rid of our custom BinaryMessagePipe
. If we want to be able to encode circular structures we would have to go with msgpackr. If this is not an required both libraries should be more or less feature equivalent.
(@tsmaeder @paul-marechal FYI)
I believe the safe route would be to use If we feel more frisky, then we could give I also don't think it's worth the hassle of supporting circular references... I'd rather we create clean types to send over the wire, the idea being that as good as the serializer is we still need to make sure the data we pass through it makes sense: objects containing only the necessary fields, no circular references. |
Looking at From our usage point of view we only care about converting our JSON messages into buffers for fast and efficient transport, unless someone has a different opinion I don't think the actual protocol matters for us. We won't extend the protocol to support things outside of the current JSON support. With that being said, I would be in favor of replacing the Theia custom encoders with |
I have two ideas:
It would be interesting to see if (1) is viable using |
One of the reasons I introduced read/writeBuffers in my original approach was to prevent unnecessary copying of stuff in scenarios like routing and multiplexing. If I have an API like this:
it forces us to make a copy to access the read data at all. So forwarding a message becomes:
So we copy the object twice: first from the incoming byte array to an object, then from the object to the outgoing by array. The same applies to multiplexing channels. We really should not be engaging any encoding/decoding when we're just forwarding/routing byte buffers.
So to me, it seems like sending bytes over the wire is a different thing/API from remotely sending objects. |
As @paul-marechal suggested, just encoding the message into a byte array and wrapping that in a routing object should not incur much encoding/decoding overhead. We will copy the whole message more times than necessary, but we're already doing that. In the long run, we could get away from routing over the |
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Rename existing "old" implementation into `RecursiveMessageEncoder/Decoder - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes eclipse-theia#11159 Contributed on behalf of STMicroelectronics
- Refactor RpcMessageEncoder/RpcMessageDecoder` - Extract generic interfaces - Provide default implementation based on msgpackR - Update message encoder test cases - Introduce reusable `AbstractChannel` implementation to reduce boilerplate code for channel setup Fixes #11159 Contributed on behalf of STMicroelectronics
With #11011 a new message rpc protocl will be integrated into Theia's core messaging API.
During the review a couple of issues and potential improvments where identified.
Ideally we can make the binary encoding/decoding an implementation detail of the channel implementation and the Channel itself only sends/receives messages. It has to be investigated weather this is feasible especially with the Plugin RPC API in mind. A solution is required that still allows to directly forwards received messages in the
hosted-plugin-process
andplugin-host
process without having to decode the entire messages. (See also Integrate new message-rpc prototype into core messaging API (extensions) #11011 (comment))We (EclipseSource) plan to contribute this on behalf of STMicroelectronics
The text was updated successfully, but these errors were encountered: