Skip to content

Commit a802b20

Browse files
committed
test(vm): make precompile benchmarks opt-in
1 parent 9d4e1d1 commit a802b20

2 files changed

Lines changed: 25 additions & 12 deletions

File tree

framework/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ def configureTestTask = { Task t ->
125125
}
126126
t.maxHeapSize = "512m"
127127
t.maxParallelForks = Math.max(1, Math.min(4, Runtime.runtime.availableProcessors()))
128+
t.systemProperty 'runPrecompileBenchmark',
129+
System.getProperty('runPrecompileBenchmark', 'false')
128130
t.doFirst {
129131
t.forkEvery = 100
130132
}

framework/src/test/java/org/tron/common/runtime/vm/PrecompileBenchmark.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
1414
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
1515
import org.bouncycastle.crypto.signers.ECDSASigner;
16+
import org.junit.Assume;
17+
import org.junit.Before;
1618
import org.junit.Test;
1719
import org.tron.common.crypto.ECKey;
1820
import org.tron.common.crypto.ECKey.ECDSASignature;
@@ -22,9 +24,9 @@
2224
/**
2325
* Manual microbenchmarks comparing the ECRecover (3000 gas) precompile
2426
* against the new P256VERIFY (6900 gas) precompile from TIP-7951. Not part
25-
* of the regular test suite — invoke explicitly:
27+
* of the regular test suite. It is opt-in behind a system property:
2628
*
27-
* ./gradlew :framework:test --tests \
29+
* ./gradlew :framework:test -DrunPrecompileBenchmark=true --tests \
2830
* org.tron.common.runtime.vm.PrecompileBenchmark -i
2931
*
3032
* Four @Test methods, each independent:
@@ -33,16 +35,18 @@
3335
* returns short-circuit before ECDSA math.
3436
* - compareDiverseInputs: rotates over N distinct keypairs to defeat
3537
* any per-key caching and branch-predictor bias.
36-
* - coldNoWarmup: no warmup, distinct input each call, first
38+
* - coldNoWarmup: no execute() warmup, distinct input each call, first
3739
* 100 calls bucketed — closer to the mainnet
3840
* case where P256VERIFY is invoked rarely and
3941
* the JVM has not JIT-compiled the path yet.
4042
*
4143
* Single-threaded, pure-Java BouncyCastle path. The first three tests use a
42-
* 5000-iteration JIT warmup; coldNoWarmup deliberately skips it.
44+
* 5000-iteration execute() warmup; coldNoWarmup deliberately skips it. Test
45+
* input generation happens before timing and may load cryptographic helper code.
4346
*/
4447
public class PrecompileBenchmark {
4548

49+
private static final String RUN_PROPERTY = "runPrecompileBenchmark";
4650
private static final int WARMUP_ITERS = 5_000;
4751
private static final int MEASURE_ITERS = 5_000;
4852
private static final int ROUNDS = 5;
@@ -53,6 +57,12 @@ public class PrecompileBenchmark {
5357
private static final PrecompiledContracts.P256Verify P256_VERIFY =
5458
new PrecompiledContracts.P256Verify();
5559

60+
@Before
61+
public void requireExplicitOptIn() {
62+
Assume.assumeTrue("set -D" + RUN_PROPERTY + "=true to run manual benchmarks",
63+
Boolean.getBoolean(RUN_PROPERTY));
64+
}
65+
5666
// First entry from go-ethereum's EIP-7951 conformance vectors — known-valid.
5767
private static final String VALID_P256_INPUT =
5868
"4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4d"
@@ -358,19 +368,20 @@ private static byte[] deterministicHash(int seed) {
358368
/** ============================== TEST 4 ============================== */
359369

360370
/**
361-
* Cold no-warmup measurement. Skips the {@code WARMUP_ITERS} prelude so the
362-
* first call pays full JIT/classloading tax — closer to the TRON mainnet
363-
* scenario where P256VERIFY is invoked at low frequency and the precompile
364-
* path rarely reaches C2 steady state.
371+
* Cold no-warmup measurement. Skips the {@code WARMUP_ITERS} execute()
372+
* prelude so the first measured precompile call sees an unprimed execute path
373+
* — closer to the TRON mainnet scenario where P256VERIFY is invoked at low
374+
* frequency and the precompile path rarely reaches C2 steady state.
365375
*
366376
* <p>Reports the first call alone plus bucketed averages over the first 100
367377
* calls so the JIT promotion curve is visible. Each call uses a distinct
368-
* input (fresh keypair / signature) to defeat any per-input caching. P256 is
369-
* timed first so the precompile path is genuinely cold.
378+
* input (fresh keypair / signature) to defeat any per-input caching. Inputs
379+
* are generated before timing, so this does not measure cryptographic helper
380+
* classloading performed by key generation.
370381
*
371-
* <p>For a fully cold measurement, run this test alone in a fresh JVM:
382+
* <p>For the coldest execute() measurement, run this test alone in a fresh JVM:
372383
*
373-
* ./gradlew :framework:test --no-daemon --tests \
384+
* ./gradlew :framework:test --no-daemon -DrunPrecompileBenchmark=true --tests \
374385
* 'org.tron.common.runtime.vm.PrecompileBenchmark.coldNoWarmup' -i
375386
*
376387
* Otherwise the other @Test methods running first will already have

0 commit comments

Comments
 (0)