Skip to content

Conversation

@edeandrea
Copy link
Collaborator

Publishing all the scripts & documentation to run official benchmarks.

@edeandrea edeandrea marked this pull request as ready for review October 17, 2025 21:10
@edeandrea
Copy link
Collaborator Author

@holly-cummins @franz1981 @willr3 would you all mind reviewing?

I still need to add documentation

@franz1981
Copy link

@Sanne can you check if we are happy already with postgres as it is configured?

For local and remote it doesn't bound the CPU set nor the mount of full cores to use whilst would be a good idea to have both I think.
Additionally, depending on what we want to measure maybe we are not interested in fsync each transaction (although the default hammered endpoint here is just a query on immutable data ;))

@franz1981
Copy link

franz1981 commented Oct 20, 2025

By running

$ ./run-benchmarks.sh  -q 3.28.4 -s 3.5.6

I got:

[jbang] Resolving dependencies...
[jbang]    io.hyperfoil.tools:qDup:0.10.6
[jbang] Dependencies resolved
05:48:29.541 Running qDup version 0.10.6 
05:48:30.817 output path = /tmp//20251020_054829                                                                                                                                                                                      
05:48:30.817 stream logging enabled                                                                                                                                                                                                   
05:48:30.853 json server listening at fedora.fritz.box:31337                                                                                                                                                                          
05:48:30.887 test-runner-setup@target-host. failed to start shell process: java.io.IOException: Cannot run program "script" (in directory "/home/forked_franz"): error=2, No such file or directory                                   
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)                                                                                                                                                         
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)                                                                                                                                                         
        at io.hyperfoil.tools.qdup.shell.LocalShell.connectShell(LocalShell.java:66)                                                                                                                                                  
        at io.hyperfoil.tools.qdup.shell.AbstractShell.connect(AbstractShell.java:240)                                                                                                                                                
        at io.hyperfoil.tools.qdup.shell.AbstractShell.getShell(AbstractShell.java:127)                                                                                                                                               
        at io.hyperfoil.tools.qdup.Run.lambda$queueSetupScripts$17(Run.java:755)                                                                                                                                                      
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)                                                                                                                                                         
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)                                                                                                                                  
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)                                                                                                                                  
        at java.base/java.lang.Thread.run(Thread.java:1583)                                                                                                                                                                           
Caused by: java.io.IOException: error=2, No such file or directory                                                                                                                                                                    
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)                                                                                                                                                                 
        at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)                                                                                                                                                               
        at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)                                                                                                                                                                
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)                                                                                                                                                         
        ... 9 more                                                                                                                                                                                                                    
                                                                                                                                                                                                                                      
05:48:30.887 test-cgroups-setup@target-host. failed to start shell process: java.io.IOException: Cannot run program "script" (in directory "/home/forked_franz"): error=2, No such file or directory                                  
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)                                                                                                                                                         
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)                                                                                                                                                         
        at io.hyperfoil.tools.qdup.shell.LocalShell.connectShell(LocalShell.java:66)                                                                                                                                                  
        at io.hyperfoil.tools.qdup.shell.AbstractShell.connect(AbstractShell.java:240)                                                                                                                                                
        at io.hyperfoil.tools.qdup.shell.AbstractShell.getShell(AbstractShell.java:127)                                                                                                                                               
        at io.hyperfoil.tools.qdup.Run.lambda$queueSetupScripts$17(Run.java:755)                                                                                                                                                      
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)                                                                                                                                                         
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)                                                                                                                                  
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)                                                                                                                                  
        at java.base/java.lang.Thread.run(Thread.java:1583)                                                                                                                                                                           
Caused by: java.io.IOException: error=2, No such file or directory                                                                                                                                                                    
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)                                                                                                                                                                 
        at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)                                                                                                                                                               
        at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)                                                                                                                                                                
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)                                                                                                                                                         
        ... 9 more                                                                                                                                                                                                                    
                                                                                                                                                                                                                                      
05:48:30.888 test-runner-setup@target-host. failed to connect to target-host LOCAL                                                                                                                                                    
05:48:30.888 test-cgroups-setup@target-host. failed to connect to target-host LOCAL                                                                                                                                                   
05:48:30.888 setup failed to connect LOCAL                                                                                                                                                                                            
05:48:30.888 setup failed to connect LOCAL                                                                                                                                                                                            
05:48:30,888 [ :- @  ] failed to connect all ssh sessions for setup                                                                                                                                                                   
05:48:30.889 Skipping cleanup - Abort has been defined to not run any cleanup scripts                                                                                                                                                 
Finished in 00.015 at /tmp//20251020_054829                                                                                                                                                                                           
05:48:30.895 ignoring stop call when already stopped

config.repo.branch: main
config.repo.url: https://github.com/quarkusio/spring-quarkus-perf-comparison.git

RUN.WRK_BIN: jbang wrk@hyperfoil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what is reported by wrk while extracting manually the report:

wrk.html

Some notes:

  1. calibration phase duration is hardcoded in the command (which is not great)
  2. the report is pretty boring per se: latencies are useless (due to coordinated omission) and, as expected, throughput is stable

Which makes the report per se not as interesting as I was hoping (due to the simplicity of the workload...)
In short: I don't think we need to extract the report if we want to keep this test as simple as this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edeandrea PTAL

@franz1981
Copy link

franz1981 commented Oct 20, 2025

One additional note re #15 (comment)

I was interested into getting (not now, but in a future), the time to peak throughput metric.
This can be obtained by observing when the throughput stabilize which can be computed from all.json latencies in /tmp/hyperfoil/run/0000:

all.json

image

by:

  • computing the throughput per each serie as responseCount / (endTime - startTime)
  • checking when it doesn't change (sampled variance is low)
  • find the first serie startTime when it happens

To be fair this is gross (it relies on a sampled throughput w 1 second granularity, which is not so wow) and imprecise, but is easy and give a rough idea of the time required to stabilize.

The downside re wrk: the method described above is not complete as wrk run a pre calibration phase too w arbitrary length, and is not correct to ignore it, which means that the previous computation should include the calibration series too.

Probability the best way (for Hotspot at least) to extract the mentioned metric is to perform a run with JFR events re compilation on (see https://sap.github.io/SapMachine/jfrevents/21#compilation) and consider the server in steady state only when there are none (excluding the server's stop which will likely cause deoptimizations and new compilation due to the newly taken branches).

@franz1981
Copy link

@edeandrea re #15 (comment) I've commented at Hyperfoil/qDup#250

@edeandrea
Copy link
Collaborator Author

edeandrea commented Oct 20, 2025

By running

$ ./run-benchmarks.sh  -q 3.28.4 -s 3.5.6

I got:

[jbang] Resolving dependencies...
[jbang]    io.hyperfoil.tools:qDup:0.10.6
[jbang] Dependencies resolved
05:48:29.541 Running qDup version 0.10.6 
05:48:30.817 output path = /tmp//20251020_054829                                                                                                                                                                                      
05:48:30.817 stream logging enabled                                                                                                                                                                                                   
05:48:30.853 json server listening at fedora.fritz.box:31337                                                                                                                                                                          
05:48:30.887 test-runner-setup@target-host. failed to start shell process: java.io.IOException: Cannot run program "script" (in directory "/home/forked_franz"): error=2, No such file or directory                                   
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)                                                                                                                                                         
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)                                                                                                                                                         
        at io.hyperfoil.tools.qdup.shell.LocalShell.connectShell(LocalShell.java:66)                                                                                                                                                  
        at io.hyperfoil.tools.qdup.shell.AbstractShell.connect(AbstractShell.java:240)                                                                                                                                                
        at io.hyperfoil.tools.qdup.shell.AbstractShell.getShell(AbstractShell.java:127)                                                                                                                                               
        at io.hyperfoil.tools.qdup.Run.lambda$queueSetupScripts$17(Run.java:755)                                                                                                                                                      
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)                                                                                                                                                         
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)                                                                                                                                  
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)                                                                                                                                  
        at java.base/java.lang.Thread.run(Thread.java:1583)                                                                                                                                                                           
Caused by: java.io.IOException: error=2, No such file or directory                                                                                                                                                                    
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)                                                                                                                                                                 
        at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)                                                                                                                                                               
        at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)                                                                                                                                                                
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)                                                                                                                                                         
        ... 9 more                                                                                                                                                                                                                    
                                                                                                                                                                                                                                      
05:48:30.887 test-cgroups-setup@target-host. failed to start shell process: java.io.IOException: Cannot run program "script" (in directory "/home/forked_franz"): error=2, No such file or directory                                  
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)                                                                                                                                                         
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)                                                                                                                                                         
        at io.hyperfoil.tools.qdup.shell.LocalShell.connectShell(LocalShell.java:66)                                                                                                                                                  
        at io.hyperfoil.tools.qdup.shell.AbstractShell.connect(AbstractShell.java:240)                                                                                                                                                
        at io.hyperfoil.tools.qdup.shell.AbstractShell.getShell(AbstractShell.java:127)                                                                                                                                               
        at io.hyperfoil.tools.qdup.Run.lambda$queueSetupScripts$17(Run.java:755)                                                                                                                                                      
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)                                                                                                                                                         
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)                                                                                                                                  
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)                                                                                                                                  
        at java.base/java.lang.Thread.run(Thread.java:1583)                                                                                                                                                                           
Caused by: java.io.IOException: error=2, No such file or directory                                                                                                                                                                    
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)                                                                                                                                                                 
        at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)                                                                                                                                                               
        at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)                                                                                                                                                                
        at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)                                                                                                                                                         
        ... 9 more                                                                                                                                                                                                                    
                                                                                                                                                                                                                                      
05:48:30.888 test-runner-setup@target-host. failed to connect to target-host LOCAL                                                                                                                                                    
05:48:30.888 test-cgroups-setup@target-host. failed to connect to target-host LOCAL                                                                                                                                                   
05:48:30.888 setup failed to connect LOCAL                                                                                                                                                                                            
05:48:30.888 setup failed to connect LOCAL                                                                                                                                                                                            
05:48:30,888 [ :- @  ] failed to connect all ssh sessions for setup                                                                                                                                                                   
05:48:30.889 Skipping cleanup - Abort has been defined to not run any cleanup scripts                                                                                                                                                 
Finished in 00.015 at /tmp//20251020_054829                                                                                                                                                                                           
05:48:30.895 ignoring stop call when already stopped

Works on my machine :D (although I'm not using LOCAL - i'm ssh'ing to another machine.

@franz1981
Copy link

@edeandrea what happen if you run it locally?

@edeandrea
Copy link
Collaborator Author

@edeandrea what happen if you run it locally?

I haven't tried yet because I'm on a mac....I'm focusing on remote linux first, since thats the use case for running in the perf lab.

@edeandrea
Copy link
Collaborator Author

@Sanne can you check if we are happy already with postgres as it is configured?

For local and remote it doesn't bound the CPU set nor the mount of full cores to use whilst would be a good idea to have both I think. Additionally, depending on what we want to measure maybe we are not interested in fsync each transaction (although the default hammered endpoint here is just a query on immutable data ;))

Just as a note - this is exactly what the benchmark was doing in the lab before we started any of this (well, different app, but read-only on immutable data).

If it makes sense to change the benchmark to something else, then lets investigate what we'd like to do.

- set-state: PROFILER_JVM_ARGS -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints

ensure-gh-cli-linux:
- script: sudo
Copy link

@franz1981 franz1981 Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A sudo script requires users to interact via a prompt.
Indeed, locally I got a

05:34:22,742 [ test-runner:setup-725 @ target-host ] ensure-gh-cli-linux                                                                                                                                                              
05:39:22,845 [ test-runner:setup-725 @ target-host ] [sudo] password for forked_franz:                                                                                                                                                
05:39:22,845 [ test-runner:setup-725 @ target-host ] sudo: timed out reading password                                                                                                                                                 
05:39:24,590 [ test-runner:setup-725 @ target-host ] sudo: a password is required     

which make it unable to be installed.
On the server maybe we can, but still...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A requirement is that you have to have passwordless sudo privs set up on the host machine. Kinda sucks, but it is what it is (I don't know another way around it).

@edeandrea
Copy link
Collaborator Author

@franz1981 / @holly-cummins

i'm starting to feel like there are lots (of valid) comments on the PR. I'm also not a benchmarking expert, so there are probably specific things with regard to wrk that I may not be 100% accurate here.

Would it make more sense to merge this PR and then add specific & targeted issues to fix things up?

WDYT?

@edeandrea edeandrea changed the title [WIP] Publish scripts to run benchmarks Publish scripts to run benchmarks Oct 22, 2025
@edeandrea
Copy link
Collaborator Author

@franz1981 / @holly-cummins

i'm starting to feel like there are lots (of valid) comments on the PR. I'm also not a benchmarking expert, so there are probably specific things with regard to wrk that I may not be 100% accurate here.

Would it make more sense to merge this PR and then add specific & targeted issues to fix things up?

WDYT?

Unless either of you have any objections, I'm going to merge this.

@holly-cummins
Copy link
Collaborator

Sorry, this review request got sent into spam. (Thanks, email provider.)

But I'm +1 to merge-and-iterate.

holly-cummins
holly-cummins previously approved these changes Oct 23, 2025
@holly-cummins
Copy link
Collaborator

I think the 'benchmarks' folder name could make the purpose clearer (since there are benchmark-y scripts in the top level, too. But that's something we can iterate. I guess we'll need to update the perf-lab when we do, so it's not super-trivial.

@edeandrea
Copy link
Collaborator Author

I think the 'benchmarks' folder name could make the purpose clearer (since there are benchmark-y scripts in the top level, too. But that's something we can iterate. I guess we'll need to update the perf-lab when we do, so it's not super-trivial.

Let's solve the naming thing now, as the perf lab changes haven't yet been implemented. Maybe scripts/benchmarks to keep everything co-located?

Or scripts/acceptable to go along with your naming convention in the README?

Or scripts/perf-lab?

@holly-cummins
Copy link
Collaborator

holly-cummins commented Oct 23, 2025

I think the 'benchmarks' folder name could make the purpose clearer (since there are benchmark-y scripts in the top level, too. But that's something we can iterate. I guess we'll need to update the perf-lab when we do, so it's not super-trivial.

Let's solve the naming thing now, as the perf lab changes haven't yet been implemented.

Ah, in that case, yes, let's figure it out.

Maybe scripts/benchmarks to keep everything co-located?

I think putting it into scripts is probably logic, since all the new stuff is a script.

Or scripts/acceptable to go along with your naming convention in the README?
Or scripts/perf-lab?

I think 'acceptable' might make sense only to me. :)
'perf-lab' was my first thought but I guess if these scripts can be run on a local machine, it doesn't quite fit.

But actually maybe it still does, because the idea is you're running the perf lab scripts locally.

Let me make sure I understand the layout. There's three modes of running, right? "Quick and dirty", "you want to do it right but only have a laptop", and "you have access to a perf lab (basically, you're John O'Hara in disguise)". Q&D lives in the top-level in scripts, with instructions in the main readme. YWTDIR (you want to do it right) and YAJOH (you are John O'Hara) share all common scripts? But YWTDIR needs extra instructions in a readme to explain all of what's going on, because you're not John O'Hara, and YAJOH is triggered from elsewhere, using the scripts source-controlled here?

If that's right, I think I vote for

scripts and scripts/perf-lab, and then if you run the scripts/perf-lab scripts you have the smug satisfaction that you're running the proper scripts.

@holly-cummins
Copy link
Collaborator

Based on all that, maybe we should move Q&D into its own subdirectory under scripts?

That would be tidier, but it means the getting started experience is worse. So tradeoffs.

Having to type scripts/<everything> is slightly tedious, a further level of nesting would be extra-annoying.

@holly-cummins
Copy link
Collaborator

Let me make sure I understand the layout. There's three modes of running, right? "Quick and dirty", "you want to do it right but only have a laptop", and "you have access to a perf lab (basically, you're John O'Hara in disguise)".
Q&D lives in the top-level in scripts, with instructions in the main readme.

correct

YWTDIR (you want to do it right) and YAJOH (you are John O'Hara) share all common scripts? But YWTDIR needs extra instructions in a readme to explain all of what's going on, because you're not John O'Hara

There isn't anything shared between Q&D and YWTDIR/YAJOH.

Sorry, that's what I was trying to say. I know Q&D is distinct. So If it was a Venn diagram, Q&D would be one circle and the YWTDIR and YAJOH circles would overlap completely.

@edeandrea
Copy link
Collaborator Author

Ok so just to complete this thought, we want to move everything in /benchmarks to /scripts/perf-lab?

@holly-cummins
Copy link
Collaborator

Ok so just to complete this thought, we want to move everything in /benchmarks to /scripts/perf-lab?

Yes, I think so :)

@franz1981
Copy link

we want to move everything in /benchmarks to /scripts/perf-lab?

👍

@edeandrea edeandrea merged commit 4014528 into quarkusio:main Oct 24, 2025
1 check passed
@edeandrea edeandrea deleted the open-benchmarks branch October 24, 2025 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants