37
37
import org .hyperledger .besu .evm .gascalculator .ShanghaiGasCalculator ;
38
38
import org .hyperledger .besu .evm .precompile .PrecompiledContract ;
39
39
40
+ import java .io .IOException ;
40
41
import java .io .PrintStream ;
41
- import java .util .HashMap ;
42
+ import java .io .PrintWriter ;
43
+ import java .nio .charset .StandardCharsets ;
44
+ import java .nio .file .Files ;
45
+ import java .nio .file .Path ;
46
+ import java .nio .file .Paths ;
42
47
import java .util .LinkedHashMap ;
43
48
import java .util .Locale ;
44
49
import java .util .Map ;
@@ -175,6 +180,11 @@ public void precompile(
175
180
}
176
181
});
177
182
183
+ if (filteredTestCases .isEmpty ()) {
184
+ output .println ("No test cases matched the pattern: " + config .testCasePattern ().orElse (null ));
185
+ return ;
186
+ }
187
+
178
188
if (config .warmInvert ()) {
179
189
runPrecompileInvertedWarmup (filteredTestCases , contract );
180
190
} else {
@@ -186,25 +196,57 @@ private void runPrecompile(
186
196
final Map <String , Bytes > testCases , final PrecompiledContract contract ) {
187
197
188
198
// Fully warmup and execute, test case by test case
199
+ Map <String , DescriptiveStatistics > timeStatsMap = new LinkedHashMap <>();
189
200
for (final Map .Entry <String , Bytes > testCase : testCases .entrySet ()) {
190
201
try {
191
202
/*final double execTime =*/ runPrecompileBenchmark (
192
203
testCase .getKey (), testCase .getValue (), contract );
193
204
long gasCost = contract .gasRequirement (testCase .getValue ());
194
205
// logPrecompilePerformance(testCase.getKey(), gasCost, execTime);
195
206
logResultsWithError (testCase .getKey (), gasCost , timeStats );
207
+ timeStatsMap .put (testCase .getKey (), timeStats );
196
208
} catch (final IllegalArgumentException e ) {
197
209
output .printf ("%s Input is Invalid%n" , testCase .getKey ());
198
210
}
199
211
}
212
+
213
+ // Also log csv output
214
+ // output.println("Test,Iteration,Time (ns)");
215
+ Path out = Paths .get ("benchmark_results.csv" );
216
+ try (PrintWriter csv =
217
+ new PrintWriter (Files .newBufferedWriter (out , StandardCharsets .UTF_8 ), true )) {
218
+ csv .println ("case,iteration,time (ns)" );
219
+ for (final Map .Entry <String , DescriptiveStatistics > testCaseStats : timeStatsMap .entrySet ()) {
220
+ String testCase = testCaseStats .getKey ();
221
+ double [] values = testCaseStats .getValue ().getValues ();
222
+ if (values .length != execIterations ) {
223
+ System .err .printf (
224
+ "⚠️ %s: expected %d samples but got %d%n" , testCase , execIterations , values .length );
225
+ }
226
+ for (int i = 0 ; i < values .length ; i ++) {
227
+ long ns = (long ) values [i ]; // back to raw nanoseconds
228
+ // build the CSV line “case,iteration,ns”
229
+ csv .println (testCase + "," + i + "," + ns );
230
+ }
231
+ }
232
+ output .println (
233
+ "✔️ Wrote "
234
+ + timeStatsMap .size ()
235
+ + " cases × "
236
+ + execIterations
237
+ + " samples → "
238
+ + out .toAbsolutePath ());
239
+ } catch (IOException e ) {
240
+ throw new RuntimeException (e );
241
+ }
200
242
}
201
243
202
244
// compute mean ± error on derived‐gas and MGps (99.9% CI).
203
245
private void logResultsWithError (
204
246
final String testCase , final long gasCost , final DescriptiveStatistics timeStats ) {
205
247
precompileTableHeader .run ();
206
248
int n = (int ) timeStats .getN ();
207
- double meanTime = timeStats .getMean ();
249
+ double meanTime = timeStats .getMean () / 1e9 ;
208
250
// double sdTime = timeStats.getStandardDeviation();
209
251
// double seTime = sdTime / Math.sqrt(n);
210
252
@@ -218,7 +260,8 @@ private void logResultsWithError(
218
260
219
261
// 3) compute throughput per iteration (MGps) and its stats
220
262
DescriptiveStatistics tpStats = new DescriptiveStatistics (execIterations );
221
- for (double tSec : timeStats .getValues ()) {
263
+ for (double tNs : timeStats .getValues ()) {
264
+ double tSec = tNs / 1e9 ;
222
265
double mgps = gasCost / tSec / 1_000_000.0 ;
223
266
tpStats .addValue (mgps );
224
267
}
@@ -250,7 +293,7 @@ private void runPrecompileInvertedWarmup(
250
293
}
251
294
}
252
295
253
- Map <String , DescriptiveStatistics > timeStatsMap = new HashMap <>();
296
+ Map <String , DescriptiveStatistics > timeStatsMap = new LinkedHashMap <>();
254
297
// Also run all test cases in serial inside one iteration
255
298
// Map<String, Long> totalElapsedByTestName = new HashMap<>();
256
299
int executions = 0 ;
@@ -267,7 +310,7 @@ private void runPrecompileInvertedWarmup(
267
310
// add the time to the stats for this test case
268
311
timeStatsMap
269
312
.computeIfAbsent (testCase .getKey (), k -> new DescriptiveStatistics ())
270
- .addValue (iterationElapsed / 1e9 );
313
+ .addValue (( double ) iterationElapsed );
271
314
}
272
315
}
273
316
executions ++;
@@ -285,6 +328,36 @@ private void runPrecompileInvertedWarmup(
285
328
output .printf ("%s Input is Invalid%n" , testCase .getKey ());
286
329
}
287
330
}
331
+
332
+ // Also log csv output
333
+ // output.println("Test,Iteration,Time (ns)");
334
+ Path out = Paths .get ("benchmark_results_inverted.csv" );
335
+ try (PrintWriter csv =
336
+ new PrintWriter (Files .newBufferedWriter (out , StandardCharsets .UTF_8 ), true )) {
337
+ csv .println ("case,iteration,time (ns)" );
338
+ for (final Map .Entry <String , DescriptiveStatistics > testCaseStats : timeStatsMap .entrySet ()) {
339
+ String testCase = testCaseStats .getKey ();
340
+ double [] values = testCaseStats .getValue ().getValues ();
341
+ if (values .length != execIterations ) {
342
+ System .err .printf (
343
+ "⚠️ %s: expected %d samples but got %d%n" , testCase , execIterations , values .length );
344
+ }
345
+ for (int i = 0 ; i < values .length ; i ++) {
346
+ long ns = (long ) values [i ]; // back to raw nanoseconds
347
+ // build the CSV line “case,iteration,ns”
348
+ csv .println (testCase + "," + i + "," + ns );
349
+ }
350
+ }
351
+ output .println (
352
+ "✔️ Wrote "
353
+ + timeStatsMap .size ()
354
+ + " cases × "
355
+ + execIterations
356
+ + " samples → "
357
+ + out .toAbsolutePath ());
358
+ } catch (IOException e ) {
359
+ throw new RuntimeException (e );
360
+ }
288
361
}
289
362
290
363
/**
@@ -333,7 +406,7 @@ protected double runPrecompileBenchmark(
333
406
long iterationStart = System .nanoTime ();
334
407
final var result = contract .computePrecompile (arg , fakeFrame );
335
408
long iterationElapsed = System .nanoTime () - iterationStart ;
336
- timeStats .addValue (iterationElapsed / 1e9 );
409
+ timeStats .addValue (( double ) iterationElapsed );
337
410
338
411
totalElapsed += iterationElapsed ;
339
412
executions ++;
0 commit comments