Skip to content
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

Add QuickJS as a Javascript engine option #4622

Closed
wants to merge 1 commit into from
Closed

Conversation

nickva
Copy link
Contributor

@nickva nickva commented May 25, 2023

https://bellard.org/quickjs
https://fuchsia.googlesource.com/third_party/quickjs/

Some benefits over SM:

  • Small. We're using 6 or so C files vs 700+ SM91 C++ files.

  • Built with Apache CouchDB as opposed having to maintain a separate SM package, like for RHEL9, for instance, where they dropped support for SM already. (see RHEL 9 Support for CouchDB #4154).

  • Embedding friendly. Designed from ground-up for embedding. SM has been updating the C++ API such that we have to keep copy-pasting new versions of our C++ code every year or so. (see try compiling for sm 102 #4305).

  • Easy to modify to accept Spidermonkey 1.8.5 top level functions for map/reduce code so we don't have have to parse the JS, AST trasform it, and then re-compile it.

  • Configurable runtime feature set - can disable workers, promises and other API and features which may not work well in a backend JS environment. Some users may want more, some may want to disable even Date(time) features to hedge again Spectre-style attacks (spectreattack.com).

  • Allows granular time (reduction) trackign if we wanted to provide a runtime allowance for each function.

  • Better sandboxing. Creating a whole JSRuntime takes only 300 microseconds, so we can afford to do that on reset. JSRuntimes cannot share JS data or object between them.

  • Seems to be faster in preliminary benchmarking with small concurrent VDU and view builds: https://gist.github.com/nickva/ed239651114794ebb138b1f16c5f6758 Results seem promising: - 4x faster than SM 1.8.5 - 5x faster than SM 91 - 6x reduced memory usage per couchjs process (5MB vs 30MB)

  • Allows compiling JS bytecode ahead of time a C array of bytes.

QuickJS can be built alongside spidermonkey and toggled on/off at runtime:

./configure --dev --js-engine=quickjs

This makes it the default engine. But spidermonkey can still be set in the config option.

[couchdb]
js_engine = spidermonkey | quickjs

Only tested on MacOS and Linux. All make check tests pass there.

Issue: #4448

@nickva
Copy link
Contributor Author

nickva commented May 25, 2023

Some quick and dirty benchmarking

TL;DR:

  • 3x faster than SM 1.8.5
  • 4x faster than SM 91
  • 6x reduced memory usage per couchjs process (5MB vs 30MB).

Needs more benchmarking but so far looks decent. And the lower resource consumption should be a benefit running in the new fedramp kube environment.

Setup Details

MacOS Intel, Erlang 24, ./dev/run -n1

Benchmark script: https://gist.github.com/nickva/c0cbf6a556cc2dc7dd6ee79f504f5f84.

  • 20 concurrent workers create a db and:
    • Insert 100 docs, 10 ddoc(views) and query the views
    • Repeat that 3 times in a row

Results measured by the zsh time command as % time ./stampede_dbs_ddocs_vdus.py .... CPU usage is reported for the client not the couchjs process or Erlang VM. Some example of resource usage is provided below as btop screenshots.

QuickJS

./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.10s user 0.22s system 7% cpu 18.754 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.05s user 0.21s system 6% cpu 18.438 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.06s user 0.21s system 6% cpu 18.591 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.06s user 0.20s system 6% cpu 18.279 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.09s user 0.22s system 6% cpu 18.822 total

Memory usage 5MB-7MB RSS per couchjs process (based on btop output)

Spidermonkey 1.8.5

./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.33s user 0.25s system 2% cpu 1:06.80 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.31s user 0.24s system 2% cpu 1:05.80 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.32s user 0.24s system 2% cpu 1:04.34 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.31s user 0.23s system 2% cpu 1:03.00 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.34s user 0.25s system 2% cpu 1:13.93 total

Spidermonkey 91

./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.11s user 0.21s system 1% cpu 1:31.13 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.09s user 0.20s system 1% cpu 1:24.22 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.10s user 0.21s system 1% cpu 1:35.53 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.06s user 0.20s system 1% cpu 1:20.57 total
./stampede_dbs_ddocs_vdus.py -x 10 -n 100 -w 20 -t 3  1.07s user 0.20s system 1% cpu 1:22.06 total

Memory usage 30-32MB RSS per couchjs process (based on btop output)

Runtime metrics capture (also quick and dirty courtesy of btop):

file1 file2

The CPU usage graph is quite telling I think.

https://bellard.org/quickjs
https://fuchsia.googlesource.com/third_party/quickjs/

Some benefits over SM:

 * Small. We're using 6 or so C files vs 700+ SM91 C++ files.

 * Built with Apache CouchDB as opposed having to maintain a separate SM
   package, like for RHEL9, for instance, where they dropped support for SM
   already. (see apache#4154).

 * Embedding friendly. Designed from ground-up for embedding. SM has been
   updating the C++ API such that we have to keep copy-pasting new versions of
   our C++ code every year or so. (see
   apache#4305).

 * Easy to modify to accept Spidermonkey 1.8.5 top level functions for
   map/reduce code so we don't have have to parse the JS, AST trasform it, and
   then re-compile it.

 * Configurable runtime feature set - can disable workers, promises and other
   API and features which may not work well in a backend JS environment. Some
   users may want more, some may want to disable even Date(time) features to
   hedge again Spectre-style attacks (spectreattack.com).

 * Allows granular time (reduction) trackign if we wanted to provide a runtime
   allowance for each function.

 * Better sandboxing. Creating a whole JSRuntime takes only 300 microseconds, so
   we can afford to do that on reset. JSRuntimes cannot share JS data or object
   between them.

 * Seems to be faster in preliminary benchmarking with small
   concurrent VDU and view builds:
     https://gist.github.com/nickva/ed239651114794ebb138b1f16c5f6758
   Results seem promising:
     - 4x faster than SM 1.8.5
     - 5x faster than SM 91
     - 6x reduced memory usage per couchjs process (5MB vs 30MB)

 * Allows compiling JS bytecode ahead of time a C array of bytes.

QuickJS can be built alongside spidermonkey and toggled on/off at runtime:

```
./configure --dev --js-engine=quickjs
```

This makes it the default engine. But spidermonkey can still be set in the
config option.

```
[couchdb]
js_engine = spidermonkey | quickjs
```

Only tested on MacOS and Linux. All `make check` tests pass there.
@rnewson
Copy link
Member

rnewson commented May 25, 2023

This looks to be a great improvement on several fronts. I think we should go all in on this. maybe optional for a release or two and then fully switch? once we can assume an embedded JS engine we can boost a number of areas (like VDU's).

@nickva
Copy link
Contributor Author

nickva commented May 30, 2023

Switching pull request to use the branch off the Apache CouchDB main since otherwise Jenkinsfile updates don't have an effect. Closing in favor of #4627

@nickva nickva closed this May 30, 2023
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.

None yet

2 participants