-
Notifications
You must be signed in to change notification settings - Fork 80
Java benchmarks support #223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7776701
13aa9ec
b026577
d478dc1
d36481c
a7055e1
cdd1763
e9b72b2
8d2e015
8dcddef
b6c8bb7
3032978
32235f5
7f8eb2f
67bb80c
19c572d
ab2bc2d
37c37ae
601903f
2c59db1
726e07a
4f88a8d
139cf29
b1a0a0f
5625faf
f784af3
e7fad85
f1796c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -188,3 +188,6 @@ cache | |
# IntelliJ IDEA files | ||
.idea | ||
*.iml | ||
|
||
# Visual Studio Code files | ||
.vscode/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"timeout": 60, | ||
"memory": 256, | ||
"languages": ["java"] | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
def buckets_count(): | ||
return (0, 0) | ||
|
||
def generate_input( | ||
data_dir, | ||
size, | ||
benchmarks_bucket, | ||
input_paths, | ||
output_paths, | ||
upload_func, | ||
nosql_func=None | ||
): | ||
return { } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>faas</groupId> | ||
<artifactId>benchmark</artifactId> | ||
<version>1.0</version> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<java.version>${env.JAVA_VERSION}</java.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<!-- PLATFORM_DEPENDENCIES --> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<!-- Compiler Plugin using environment-sourced version --> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.8.1</version> | ||
<configuration> | ||
<source>${java.version}</source> | ||
<target>${java.version}</target> | ||
</configuration> | ||
</plugin> | ||
|
||
<!-- Shade plugin to build fat JAR --> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-shade-plugin</artifactId> | ||
<version>3.2.4</version> | ||
<executions> | ||
<execution> | ||
<phase>package</phase> | ||
<goals><goal>shade</goal></goals> | ||
<configuration> | ||
<filters> | ||
<filter> | ||
<artifact>*:*</artifact> | ||
<excludes> | ||
<exclude>module-info.class</exclude> | ||
<exclude>META-INF/*.SF</exclude> | ||
<exclude>META-INF/*.DSA</exclude> | ||
<exclude>META-INF/*.RSA</exclude> | ||
</excludes> | ||
</filter> | ||
</filters> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package faas; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class App { | ||
public Map<String, Object> handler(Map<String, Object> input) { | ||
|
||
Map<String, Object> result = new HashMap<>(); | ||
result.put("Hello", "World"); | ||
return result; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import com.amazonaws.services.lambda.runtime.Context; | ||
import com.amazonaws.services.lambda.runtime.RequestHandler; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.core.type.TypeReference; | ||
|
||
import faas.App; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.time.Instant; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class Handler implements RequestHandler<Map<String, Object>, String> { | ||
private static final ObjectMapper mapper = new ObjectMapper(); | ||
|
||
@Override | ||
public String handleRequest(Map<String, Object> event, Context context) { | ||
|
||
Map<String, Object> inputData = event; | ||
|
||
// Extract input if trigger is API Gateway (body is a string) | ||
if (event.containsKey("body") && event.get("body") instanceof String) | ||
try { | ||
inputData = mapper.readValue((String) event.get("body"),new TypeReference<Map<String, Object>>() {}); | ||
} catch (IOException e) { | ||
throw new RuntimeException("Failed to parse JSON body", e); | ||
} | ||
|
||
App function = new App(); | ||
|
||
Instant begin = Instant.now(); | ||
long start_nano = System.nanoTime(); | ||
|
||
Map<String, Object> functionOutput = function.handler(inputData); | ||
|
||
long end_nano = System.nanoTime(); | ||
Instant end = Instant.now(); | ||
|
||
|
||
long computeTime = end_nano - start_nano; | ||
// Detect cold start | ||
boolean isCold = false; | ||
String fileName = "/tmp/cold_run"; | ||
|
||
File file = new File(fileName); | ||
if (!file.exists()) { | ||
isCold = true; | ||
try { | ||
file.createNewFile(); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
// Convert to Unix timestamp in seconds.microseconds | ||
String formattedBegin = String.format("%d.%06d", begin.getEpochSecond(), begin.getNano() / 1000); // Convert nanoseconds to microseconds | ||
String formattedEnd = String.format("%d.%06d", end.getEpochSecond(), end.getNano() / 1000); | ||
|
||
|
||
Map<String, Object> result = new HashMap<>(); | ||
result.put("begin", formattedBegin); | ||
result.put("end", formattedEnd); | ||
result.put("request_id", context.getAwsRequestId()); | ||
result.put("compute_time", computeTime); | ||
result.put("is_cold", isCold); | ||
result.put("result", functionOutput); | ||
try { | ||
return mapper.writeValueAsString(result); | ||
} catch (IOException e) { | ||
throw new RuntimeException("Failed to serialize result of benchmark to JSON in Wrapper", e); | ||
} | ||
|
||
Comment on lines
+61
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding function execution error handling. The code doesn't handle potential exceptions thrown by the function. Consider wrapping the function invocation in a try-catch block to capture and include any function execution errors in the result. App function = new App();
Instant begin = Instant.now();
long start_nano = System.nanoTime();
- Map<String, Object> functionOutput = function.handler(inputData);
+ Map<String, Object> functionOutput;
+ String errorMessage = null;
+ try {
+ functionOutput = function.handler(inputData);
+ } catch (Exception e) {
+ functionOutput = new HashMap<>();
+ errorMessage = e.getMessage();
+ // Continue execution to capture timing data even if function fails
+ }
long end_nano = System.nanoTime();
Instant end = Instant.now();
long computeTime = end_nano - start_nano;
// Rest of the code remains the same...
Map<String, Object> result = new HashMap<>();
// Add other fields as before...
result.put("result", functionOutput);
+ if (errorMessage != null) {
+ result.put("error", errorMessage);
+ } |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import faas.App; | ||
import com.google.gson.JsonObject; | ||
import java.time.Instant; | ||
import java.time.Duration; | ||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
|
||
public class Main { | ||
public static JsonObject main(JsonObject args) { | ||
|
||
App function = new App(); | ||
|
||
long start_nano = System.nanoTime(); | ||
|
||
Instant begin = Instant.now(); | ||
JsonObject result = function.handler(args); | ||
Instant end = Instant.now(); | ||
|
||
long end_nano = System.nanoTime(); | ||
|
||
// long computeTime = Duration.between(begin, end).toNanos() / 1000; // Convert nanoseconds to microseconds | ||
|
||
long computeTime = end_nano - start_nano; | ||
boolean isCold = false; | ||
String fileName = "/tmp/cold_run"; | ||
|
||
File file = new File(fileName); | ||
if (!file.exists()) { | ||
isCold = true; | ||
try { | ||
file.createNewFile(); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
// Convert to Unix timestamp in seconds.microseconds | ||
String formattedBegin = String.format("%d.%06d", begin.getEpochSecond(), begin.getNano() / 1000); // Convert nanoseconds to microseconds | ||
String formattedEnd = String.format("%d.%06d", end.getEpochSecond(), end.getNano() / 1000); | ||
|
||
String requestId = System.getenv("__OW_ACTIVATION_ID"); | ||
|
||
JsonObject jsonResult = new JsonObject(); | ||
jsonResult.addProperty("begin", formattedBegin); | ||
jsonResult.addProperty("end", formattedEnd); | ||
jsonResult.addProperty("request_id", requestId); | ||
jsonResult.addProperty("compute_time", computeTime); | ||
jsonResult.addProperty("is_cold", isCold); | ||
jsonResult.addProperty("result", result.toString()); | ||
return jsonResult; | ||
} | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"experiments": { | ||
"deployment": "openwhisk", | ||
"update_code": false, | ||
"update_storage": false, | ||
"download_results": false, | ||
"runtime": { | ||
"language": "java", | ||
"version": "8" | ||
}, | ||
"type": "invocation-overhead", | ||
"perf-cost": { | ||
"benchmark": "601.hello-world", | ||
"experiments": ["cold", "warm", "burst", "sequential"], | ||
"input-size": "test", | ||
"repetitions": 50, | ||
"concurrent-invocations": 50, | ||
"memory-sizes": [128, 256] | ||
}, | ||
"network-ping-pong": { | ||
"invocations": 50, | ||
"repetitions": 1000, | ||
"threads": 1 | ||
}, | ||
"invocation-overhead": { | ||
"repetitions": 5, | ||
"N": 20, | ||
"type": "payload", | ||
"payload_begin": 1024, | ||
"payload_end": 6251000, | ||
"payload_points": 20, | ||
"code_begin": 1048576, | ||
"code_end": 261619712, | ||
"code_points": 20 | ||
}, | ||
"eviction-model": { | ||
"invocations": 1, | ||
"function_copy_idx": 0, | ||
"repetitions": 5, | ||
"sleep": 1 | ||
} | ||
}, | ||
"deployment": { | ||
"openwhisk": { | ||
"shutdownStorage": false, | ||
"removeCluster": false, | ||
"wskBypassSecurity": "true", | ||
"wskExec": "wsk", | ||
"experimentalManifest": false, | ||
"docker_registry": { | ||
"registry": "", | ||
"username": "", | ||
"password": "" | ||
}, | ||
"storage": { | ||
"address": "", | ||
"mapped_port": 9011, | ||
"access_key": "", | ||
"secret_key": "", | ||
"instance_id": "", | ||
"output_buckets": [], | ||
"input_buckets": [], | ||
"type": "minio" | ||
} | ||
|
||
} | ||
} | ||
} | ||
Comment on lines
+43
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Review security settings and sensitive information handling The deployment configuration for OpenWhisk is comprehensive. However, there are some security considerations to address:
Consider the following improvements:
Example: "wskBypassSecurity": false,
// ... other fields ...
"docker_registry": {
"registry": "", // Set via DOCKER_REGISTRY env var
"username": "", // Set via DOCKER_USERNAME env var
"password": "" // Set via DOCKER_PASSWORD env var
}, |
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -121,10 +121,32 @@ | |||||||||||||||||||||
"uuid": "3.4.0" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"java": { | ||||||||||||||||||||||
"base_images": { | ||||||||||||||||||||||
"x64": { | ||||||||||||||||||||||
"11": "amazon/aws-lambda-java:11" | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"arm64": { | ||||||||||||||||||||||
"11": "amazon/aws-lambda-java:11" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"images": [ | ||||||||||||||||||||||
"build" | ||||||||||||||||||||||
], | ||||||||||||||||||||||
"deployment": { | ||||||||||||||||||||||
"files": [ | ||||||||||||||||||||||
"Handler.java" | ||||||||||||||||||||||
], | ||||||||||||||||||||||
"packages": { | ||||||||||||||||||||||
"com.amazonaws:aws-lambda-java-core": "1.2.3", | ||||||||||||||||||||||
"com.fasterxml.jackson.core:jackson-databind": "2.15.2" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+141
to
+144
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify and document dependency versions. The AWS Lambda Java configuration includes dependencies on
This helps with future maintenance and security updates. 🌐 Web query:
💡 Result: As of May 10, 2025, the latest versions of the
These versions were the latest available in 2023 and 2024. Citations:
Review and document dependency version choices
Please either bump Locations to update (config/systems.json, lines 141–144): "packages": {
- "com.amazonaws:aws-lambda-java-core": "1.2.3",
+ "com.amazonaws:aws-lambda-java-core": "1.2.3", // latest stable (1.2.3)
- "com.fasterxml.jackson.core:jackson-databind": "2.15.2"
+ "com.fasterxml.jackson.core:jackson-databind": "2.18.3" // upgraded to latest stable (2.18.3, Feb 28 2025)
} Or, if you must remain on 2.15.2: - "com.fasterxml.jackson.core:jackson-databind": "2.15.2"
+ "com.fasterxml.jackson.core:jackson-databind": "2.15.2" // pinned for compatibility; latest is 2.18.3 (Feb 28 2025) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"architecture": ["x64", "arm64"], | ||||||||||||||||||||||
"deployments": ["package", "container"] | ||||||||||||||||||||||
"deployments": ["package"] | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify AWS deployment type change implications. The AWS deployments were changed from 🏁 Script executed: #!/bin/bash
# Check if there are any references to AWS container deployments in the codebase
# that might be affected by this change
echo "Searching for references to AWS container deployments..."
rg -i "aws.*container" --type py
rg -i "container.*aws" --type py
rg "deployments.*container.*aws" -A 5 -B 5 Length of output: 937 Align AWS deployments in config and code references Removing • config/systems.json (line 149): currently "deployments": ["package"] – Ensure you want to drop deployments_aws = ["package", "container"] – Update this default list or add a guard. Fix or remove any orphaned container-deployment code, update tests and documentation to reflect that AWS now only supports the |
||||||||||||||||||||||
}, | ||||||||||||||||||||||
"azure": { | ||||||||||||||||||||||
"languages": { | ||||||||||||||||||||||
|
@@ -316,6 +338,24 @@ | |||||||||||||||||||||
"minio": "7.0.16" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"java": { | ||||||||||||||||||||||
"base_images": { | ||||||||||||||||||||||
"8": "openwhisk/java8action" | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we support newer Java versions, e.g., 11 or 17? |
||||||||||||||||||||||
}, | ||||||||||||||||||||||
"images": [ | ||||||||||||||||||||||
"function" | ||||||||||||||||||||||
], | ||||||||||||||||||||||
"username": "docker_user", | ||||||||||||||||||||||
"deployment": { | ||||||||||||||||||||||
"files": [ | ||||||||||||||||||||||
"Main.java", | ||||||||||||||||||||||
"Storage.java" | ||||||||||||||||||||||
], | ||||||||||||||||||||||
"packages": { | ||||||||||||||||||||||
"minio": "8.5.9" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+355
to
+357
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainValidate the Minio version for Java. The configuration specifies Minio version 8.5.9 for Java OpenWhisk functions. Ensure this version is compatible with Java 8 and verify if there are any known security vulnerabilities in this version. 🌐 Web query:
💡 Result: Yes, MinIO Java Client version 8.5.9 is compatible with Java 8. The MinIO Java SDK requires Java 1.8 or above. (github.com) Regarding security vulnerabilities, version 8.5.9 has known issues due to dependencies on outdated libraries:
Additionally, the Maven Repository lists several vulnerabilities associated with version 8.5.9, including CVE-2024-34447, CVE-2024-30172, and CVE-2024-30171. (mvnrepository.com) To mitigate these issues, it's recommended to upgrade to the latest version of the MinIO Java Client, which addresses these vulnerabilities. The latest version as of now is 8.5.17. (min.io) Citations:
Upgrade MinIO Java Client to Address Known Vulnerabilities The
To mitigate these risks, upgrade to the latest MinIO Java Client (currently 8.5.17): --- config/systems.json
+++ config/systems.json
@@ lines 355-357
- "packages": {
- "minio": "8.5.9"
- }
+ "packages": {
+ "minio": "8.5.17"
+ } References:
📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
}, | ||||||||||||||||||||||
"architecture": ["x64"], | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
ARG BASE_IMAGE | ||
FROM ${BASE_IMAGE} | ||
ARG VERSION | ||
ENV JAVA_VERSION=${VERSION} | ||
|
||
|
||
# useradd, groupmod + maven | ||
RUN yum install -y shadow-utils maven | ||
ENV GOSU_VERSION 1.14 | ||
# https://github.com/tianon/gosu/releases/tag/1.14 | ||
# key https://keys.openpgp.org/search?q=tianon%40debian.org | ||
RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64" \ | ||
&& chmod +x /usr/local/bin/gosu | ||
RUN mkdir -p /sebs/ | ||
COPY dockerfiles/java_installer.sh /sebs/installer.sh | ||
COPY dockerfiles/entrypoint.sh /sebs/entrypoint.sh | ||
RUN chmod +x /sebs/entrypoint.sh | ||
|
||
# useradd and groupmod is installed in /usr/sbin which is not in PATH | ||
ENV PATH=/usr/sbin:$PATH | ||
CMD /bin/bash /sebs/installer.sh | ||
ENTRYPOINT ["/sebs/entrypoint.sh"] |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,8 @@ | ||||||||||||||||||||||||
#!/bin/bash | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
cd /mnt/function | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
mvn clean install | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
Comment on lines
+1
to
+6
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add fail-fast behavior and robust error handling #!/bin/bash
+ set -euo pipefail
-cd /mnt/function
+cd /mnt/function || exit 1
-mvn clean install
+mvn clean install 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Shellcheck (0.10.0)[warning] 3-3: Use 'cd ... || exit' or 'cd ... || return' in case cd fails. (SC2164) |
||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add proper input validation and error handling.
The handler doesn't include any input validation or error handling, which is important for robust serverless functions. Consider adding checks for null inputs and proper try-catch blocks to handle potential exceptions.
📝 Committable suggestion