Skip to content

Commit

Permalink
Improve new DefaultChannelId (#13960)
Browse files Browse the repository at this point in the history
Motivation:
The instantiation process of DefaultChannelId presents opportunities for
optimization.

Modifications:
Use the local stack when creating an instance.
Employ `Unsafe`.

Result:
Enhanced Performance.
  • Loading branch information
jchrys committed Apr 10, 2024
1 parent 02b54ca commit e19c91f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package io.netty.microbench.channel;

import io.netty.channel.DefaultChannelId;
import io.netty.microbench.util.AbstractMicrobenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;

import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(2)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 8, time = 1)
public class DefaultChannelIdBenchmark extends AbstractMicrobenchmark {

@Param({ "false", "true" })
private boolean noUnsafe;

@Setup(Level.Trial)
public void setup() {
System.setProperty("io.netty.noUnsafe", Boolean.valueOf(noUnsafe).toString());
}

@Benchmark
public DefaultChannelId newInstance() {
return DefaultChannelId.newInstance();
}

}
54 changes: 33 additions & 21 deletions transport/src/main/java/io/netty/channel/DefaultChannelId.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import static io.netty.util.internal.MacAddressUtil.defaultMachineId;
import static io.netty.util.internal.MacAddressUtil.parseMAC;
import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;

/**
* The default {@link ChannelId} implementation.
Expand Down Expand Up @@ -189,48 +190,59 @@ static int defaultProcessId() {
private transient String longValue;

private DefaultChannelId() {
data = new byte[MACHINE_ID.length + PROCESS_ID_LEN + SEQUENCE_LEN + TIMESTAMP_LEN + RANDOM_LEN];
final byte[] data = new byte[MACHINE_ID.length + PROCESS_ID_LEN + SEQUENCE_LEN + TIMESTAMP_LEN + RANDOM_LEN];
int i = 0;

// machineId
System.arraycopy(MACHINE_ID, 0, data, i, MACHINE_ID.length);
i += MACHINE_ID.length;

// processId
i = writeInt(i, PROCESS_ID);
writeInt(data, i, PROCESS_ID);
i += Integer.BYTES;

// sequence
i = writeInt(i, nextSequence.getAndIncrement());
writeInt(data, i, nextSequence.getAndIncrement());
i += Integer.BYTES;

// timestamp (kind of)
i = writeLong(i, Long.reverse(System.nanoTime()) ^ System.currentTimeMillis());
writeLong(data, i, Long.reverse(System.nanoTime()) ^ System.currentTimeMillis());
i += Long.BYTES;

// random
int random = PlatformDependent.threadLocalRandom().nextInt();
i = writeInt(i, random);
writeInt(data, i, random);
i += Integer.BYTES;
assert i == data.length;

this.data = data;
hashCode = Arrays.hashCode(data);
}

private int writeInt(int i, int value) {
data[i ++] = (byte) (value >>> 24);
data[i ++] = (byte) (value >>> 16);
data[i ++] = (byte) (value >>> 8);
data[i ++] = (byte) value;
return i;
private static void writeInt(byte[] data, int i, int value) {
if (PlatformDependent.isUnaligned()) {
PlatformDependent.putInt(data, i, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
return;
}
data[i] = (byte) (value >>> 24);
data[i + 1] = (byte) (value >>> 16);
data[i + 2] = (byte) (value >>> 8);
data[i + 3] = (byte) value;
}

private int writeLong(int i, long value) {
data[i ++] = (byte) (value >>> 56);
data[i ++] = (byte) (value >>> 48);
data[i ++] = (byte) (value >>> 40);
data[i ++] = (byte) (value >>> 32);
data[i ++] = (byte) (value >>> 24);
data[i ++] = (byte) (value >>> 16);
data[i ++] = (byte) (value >>> 8);
data[i ++] = (byte) value;
return i;
private static void writeLong(byte[] data, int i, long value) {
if (PlatformDependent.isUnaligned()) {
PlatformDependent.putLong(data, i, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
return;
}
data[i] = (byte) (value >>> 56);
data[i + 1] = (byte) (value >>> 48);
data[i + 2] = (byte) (value >>> 40);
data[i + 3] = (byte) (value >>> 32);
data[i + 4] = (byte) (value >>> 24);
data[i + 5] = (byte) (value >>> 16);
data[i + 6] = (byte) (value >>> 8);
data[i + 7] = (byte) value;
}

@Override
Expand Down

0 comments on commit e19c91f

Please sign in to comment.