Skip to content
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

MqttEncoder optimisation proposal #13940

Open
Munoon opened this issue Mar 29, 2024 · 0 comments
Open

MqttEncoder optimisation proposal #13940

Munoon opened this issue Mar 29, 2024 · 0 comments

Comments

@Munoon
Copy link

Munoon commented Mar 29, 2024

Current MqttEncoder make a lot of class casts, which can be improved with the methods, that returns concreete type.

For example, this code:

static ByteBuf doEncode(ChannelHandlerContext ctx,
MqttMessage message) {
switch (message.fixedHeader().messageType()) {
case CONNECT:
return encodeConnectMessage(ctx, (MqttConnectMessage) message);

May be refactored as follow:

switch (message.fixedHeader().messageType()) {
    case CONNECT:
        return encodeConnectMessage(ctx, message.asConnectMessage());

Where default implementation of asConnectMessage method throws ClassCastException while MqttConnectMessage overrides this method and return this.

A simple benchmark shows, that such refactoring sligtly improves the performance:

Benchmark                                  Mode  Cnt       Score       Error  Units
MqttEncoderBench.doEncode                 thrpt   20  407587,038 ± 21522,217  ops/s
MqttEncoderBench.doEncodeWithTypeMethods  thrpt   20  419308,953 ± 10095,722  ops/s
Benchmark code
package io.netty.handler.codec.mqtt;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.microbench.channel.EmbeddedChannelHandlerContext;
import io.netty.microbench.util.AbstractMicrobenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;

@State(Scope.Benchmark)
public class MqttEncoderBench extends AbstractMicrobenchmark {
    MqttMessage[] messages;
    ChannelHandlerContext context;

    @Setup
    public void initData() {
        messages = new MqttMessage[] {
                MqttMessageBuilders.connect().clientId("testClientId").build(),
                MqttMessageBuilders.connAck().returnCode(MqttConnectReturnCode.CONNECTION_ACCEPTED).build(),
                MqttMessageBuilders.subscribe().messageId(1).addSubscription(MqttQoS.AT_MOST_ONCE, "/test").build(),
                MqttMessageBuilders.subAck().packetId(1).addGrantedQos(MqttQoS.AT_MOST_ONCE).build(),
                MqttMessageBuilders.publish().topicName("/test").payload(Unpooled.EMPTY_BUFFER).qos(MqttQoS.AT_LEAST_ONCE).build(),
                MqttMessageBuilders.disconnect().build(),
                MqttMessage.PINGREQ,
                MqttMessage.PINGRESP
        };

        ByteBufAllocator alloc = UnpooledByteBufAllocator.DEFAULT;
        ChannelHandler handler = new MqttDecoder();
        EmbeddedChannel channel = new EmbeddedChannel();
        context = new EmbeddedChannelHandlerContext(alloc, handler, channel) {
            @Override
            protected void handleException(Throwable t) {
                t.printStackTrace();
            }
        };
    }

    @Benchmark
    public void doEncode(Blackhole blackhole) {
        for (MqttMessage message : messages) {
            ByteBuf byteBuf = MqttEncoder.doEncode(context, message);
            byteBuf.release();
            blackhole.consume(byteBuf);
        }
    }

    @Benchmark
    public void doEncodeWithTypeMethods(Blackhole blackhole) {
        for (MqttMessage message : messages) {
            ByteBuf byteBuf = MqttEncoder.doEncodeTypeMethod(context, message);
            byteBuf.release();
            blackhole.consume(byteBuf);
        }
    }
}

If this proposal look good for you, I'd be happy to create a pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant