Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright contributors to Besu.
*
* Licensed 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations.v2;

import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.bytesToUInt256;
import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.randomUInt256Value;

import org.hyperledger.besu.evm.UInt256;

import java.util.concurrent.ThreadLocalRandom;

import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;

/**
* Abstract base class for shift operation benchmarks (SHL, SHR, SAR).
*
* <p>Provides shared test case definitions and setup logic.
*/
public abstract class AbstractShiftOperationBenchmarkV2 extends BinaryOperationBenchmarkV2 {

/** Test cases covering different execution paths for shift operations. */
public enum Case {
/** Shift by 0 - no shift needed. */
SHIFT_0,
/** Small shift by 1 bit. */
SHIFT_1,
/** Medium shift by 128 bits. */
SHIFT_128,
/** Large shift by 255 bits (max valid). */
SHIFT_255,
/** Overflow: shift of exactly 256. */
OVERFLOW_SHIFT_256,
/** Overflow: shift amount > 4 bytes. */
OVERFLOW_LARGE_SHIFT,
/** Random values (original behavior). */
FULL_RANDOM
}

@Param({
"SHIFT_0",
"SHIFT_1",
"SHIFT_128",
"SHIFT_255",
"OVERFLOW_SHIFT_256",
"OVERFLOW_LARGE_SHIFT",
"FULL_RANDOM"
})
protected String caseName;

@Setup(Level.Iteration)
@Override
public void setUp() {
frame = BenchmarkHelperV2.createMessageCallFrame();

final Case scenario = Case.valueOf(caseName);
aPool = new UInt256[SAMPLE_SIZE]; // shift amount (pushed second, popped first)
bPool = new UInt256[SAMPLE_SIZE]; // value (pushed first, popped second)

final ThreadLocalRandom random = ThreadLocalRandom.current();

for (int i = 0; i < SAMPLE_SIZE; i++) {
switch (scenario) {
case SHIFT_0:
aPool[i] = UInt256.ZERO;
bPool[i] = randomUInt256Value(random);
break;

case SHIFT_1:
aPool[i] = UInt256.ONE;
bPool[i] = randomUInt256Value(random);
break;

case SHIFT_128:
aPool[i] = UInt256.fromInt(128);
bPool[i] = randomUInt256Value(random);
break;

case SHIFT_255:
aPool[i] = UInt256.fromInt(255);
bPool[i] = randomUInt256Value(random);
break;

case OVERFLOW_SHIFT_256:
aPool[i] = UInt256.fromInt(256); // 256
bPool[i] = randomUInt256Value(random);
break;

case OVERFLOW_LARGE_SHIFT:
aPool[i] = bytesToUInt256(new byte[] {0x01, 0x00, 0x00, 0x00, 0x00, 0x00});
bPool[i] = randomUInt256Value(random);
break;

case FULL_RANDOM:
default:
final byte[] shift = new byte[1 + random.nextInt(4)];
final byte[] value = new byte[1 + random.nextInt(32)];
random.nextBytes(shift);
random.nextBytes(value);
aPool[i] = bytesToUInt256(shift);
bPool[i] = bytesToUInt256(value);
break;
}
}
index = 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.v2.AddOperationV2;
import org.hyperledger.besu.evm.v2.operation.AddOperationV2;

public class AddOperationBenchmarkV2 extends BinaryOperationBenchmarkV2 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import org.apache.tuweni.bytes.Bytes32;

Expand Down Expand Up @@ -101,4 +102,44 @@ static void pushUInt256(final MessageFrame frame, final org.hyperledger.besu.evm
s[dst + 3] = value.u0();
frame.setTopV2(top + 1);
}

/**
* Generates a random UInt256 value.
*
* @param random thread-local random source
* @return random UInt256 value
*/
static org.hyperledger.besu.evm.UInt256 randomUInt256Value(final ThreadLocalRandom random) {
final byte[] value = new byte[32];
random.nextBytes(value);
return org.hyperledger.besu.evm.UInt256.fromBytesBE(value);
}

/**
* Generates a random positive signed 256-bit UInt256 value (sign bit cleared).
*
* @param random thread-local random source
* @return random positive UInt256 value
*/
static org.hyperledger.besu.evm.UInt256 randomPositiveUInt256Value(
final ThreadLocalRandom random) {
final byte[] value = new byte[32];
random.nextBytes(value);
value[0] = (byte) (value[0] & 0x7F);
return org.hyperledger.besu.evm.UInt256.fromBytesBE(value);
}

/**
* Generates a random negative signed 256-bit UInt256 value (sign bit set).
*
* @param random thread-local random source
* @return random negative UInt256 value
*/
static org.hyperledger.besu.evm.UInt256 randomNegativeUInt256Value(
final ThreadLocalRandom random) {
final byte[] value = new byte[32];
random.nextBytes(value);
value[0] = (byte) (value[0] | 0x80);
return org.hyperledger.besu.evm.UInt256.fromBytesBE(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright contributors to Besu.
*
* Licensed 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations.v2;

import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.bytesToUInt256;
import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.randomNegativeUInt256Value;
import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.randomPositiveUInt256Value;
import static org.hyperledger.besu.ethereum.vm.operations.v2.BenchmarkHelperV2.randomUInt256Value;

import org.hyperledger.besu.evm.UInt256;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.v2.operation.SarOperationV2;

import java.util.concurrent.ThreadLocalRandom;

import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;

public class SarOperationBenchmarkV2 extends BinaryOperationBenchmarkV2 {

/** Test cases covering different execution paths for SAR operations. */
public enum Case {
/** Shift by 0 - early return path. */
SHIFT_0,
/** Negative number with shift=1 - tests sign extension. */
NEGATIVE_SHIFT_1,
/** Value with all bits set with shift=1. */
ALL_BITS_SHIFT_1,
/** Positive number with shift=1 - no sign extension needed. */
POSITIVE_SHIFT_1,
/** Negative number with medium shift. */
NEGATIVE_SHIFT_128,
/** Negative number with max shift. */
NEGATIVE_SHIFT_255,
/** Positive number with medium shift. */
POSITIVE_SHIFT_128,
/** Positive number with max shift. */
POSITIVE_SHIFT_255,
/** Overflow: shift >= 256. */
OVERFLOW_SHIFT_256,
/** Overflow: shift amount > 4 bytes. */
OVERFLOW_LARGE_SHIFT,
/** Random values. */
FULL_RANDOM
}

@Param({
"SHIFT_0",
"NEGATIVE_SHIFT_1",
"POSITIVE_SHIFT_1",
"ALL_BITS_SHIFT_1",
"NEGATIVE_SHIFT_128",
"NEGATIVE_SHIFT_255",
"POSITIVE_SHIFT_128",
"POSITIVE_SHIFT_255",
"OVERFLOW_SHIFT_256",
"OVERFLOW_LARGE_SHIFT",
"FULL_RANDOM"
})
protected String caseName;

@Setup(Level.Iteration)
@Override
public void setUp() {
frame = BenchmarkHelperV2.createMessageCallFrame();

final Case scenario = Case.valueOf(caseName);
aPool = new UInt256[SAMPLE_SIZE];
bPool = new UInt256[SAMPLE_SIZE];

final ThreadLocalRandom random = ThreadLocalRandom.current();

for (int i = 0; i < SAMPLE_SIZE; i++) {
switch (scenario) {
case SHIFT_0:
aPool[i] = UInt256.fromInt(0);
bPool[i] = randomUInt256Value(random);
break;

case NEGATIVE_SHIFT_1:
aPool[i] = UInt256.fromInt(1);
bPool[i] = randomNegativeUInt256Value(random);
break;

case ALL_BITS_SHIFT_1:
aPool[i] = UInt256.fromInt(1);
bPool[i] = UInt256.MAX;
break;

case POSITIVE_SHIFT_1:
aPool[i] = UInt256.fromInt(1);
bPool[i] = randomPositiveUInt256Value(random);
break;

case NEGATIVE_SHIFT_128:
aPool[i] = UInt256.fromInt(128);
bPool[i] = randomNegativeUInt256Value(random);
break;

case NEGATIVE_SHIFT_255:
aPool[i] = UInt256.fromInt(255);
bPool[i] = randomNegativeUInt256Value(random);
break;

case POSITIVE_SHIFT_128:
aPool[i] = UInt256.fromInt(128);
bPool[i] = randomPositiveUInt256Value(random);
break;
case POSITIVE_SHIFT_255:
aPool[i] = UInt256.fromInt(255);
bPool[i] = randomPositiveUInt256Value(random);
break;

case OVERFLOW_SHIFT_256:
aPool[i] = UInt256.fromInt(256);
bPool[i] = randomUInt256Value(random);
break;

case OVERFLOW_LARGE_SHIFT:
aPool[i] = bytesToUInt256(new byte[] {0x01, 0x00, 0x00, 0x00, 0x00, 0x00});
bPool[i] = randomUInt256Value(random);
break;

case FULL_RANDOM:
default:
final byte[] shift = new byte[1 + random.nextInt(2)];
final byte[] value = new byte[1 + random.nextInt(32)];
random.nextBytes(shift);
random.nextBytes(value);
aPool[i] = bytesToUInt256(shift);
bPool[i] = bytesToUInt256(value);
break;
}
}
index = 0;
}

@Override
protected Operation.OperationResult invoke(final MessageFrame frame) {
return SarOperationV2.staticOperation(frame, frame.stackDataV2());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright contributors to Besu.
*
* Licensed 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations.v2;

import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.v2.operation.ShlOperationV2;

public class ShlOperationBenchmarkV2 extends AbstractShiftOperationBenchmarkV2 {

@Override
protected Operation.OperationResult invoke(final MessageFrame frame) {
return ShlOperationV2.staticOperation(frame, frame.stackDataV2());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright contributors to Besu.
*
* Licensed 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.vm.operations.v2;

import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.v2.operation.ShrOperationV2;

public class ShrOperationBenchmarkV2 extends AbstractShiftOperationBenchmarkV2 {

@Override
protected Operation.OperationResult invoke(final MessageFrame frame) {
return ShrOperationV2.staticOperation(frame, frame.stackDataV2());
}
}
Loading
Loading