mirror of https://github.com/hyperledger/besu
Add benchmark for BlockHashOperation (#203)
Includes a reusable OperationBenchmarkHelper to make writing EVM opcode benchmarks easier in future. Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
8fa45725f2
commit
ab77bce927
@ -0,0 +1,72 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.vm.operations; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.mainnet.ConstantinopleGasCalculator; |
||||
import tech.pegasys.pantheon.ethereum.vm.BlockHashLookup; |
||||
import tech.pegasys.pantheon.ethereum.vm.MessageFrame; |
||||
import tech.pegasys.pantheon.util.bytes.Bytes32; |
||||
import tech.pegasys.pantheon.util.uint.UInt256; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
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.TearDown; |
||||
|
||||
@State(Scope.Thread) |
||||
public class BlockHashOperationBenchmark { |
||||
|
||||
@Param({ |
||||
"1", // Worst-case scenario
|
||||
"125", // Must iterate up the chain
|
||||
"255" // Hash available directly via current header's parentHash
|
||||
}) |
||||
public long blockNumber; |
||||
|
||||
private OperationBenchmarkHelper operationBenchmarkHelper; |
||||
private BlockHashOperation operation; |
||||
private MessageFrame frame; |
||||
|
||||
@Setup |
||||
public void prepare() throws Exception { |
||||
operationBenchmarkHelper = OperationBenchmarkHelper.create(); |
||||
operation = new BlockHashOperation(new ConstantinopleGasCalculator()); |
||||
frame = operationBenchmarkHelper.createMessageFrame(); |
||||
} |
||||
|
||||
@TearDown |
||||
public void cleanUp() throws Exception { |
||||
operationBenchmarkHelper.cleanUp(); |
||||
} |
||||
|
||||
@Benchmark |
||||
public Bytes32 executeOperation() { |
||||
frame.pushStackItem(UInt256.of(blockNumber).getBytes()); |
||||
operation.execute(frame); |
||||
return frame.popStackItem(); |
||||
} |
||||
|
||||
@Benchmark |
||||
public Bytes32 executeOperationWithEmptyHashCache() { |
||||
final MessageFrame cleanFrame = |
||||
operationBenchmarkHelper |
||||
.createMessageFrameBuilder() |
||||
.blockHashLookup(new BlockHashLookup(frame.getBlockHeader(), frame.getBlockchain())) |
||||
.build(); |
||||
cleanFrame.pushStackItem(UInt256.of(blockNumber).getBytes()); |
||||
operation.execute(cleanFrame); |
||||
return cleanFrame.popStackItem(); |
||||
} |
||||
} |
@ -0,0 +1,113 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.vm.operations; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockBody; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; |
||||
import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture; |
||||
import tech.pegasys.pantheon.ethereum.core.MessageFrameTestFixture; |
||||
import tech.pegasys.pantheon.ethereum.vm.MessageFrame; |
||||
import tech.pegasys.pantheon.services.kvstore.RocksDbKeyValueStorage; |
||||
import tech.pegasys.pantheon.util.uint.UInt256; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
|
||||
import com.google.common.io.MoreFiles; |
||||
import com.google.common.io.RecursiveDeleteOption; |
||||
|
||||
public class OperationBenchmarkHelper { |
||||
|
||||
private final Path storageDirectory; |
||||
private final RocksDbKeyValueStorage keyValueStorage; |
||||
private final MessageFrame messageFrame; |
||||
|
||||
private OperationBenchmarkHelper( |
||||
final Path storageDirectory, |
||||
final RocksDbKeyValueStorage keyValueStorage, |
||||
final MessageFrame messageFrame) { |
||||
this.storageDirectory = storageDirectory; |
||||
this.keyValueStorage = keyValueStorage; |
||||
this.messageFrame = messageFrame; |
||||
} |
||||
|
||||
public static OperationBenchmarkHelper create() throws IOException { |
||||
final Path storageDirectory = Files.createTempDirectory("benchmark"); |
||||
final RocksDbKeyValueStorage keyValueStorage = RocksDbKeyValueStorage.create(storageDirectory); |
||||
|
||||
final ExecutionContextTestFixture executionContext = |
||||
ExecutionContextTestFixture.builder().keyValueStorage(keyValueStorage).build(); |
||||
final MutableBlockchain blockchain = executionContext.getBlockchain(); |
||||
|
||||
for (int i = 1; i < 256; i++) { |
||||
blockchain.appendBlock( |
||||
new Block( |
||||
new BlockHeaderTestFixture() |
||||
.parentHash(blockchain.getChainHeadHash()) |
||||
.number(i) |
||||
.difficulty(UInt256.ONE) |
||||
.buildHeader(), |
||||
new BlockBody(emptyList(), emptyList())), |
||||
emptyList()); |
||||
} |
||||
final MessageFrame messageFrame = |
||||
new MessageFrameTestFixture() |
||||
.executionContextTestFixture(executionContext) |
||||
.blockHeader( |
||||
new BlockHeaderTestFixture() |
||||
.parentHash(blockchain.getChainHeadHash()) |
||||
.number(blockchain.getChainHeadBlockNumber() + 1) |
||||
.difficulty(UInt256.ONE) |
||||
.buildHeader()) |
||||
.build(); |
||||
return new OperationBenchmarkHelper(storageDirectory, keyValueStorage, messageFrame); |
||||
} |
||||
|
||||
public MessageFrame createMessageFrame() { |
||||
return createMessageFrameBuilder().build(); |
||||
} |
||||
|
||||
public MessageFrame.Builder createMessageFrameBuilder() { |
||||
return MessageFrame.builder() |
||||
.type(MessageFrame.Type.MESSAGE_CALL) |
||||
.messageFrameStack(messageFrame.getMessageFrameStack()) |
||||
.blockchain(messageFrame.getBlockchain()) |
||||
.worldState(messageFrame.getWorldState()) |
||||
.initialGas(messageFrame.getRemainingGas()) |
||||
.address(messageFrame.getContractAddress()) |
||||
.originator(messageFrame.getOriginatorAddress()) |
||||
.contract(messageFrame.getRecipientAddress()) |
||||
.gasPrice(messageFrame.getGasPrice()) |
||||
.inputData(messageFrame.getInputData()) |
||||
.sender(messageFrame.getSenderAddress()) |
||||
.value(messageFrame.getValue()) |
||||
.apparentValue(messageFrame.getApparentValue()) |
||||
.code(messageFrame.getCode()) |
||||
.blockHeader(messageFrame.getBlockHeader()) |
||||
.depth(messageFrame.getMessageStackDepth()) |
||||
.isStatic(messageFrame.isStatic()) |
||||
.completer(messageFrame -> {}) |
||||
.miningBeneficiary(messageFrame.getMiningBeneficiary()) |
||||
.blockHashLookup(messageFrame.getBlockHashLookup()); |
||||
} |
||||
|
||||
public void cleanUp() throws IOException { |
||||
keyValueStorage.close(); |
||||
MoreFiles.deleteRecursively(storageDirectory, RecursiveDeleteOption.ALLOW_INSECURE); |
||||
} |
||||
} |
Loading…
Reference in new issue