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

deps: add simdutf dependency #45803

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

anonrig
Copy link
Member

@anonrig anonrig commented Dec 9, 2022

simdutf provides a faster way of providing utf8 operations with SIMD instructions. @nodejs/undici team was looking for a way to validate utf8 input, and this dependency can make it happen.

Edit: I'm proposing either exposing the following functionality through a new module (like node:encoding) or through util.types or buffer

  • validate_ascii(string)
  • validate_utf8(string)
  • count_utf8(string)

PS: simdutf supports more features, and depending on the need, it makes more sense to expose them through a new module, instead of util.types or buffer.

@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented Dec 9, 2022

Review requested:

@nodejs-github-bot nodejs-github-bot added build Issues and PRs related to build files or the CI. dependencies Pull requests that update a dependency file. needs-ci PRs that need a full CI run. tools Issues and PRs related to the tools directory. labels Dec 9, 2022
@anonrig anonrig force-pushed the deps/simdutf branch 2 times, most recently from 2c20c9a to 6daa546 Compare Dec 9, 2022
@anonrig anonrig changed the title dep: add simdutf dependency deps: add simdutf dependency Dec 9, 2022
@KhafraDev
Copy link
Member

KhafraDev commented Dec 9, 2022

This would help speedup both ws and undici's WebSocket implementation (which is still WIP). When we receive a text frame or receive a close frame with a reason, we need to validate that the buffer contains valid utf-8.

There are a few ways of doing so currently: a js implementation by default in both undici and ws, and optionally a package such as utf-8-validate. Note that simdutf is many times faster than the c++ version of utf-8-validate in the benchmark above, and the js fallback version is the slowest.

Here is a PR from @lpinca that shows massive speedups when using simdutf: websockets/utf-8-validate#101. Considering how widespread usage of ws is, exposing a very fast ability to validate utf-8 would improve a ton of the ecosystem.

@anonrig anonrig force-pushed the deps/simdutf branch 2 times, most recently from 5027cae to e94ba5f Compare Dec 9, 2022
@richardlau richardlau added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 9, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 9, 2022
@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented Dec 9, 2022

@anonrig anonrig force-pushed the deps/simdutf branch 2 times, most recently from bed88cc to 4269faf Compare Dec 9, 2022
deps/simdutf/simdutf.gyp Outdated Show resolved Hide resolved
@anonrig anonrig force-pushed the deps/simdutf branch 3 times, most recently from ced7ef2 to 5566c99 Compare Dec 10, 2022
@anonrig anonrig added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 10, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 10, 2022
@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented Dec 10, 2022

@anonrig anonrig added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 10, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 10, 2022
@anonrig anonrig added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Dec 15, 2022
Copy link
Contributor

@mscdex mscdex left a comment

Can we see some real improvements in node core performance before landing this? At least one additional commit that changes node core to use the dependency would be ideal.

@anonrig anonrig added the commit-queue-rebase Add this label to allow the Commit Queue to land a PR in several commits. label Dec 15, 2022
@anonrig
Copy link
Member Author

anonrig commented Dec 15, 2022

@mscdex I pushed a new commit adding fatal flag support to TextDecoder with UTF-8, and updated the benchmarks. Here are the results:

                                                                                                        confidence improvement accuracy (*)    (**)   (***)
util/text-decoder.js type='ArrayBuffer' n=100 len=16384 fatal=1 ignoreBOM=0 encoding='utf-8'                   ***    201.64 %      ±11.06% ±14.83% ±19.53%
util/text-decoder.js type='ArrayBuffer' n=100 len=16384 fatal=1 ignoreBOM=1 encoding='utf-8'                   ***    204.37 %      ±11.60% ±15.53% ±20.42%
util/text-decoder.js type='ArrayBuffer' n=100 len=256 fatal=1 ignoreBOM=0 encoding='utf-8'                     ***    137.29 %      ±11.01% ±14.78% ±19.51%
util/text-decoder.js type='ArrayBuffer' n=100 len=256 fatal=1 ignoreBOM=1 encoding='utf-8'                     ***    145.26 %       ±6.88%  ±9.21% ±12.10%
util/text-decoder.js type='Buffer' n=100 len=16384 fatal=0 ignoreBOM=0 encoding='utf-8'                        ***    -13.82 %       ±6.17%  ±8.21% ±10.69%
util/text-decoder.js type='Buffer' n=100 len=16384 fatal=1 ignoreBOM=0 encoding='utf-8'                          *     -5.91 %       ±4.55%  ±6.06%  ±7.90%
util/text-decoder.js type='Buffer' n=100 len=256 fatal=1 ignoreBOM=0 encoding='utf-8'                          ***    142.20 %       ±9.94% ±13.35% ±17.61%
util/text-decoder.js type='Buffer' n=100 len=256 fatal=1 ignoreBOM=1 encoding='utf-8'                          ***    145.59 %       ±7.80% ±10.40% ±13.59%
util/text-decoder.js type='SharedArrayBuffer' n=100 len=16384 fatal=1 ignoreBOM=0 encoding='utf-8'             ***    208.85 %       ±9.21% ±12.37% ±16.33%
util/text-decoder.js type='SharedArrayBuffer' n=100 len=16384 fatal=1 ignoreBOM=1 encoding='utf-8'             ***    207.60 %      ±12.01% ±16.11% ±21.24%
util/text-decoder.js type='SharedArrayBuffer' n=100 len=256 fatal=1 ignoreBOM=0 encoding='utf-8'               ***    128.74 %      ±11.29% ±15.20% ±20.14%
util/text-decoder.js type='SharedArrayBuffer' n=100 len=256 fatal=1 ignoreBOM=1 encoding='utf-8'               ***    144.48 %       ±7.65% ±10.23% ±13.40%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 72 comparisons, you can thus expect the following amount of false-positive results:
  3.60 false positives, when considering a   5% risk acceptance (*, **, ***),
  0.72 false positives, when considering a   1% risk acceptance (**, ***),
  0.07 false positives, when considering a 0.1% risk acceptance (***)

@mscdex
Copy link
Contributor

mscdex commented Dec 16, 2022

It doesn't compile in CI

lib/internal/encoding.js Outdated Show resolved Hide resolved
@bnoordhuis
Copy link
Member

bnoordhuis commented Dec 16, 2022

@anonrig can you check the before/after binary size?

@anonrig
Copy link
Member Author

anonrig commented Dec 16, 2022

@anonrig can you check the before/after binary size?

➜  node git:(deps/simdutf) ✗ wc -c ./node-main
 88997377 ./node-main
➜  node git:(deps/simdutf) ✗ wc -c ./out/Release/node
 89144657 ./out/Release/node

@lpinca
Copy link
Member

lpinca commented Dec 16, 2022

94008984 -> 94112632 on my machine which is surprisingly small.

It's 116492 -> 631404 for utf-8-validate. Perhaps this is caused by the introduction of the node-addon-api dependency.

@anonrig
Copy link
Member Author

anonrig commented Dec 16, 2022

It doesn't compile in CI

@mscdex This is caused by our CIs. I believe we need to use a more recent compiler/assembler on CI. @nodejs/build wdyt?

@mscdex
Copy link
Contributor

mscdex commented Dec 16, 2022

I believe we need to use a more recent compiler/assembler on CI

Well, node still supports building with (at least) gcc 8.3, so we need to make sure node can still compile on gcc 8.

@anonrig
Copy link
Member Author

anonrig commented Dec 16, 2022

I believe we need to use a more recent compiler/assembler on CI

Well, node still supports building with (at least) gcc 8.3, so we need to make sure node can still compile on gcc 8.

@mscdex It builds correctly on GCC-8. Benchmark CI machine has ubuntu 16.04, which has a different/outdated packages compared to all of our other CI machines.

@mscdex
Copy link
Contributor

mscdex commented Dec 16, 2022

Benchmark CI machine has ubuntu 16.04, which has a different/outdated packages compared to all of our other CI machines.

If it's using the ubuntu-toolchain-r/test PPA to get GCC 8 (since GCC 8 is not available via the official Ubuntu repositories for 16.04), then it should be using GCC 8.4.0 which should be new enough.

Can we get confirmation on the build environment tool versions from @nodejs/build ?

@anonrig anonrig added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 16, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 16, 2022
@nodejs-github-bot
Copy link
Contributor

nodejs-github-bot commented Dec 16, 2022

@richardlau
Copy link
Member

richardlau commented Dec 16, 2022

Benchmark CI machine has ubuntu 16.04, which has a different/outdated packages compared to all of our other CI machines.

If it's using the ubuntu-toolchain-r/test PPA to get GCC 8 (since GCC 8 is not available via the official Ubuntu repositories for 16.04), then it should be using GCC 8.4.0 which should be new enough.

Can we get confirmation on the build environment tool versions from @nodejs/build ?

iojs@test-nearform--intel-ubuntu1604-x64-2:~$ gcc-8 --version
gcc-8 (Ubuntu 8.4.0-1ubuntu1~16.04.1) 8.4.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

iojs@test-nearform--intel-ubuntu1604-x64-2:~$

on the list of technical debt for the Build WG is upgrading the benchmark machine to something newer than Ubuntu 16.04.

@mscdex
Copy link
Contributor

mscdex commented Dec 16, 2022

With the build tools being the same versions then, that must mean that the benchmark machine has opposite CPU feature availability (AVX512-wise) compared to the other x64 CI machines (e.g. benchmark CI has them and test CI does not or vice versa).

Either way, I think this shows there is something not quite right with the compile-time CPU checks.

@richardlau
Copy link
Member

richardlau commented Dec 16, 2022

FWIW the machine has the latest available binutils package for Ubuntu 16.04:

root@test-nearform--intel-ubuntu1604-x64-2:~# apt show binutils
Package: binutils
Version: 2.26.1-1ubuntu1~16.04.8
Priority: optional
Section: devel
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Matthias Klose <doko@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 13.7 MB
Provides: binutils-gold, elf-binutils
Depends: libc6 (>= 2.14), zlib1g (>= 1:1.2.0)
Suggests: binutils-doc (>= 2.26.1-1ubuntu1~16.04.8)
Conflicts: binutils-gold (<< 2.20.51.20100415), binutils-mingw-w64-i686 (<< 2.23.52.20130612-1+3), binutils-mingw-w64-x86-64 (<< 2.23.52.20130612-1+3), elf-binutils, gas, modutils (<< 2.4.19-1)
Breaks: binutils-mingw-w64-i686 (<< 2.23.52.20130612-1+3), binutils-mingw-w64-x86-64 (<< 2.23.52.20130612-1+3)
Replaces: binutils-gold (<< 2.20.51.20100415), binutils-mingw-w64-i686 (<< 2.23.52.20130612-1+3), binutils-mingw-w64-x86-64 (<< 2.23.52.20130612-1+3)
Task: ubuntu-desktop, ubuntu-usb, kubuntu-desktop, kubuntu-full, edubuntu-desktop, edubuntu-usb, xubuntu-core, xubuntu-desktop, mythbuntu-frontend, mythbuntu-desktop, mythbuntu-backend-slave, mythbuntu-backend-master, mythbuntu-backend-master, lubuntu-live, ubuntustudio-desktop-core, ubuntustudio-desktop, ubuntu-gnome-desktop, ubuntu-touch, ubuntukylin-desktop, ubuntu-mate-core, ubuntu-mate-desktop, ubuntu-mate-cloudtop
Build-Essential: yes
Supported: 5y
Download-Size: 2,312 kB
APT-Manual-Installed: no
APT-Sources: http://ie.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages
Description: GNU assembler, linker and binary utilities
 The programs in this package are used to assemble, link and manipulate
 binary and object files.  They may be used in conjunction with a compiler
 and various libraries to build programs.

N: There are 2 additional records. Please use the '-a' switch to see them.
root@test-nearform--intel-ubuntu1604-x64-2:~#

and here's the last entry in /proc/cpuinfo on the machine:

processor       : 87
vendor_id       : GenuineIntel
cpu family      : 6
model           : 79
model name      : Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz
stepping        : 1
microcode       : 0xb000038
cpu MHz         : 1200.117
cache size      : 56320 KB
physical id     : 1
siblings        : 44
core id         : 28
cpu cores       : 22
apicid          : 121
initial apicid  : 121
fpu             : yes
fpu_exception   : yes
cpuid level     : 20
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb invpcid_single intel_pt ssbd ibrs ibpb stibp kaiser tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdseed adx smap xsaveopt cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts md_clear flush_l1d
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit
bogomips        : 4390.97
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:

@anonrig
Copy link
Member Author

anonrig commented Dec 16, 2022

Either way, I think this shows there is something not quite right with the compile-time CPU checks.

16.04 is unsupported as of April 2021. The build team has already planned to upgrade the machine, and all supported CI machines have a passing build & tests. I believe this should not be a blocker.

@mscdex
Copy link
Contributor

mscdex commented Dec 17, 2022

I believe this should not be a blocker.

I'd like to be able to run the benchmarks in CI to verify the benchmark results, especially since there seems to be some configurations missing from the provided output.

Co-authored-by: Daniel Lemire <daniel@lemire.me>
@anonrig
Copy link
Member Author

anonrig commented Dec 17, 2022

@mscdex With the help of @lemire, I've added the necessary configuration to disable AVX512 for old setups, such as our benchmark CI.

The benchmark result can be seen from: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1272/console

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. build Issues and PRs related to build files or the CI. commit-queue-rebase Add this label to allow the Commit Queue to land a PR in several commits. dependencies Pull requests that update a dependency file. needs-ci PRs that need a full CI run. review wanted PRs that need reviews. tools Issues and PRs related to the tools directory.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet