Skip to content

Commit

Permalink
WIP run using Graal Node.js
Browse files Browse the repository at this point in the history
  • Loading branch information
guilgaly committed Oct 3, 2024
1 parent c3bc9d6 commit 87bf63a
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 237 deletions.
12 changes: 9 additions & 3 deletions js/cli/src/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ export const bundle = async (options: BundleOptions): Promise<void> => {
- bundleFile: ${options.bundleFile}
- typescript: ${options.typescript}`);

const contents = options.simulations.map((s) => `export { default as "${s.name}" } from "./${s.path}";`).join("\n");
const contents = `
${options.simulations.map((s, i) => `import simulation_${i} from "./${s.path}";`).join("\n")}
export const gatling = {
${options.simulations.map((s, i) => `"${s.name}": simulation_${i}`).join(",\n")}
};
`;

const plugins = options.typescript ? [esbuildPluginTsc({ force: true })] : [];
await esbuild.build({
Expand All @@ -29,8 +35,8 @@ export const bundle = async (options: BundleOptions): Promise<void> => {
bundle: true,
minify: false,
sourcemap: true,
format: "iife",
globalName: "gatling",
platform: "node",
format: "cjs",
plugins
});
};
53 changes: 25 additions & 28 deletions js/cli/src/dependencies/graalVm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { versions } from "./versions";

export const installGraalVm = async (gatlingHomeDir: string, downloadDir: string): Promise<string> => {
const { os, arch, extension, homePath, binPath } = graalVmPlatformParams();
const graalvmRootPath = `${gatlingHomeDir}/graalvm/${versions.graalvm.jdk}`;
const graalvmRootPath = `${gatlingHomeDir}/graalnodejs/${versions.graalvm.js}`;
const graalvmHomePath = `${graalvmRootPath}${homePath}`;
const graalvmJavaPath = `${graalvmHomePath}${binPath}`;

if (!existsSync(graalvmJavaPath)) {
const url = `https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${versions.graalvm.jdk}/graalvm-community-jdk-${versions.graalvm.jdk}_${os}-${arch}_bin.${extension}`;
const downloadPath = `${downloadDir}/graalvm.${extension}`;
const url = `https://github.com/oracle/graaljs/releases/download/graal-${versions.graalvm.js}/graalnodejs-community-jvm-${versions.graalvm.js}-${os}-${arch}.${extension}`;
const downloadPath = `${downloadDir}/graalnodejs.${extension}`;

if (existsSync(graalvmRootPath)) {
await fs.rm(graalvmRootPath, { recursive: true });
Expand All @@ -25,10 +25,10 @@ export const installGraalVm = async (gatlingHomeDir: string, downloadDir: string
}
await fs.mkdir(graalvmRootPath, { recursive: true });

logger.info(`Downloading GraalVM Community Edition ${versions.graalvm.jdk} to ${downloadPath}`);
logger.info(`Downloading GraalNodeJs Community Edition ${versions.graalvm.jdk} to ${downloadPath}`);
await downloadFile(url, downloadPath);

logger.info(`Unpacking GraalVM to ${graalvmRootPath}`);
logger.info(`Unpacking GraalNodeJs Community Edition to ${graalvmRootPath}`);
await decompress(downloadPath, graalvmRootPath, {
map: (file) => {
// Remove first level of file name, because it already contains a root directory
Expand All @@ -39,36 +39,33 @@ export const installGraalVm = async (gatlingHomeDir: string, downloadDir: string

await fs.rm(downloadPath);
} else {
logger.info(`GraalVM Community Edition ${versions.graalvm.jdk} already installed at ${graalvmRootPath}`);
logger.info(`GraalNodeJs Community Edition ${versions.graalvm.jdk} already installed at ${graalvmRootPath}`);
}

return graalvmHomePath;
};

const graalVmPlatformParams = () => {
if (osType === "Linux") {
const os = "linux";
const extension = "tar.gz";
const homePath = "";
const binPath = "/bin/java";
if (osArch === "x64") {
return { os, arch: "x64", extension, homePath, binPath };
} else if (osArch === "arm64") {
return { os, arch: "aarch64", extension, homePath, binPath };
}
} else if (osType === "Darwin") {
const os = "macos";
const extension = "tar.gz";
const homePath = "/Contents/Home";
const binPath = "/bin/java";
if (osArch === "x64") {
return { os, arch: "x64", extension, homePath, binPath };
} else if (osArch === "arm64") {
return { os, arch: "aarch64", extension, homePath, binPath };
}
const homePath = "";
const binPath = "/bin/node";

let osAndArch: [string, string] | undefined = undefined;
let extension = "tar.gz";
if (osType === "Linux" && osArch === "x64") {
osAndArch = ["linux", "amd64"];
} else if (osType === "Linux" && osArch === "arm64") {
osAndArch = ["linux", "aarch64"];
} else if (osType === "Darwin" && osArch === "x64") {
osAndArch = ["macos", "amd64"];
} else if (osType === "Darwin" && osArch === "arm64") {
osAndArch = ["macos", "aarch64"];
} else if (osType === "Windows_NT" && osArch === "x64") {
return { os: "windows", arch: "x64", extension: "zip", homePath: "", binPath: "/bin/java.exe" };
osAndArch = ["windows", "amd64"];
extension = "zip";
}
if (osAndArch === undefined) {
throw Error(`Operating system type '${osType}' with architecture '${osArch}' is not currently supported.`);
}

throw Error(`Operating system type '${osType}' with architecture '${osArch}' is not currently supported.`);
return { os: osAndArch[0], arch: osAndArch[1], extension, homePath, binPath };
};
29 changes: 21 additions & 8 deletions js/cli/src/java.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,33 @@ export const runJavaProcess = (
additionalClasspathElements: string[],
javaArgs: string[],
mainClassArgs: string[]
): Promise<void> =>
// TODO escape strings or pass args some other way
runNodeProcess(
options,
additionalClasspathElements,
javaArgs,
`Java.type("${mainClass}").main([${mainClassArgs.map((arg) => `"${arg}"`).join(",")}]);`
);

export const runNodeProcess = (
options: RunJavaProcessOptions,
additionalClasspathElements: string[],
javaArgs: string[],
evalScript: string
): Promise<void> => {
const command = `${options.graalvmHome}/bin/java`;
const command = `${options.graalvmHome}/bin/node`;
const classpathSeparator = osType === "Windows_NT" ? ";" : ":";
const classpath = [...additionalClasspathElements, options.jvmClasspath].join(classpathSeparator);
const allArgs = [
"-server",
"-XX:+HeapDumpOnOutOfMemoryError",
"-XX:MaxInlineLevel=20",
"-XX:MaxTrivialSize=12",
"-classpath",
"--vm.XX:+HeapDumpOnOutOfMemoryError",
"--vm.XX:MaxInlineLevel=20",
"--vm.XX:MaxTrivialSize=12",
"--vm.classpath",
classpath,
...javaArgs,
mainClass,
...mainClassArgs
"--eval",
evalScript
];

const spawned = spawn(command, allArgs, {
Expand Down
28 changes: 21 additions & 7 deletions js/cli/src/run.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { logger } from "./log";
import { versions } from "./dependencies";
import { RunJavaProcessOptions, runJavaProcess } from "./java";
import { RunJavaProcessOptions, runJavaProcess, runNodeProcess } from "./java";

export interface RunSimulationOptions extends RunJavaProcessOptions {
simulation: string;
Expand All @@ -25,12 +25,12 @@ export const runSimulation = async (options: RunSimulationOptions): Promise<void
- resultsFolder: ${options.resultsFolder}`);

const additionalClasspathElements = [options.resourcesFolder];
const jitTuningArgs = ["-XX:JVMCINativeLibraryThreadFraction=0.8", "-Dgraal.MethodInlineBailoutLimit=500"];
const memoryArgs = options.memory !== undefined ? [`-Xms${options.memory}M`, `-Xmx${options.memory}M`] : [];
const jitTuningArgs = ["--vm.XX:JVMCINativeLibraryThreadFraction=0.8", "--vm.Dgraal.MethodInlineBailoutLimit=500"];
const memoryArgs = options.memory !== undefined ? [`--vm.Xms${options.memory}M`, `--vm.Xmx${options.memory}M`] : [];
const javaArgs = [
...Object.entries(options.runParameters).map(([key, value]) => `-D${key}=${value}`),
`-Dgatling.js.bundle.filePath=${options.bundleFile}`,
`-Dgatling.js.simulation=${options.simulation}`,
...Object.entries(options.runParameters).map(([key, value]) => `--vm.D${key}=${value}`),
`--vm.Dgatling.js.bundle.filePath=${options.bundleFile}`,
`--vm.Dgatling.js.simulation=${options.simulation}`,
...jitTuningArgs,
...memoryArgs
];
Expand All @@ -45,7 +45,21 @@ export const runSimulation = async (options: RunSimulationOptions): Promise<void
versions.gatling.jsAdapter
];

return runJavaProcess(options, "io.gatling.app.Gatling", additionalClasspathElements, javaArgs, simulationArgs);
const evalScript = `
const simulationInitializer = () => {
const bundle = require("./${options.bundleFile}");
const jsSimulation = bundle.gatling["${options.simulation}"];
const JsSimulationWrapper = Java.type("io.gatling.js.JsSimulation");
return new JsSimulationWrapper(jsSimulation);
}
const Gatling = Java.type("io.gatling.app.Gatling");
// TODO escape strings or pass args some other way
Gatling.run([${simulationArgs.map((arg) => `"${arg}"`)}], simulationInitializer);
`;

return runNodeProcess(options, additionalClasspathElements, javaArgs, evalScript);
};

export const runRecorder = async (options: RunRecorderOptions): Promise<void> => {
Expand Down

This file was deleted.

23 changes: 6 additions & 17 deletions jvm/adapter/src/main/java/io/gatling/js/JsSimulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,14 @@

package io.gatling.js;

import com.oracle.truffle.js.lang.JavaScriptLanguageHack;
import io.gatling.javaapi.core.PopulationBuilder;
import io.gatling.javaapi.core.Simulation;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public class JsSimulation extends Simulation {

static {
try {
// Implemented in as separate class because Lookup#defineClass() needs to be called from the
// same package as the class being defined
JavaScriptLanguageHack.allowThreadAccess();
} catch (IOException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}

public JsSimulation() {
// Implemented in a separate class to defer loading any GraalJS class until after the modified
// class has been loaded in this class's static block
JsSimulationHelper.loadSimulation(this::setUp);
public JsSimulation(Consumer<Function<List<PopulationBuilder>, SetUp>> jsSimulation) {
jsSimulation.accept(this::setUp);
}
}
95 changes: 0 additions & 95 deletions jvm/adapter/src/main/java/io/gatling/js/JsSimulationHelper.java

This file was deleted.

Loading

0 comments on commit 87bf63a

Please sign in to comment.