HTTP Benchmark Details
Overview
Run the following command to create the Java version of the example benchmark program:
-
jbang tulip-cli@wfouche init Java
This command creates various files and directories:
├── benchmark_config.json ├── io │ └── tulip │ ├── App.java │ └── HttpUser.java ├── run_bench.cmd └── run_bench.sh |
Source Code
App.java
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.github.wfouche.tulip:tulip-runtime:2.1.5
//DEPS org.springframework.boot:spring-boot-starter-web:3.4.2
//DEPS org.slf4j:slf4j-api:2.0.16
//DEPS ch.qos.logback:logback-core:1.5.16
//DEPS ch.qos.logback:logback-classic:1.5.16
//SOURCES HttpUser.java
//JAVA 21
package io.tulip;
import io.github.wfouche.tulip.api.TulipApi;
public class App {
public static void main(String[] args) {
TulipApi.runTulip("benchmark_config.json");
}
}
Configuration Data
{
"actions": {
"description": "Spring RestClient Benchmark [Java]",
"output_filename": "benchmark_output.json",
"report_filename": "benchmark_report.html",
"user_class": "io.tulip.HttpUser",
"user_params": {
"protocol": "http",
"host": "jsonplaceholder.typicode.com",
"connectTimeoutMillis": 500,
"readTimeoutMillis": 2000,
"debug": true
},
"user_actions": {
"1": "GET:posts",
"2": "GET:comments",
"3": "GET:todos"
}
},
"workflows": {
"api-user": {
"-": {
"1": 0.40,
"3": 0.60
},
"1": {
"2": 1.0
},
"2": {
"-": 1.0
},
"3": {
"-": 1.0
}
}
},
"benchmarks": {
"onStart": {
"save_stats": false,
"scenario_actions": [ {"id": 0} ]
},
"REST1": {
"enabled": true,
"aps_rate": 10.0,
"scenario_actions": [
{
"id": 1
}
],
"time": {
"pre_warmup_duration": 30,
"warmup_duration": 10,
"benchmark_duration": 30,
"benchmark_iterations": 3
}
},
"REST2": {
"enabled": true,
"aps_rate": 10.0,
"scenario_actions": [
{
"id": 1, "weight": 10
},
{
"id": 2, "weight": 40
},
{
"id": 3, "weight": 50
}
],
"time": {
"pre_warmup_duration": 30,
"warmup_duration": 10,
"benchmark_duration": 30,
"benchmark_iterations": 3
}
},
"REST3": {
"enabled": true,
"aps_rate": 10.0,
"scenario_workflow": "api-user",
"time": {
"pre_warmup_duration": 30,
"warmup_duration": 10,
"benchmark_duration": 30,
"benchmark_iterations": 3
}
},
"REST3.max": {
"enabled": true,
"aps_rate": 0.0,
"scenario_workflow": "api-user",
"time": {
"pre_warmup_duration": 30,
"warmup_duration": 10,
"benchmark_duration": 30,
"benchmark_iterations": 3
}
},
"onStop": {
"save_stats": false,
"scenario_actions": [ {"id": 100} ]
}
},
"contexts": {
"Context-1": {
"enabled": true,
"num_users": 128,
"num_threads": 8
}
}
}
HttpUser.java
package io.tulip;
import io.github.wfouche.tulip.api.*;
import java.util.concurrent.ThreadLocalRandom;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpUser extends TulipUser {
public HttpUser(int userId, int threadId) {
super(userId, threadId);
}
public boolean onStart() {
// Initialize the shared RestClient object only once
if (getUserId() == 0) {
logger.info("Java");
logger.info("Initializing static data");
var connectTimeout = Integer.valueOf(
getUserParamValue("connectTimeoutMillis"));
var readTimeout = Integer.valueOf(
getUserParamValue("readTimeoutMillis"));
var factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(readTimeout);
var url = getUserParamValue("protocol")
+ "://" + getUserParamValue("host");
restClient = RestClient.builder()
.requestFactory(factory)
.baseUrl(url)
.build();
debug = Boolean.valueOf(getUserParamValue("debug"));
logger.info("debug = " + debug);
if (debug) {
logger.info(url);
}
}
return true;
}
// Action 1: GET /posts/{id}
public boolean action1() {
int id = ThreadLocalRandom.current().nextInt(100)+1;
return serviceCall("/posts/{id}", id);
}
// Action 2: GET /comments/{id}
public boolean action2() {
int id = ThreadLocalRandom.current().nextInt(500)+1;
return serviceCall("/comments/{id}", id);
}
// Action 3: GET /todos/{id}
public boolean action3() {
int id = ThreadLocalRandom.current().nextInt(200)+1;
return serviceCall("/todos/{id}", id);
}
public boolean onStop() {
return true;
}
private boolean serviceCall(String uri, int id) {
boolean rc;
try {
String rsp = restClient.get()
.uri(uri, id)
.retrieve()
.body(String.class);
rc = (rsp != null && rsp.length() > 2);
} catch (RestClientException e) {
rc = false;
}
return rc;
}
// RestClient object
private static RestClient restClient;
// Debug flag
private static boolean debug = false;
// Logger
private static final Logger logger = LoggerFactory.getLogger(HttpUser.class);
}
Benchmark Scripts
#!/bin/bash
rm -f benchmark_report.html
export JBANG_JAVA_OPTIONS="-server -Xms2g -Xmx2g -XX:+UseZGC -XX:+ZGenerational"
jbang run io/tulip/App.java (1)
echo ""
#w3m -dump -cols 205 benchmark_report.html
lynx -dump -width 205 benchmark_report.html
#jbang run asciidoc@wfouche benchmark_config.adoc
#jbang export fatjar io/tulip/App.java
1 | Command that starts the benchmark |
if exist benchmark_report.html del benchmark_report.html
set JBANG_JAVA_OPTIONS=-server -Xms2g -Xmx2g -XX:+UseZGC -XX:+ZGenerational
call jbang run io\tulip\App.java (1)
@echo off
echo.
REM w3m.exe -dump -cols 205 benchmark_report.html
REM lynx.exe -dump -width 205 benchmark_report.html
start benchmark_report.html
REM jbang run asciidoc@wfouche benchmark_config.adoc
REM start benchmark_config.html
REM jbang export fatjar io\tulip\App.java
1 | Command that starts the benchmark |
Configuration Report
- Description
-
Spring RestClient Benchmark [Java]
- Filename
-
benchmark_config.json
Actions
id | value | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
description |
Spring RestClient Benchmark [Java] |
||||||||||||
output_filename |
benchmark_output.json |
||||||||||||
report_filename |
benchmark_report.html |
||||||||||||
user_class |
io.tulip.HttpUser |
||||||||||||
user_params |
|
||||||||||||
user_actions |
|
Benchmarks
REST1
id | value | ||||||||
---|---|---|---|---|---|---|---|---|---|
enabled |
True |
||||||||
aps_rate |
10.0 |
||||||||
worker_thread_queue_size |
0 |
||||||||
scenario_actions |
|
||||||||
time |
|
REST2
id | value | ||||||||
---|---|---|---|---|---|---|---|---|---|
enabled |
True |
||||||||
aps_rate |
10.0 |
||||||||
worker_thread_queue_size |
0 |
||||||||
scenario_actions |
|
||||||||
time |
|
REST3
id | value | ||||||||
---|---|---|---|---|---|---|---|---|---|
enabled |
True |
||||||||
aps_rate |
10.0 |
||||||||
worker_thread_queue_size |
0 |
||||||||
scenario_workflow |
|||||||||
time |
|