Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Reapply "Optimize varint writing"
Inspired by the approach described at the bottom of https://richardstartin.github.io/posts/dont-use-protobuf-for-telemetry Given that we do a lot of varint writing as well, this should provide a small performance boost for larger/complex packets whilst not regressing hard on smaller packets. This includes a test to ensure that the behavior is as expected and fixes the initialization loop so that the correct results will be given. Much thanks to @octylFractal for acting as my duck while trying to figure this out.
Dieser Commit ist enthalten in:
Ursprung
e531cdb373
Commit
4ca97a6df9
@ -62,6 +62,17 @@ public enum ProtocolUtils {
|
||||
private static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||
private static final QuietDecoderException BAD_VARINT_CACHED =
|
||||
new QuietDecoderException("Bad varint decoded");
|
||||
private static final int[] VAR_INT_BYTE_LENGTHS = new int[33];
|
||||
|
||||
static {
|
||||
// Inspired by https://richardstartin.github.io/posts/dont-use-protobuf-for-telemetry
|
||||
// This has been slightly modified in that we reduce the length to 32-bit only, since Velocity
|
||||
// doesn't look at any part of the Minecraft protocol that requires us to look at VarLongs.
|
||||
for (int i = 0; i <= 32; ++i) {
|
||||
VAR_INT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
|
||||
}
|
||||
VAR_INT_BYTE_LENGTHS[32] = 1; // Special case for the number 0.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a Minecraft-style VarInt from the specified {@code buf}.
|
||||
@ -97,21 +108,22 @@ public enum ProtocolUtils {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public static int varintBytes(int value) {
|
||||
return VAR_INT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(value)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a Minecraft-style VarInt to the specified {@code buf}.
|
||||
* @param buf the buffer to read from
|
||||
* @param value the integer to write
|
||||
*/
|
||||
public static void writeVarInt(ByteBuf buf, int value) {
|
||||
while (true) {
|
||||
if ((value & 0xFFFFFF80) == 0) {
|
||||
buf.writeByte(value);
|
||||
return;
|
||||
}
|
||||
|
||||
buf.writeByte(value & 0x7F | 0x80);
|
||||
int length = varintBytes(value);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
buf.writeByte(((byte) ((value & 0x7F) | 0x80)));
|
||||
value >>>= 7;
|
||||
}
|
||||
buf.writeByte((byte) value);
|
||||
}
|
||||
|
||||
public static String readString(ByteBuf buf) {
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.velocitypowered.proxy.protocol;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ProtocolUtilsTest {
|
||||
|
||||
@Test
|
||||
void negativeVarIntBytes() {
|
||||
assertEquals(5, ProtocolUtils.varintBytes(-1));
|
||||
assertEquals(5, ProtocolUtils.varintBytes(Integer.MIN_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroVarIntBytes() {
|
||||
assertEquals(1, ProtocolUtils.varintBytes(0));
|
||||
assertEquals(1, ProtocolUtils.varintBytes(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void ensureConsistencyAcrossNumberBits() {
|
||||
for (int i = 0; i <= 31; i++) {
|
||||
int number = (1 << i) - 1;
|
||||
assertEquals(conventionalWrittenBytes(number), ProtocolUtils.varintBytes(number),
|
||||
"mismatch with " + i + "-bit number");
|
||||
}
|
||||
}
|
||||
|
||||
private int conventionalWrittenBytes(int value) {
|
||||
int wouldBeWritten = 0;
|
||||
while (true) {
|
||||
if ((value & ~0x7FL) == 0) {
|
||||
wouldBeWritten++;
|
||||
return wouldBeWritten;
|
||||
} else {
|
||||
wouldBeWritten++;
|
||||
value >>>= 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren