Skip to content

Commit 48060a0

Browse files
authored
Extend RecyclerBytesStreamOutput benchmark with vlongs (#141640)
`RecyclerBytesStreamOutput#writeVLong` is not particularly optimal today. This commit adds a benchmark anyway to lay the groundwork for improving it.
1 parent 6a0b4eb commit 48060a0

File tree

1 file changed

+127
-19
lines changed

1 file changed

+127
-19
lines changed

benchmarks/src/main/java/org/elasticsearch/benchmark/bytes/RecyclerBytesStreamOutputWriteBenchmark.java

Lines changed: 127 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
@Fork(1)
3838
public class RecyclerBytesStreamOutputWriteBenchmark {
3939

40-
// large enough to negate stream reset
41-
// and not too large to stay under stream limit of 2GB on worst case (5 bytes vint)
40+
// large enough to negate stream reset and not too large to stay under stream limit of 2GB on worst case (9 bytes vlong)
4241
private static final int WRITES_PER_ITERATION = 400_000;
4342
private static final int RANDOM_NUMS_PER_ITERATION = 1000;
43+
private static final int LOOPS_PER_ITERATION = WRITES_PER_ITERATION / RANDOM_NUMS_PER_ITERATION;
4444
private static final int PAGE_SIZE = 16384;
4545

4646
private ThreadLocalRandom random = ThreadLocalRandom.current();
@@ -50,39 +50,84 @@ public class RecyclerBytesStreamOutputWriteBenchmark {
5050
private int[] vint4Bytes;
5151
private int[] vint5Bytes;
5252
private int[] vintNegBytes;
53+
private long[] vlong1Byte;
54+
private long[] vlong2Bytes;
55+
private long[] vlong3Bytes;
56+
private long[] vlong4Bytes;
57+
private long[] vlong5Bytes;
58+
private long[] vlong6Bytes;
59+
private long[] vlong7Bytes;
60+
private long[] vlong8Bytes;
61+
private long[] vlong9Bytes;
62+
5363
private RecyclerBytesStreamOutput output = new RecyclerBytesStreamOutput(new SinglePageStream());
5464

5565
private int randomVInt(int vIntByteSize, boolean isNeg) {
56-
return (isNeg ? -1 : 1) * switch (vIntByteSize) {
66+
if (isNeg) {
67+
return random.nextInt(Integer.MIN_VALUE, 0);
68+
}
69+
return switch (vIntByteSize) {
5770
case 1 -> random.nextInt(0, 1 << 7);
5871
case 2 -> random.nextInt(1 << 7, 1 << 14);
5972
case 3 -> random.nextInt(1 << 14, 1 << 21);
6073
case 4 -> random.nextInt(1 << 21, 1 << 28);
61-
case 5 -> random.nextInt(1 << 28, 1 << 30);
74+
case 5 -> random.nextInt((1 << 28) - 1, Integer.MAX_VALUE) + 1; // ±1 because upper bound is exclusive
6275
default -> throw new IllegalArgumentException("number of bytes must be between 1 and 5");
6376
};
6477
}
6578

66-
private int[] randomArray(int vIntByteSize, boolean isNeg) {
79+
private int[] randomVInts(int vIntByteSize, boolean isNeg) {
6780
final var out = new int[RANDOM_NUMS_PER_ITERATION];
6881
for (var i = 0; i < RANDOM_NUMS_PER_ITERATION; i++) {
6982
out[i] = randomVInt(vIntByteSize, isNeg);
7083
}
7184
return out;
7285
}
7386

87+
private long[] randomVLongs(int bytes) {
88+
final var out = new long[RANDOM_NUMS_PER_ITERATION];
89+
final long upperBound, lowerBound, offset;
90+
if (bytes == 1) {
91+
upperBound = 1 << 7;
92+
lowerBound = 0L;
93+
offset = 0L;
94+
} else if (bytes == 9) {
95+
upperBound = Long.MAX_VALUE;
96+
lowerBound = (1L << 56) - 1;
97+
offset = 1L; // ±1 because upper bound is exclusive
98+
} else {
99+
upperBound = 1L << (bytes * 7);
100+
lowerBound = upperBound >> 7;
101+
offset = 0L;
102+
}
103+
for (var i = 0; i < RANDOM_NUMS_PER_ITERATION; i++) {
104+
out[i] = random.nextLong(lowerBound, upperBound) + offset;
105+
}
106+
return out;
107+
}
108+
74109
@Setup(Level.Iteration)
75110
public void resetNums() {
76-
vint1Byte = randomArray(1, false);
77-
vint2Bytes = randomArray(2, false);
78-
vint3Bytes = randomArray(3, false);
79-
vint4Bytes = randomArray(4, false);
80-
vint5Bytes = randomArray(5, false);
81-
vintNegBytes = randomArray(random.nextInt(1, 6), true);
111+
vint1Byte = randomVInts(1, false);
112+
vint2Bytes = randomVInts(2, false);
113+
vint3Bytes = randomVInts(3, false);
114+
vint4Bytes = randomVInts(4, false);
115+
vint5Bytes = randomVInts(5, false);
116+
vintNegBytes = randomVInts(0, true);
117+
118+
vlong1Byte = randomVLongs(1);
119+
vlong2Bytes = randomVLongs(2);
120+
vlong3Bytes = randomVLongs(3);
121+
vlong4Bytes = randomVLongs(4);
122+
vlong5Bytes = randomVLongs(5);
123+
vlong6Bytes = randomVLongs(6);
124+
vlong7Bytes = randomVLongs(7);
125+
vlong8Bytes = randomVLongs(8);
126+
vlong9Bytes = randomVLongs(9);
82127
}
83128

84-
private void writeLoop(int[] nums) throws IOException {
85-
for (int reps = 0; reps < WRITES_PER_ITERATION / nums.length; reps++) {
129+
private void writeVIntLoop(int[] nums) throws IOException {
130+
for (int reps = 0; reps < LOOPS_PER_ITERATION; reps++) {
86131
for (var n : nums) {
87132
output.writeVInt(n);
88133
}
@@ -93,37 +138,100 @@ private void writeLoop(int[] nums) throws IOException {
93138
@Benchmark
94139
@OperationsPerInvocation(WRITES_PER_ITERATION)
95140
public void writeVInt1() throws IOException {
96-
writeLoop(vint1Byte);
141+
writeVIntLoop(vint1Byte);
97142
}
98143

99144
@Benchmark
100145
@OperationsPerInvocation(WRITES_PER_ITERATION)
101146
public void writeVInt2() throws IOException {
102-
writeLoop(vint2Bytes);
147+
writeVIntLoop(vint2Bytes);
103148
}
104149

105150
@Benchmark
106151
@OperationsPerInvocation(WRITES_PER_ITERATION)
107152
public void writeVInt3() throws IOException {
108-
writeLoop(vint3Bytes);
153+
writeVIntLoop(vint3Bytes);
109154
}
110155

111156
@Benchmark
112157
@OperationsPerInvocation(WRITES_PER_ITERATION)
113158
public void writeVInt4() throws IOException {
114-
writeLoop(vint4Bytes);
159+
writeVIntLoop(vint4Bytes);
115160
}
116161

117162
@Benchmark
118163
@OperationsPerInvocation(WRITES_PER_ITERATION)
119164
public void writeVInt5() throws IOException {
120-
writeLoop(vint5Bytes);
165+
writeVIntLoop(vint5Bytes);
121166
}
122167

123168
@Benchmark
124169
@OperationsPerInvocation(WRITES_PER_ITERATION)
125170
public void writeVIntNeg() throws IOException {
126-
writeLoop(vintNegBytes);
171+
writeVIntLoop(vintNegBytes);
172+
}
173+
174+
private void writeVLongLoop(long[] nums) throws IOException {
175+
for (int reps = 0; reps < LOOPS_PER_ITERATION; reps++) {
176+
for (var n : nums) {
177+
output.writeVLong(n);
178+
}
179+
}
180+
output.seek(0);
181+
}
182+
183+
@Benchmark
184+
@OperationsPerInvocation(WRITES_PER_ITERATION)
185+
public void writeVLong1() throws IOException {
186+
writeVLongLoop(vlong1Byte);
187+
}
188+
189+
@Benchmark
190+
@OperationsPerInvocation(WRITES_PER_ITERATION)
191+
public void writeVLong2() throws IOException {
192+
writeVLongLoop(vlong2Bytes);
193+
}
194+
195+
@Benchmark
196+
@OperationsPerInvocation(WRITES_PER_ITERATION)
197+
public void writeVLong3() throws IOException {
198+
writeVLongLoop(vlong3Bytes);
199+
}
200+
201+
@Benchmark
202+
@OperationsPerInvocation(WRITES_PER_ITERATION)
203+
public void writeVLong4() throws IOException {
204+
writeVLongLoop(vlong4Bytes);
205+
}
206+
207+
@Benchmark
208+
@OperationsPerInvocation(WRITES_PER_ITERATION)
209+
public void writeVLong5() throws IOException {
210+
writeVLongLoop(vlong5Bytes);
211+
}
212+
213+
@Benchmark
214+
@OperationsPerInvocation(WRITES_PER_ITERATION)
215+
public void writeVLong6() throws IOException {
216+
writeVLongLoop(vlong6Bytes);
217+
}
218+
219+
@Benchmark
220+
@OperationsPerInvocation(WRITES_PER_ITERATION)
221+
public void writeVLong7() throws IOException {
222+
writeVLongLoop(vlong7Bytes);
223+
}
224+
225+
@Benchmark
226+
@OperationsPerInvocation(WRITES_PER_ITERATION)
227+
public void writeVLong8() throws IOException {
228+
writeVLongLoop(vlong8Bytes);
229+
}
230+
231+
@Benchmark
232+
@OperationsPerInvocation(WRITES_PER_ITERATION)
233+
public void writeVLong9() throws IOException {
234+
writeVLongLoop(vlong9Bytes);
127235
}
128236

129237
// recycle same page, we never read previous pages

0 commit comments

Comments
 (0)