Skip to content

loriswit/mjsuite

Repository files navigation

μJSuite

μJSuite is a tool that can run different workloads on different IoT-friendly JavaScript engines. Each engine is automatically built from source and gets executed inside a Docker container. This tool can be used to generate benchmarks and compare the performances of different engines.

You can find collections of generated benchmarks in this repository.

Usage

Prerequisite

To run μJSuite, all you need is Docker to be installed on the target machine.

Make sure the perf_event_paranoid system variable is set to 2 or lower, as some Linux distributions seem to set it higher by default. This is required for μJSuite to be able to measure performance statistics. To fix this, run the following command:

sudo sysctl -w kernel.perf_event_paranoid=2

There's no need to manually setup μJSuite. The first time you run the command line tool, it will automatically download dependencies and build the source code.

Command line

Clone or download this repository, then run bin/mjsuite (or bin\mjsuite on Windows) from the root of the project. To get a list of available commands and options, run bin/mjsuite help.

When requested as an argument or option, a workload must match a script in the workloads directory (without the .js extension), and an engine must match one of the folders in the engines directory.

All available commands are described below. Each of them provides a --help option that displays additional information about their usage.

Benchmark

bin/mjsuite benchmark [options]
bin/mjsuite bm [options]

This command runs all workloads with all engines and generates a benchmark. The results are then written into a JSON file. You can also specify which workloads and engines to run using the options below.

When encountering a new engine, μJSuite will automatically download its source code and build a Docker image. This will take some time to complete, depending on the engine.

The following options are available:

  • -w, --workload <workloads...>: the workload(s) to run (default: all).
  • -e, --engine <engines...>: the engine(s) to use (default: all).
  • -o, --output <filename>: the output file that will store the results.
  • -p, --plot: display plots immediately after the benchmark is generated.

The --workload and --engine options also support negative filtering. For example, running bin/mjsuite benchmark --engine !jerryscript will select every engine except JerryScript.

Engine

To list all available engines, run:

bin/mjsuite engine list

To download and build a specific engine, run:

bin/mjsuite engine setup <engine>

Note that this is done automatically when the benchmark command encounters a new engine. Running this command again will rebuild the engine and overwrite the existing image.

Workload

To list all available workloads, run:

bin/mjsuite workload list

Plots

To draw plots for an already generated benchmark, run:

bin/mjsuite plot <benchmark>

where <benchmark> is a path to the target JSON file (previously generated by the benchmark command).

Example

❯ bin/mjsuite benchmark --workload array-sort --engine jerryscript --plot
Running workload 'array-sort' with engine JerryScript
Workload finished in 853 ms
Saved results to benchmark_2023-06-12_19-29-22.json

Current limitations

Running bin/mjsuite will start μJSuite inside a Docker container, which may cause errors on ARM machines. If you get errors during the setup about lzma-native, try installing Node.js manually, then install dependencies, build the source code and run μJSuite by calling node directly:

npm install
npm run build
node build/main <arg...>

Drawing plots is also not supported inside Docker containers, so follow the same process if needed.

Contributing

Adding an engine

To add a new engine to the project, create a new folder in the engines directory. This folder must contain a manifest file, a Dockerfile and a workload template (optional).

Manifest

Create a manifest.json containing an object with the following fields:

  • name: the name of the engine.
  • repository: the GitHub repository of the engine, in the form user/repo.
  • version: a git tag referencing the target version. If the sha property is provided, this becomes just informative.
  • sha (optional): the target commit SHA hash, which will overwrite the version tag. Helpful when the repository doesn't provide tags.
  • source (optional): a URL to the source code. If set, μJSuite will download from this URL instead of GitHub. Helpful with embeddable engines that provide pre-processed packaged source code.
  • clone (optional): set to true to clone the repository instead of simply downloading it. This will take more time, but some engines require the source code to be in a git repository in order to be built.

Note: when running μJSuite, the engine argument must match the name of the folder, not the name specified in the manifest.

Dockerfile

The Dockerfile must describe how to build the source code of the engine. When executed, the Dockerfile receives srcPath as an argument, which contains the full path to the source code. This argument can be used to copy the source code into the image (e.g., COPY $srcPath ./)

Once the engine is compiled, we want the image to only contain the executable (and its dependencies, if any) without all the build tools and cache. This can be achieved with multi-stage builds. We also need the final image to include both the Perf and GNU Time tools. Make sure to provide a version of GNU Time that is recent enough, as older versions are known to report wrong measurements.

The entry point of the container must be set to the engine executable file and must not include arguments.

Workload template

Since different engines can have different specifications, some of them may need some adjustments before being able to run a workload (e.g., the console.log function could be named differently). If such adjustments are needed, we can create a template.js file with the following syntax:

// code being executed before the workload
const console = { log: print }

// workload will be inserted here
${workload}

// code being executed after the workload
print(duration)

If no adjustments are needed, there's no need to create this file.

Adding a workload

To add a new workload, simply create a JavaScript file in the workloads directory. As a convention, workloads should start with the line var N = #, which specifies the number of iterations in the workload.

Workloads should follow older ECMAScript standards so that most engines will be able to run it. Note that engines that can't process a workload will be skipped during benchmark generation.

For now, workloads cannot depend on external source files or assets (i.e. images). The whole code and data must reside inside a single JavaScript file.

Troubleshooting

If μJSuite fails to work as expected, you can run it with the --verbose option. This will increase the amount of information being printed to the console, which can be helpful to resolve problems.

About

A JavaScript Suite Benchmark for IoT-friendly JavaScript Engines

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published