diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 4f691caefd3a78..ba6334b0346985 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -3,7 +3,7 @@ env: es6: true parserOptions: - ecmaVersion: 2016 + ecmaVersion: 2017 rules: # Possible Errors @@ -40,6 +40,7 @@ rules: no-octal: 2 no-redeclare: 2 no-self-assign: 2 + no-throw-literal: 2 no-unused-labels: 2 no-useless-call: 2 no-useless-escape: 2 @@ -102,6 +103,7 @@ rules: no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] no-tabs: 2 no-trailing-spaces: 2 + one-var-declaration-per-line: 2 operator-linebreak: [2, after] quotes: [2, single, avoid-escape] semi: 2 @@ -111,6 +113,7 @@ rules: space-in-parens: [2, never] space-infix-ops: 2 space-unary-ops: 2 + unicode-bom: 2 # ECMAScript 6 # http://eslint.org/docs/rules/#ecmascript-6 diff --git a/AUTHORS b/AUTHORS index f52fb4d2d72c28..6d4c9842d4774c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -935,7 +935,7 @@ Felix Becker Igor Klopov Tsarevich Dmitry Ojas Shirekar -Noah Rose +Noah Rose Ledesma Rafael Cepeda Chinedu Francis Nwafili Braydon Fuller diff --git a/CHANGELOG.md b/CHANGELOG.md index b2e4952504f0ad..f284727f76cba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,15 +28,21 @@ release. -7.4.0
+7.7.1
+7.7.0
+7.6.0
+7.5.0
+7.4.0
7.3.0
7.2.1
7.2.0
7.1.0
7.0.0
- -6.9.4
+ +6.10.0
+6.9.5
+6.9.4
6.9.3
6.9.2
6.9.1
@@ -76,7 +82,9 @@ release. 5.0.0
-4.7.2
+4.8.0
+4.7.3
+4.7.2
4.7.1
4.7.0
4.6.2
diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 7ac8f49ee09ff0..4ce11257b707f2 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -4,6 +4,9 @@ * [Issues and Pull Requests](#issues-and-pull-requests) * [Accepting Modifications](#accepting-modifications) + - [Internal vs. Public API](#internal-vs-public-api) + - [Breaking Changes](#breaking-changes) + - [Deprecations](#deprecations) - [Involving the CTC](#involving-the-ctc) * [Landing Pull Requests](#landing-pull-requests) - [Technical HOWTO](#technical-howto) @@ -84,6 +87,206 @@ All pull requests that modify executable code should be subjected to continuous integration tests on the [project CI server](https://ci.nodejs.org/). +### Internal vs. Public API + +Due to the nature of the JavaScript language, it can often be difficult to +establish a clear distinction between which parts of the Node.js implementation +represent the "public" API Node.js users should assume to be stable and which +are considered part of the "internal" implementation detail of Node.js itself. +A general rule of thumb has been to base the determination off what +functionality is actually *documented* in the official Node.js API +documentation. However, it has been repeatedly demonstrated that either the +documentation does not completely cover implemented behavior or that Node.js +users have come to rely heavily on undocumented aspects of the Node.js +implementation. + +While there are numerous exceptions, the following general rules should be +followed to determine which aspects of the Node.js API are considered +"internal": + +- Any and all functionality exposed via `process.binding(...)` is considered to + be internal and *not* part of the Node.js Public API. +- Any and all functionality implemented in `lib/internal/**/*.js` that is not + re-exported by code in `lib/*.js`, or is not documented as part of the + Node.js Public API, is considered to be internal. +- Any object property or method whose key is a non-exported `Symbol` is + considered to be an internal property. +- Any object property or method whose key begins with the underscore `_` prefix, + and is not documented as part of the Node.js Public API, is considered to be + an internal property. +- Any object, property, method, argument, behavior, or event not documented in + the Node.js documentation is considered to be internal. +- Any native C/C++ APIs/ABIs exported by the Node.js `*.h` header files that + are hidden behind the `NODE_WANT_INTERNALS` flag are considered to be + internal. + +Exception to each of these points can be made if use or behavior of a given +internal API can be demonstrated to be sufficiently relied upon by the Node.js +ecosystem such that any changes would cause too much breakage. The threshold +for what qualifies as "too much breakage" is to be decided on a case-by-case +basis by the CTC. + +If it is determined that a currently undocumented object, property, method, +argument, or event *should* be documented, then a pull request adding the +documentation is required in order for it to be considered part of the "public" +API. + +Making a determination about whether something *should* be documented can be +difficult and will need to be handled on a case-by-case basis. For instance, if +one documented API cannot be used successfully without the use of a second +*currently undocumented* API, then the second API *should* be documented. If +using an API in a manner currently undocumented achieves a particular useful +result, a decision will need to be made whether or not that falls within the +supported scope of that API; and if it does, it should be documented. + +Breaking changes to internal elements are permitted in semver-patch or +semver-minor commits but Collaborators should take significant care when +making and reviewing such changes. Before landing such commits, an effort +must be made to determine the potential impact of the change in the ecosystem +by analyzing current use and by validating such changes through ecosystem +testing using the [Canary in the Goldmine](https://github.com/nodejs/citgm) +tool. If a change cannot be made without ecosystem breakage, then CTC review is +required before landing the change as anything less than semver-major. + +If a determination is made that a particular internal API (for instance, an +underscore `_` prefixed property) is sufficiently relied upon by the ecosystem +such that any changes may break user code, then serious consideration should be +given to providing an alternative Public API for that functionality before any +breaking changes are made. + +### Breaking Changes + +Backwards-incompatible changes may land on the master branch at any time after +sufficient review by collaborators and approval of at least two CTC members. + +Examples of breaking changes include, but are not necessarily limited to, +removal or redefinition of existing API arguments, changing return values +(except when return values do not currently exist), removing or modifying +existing properties on an options argument, adding or removing errors, +changing error messages in any way, altering expected timing of an event (e.g. +moving from sync to async responses or vice versa), and changing the +non-internal side effects of using a particular API. + +With a few notable exceptions outlined below, when backwards incompatible +changes to a *Public* API are necessary, the existing API *must* be deprecated +*first* and the new API either introduced in parallel or added after the next +major Node.js version following the deprecation as a replacement for the +deprecated API. In other words, as a general rule, existing *Public* APIs +*must not* change (in a backwards incompatible way) without a deprecation. + +Exception to this rule is given in the following cases: + +* Adding or removing errors thrown or reported by a Public API; +* Changing error messages; +* Altering the timing and non-internal side effects of the Public API. + +Such changes *must* be handled as semver-major changes but MAY be landed +without a [Deprecation cycle](#deprecation-cycle). + +From time-to-time, in particularly exceptional cases, the CTC may be asked to +consider and approve additional exceptions to this rule. + +Purely additive changes (e.g. adding new events to EventEmitter +implementations, adding new arguments to a method in a way that allows +existing code to continue working without modification, or adding new +properties to an options argument) are handled as semver-minor changes. + +Note that errors thrown, along with behaviors and APIs implemented by +dependencies of Node.js (e.g. those originating from V8) are generally not +under the control of Node.js and therefore *are not directly subject to this +policy*. However, care should still be taken when landing updates to +dependencies when it is known or expected that breaking changes to error +handling may have been made. Additional CI testing may be required. + +#### When breaking changes actually break things + +Breaking changes are difficult primarily because they change the fundamental +assumptions a user of Node.js has when writing their code and can cause +existing code to stop functioning as expected -- costing developers and users +time and energy to fix. + +Because breaking (semver-major) changes are permitted to land in master at any +time, it should be *understood and expected* that at least some subset of the +user ecosystem *may* be adversely affected *in the short term* when attempting +to build and use Node.js directly from master. This potential instability is +precisely why Node.js offers distinct Current and LTS release streams that +offer explicit stability guarantees. + +Specifically: + +* Breaking changes should *never* land in Current or LTS except when: + * Resolving critical security issues. + * Fixing a critical bug (e.g. fixing a memory leak) requires a breaking + change. + * There is CTC consensus that the change is required. +* If a breaking commit does accidentally land in a Current or LTS branch, an + attempt to fix the issue will be made before the next release; If no fix is + provided then the commit will be reverted. + +When any change is landed in master, and it is determined that the such +changes *do* break existing code, a decision may be made to revert those +changes either temporarily or permanently. However, the decision to revert or +not can often be based on many complex factors that are not easily codified. It +is also possible that the breaking commit can be labeled retroactively as a +semver-major change that will not be backported to Current or LTS branches. + +### Deprecations + +Deprecation refers to the identification of Public APIs that should no longer +be used and that may be removed or modified in non-backwards compatible ways in +a future major release of Node.js. Deprecation *may* be used with internal APIs +if there is expected impact on the user community. + +Node.js uses three fundamental Deprecation levels: + +* *Documentation-Only Deprecation* refers to elements of the Public API that are + being staged for deprecation in a future Node.js major release. An explicit + notice indicating the deprecated status is added to the API documentation + *but no functional changes are implemented in the code*. There will be no + runtime deprecation warning emitted for such deprecations. + +* *Runtime Deprecation* refers to the use of process warnings emitted at + runtime the first time that a deprecated API is used. A command-line + switch can be used to escalate such warnings into runtime errors that will + cause the Node.js process to exit. As with Documentation-Only Deprecation, + the documentation for the API must be updated to clearly indicate the + deprecated status. + +* *End-of-life* refers to APIs that have gone through Runtime Deprecation and + are ready to be removed from Node.js entirely. + +Documentation-Only Deprecations *may* be handled as semver-minor or +semver-major changes. Such deprecations have no impact on the successful +operation of running code and therefore should not be viewed as breaking +changes. + +Runtime Deprecations and End-of-life APIs (internal or public) *must* be +handled as semver-major changes unless there is CTC consensus to land the +deprecation as a semver-minor. + +All Documentation-Only and Runtime deprecations will be assigned a unique +identifier that can be used to persistently refer to the deprecation in +documentation, emitted process warnings, or errors thrown. Documentation for +these identifiers will be included in the Node.js API documentation and will +be immutable once assigned. Even if End-of-Life code is removed from Node.js, +the documentation for the assigned deprecation identifier must remain in the +Node.js API documentation. + + +A "Deprecation cycle" is one full Node.js major release during which an API +has been in one of the three Deprecation levels. (Note that Documentation-Only +Deprecations may land in a Node.js minor release but must not be upgraded to +a Runtime Deprecation until the next major release.) + +No API can be moved to End-of-life without first having gone through a +Runtime Deprecation cycle. + +A best effort will be made to communicate pending deprecations and associated +mitigations with the ecosystem as soon as possible (preferably *before* the pull +request adding the deprecation lands in master). All deprecations included in +a Node.js release should be listed prominently in the "Notable Changes" section +of the release notes. + ### Involving the CTC Collaborators may opt to elevate pull requests or issues to the CTC for @@ -291,7 +494,7 @@ You can find more information [in the full LTS plan](https://github.com/nodejs/l #### How does LTS work? -Once a stable branch enters LTS, changes in that branch are limited to bug +Once a Current branch enters LTS, changes in that branch are limited to bug fixes, security updates, possible npm updates, documentation updates, and certain performance improvements that can be demonstrated to not break existing applications. Semver-minor changes are only permitted if required for bug fixes @@ -299,7 +502,7 @@ and then only on a case-by-case basis with LTS WG and possibly Core Technical Committee (CTC) review. Semver-major changes are permitted only if required for security related fixes. -Once a stable branch moves into Maintenance mode, only **critical** bugs, +Once a Current branch moves into Maintenance mode, only **critical** bugs, **critical** security fixes, and documentation updates will be permitted. #### Landing semver-minor commits in LTS diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c60eeb1c6e3040..290cad8faaeb7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ For general help using Node.js, please file an issue at the [Node.js help repository](https://github.com/nodejs/help/issues). Discussion of non-technical topics including subjects like intellectual -property, trademark and high level project questions should move to the +property, trademark, and high level project questions should move to the [Technical Steering Committee (TSC)](https://github.com/nodejs/TSC/issues) instead. @@ -46,15 +46,6 @@ $ git remote add upstream git://github.com/nodejs/node.git For developing new features and bug fixes, the `master` branch should be pulled and built upon. -#### Respect the stability index - -The rules for the master branch are less strict; consult the -[stability index](./doc/api/documentation.md#stability-index) for details. - -In a nutshell, modules are at varying levels of API stability. Bug fixes are -always welcome but API or behavioral changes to modules at stability level 3 -(Locked) are off-limits. - #### Dependencies Node.js has several bundled dependencies in the *deps/* and the *tools/* @@ -85,6 +76,9 @@ Create a branch and start hacking: $ git checkout -b my-branch -t origin/master ``` +Any text you write should follow the [Style Guide](doc/STYLE_GUIDE.md), +including comments and API documentation. + ### Step 3: Commit Make sure git knows your name and email address: @@ -109,8 +103,8 @@ changed and why. Follow these guidelines when writing one: lowercase with the exception of proper nouns, acronyms, and the ones that refer to code, like function/variable names. The description should be prefixed with the name of the changed subsystem and start with an - imperative verb, for example, "net: add localAddress and localPort - to Socket". + imperative verb. Example: "net: add localAddress and localPort + to Socket" 2. Keep the second line blank. 3. Wrap all other lines at 72 columns. @@ -121,11 +115,11 @@ subsystem: explain the commit in one line Body of commit message is a few lines of text, explaining things in more detail, possibly giving some background about the issue -being fixed, etc. etc. +being fixed, etc. The body of the commit message can be several paragraphs, and please do proper word-wrap and keep columns shorter than about -72 characters or so. That way `git log` will show things +72 characters or so. That way, `git log` will show things nicely even when it is indented. ``` @@ -175,14 +169,16 @@ Windows: (See the [BUILDING.md](./BUILDING.md) for more details.) -Make sure the linter is happy and that all tests pass. Please, do not submit -patches that fail either check. +Make sure the linter does not report any issues and that all tests pass. Please +do not submit patches that fail either check. Running `make test`/`vcbuild test` will run the linter as well unless one or more tests fail. If you want to run the linter without running tests, use -`make lint`/`vcbuild jslint`. +`make lint`/`vcbuild jslint`. At this time, only JavaScript linting is +available on Windows. `make lint` on POSIX will run both JavaScript linting and +C++ linting. If you are updating tests and just want to run a single test to check it, you can use this syntax to run it exactly as the test harness would: @@ -214,7 +210,7 @@ Pull requests are usually reviewed within a few days. ### Step 7: Discuss and update You will probably get feedback or requests for changes to your Pull Request. -This is a big part of the submission process, so don't be disheartened! +This is a big part of the submission process so don't be disheartened! To make changes to an existing Pull Request, make the changes to your branch. When you push that branch to your fork, GitHub will automatically update the @@ -252,7 +248,7 @@ If in doubt, you can always ask for guidance in the Pull Request or on Feel free to post a comment in the Pull Request to ping reviewers if you are awaiting an answer on something. If you encounter words or acronyms that -seem unfamiliar, check out this +seem unfamiliar, refer to this [glossary](https://sites.google.com/a/chromium.org/dev/glossary). Note that multiple commits often get squashed when they are landed (see the @@ -260,7 +256,7 @@ notes about [commit squashing](#commit-squashing)). ### Step 8: Landing -In order to get landed, a Pull Request needs to be reviewed and +In order to land, a Pull Request needs to be reviewed and [approved](#getting-approvals-for-your-pull-request) by at least one Node.js Collaborator and pass a [CI (Continuous Integration) test run](#ci-testing). @@ -280,8 +276,8 @@ your name on it. Congratulations and thanks for your contribution! ### Commit Squashing -When the commits in your Pull Request get landed, they will be squashed -into one commit per logical change, with metadata added to the commit +When the commits in your Pull Request land, they will be squashed +into one commit per logical change. Metadata will be added to the commit message (including links to the Pull Request, links to relevant issues, and the names of the reviewers). The commit history of your Pull Request, however, will stay intact on the Pull Request page. @@ -311,9 +307,9 @@ Every Pull Request needs to be tested to make sure that it works on the platforms that Node.js supports. This is done by running the code through the CI system. -Only a Collaborator can request a CI run. Usually one of them will do it +Only a Collaborator can start a CI run. Usually one of them will do it for you as approvals for the Pull Request come in. -If not, you can ask a Collaborator to request a CI run. +If not, you can ask a Collaborator to start a CI run. ### Waiting Until the Pull Request Gets Landed diff --git a/LICENSE b/LICENSE index 4ffd4869b2360a..d17113b221c0c3 100644 --- a/LICENSE +++ b/LICENSE @@ -1070,123 +1070,3 @@ The externally maintained libraries used by Node.js are: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ - -- node-weak, located at test/gc/node_modules/weak, is licensed as follows: - """ - Copyright (c) 2011, Ben Noordhuis - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - """ - -- v8_inspector, located at deps/v8_inspector/third_party/v8_inspector, is licensed as follows: - """ - // Copyright 2015 The Chromium Authors. All rights reserved. - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // * Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // * Redistributions in binary form must reproduce the above - // copyright notice, this list of conditions and the following disclaimer - // in the documentation and/or other materials provided with the - // distribution. - // * Neither the name of Google Inc. nor the names of its - // contributors may be used to endorse or promote products derived from - // this software without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """ - -- jinja2, located at deps/v8_inspector/third_party/jinja2, is licensed as follows: - """ - Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details. - - Some rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """ - -- markupsafe, located at deps/v8_inspector/third_party/markupsafe, is licensed as follows: - """ - Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS - for more details. - - Some rights reserved. - - Redistribution and use in source and binary forms of the software as well - as documentation, with or without modification, are permitted provided - that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT - NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGE. - """ diff --git a/Makefile b/Makefile index d17930776f3d67..410f643c91bd59 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,8 @@ TEST_CI_ARGS ?= STAGINGSERVER ?= node-www LOGLEVEL ?= silent OSTYPE := $(shell uname -s | tr '[A-Z]' '[a-z]') +COVTESTS ?= test +GTEST_FILTER ?= "*" ifdef JOBS PARALLEL_ARGS = -j $(JOBS) @@ -113,8 +115,77 @@ distclean: check: test +# Remove files generated by running coverage, put the non-instrumented lib back +# in place +coverage-clean: + if [ -d lib_ ]; then rm -rf lib; mv lib_ lib; fi + -rm -rf node_modules + -rm -rf gcovr testing + -rm -rf out/$(BUILDTYPE)/.coverage + -rm -rf .cov_tmp coverage + -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcda + -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda + -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcno + -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing*.gcno + +# Build and test with code coverage reporting. Leave the lib directory +# instrumented for any additional runs the user may want to make. +# For C++ coverage reporting, this needs to be run in conjunction with configure +# --coverage. html coverage reports will be created under coverage/ + +coverage: coverage-test + +coverage-build: all + mkdir -p node_modules + if [ ! -d node_modules/istanbul-merge ]; then \ + $(NODE) ./deps/npm install istanbul-merge; fi + if [ ! -d node_modules/nyc ]; then $(NODE) ./deps/npm install nyc; fi + if [ ! -d gcovr ]; then git clone --depth=1 \ + --single-branch git://github.com/gcovr/gcovr.git; fi + if [ ! -d testing ]; then git clone --depth=1 \ + --single-branch https://github.com/nodejs/testing.git; fi + if [ ! -f gcovr/scripts/gcovr.orig ]; then \ + (cd gcovr && patch -N -p1 < \ + "$(CURDIR)/testing/coverage/gcovr-patches.diff"); fi + if [ -d lib_ ]; then rm -rf lib; mv lib_ lib; fi + mv lib lib_ + $(NODE) ./node_modules/.bin/nyc instrument lib_/ lib/ + $(MAKE) + +coverage-test: coverage-build + -rm -rf out/$(BUILDTYPE)/.coverage + -rm -rf .cov_tmp + -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcda + -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda + -$(MAKE) $(COVTESTS) + mv lib lib__ + mv lib_ lib + mkdir -p coverage .cov_tmp + $(NODE) ./node_modules/.bin/istanbul-merge --out \ + .cov_tmp/libcov.json 'out/Release/.coverage/coverage-*.json' + (cd lib && .$(NODE) ../node_modules/.bin/nyc report \ + --temp-directory "$(CURDIR)/.cov_tmp" -r html \ + --report-dir "../coverage") + -(cd out && "../gcovr/scripts/gcovr" --gcov-exclude='.*deps' \ + --gcov-exclude='.*usr' -v -r Release/obj.target/node \ + --html --html-detail -o ../coverage/cxxcoverage.html) + mv lib lib_ + mv lib__ lib + @echo -n "Javascript coverage %: " + @grep -B1 Lines coverage/index.html | head -n1 \ + | sed 's/<[^>]*>//g'| sed 's/ //g' + @echo -n "C++ coverage %: " + @grep -A3 Lines coverage/cxxcoverage.html | grep style \ + | sed 's/<[^>]*>//g'| sed 's/ //g' + cctest: all - @out/$(BUILDTYPE)/$@ + @out/$(BUILDTYPE)/$@ --gtest_filter=$(GTEST_FILTER) + +list-gtests: +ifeq (,$(wildcard out/$(BUILDTYPE)/cctest)) + $(error Please run 'make cctest' first) +endif + @out/$(BUILDTYPE)/cctest --gtest_list_tests v8: tools/make-v8.sh @@ -133,10 +204,13 @@ test-parallel: all test-valgrind: all $(PYTHON) tools/test.py --mode=release --valgrind sequential parallel message -test/gc/node_modules/weak/build/Release/weakref.node: $(NODE_EXE) +# Implicitly depends on $(NODE_EXE). We don't depend on it explicitly because +# it always triggers a rebuild due to it being a .PHONY rule. See the comment +# near the build-addons rule for more background. +test/gc/build/Release/binding.node: test/gc/binding.cc test/gc/binding.gyp $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --python="$(PYTHON)" \ - --directory="$(shell pwd)/test/gc/node_modules/weak" \ + --directory="$(shell pwd)/test/gc" \ --nodedir="$(shell pwd)" # Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale. @@ -171,7 +245,7 @@ test/addons/.buildstamp: config.gypi \ # Cannot use $(wildcard test/addons/*/) here, it's evaluated before # embedded addons have been generated from the documentation. @for dirname in test/addons/*/; do \ - echo "\nBuilding addon $$PWD/$$dirname" ; \ + printf "\nBuilding addon $$PWD/$$dirname\n" ; \ env MAKEFLAGS="-j1" $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp \ --loglevel=$(LOGLEVEL) rebuild \ --python="$(PYTHON)" \ @@ -188,12 +262,21 @@ test/addons/.buildstamp: config.gypi \ # TODO(bnoordhuis) Force rebuild after gyp update. build-addons: $(NODE_EXE) test/addons/.buildstamp -test-gc: all test/gc/node_modules/weak/build/Release/weakref.node +ifeq ($(OSTYPE),$(filter $(OSTYPE),darwin aix)) + XARGS = xargs +else + XARGS = xargs -r +endif +clear-stalled: + ps awwx | grep Release/node | grep -v grep | cat + ps awwx | grep Release/node | grep -v grep | awk '{print $$1}' | $(XARGS) kill + +test-gc: all test/gc/build/Release/binding.node $(PYTHON) tools/test.py --mode=release gc test-build: | all build-addons -test-all: test-build test/gc/node_modules/weak/build/Release/weakref.node +test-all: test-build test/gc/build/Release/binding.node $(PYTHON) tools/test.py --mode=debug,release test-all-valgrind: test-build @@ -210,17 +293,27 @@ test-ci-native: | test/addons/.buildstamp $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) # This target should not use a native compiler at all -test-ci-js: +test-ci-js: | clear-stalled $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_JS_SUITES) + # Clean up any leftover processes + PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ + if [ "$${PS_OUT}" ]; then \ + echo $${PS_OUT} | $(XARGS) kill; exit 1; \ + fi test-ci: LOGLEVEL := info -test-ci: | build-addons +test-ci: | clear-stalled build-addons out/Release/cctest --gtest_output=tap:cctest.tap $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) $(CI_JS_SUITES) + # Clean up any leftover processes + PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ + if [ "$${PS_OUT}" ]; then \ + echo $${PS_OUT} | $(XARGS) kill; exit 1; \ + fi test-release: test-build $(PYTHON) tools/test.py --mode=release @@ -246,6 +339,10 @@ test-debugger: all test-inspector: all $(PYTHON) tools/test.py inspector +test-node-inspect: $(NODE_EXE) + USE_EMBEDDED_NODE_INSPECT=1 $(NODE) tools/test-npm-package \ + --install deps/node-inspect test + test-tick-processor: all $(PYTHON) tools/test.py tick-processor @@ -261,6 +358,11 @@ test-npm-publish: $(NODE_EXE) test-addons: test-build $(PYTHON) tools/test.py --mode=release addons +test-addons-clean: + $(RM) -rf test/addons/??_*/ + $(RM) -rf test/addons/*/build + $(RM) test/addons/.buildstamp test/addons/.docbuildstamp + test-timers: $(MAKE) --directory=tools faketime $(PYTHON) tools/test.py --mode=release timers @@ -300,6 +402,11 @@ test-v8 test-v8-intl test-v8-benchmarks test-v8-all: "$ git clone https://github.com/nodejs/node.git" endif +# Google Analytics ID used for tracking API docs page views, empty +# DOCS_ANALYTICS means no tracking scripts will be included in the +# generated .html files +DOCS_ANALYTICS ?= + apidoc_sources = $(wildcard doc/api/*.md) apidocs_html = $(apidoc_dirs) $(apiassets) $(addprefix out/,$(apidoc_sources:.md=.html)) apidocs_json = $(apidoc_dirs) $(apiassets) $(addprefix out/,$(apidoc_sources:.md=.json)) @@ -333,7 +440,8 @@ out/doc/api/%.json: doc/api/%.md [ -x $(NODE) ] && $(NODE) $(gen-json) || node $(gen-json) # check if ./node is actually set, else use user pre-installed binary -gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html --template=doc/template.html $< > $@ +gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html \ + --template=doc/template.html --analytics=$(DOCS_ANALYTICS) $< > $@ out/doc/api/%.html: doc/api/%.md @[ -e tools/doc/node_modules/js-yaml/package.json ] || \ [ -e tools/eslint/node_modules/js-yaml/package.json ] || \ @@ -498,7 +606,7 @@ PKGDIR=out/dist-osx release-only: @if [ "$(DISTTYPE)" != "nightly" ] && [ "$(DISTTYPE)" != "next-nightly" ] && \ `grep -q REPLACEME doc/api/*.md`; then \ - echo 'Please update Added: tags in the documentation first.' ; \ + echo 'Please update REPLACEME in Added: tags in doc/api/*.md (See doc/releases.md)' ; \ exit 1 ; \ fi @if [ "$(shell git status --porcelain | egrep -v '^\?\? ')" = "" ]; then \ @@ -587,7 +695,7 @@ ifeq ($(XZ), 0) ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/node-$(FULLVERSION).tar.xz.done" endif -doc-upload: tar +doc-upload: doc ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)" chmod -R ug=rw-x+X,o=r+X out/doc/ scp -pr out/doc/ $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs/ @@ -722,6 +830,7 @@ CPPLINT_FILES = $(filter-out $(CPPLINT_EXCLUDE), $(wildcard \ test/addons/*/*.h \ test/cctest/*.cc \ test/cctest/*.h \ + test/gc/binding.cc \ tools/icu/*.cc \ tools/icu/*.h \ )) @@ -753,9 +862,11 @@ endif .PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean \ check uninstall install install-includes install-bin all staticlib \ - dynamiclib test test-all test-addons build-addons website-upload pkg \ - blog blogclean tar binary release-only bench-http-simple bench-idle \ - bench-all bench bench-misc bench-array bench-buffer bench-net \ - bench-http bench-fs bench-tls cctest run-ci test-v8 test-v8-intl \ - test-v8-benchmarks test-v8-all v8 lint-ci bench-ci jslint-ci doc-only \ - $(TARBALL)-headers test-ci test-ci-native test-ci-js build-ci + dynamiclib test test-all test-addons test-addons-clean build-addons \ + website-upload pkg blog blogclean tar binary release-only \ + bench-http-simple bench-idle bench-all bench bench-misc bench-array \ + bench-buffer bench-net bench-http bench-fs bench-tls cctest run-ci test-v8 \ + test-v8-intl test-v8-benchmarks test-v8-all v8 lint-ci bench-ci jslint-ci \ + doc-only $(TARBALL)-headers test-ci test-ci-native test-ci-js build-ci \ + clear-stalled coverage-clean coverage-build coverage-test coverage \ + list-gtests diff --git a/README.md b/README.md index 05d45be7388689..5db1b427ce499e 100644 --- a/README.md +++ b/README.md @@ -155,56 +155,56 @@ more information about the governance of the Node.js project, see ### CTC (Core Technical Committee) * [addaleax](https://github.com/addaleax) - -**Anna Henningsen** <anna@addaleax.net> +**Anna Henningsen** <anna@addaleax.net> (she/her) * [bnoordhuis](https://github.com/bnoordhuis) - **Ben Noordhuis** <info@bnoordhuis.nl> * [ChALkeR](https://github.com/ChALkeR) - -**Сковорода Никита Андреевич** <chalkerx@gmail.com> -* [chrisdickinson](https://github.com/chrisdickinson) - -**Chris Dickinson** <christopher.s.dickinson@gmail.com> +**Сковорода Никита Андреевич** <chalkerx@gmail.com> (he/him) * [cjihrig](https://github.com/cjihrig) - **Colin Ihrig** <cjihrig@gmail.com> * [evanlucas](https://github.com/evanlucas) - -**Evan Lucas** <evanlucas@me.com> +**Evan Lucas** <evanlucas@me.com> (he/him) * [fishrock123](https://github.com/fishrock123) - **Jeremiah Senkpiel** <fishrock123@rocketmail.com> * [indutny](https://github.com/indutny) - **Fedor Indutny** <fedor.indutny@gmail.com> * [jasnell](https://github.com/jasnell) - -**James M Snell** <jasnell@gmail.com> +**James M Snell** <jasnell@gmail.com> (he/him) * [mhdawson](https://github.com/mhdawson) - -**Michael Dawson** <michael_dawson@ca.ibm.com> +**Michael Dawson** <michael_dawson@ca.ibm.com> (he/him) * [misterdjules](https://github.com/misterdjules) - **Julien Gilli** <jgilli@nodejs.org> * [mscdex](https://github.com/mscdex) - **Brian White** <mscdex@mscdex.net> * [MylesBorins](https://github.com/MylesBorins) - -**Myles Borins** <myles.borins@gmail.com> +**Myles Borins** <myles.borins@gmail.com> (he/him) * [ofrobots](https://github.com/ofrobots) - **Ali Ijaz Sheikh** <ofrobots@google.com> * [rvagg](https://github.com/rvagg) - **Rod Vagg** <rod@vagg.org> * [shigeki](https://github.com/shigeki) - -**Shigeki Ohtsu** <ohtsu@iij.ad.jp> +**Shigeki Ohtsu** <ohtsu@iij.ad.jp> (he/him) * [targos](https://github.com/targos) - -**Michaël Zasso** <targos@protonmail.com> +**Michaël Zasso** <targos@protonmail.com> (he/him) * [thefourtheye](https://github.com/thefourtheye) - -**Sakthipriyan Vairamani** <thechargingvolcano@gmail.com> +**Sakthipriyan Vairamani** <thechargingvolcano@gmail.com> (he/him) * [trevnorris](https://github.com/trevnorris) - **Trevor Norris** <trev.norris@gmail.com> * [Trott](https://github.com/Trott) - -**Rich Trott** <rtrott@gmail.com> +**Rich Trott** <rtrott@gmail.com> (he/him) ### Collaborators +* [abouthiroppy](https://github.com/abouthiroppy) - +**Yuta Hiroto** <hello@about-hiroppy.com> (he/him) * [ak239](https://github.com/ak239) - **Aleksei Koziatinskii** <ak239spb@gmail.com> * [andrasq](https://github.com/andrasq) - **Andras** <andras@kinvey.com> * [AndreasMadsen](https://github.com/AndreasMadsen) - -**Andreas Madsen** <amwebdk@gmail.com> +**Andreas Madsen** <amwebdk@gmail.com> (he/him) * [bengl](https://github.com/bengl) - -**Bryan English** <bryan@bryanenglish.com> +**Bryan English** <bryan@bryanenglish.com> (he/him) * [benjamingr](https://github.com/benjamingr) - **Benjamin Gruenbaum** <benjamingr@gmail.com> * [bmeck](https://github.com/bmeck) - @@ -215,12 +215,14 @@ more information about the governance of the Node.js project, see **Bartosz Sosnowski** <bartosz@janeasystems.com> * [calvinmetcalf](https://github.com/calvinmetcalf) - **Calvin Metcalf** <calvin.metcalf@gmail.com> +* [chrisdickinson](https://github.com/chrisdickinson) - +**Chris Dickinson** <christopher.s.dickinson@gmail.com> * [claudiorodriguez](https://github.com/claudiorodriguez) - **Claudio Rodriguez** <cjrodr@yahoo.com> * [danbev](https://github.com/danbev) - **Daniel Bevenius** <daniel.bevenius@gmail.com> * [edsadr](https://github.com/edsadr) - -**Adrian Estrada** <edsadr@gmail.com> +**Adrian Estrada** <edsadr@gmail.com> (he/him) * [eljefedelrodeodeljefe](https://github.com/eljefedelrodeodeljefe) - **Robert Jefe Lindstaedt** <robert.lindstaedt@gmail.com> * [estliberitas](https://github.com/estliberitas) - @@ -234,7 +236,7 @@ more information about the governance of the Node.js project, see * [geek](https://github.com/geek) - **Wyatt Preul** <wpreul@gmail.com> * [gibfahn](https://github.com/gibfahn) - -**Gibson Fahnestock** <gibfahn@gmail.com> +**Gibson Fahnestock** <gibfahn@gmail.com> (he/him) * [iarna](https://github.com/iarna) - **Rebecca Turner** <me@re-becca.org> * [imyller](https://github.com/imyller) - @@ -242,7 +244,7 @@ more information about the governance of the Node.js project, see * [isaacs](https://github.com/isaacs) - **Isaac Z. Schlueter** <i@izs.me> * [italoacasas](https://github.com/italoacasas) - -**Italo A. Casas** <me@italoacasas.com> +**Italo A. Casas** <me@italoacasas.com> (he/him) * [iWuzHere](https://github.com/iWuzHere) - **Imran Iqbal** <imran@imraniqbal.org> * [JacksonTian](https://github.com/JacksonTian) - @@ -256,23 +258,23 @@ more information about the governance of the Node.js project, see * [joshgav](https://github.com/joshgav) - **Josh Gavant** <josh.gavant@outlook.com> * [joyeecheung](https://github.com/joyeecheung) - -**Joyee Cheung** <joyeec9h3@gmail.com> +**Joyee Cheung** <joyeec9h3@gmail.com> (she/her) * [julianduque](https://github.com/julianduque) - -**Julian Duque** <julianduquej@gmail.com> +**Julian Duque** <julianduquej@gmail.com> (he/him) * [JungMinu](https://github.com/JungMinu) - -**Minwoo Jung** <jmwsoft@gmail.com> +**Minwoo Jung** <minwoo@nodesource.com> (he/him) * [lance](https://github.com/lance) - **Lance Ball** <lball@redhat.com> * [lpinca](https://github.com/lpinca) - -**Luigi Pinca** <luigipinca@gmail.com> +**Luigi Pinca** <luigipinca@gmail.com> (he/him) * [lxe](https://github.com/lxe) - **Aleksey Smolenchuk** <lxe@lxe.co> * [matthewloring](https://github.com/matthewloring) - **Matthew Loring** <mattloring@google.com> * [mcollina](https://github.com/mcollina) - -**Matteo Collina** <matteo.collina@gmail.com> +**Matteo Collina** <matteo.collina@gmail.com> (he/him) * [micnic](https://github.com/micnic) - -**Nicu Micleușanu** <micnic90@gmail.com> +**Nicu Micleușanu** <micnic90@gmail.com> (he/him) * [mikeal](https://github.com/mikeal) - **Mikeal Rogers** <mikeal.rogers@gmail.com> * [monsanto](https://github.com/monsanto) - @@ -284,7 +286,7 @@ more information about the governance of the Node.js project, see * [orangemocha](https://github.com/orangemocha) - **Alexis Campailla** <orangemocha@nodejs.org> * [othiym23](https://github.com/othiym23) - -**Forrest L Norvell** <ogd@aoaioxxysz.net> +**Forrest L Norvell** <ogd@aoaioxxysz.net> (he/him) * [petkaantonov](https://github.com/petkaantonov) - **Petka Antonov** <petka_antonov@hotmail.com> * [phillipj](https://github.com/phillipj) - @@ -296,7 +298,7 @@ more information about the governance of the Node.js project, see * [princejwesley](https://github.com/princejwesley) - **Prince John Wesley** <princejohnwesley@gmail.com> * [qard](https://github.com/qard) - -**Stephen Belanger** <admin@stephenbelanger.com> +**Stephen Belanger** <admin@stephenbelanger.com> (he/him) * [rlidwka](https://github.com/rlidwka) - **Alex Kocharin** <alex@kocharin.ru> * [rmg](https://github.com/rmg) - @@ -326,13 +328,17 @@ more information about the governance of the Node.js project, see * [tellnes](https://github.com/tellnes) - **Christian Tellnes** <christian@tellnes.no> * [thekemkid](https://github.com/thekemkid) - -**Glen Keane** <glenkeane.94@gmail.com> +**Glen Keane** <glenkeane.94@gmail.com> (he/him) * [thlorenz](https://github.com/thlorenz) - **Thorsten Lorenz** <thlorenz@gmx.de> +* [TimothyGu](https://github.com/TimothyGu) - +**Timothy Gu** <timothygu99@gmail.com> (he/him) * [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe** <m.j.tunnicliffe@gmail.com> * [vkurchatkin](https://github.com/vkurchatkin) - **Vladimir Kurchatkin** <vladimir.kurchatkin@gmail.com> +* [watilde](https://github.com/watilde) - +**Daijiro Wachi** <daijiro.wachi@gmail.com> (he/him) * [whitlockjc](https://github.com/whitlockjc) - **Jeremy Whitlock** <jwhitlock@apache.org> * [yorkie](https://github.com/yorkie) - @@ -346,14 +352,14 @@ project. ### Release Team -Releases of Node.js and io.js will be signed with one of the following GPG keys: +Node.js releases are signed with one of the following GPG keys: -* **Chris Dickinson** <christopher.s.dickinson@gmail.com> -`9554F04D7259F04124DE6B476D5A82AC7E37093B` * **Colin Ihrig** <cjihrig@gmail.com> `94AE36675C464D64BAFA68DD7434390BDBE9B9C5` * **Evan Lucas** <evanlucas@me.com> `B9AE9905FFD7803F25714661B63B535A4C206CA9` +* **Italo A. Casas** <me@italoacasas.com> +`56730D5401028683275BD23C23EFEFE93C4CFFFE` * **James M Snell** <jasnell@keybase.io> `71DCFD284A79C3B38668286BC97EC7A07EDE3FC1` * **Jeremiah Senkpiel** <fishrock@keybase.io> @@ -366,21 +372,22 @@ Releases of Node.js and io.js will be signed with one of the following GPG keys: The full set of trusted release keys can be imported by running: ```shell -gpg --keyserver pool.sks-keyservers.net --recv-keys 9554F04D7259F04124DE6B476D5A82AC7E37093B gpg --keyserver pool.sks-keyservers.net --recv-keys 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 gpg --keyserver pool.sks-keyservers.net --recv-keys FD3A5288F042B6850C66B31F09FE44734EB7990E gpg --keyserver pool.sks-keyservers.net --recv-keys 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 gpg --keyserver pool.sks-keyservers.net --recv-keys DD8F2338BAE7501E3DD5AC78C273792F7D83545D gpg --keyserver pool.sks-keyservers.net --recv-keys C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 gpg --keyserver pool.sks-keyservers.net --recv-keys B9AE9905FFD7803F25714661B63B535A4C206CA9 +gpg --keyserver pool.sks-keyservers.net --recv-keys 56730D5401028683275BD23C23EFEFE93C4CFFFE ``` See the section above on [Verifying Binaries](#verifying-binaries) for details on what to do with these keys to verify that a downloaded file is official. -Previous releases of Node.js have been signed with one of the following GPG -keys: +Previous releases may also have been signed with one of the following GPG keys: +* **Chris Dickinson** <christopher.s.dickinson@gmail.com> +`9554F04D7259F04124DE6B476D5A82AC7E37093B` * **Isaac Z. Schlueter** <i@izs.me> `93C7E9E91B49E432C2F75674B0A78B0A6C481CF6` * **Julien Gilli** <jgilli@fastmail.fm> @@ -388,6 +395,11 @@ keys: * **Timothy J Fontaine** <tjfontaine@gmail.com> `7937DFD2AB06298B2293C3187D33FF9D0246406D` +### Working Groups + +Information on the current Node.js Working Groups can be found in the +[CTC repository](https://github.com/nodejs/CTC/blob/master/WORKING_GROUPS.md). + [npm]: https://www.npmjs.com [Website]: https://nodejs.org/en/ [Contributing to the project]: CONTRIBUTING.md diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index da8e47941916cc..00000000000000 --- a/ROADMAP.md +++ /dev/null @@ -1,84 +0,0 @@ -# Node.js Roadmap - -***This is a living document, it describes the policy and priorities as they exist today but can evolve over time.*** - -## Stability Policy - -The most important consideration in every code change is the impact it will have, positive or negative, on the ecosystem (modules and applications). - -Node.js does not remove stdlib JS API. - -Shipping with current and well supported dependencies is the best way to ensure long term stability of the platform. - -Node.js will continue to adopt new V8 releases. -* When V8 ships a breaking change to their C++ API that can be handled by [`nan`](https://github.com/nodejs/nan) -the *minor* version of Node.js will be increased. -* When V8 ships a breaking change to their C++ API that can NOT be handled by [`nan`](https://github.com/nodejs/nan) -the *major* version of Node.js will be increased. -* When new features in the JavaScript language are introduced by V8 the -*minor* version number will be increased. TC39 has stated clearly that no -backwards incompatible changes will be made to the language so it is -appropriate to increase the minor rather than major. - -No new API will be added in *patch* releases. - -Any API addition will cause an increase in the *minor* version. - -## Channels - -Channels are points of collaboration with the broader community and are not strictly scoped to a repository or branch. - -* Release - Stable production ready builds. Unique version numbers following semver. -* Canary - Nightly builds w/ V8 version in Chrome Canary + changes landing to Node.js. No version designation. -* NG - "Next Generation." No version designation. - -## NG (Next Generation) - -In order for Node.js to stay competitive we need to work on the next generation of the platform which will more accurately integrate and reflect the advancements in the language and the ecosystem. - -While this constitutes a great leap forward for the platform we will be making this leap without breaking backwards compatibility with the existing ecosystem of modules. - -## Immediate Priorities - -### Debugging and Tracing - -Debugging is one of the first things from everyone's mouth, both developer and enterprise, when describing trouble they've had with Node.js. - -The goal of Node.js' effort is to build a healthy debugging and tracing ecosystem and not to try and build any "silver bullet" features for core (like the domains debacle). - -The [Tracing WG](https://github.com/nodejs/tracing-wg) is driving this effort: - -* AsyncWrap improvements - basically just iterations based on feedback from people using it. -* async-listener - userland module that will dogfood AsyncWrap as well as provide many often requested debugging features. -* Tracing - * Add tracing support for more platforms (LTTng, etc). - * [Unify the Tracing endpoint](https://github.com/nodejs/node/issues/729). - * New Chrome Debugger - Google is working on a version of Chrome's debugger that is without Chrome and can be used with Node.js. - -### Ecosystem Automation - -In order to maintain a good release cadence without harming compatibility we must do a better job of understanding exactly what impact a particular change or release will have on the ecosystem. This requires new automation. - -The initial goals for this automation are relatively simple but will create a baseline toolchain we can continue to improve upon. - -* Produce a list of modules that no longer build between two release versions. -* Produce a list of modules that use a particular core API. -* Produce detailed code coverage data for the tests in core. - -### Improve Installation and Upgrades - -* Host and maintain registry endpoints (Homebrew, apt, etc). -* Document installation and upgrade procedures with an emphasis on using nvm or nave for development and our registry endpoints for traditional package managers and production. - -### Streams - -* Fix all existing compatibility issues. -* Simplify stream creation to avoid user error. -* Explore and identify compatibility issues with [WHATWG Streams](https://github.com/whatwg/streams). -* Improve stream performance. - -### Internationalization / Localization - -* Build documentation tooling with localization support built in. -* Reduce size of ICU and ship with it by default. -* Continue growth of our i18n community. diff --git a/WORKING_GROUPS.md b/WORKING_GROUPS.md deleted file mode 100644 index 6ba06c9cafa697..00000000000000 --- a/WORKING_GROUPS.md +++ /dev/null @@ -1,281 +0,0 @@ -# Node.js Core Working Groups - -Node.js Core Working Groups are autonomous projects created by the -[Core Technical Committee (CTC)](https://github.com/nodejs/node/blob/master/GOVERNANCE.md#core-technical-committee). - -Working Groups can be formed at any time but must be ratified by the CTC. -Once formed the work defined in the Working Group charter is the -responsibility of the WG rather than the CTC. - -It is important that Working Groups are not formed pre-maturely. Working -Groups are not formed to *begin* a set of tasks but instead are formed -once that work is already underway and the contributors -think it would benefit from being done as an autonomous project. - -If the work defined in a Working Group's charter is complete, the charter -should be revoked. - -A Working Group's charter can be revoked either by consensus of the Working -Group's members or by a CTC vote. Once revoked, any future work that arises -becomes the responsibility of the CTC. - -## Joining a WG - -To find out how to join a working group, consult the GOVERNANCE.md in -the working group's repository, or in the working group's repository. - -## Starting A Core Working Group - -The process to start a Core Working Group is identical to [creating a -Top Level Working Group](https://github.com/nodejs/TSC/blob/master/WORKING_GROUPS.md#starting-a-wg). - -## Current Working Groups - -* [Website](#website) -* [Streams](#streams) -* [Build](#build) -* [Diagnostics](#diagnostics) -* [i18n](#i18n) -* [Evangelism](#evangelism) -* [Docker](#docker) -* [Addon API](#addon-api) -* [Benchmarking](#benchmarking) -* [Post-mortem](#post-mortem) -* [Intl](#intl) -* [Documentation](#documentation) -* [Testing](#testing) - - -### [Website](https://github.com/nodejs/nodejs.org) - -The website Working Group's purpose is to build and maintain a public -website for the Node.js project. - -Responsibilities include: -* Developing and maintaining a build and automation system for nodejs.org. -* Ensuring the site is regularly updated with changes made to Node.js, like - releases and features. -* Fostering and enabling a community of translators. - -### [Streams](https://github.com/nodejs/readable-stream) - -The Streams Working Group is dedicated to the support and improvement of the -Streams API as used in Node.js and the npm ecosystem. We seek to create a -composable API that solves the problem of representing multiple occurrences -of an event over time in a humane, low-overhead fashion. Improvements to the -API will be driven by the needs of the ecosystem; interoperability and -backwards compatibility with other solutions and prior versions are paramount -in importance. - -Responsibilities include: -* Addressing stream issues on the Node.js issue tracker. -* Authoring and editing stream documentation within the Node.js project. -* Reviewing changes to stream subclasses within the Node.js project. -* Redirecting changes to streams from the Node.js project to this project. -* Assisting in the implementation of stream providers within Node.js. -* Recommending versions of `readable-stream` to be included in Node.js. -* Messaging about the future of streams to give the community advance notice of - changes. - -### [Build](https://github.com/nodejs/build) - -The Build Working Group's purpose is to create and maintain a distributed -automation infrastructure. - -Responsibilities include: -* Producing packages for all target platforms. -* Running tests. -* Running performance testing and comparisons. -* Creating and managing build-containers. - -### [Diagnostics](https://github.com/nodejs/diagnostics) - -The Diagnostics Working Group's purpose is to surface a set of comprehensive, -documented, and extensible diagnostic interfaces for use by Node.js tools and -JavaScript VMs. - -Responsibilities include: -* Collaborating with V8 to integrate `v8_inspector` into Node.js. -* Collaborating with V8 to integrate `trace_event` into Node.js. -* Collaborating with Core to refine `async_wrap` and `async_hooks`. -* Maintaining and improving OS trace system integration (e.g. ETW, LTTNG, dtrace). -* Documenting diagnostic capabilities and APIs in Node.js and its components. -* Exploring opportunities and gaps, discussing feature requests, and addressing - conflicts in Node.js diagnostics. -* Fostering an ecosystem of diagnostics tools for Node.js. - -### i18n - -The i18n Working Groups handle more than just translations. They -are endpoints for community members to collaborate with each -other in their language of choice. - -Each team is organized around a common spoken language. Each -language community might then produce multiple localizations for -various project resources. - -Responsibilities include: -* Translating any Node.js materials they believe are relevant to their - community. -* Reviewing processes for keeping translations up to date and of high quality. -* Managing and monitoring social media channels in their language. -* Promoting Node.js speakers for meetups and conferences in their language. - -Note that the i18n Working Groups are distinct from the [Intl](#Intl) Working Group. - -Each language community maintains its own membership. - -* [nodejs-ar - Arabic (اللغة العربية)](https://github.com/nodejs/nodejs-ar) -* [nodejs-bg - Bulgarian (български език)](https://github.com/nodejs/nodejs-bg) -* [nodejs-bn - Bengali (বাংলা)](https://github.com/nodejs/nodejs-bn) -* [nodejs-zh-CN - Chinese (中文)](https://github.com/nodejs/nodejs-zh-CN) -* [nodejs-cs - Czech (Český Jazyk)](https://github.com/nodejs/nodejs-cs) -* [nodejs-da - Danish (Dansk)](https://github.com/nodejs/nodejs-da) -* [nodejs-de - German (Deutsch)](https://github.com/nodejs/nodejs-de) -* [nodejs-el - Greek (Ελληνικά)](https://github.com/nodejs/nodejs-el) -* [nodejs-es - Spanish (Español)](https://github.com/nodejs/nodejs-es) -* [nodejs-fa - Persian (فارسی)](https://github.com/nodejs/nodejs-fa) -* [nodejs-fi - Finnish (Suomi)](https://github.com/nodejs/nodejs-fi) -* [nodejs-fr - French (Français)](https://github.com/nodejs/nodejs-fr) -* [nodejs-he - Hebrew (עברית)](https://github.com/nodejs/nodejs-he) -* [nodejs-hi - Hindi (फिजी बात)](https://github.com/nodejs/nodejs-hi) -* [nodejs-hu - Hungarian (Magyar)](https://github.com/nodejs/nodejs-hu) -* [nodejs-id - Indonesian (Bahasa Indonesia)](https://github.com/nodejs/nodejs-id) -* [nodejs-it - Italian (Italiano)](https://github.com/nodejs/nodejs-it) -* [nodejs-ja - Japanese (日本語)](https://github.com/nodejs/nodejs-ja) -* [nodejs-ka - Georgian (ქართული)](https://github.com/nodejs/nodejs-ka) -* [nodejs-ko - Korean (조선말)](https://github.com/nodejs/nodejs-ko) -* [nodejs-mk - Macedonian (Mакедонски)](https://github.com/nodejs/nodejs-mk) -* [nodejs-ms - Malay (بهاس ملايو)](https://github.com/nodejs/nodejs-ms) -* [nodejs-nl - Dutch (Nederlands)](https://github.com/nodejs/nodejs-nl) -* [nodejs-no - Norwegian (Norsk)](https://github.com/nodejs/nodejs-no) -* [nodejs-pl - Polish (Język Polski)](https://github.com/nodejs/nodejs-pl) -* [nodejs-pt - Portuguese (Português)](https://github.com/nodejs/nodejs-pt) -* [nodejs-ro - Romanian (Română)](https://github.com/nodejs/nodejs-ro) -* [nodejs-ru - Russian (Русский)](https://github.com/nodejs/nodejs-ru) -* [nodejs-sv - Swedish (Svenska)](https://github.com/nodejs/nodejs-sv) -* [nodejs-ta - Tamil (தமிழ்)](https://github.com/nodejs/nodejs-ta) -* [nodejs-tr - Turkish (Türkçe)](https://github.com/nodejs/nodejs-tr) -* [nodejs-zh-TW - Taiwanese (Hō-ló)](https://github.com/nodejs/nodejs-zh-TW) -* [nodejs-uk - Ukrainian (Українська)](https://github.com/nodejs/nodejs-uk) -* [nodejs-vi - Vietnamese (Tiếng Việtnam)](https://github.com/nodejs/nodejs-vi) - -### [Intl](https://github.com/nodejs/Intl) - -The Intl Working Group is dedicated to support and improvement of -Internationalization (i18n) and Localization (l10n) in Node. - -Responsibilities include: -* Ensuring functionality & compliance (standards: ECMA, Unicode…) -* Supporting Globalization and Internationalization issues that come up - in the tracker -* Communicating guidance and best practices -* Refining the existing `Intl` implementation - -The Intl Working Group is not responsible for translation of content. That is the -responsibility of the specific [i18n](#i18n) group for each language. - -### [Evangelism](https://github.com/nodejs/evangelism) - -The Evangelism Working Group promotes the accomplishments -of Node.js and lets the community know how they can get involved. - -Responsibilities include: -* Facilitating project messaging. -* Managing official project social media. -* Handling the promotion of speakers for meetups and conferences. -* Handling the promotion of community events. -* Publishing regular update summaries and other promotional - content. - -### [Docker](https://github.com/nodejs/docker-iojs) - -The Docker Working Group's purpose is to build, maintain, and improve official -Docker images for the Node.js project. - -Responsibilities include: -* Keeping the official Docker images updated in line with new Node.js releases. -* Decide and implement image improvements and/or fixes. -* Maintain and improve the images' documentation. - -### [Addon API](https://github.com/nodejs/nan) - -The Addon API Working Group is responsible for maintaining the NAN project and -corresponding _nan_ package in npm. The NAN project makes available an -abstraction layer for native add-on authors for Node.js, -assisting in the writing of code that is compatible with many actively used -versions of Node.js, V8 and libuv. - -Responsibilities include: -* Maintaining the [NAN](https://github.com/nodejs/nan) GitHub repository, - including code, issues and documentation. -* Maintaining the [addon-examples](https://github.com/nodejs/node-addon-examples) - GitHub repository, including code, issues and documentation. -* Maintaining the C++ Addon API within the Node.js project, in subordination to - the Node.js CTC. -* Maintaining the Addon documentation within the Node.js project, in - subordination to the Node.js CTC. -* Maintaining the _nan_ package in npm, releasing new versions as appropriate. -* Messaging about the future of the Node.js and NAN interface to give the - community advance notice of changes. - -The current members can be found in their -[README](https://github.com/nodejs/nan#collaborators). - -### [Benchmarking](https://github.com/nodejs/benchmarking) - -The purpose of the Benchmark Working Group is to gain consensus -on an agreed set of benchmarks that can be used to: - -* track and evangelize performance gains made between Node.js releases -* avoid performance regressions between releases - -Responsibilities include: -* Identifying 1 or more benchmarks that reflect customer usage. - Likely will need more than one to cover typical Node.js use cases - including low-latency and high concurrency -* Working to get community consensus on the list chosen -* Adding regular execution of chosen benchmarks to Node.js builds -* Tracking/publicizing performance between builds/releases - -### [Post-mortem](https://github.com/nodejs/post-mortem) - -The Post-mortem Diagnostics Working Group is dedicated to the support -and improvement of postmortem debugging for Node.js. It seeks to -elevate the role of postmortem debugging for Node, to assist in the -development of techniques and tools, and to make techniques and tools -known and available to Node.js users. - -Responsibilities include: -* Defining and adding interfaces/APIs in order to allow dumps - to be generated when needed. -* Defining and adding common structures to the dumps generated - in order to support tools that want to introspect those dumps. - -### [Documentation](https://github.com/nodejs/docs) - -The Documentation Working Group exists to support the improvement of Node.js -documentation, both in the core API documentation, and elsewhere, such as the -Node.js website. Its intent is to work closely with the Evangelism, Website, and -Intl Working Groups to make excellent documentation available and accessible -to all. - -Responsibilities include: -* Defining and maintaining documentation style and content standards. -* Producing documentation in a format acceptable for the Website Working Group - to consume. -* Ensuring that Node's documentation addresses a wide variety of audiences. -* Creating and operating a process for documentation review that produces - quality documentation and avoids impeding the progress of Core work. - -### [Testing](https://github.com/nodejs/testing) - -The Node.js Testing Working Group's purpose is to extend and improve testing of -the Node.js source code. - -Responsibilities include: -* Coordinating an overall strategy for improving testing. -* Documenting guidelines around tests. -* Working with the Build Working Group to improve continuous integration. -* Improving tooling for testing. - diff --git a/benchmark/README.md b/benchmark/README.md index 8796e1e7b6ad38..17c733e6eb0b6c 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -1,417 +1,237 @@ -# Node.js core benchmark +# Node.js Core Benchmarks + +This folder contains code and data used to measure performance +of different Node.js implementations and different ways of +writing JavaScript run by the built-in JavaScript engine. + +For a detailed guide on how to write and run benchmarks in this +directory, see [the guide on benchmarks](../doc/guides/writing-and-running-benchmarks.md). + +## Table of Contents + +* [Benchmark directories](#benchmark-directories) +* [Common API](#common-api) + +## Benchmark Directories + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryPurpose
arrays + Benchmarks for various operations on array-like objects, + including Array, Buffer, and typed arrays. +
assert + Benchmarks for the assert subsystem. +
buffers + Benchmarks for the buffer subsystem. +
child_process + Benchmarks for the child_process subsystem. +
crypto + Benchmarks for the crypto subsystem. +
dgram + Benchmarks for the dgram subsystem. +
domain + Benchmarks for the domain subsystem. +
es + Benchmarks for various new ECMAScript features and their + pre-ES2015 counterparts. +
events + Benchmarks for the events subsystem. +
fixtures + Benchmarks fixtures used in various benchmarks throughout + the benchmark suite. +
fs + Benchmarks for the fs subsystem. +
http + Benchmarks for the http subsystem. +
misc + Miscellaneous benchmarks and benchmarks for shared + internal modules. +
module + Benchmarks for the module subsystem. +
net + Benchmarks for the net subsystem. +
path + Benchmarks for the path subsystem. +
process + Benchmarks for the process subsystem. +
querystring + Benchmarks for the querystring subsystem. +
streams + Benchmarks for the streams subsystem. +
string_decoder + Benchmarks for the string_decoder subsystem. +
timers + Benchmarks for the timers subsystem, including + setTimeout, setInterval, .etc. +
tls + Benchmarks for the tls subsystem. +
url + Benchmarks for the url subsystem, including the legacy + url implementation and the WHATWG URL implementation. +
util + Benchmarks for the util subsystem. +
vm + Benchmarks for the vm subsystem. +
+ +### Other Top-level files + +The top-level files include common dependencies of the benchmarks +and the tools for launching benchmarks and visualizing their output. +The actual benchmark scripts should be placed in their corresponding +directories. + +* `_benchmark_progress.js`: implements the progress bar displayed + when running `compare.js` +* `_cli.js`: parses the command line arguments passed to `compare.js`, + `run.js` and `scatter.js` +* `_cli.R`: parses the command line arguments passed to `compare.R` +* `_http-benchmarkers.js`: selects and runs external tools for benchmarking + the `http` subsystem. +* `common.js`: see [Common API](#common-api). +* `compare.js`: command line tool for comparing performance between different + Node.js binaries. +* `compare.R`: R script for statistically analyzing the output of + `compare.js` +* `run.js`: command line tool for running individual benchmark suite(s). +* `scatter.js`: command line tool for comparing the performance + between different parameters in benchmark configurations, + for example to analyze the time complexity. +* `scatter.R`: R script for visualizing the output of `scatter.js` with + scatter plots. + +## Common API + +The common.js module is used by benchmarks for consistency across repeated +tasks. It has a number of helpful functions and properties to help with +writing benchmarks. + +### createBenchmark(fn, configs[, options]) + +See [the guide on writing benchmarks](../doc/guides/writing-and-running-benchmarks.md#basics-of-a-benchmark). + +### default\_http\_benchmarker + +The default benchmarker used to run HTTP benchmarks. +See [the guide on writing HTTP benchmarks](../doc/guides/writing-and-running-benchmarks.md#creating-an-http-benchmark). + + +### PORT + +The default port used to run HTTP benchmarks. +See [the guide on writing HTTP benchmarks](../doc/guides/writing-and-running-benchmarks.md#creating-an-http-benchmark). + +### sendResult(data) + +Used in special benchmarks that can't use `createBenchmark` and the object +it returns to accomplish what they need. This function reports timing +data to the parent process (usually created by running `compare.js`, `run.js` or +`scatter.js`). -This folder contains benchmarks to measure the performance of the Node.js APIs. - -## Table of Content - -* [Prerequisites](#prerequisites) -* [Running benchmarks](#running-benchmarks) - * [Running individual benchmarks](#running-individual-benchmarks) - * [Running all benchmarks](#running-all-benchmarks) - * [Comparing node versions](#comparing-node-versions) - * [Comparing parameters](#comparing-parameters) -* [Creating a benchmark](#creating-a-benchmark) - -## Prerequisites - -Most of the HTTP benchmarks require a benchmarker to be installed, this can be -either [`wrk`][wrk] or [`autocannon`][autocannon]. - -`Autocannon` is a Node script that can be installed using -`npm install -g autocannon`. It will use the Node executable that is in the -path, hence if you want to compare two HTTP benchmark runs make sure that the -Node version in the path is not altered. - -`wrk` may be available through your preferred package manger. If not, you can -easily build it [from source][wrk] via `make`. - -By default `wrk` will be used as benchmarker. If it is not available -`autocannon` will be used in it its place. When creating a HTTP benchmark you -can specify which benchmarker should be used. You can force a specific -benchmarker to be used by providing it as an argument, e. g.: - -`node benchmark/run.js --set benchmarker=autocannon http` - -`node benchmark/http/simple.js benchmarker=autocannon` - -Basic Unix tools are required for some benchmarks. -[Git for Windows][git-for-windows] includes Git Bash and the necessary tools, -which need to be included in the global Windows `PATH`. - -To analyze the results `R` should be installed. Check you package manager or -download it from https://www.r-project.org/. - -The R packages `ggplot2` and `plyr` are also used and can be installed using -the R REPL. - -```R -$ R -install.packages("ggplot2") -install.packages("plyr") -``` - -### CRAN Mirror Issues -In the event you get a message that you need to select a CRAN mirror first. - -You can specify a mirror by adding in the repo parameter. - -If we used the "http://cran.us.r-project.org" mirror, it could look somehting like -this: - -```R -install.packages("ggplot2", repo="http://cran.us.r-project.org") -``` - -Of course, use the mirror that suits your location. -A list of mirrors is [located here](https://cran.r-project.org/mirrors.html). - -## Running benchmarks - -### Running individual benchmarks - -This can be useful for debugging a benchmark or doing a quick performance -measure. But it does not provide the statistical information to make any -conclusions about the performance. - -Individual benchmarks can be executed by simply executing the benchmark script -with node. - -```console -$ node benchmark/buffers/buffer-tostring.js - -buffers/buffer-tostring.js n=10000000 len=0 arg=true: 62710590.393305704 -buffers/buffer-tostring.js n=10000000 len=1 arg=true: 9178624.591787899 -buffers/buffer-tostring.js n=10000000 len=64 arg=true: 7658962.8891432695 -buffers/buffer-tostring.js n=10000000 len=1024 arg=true: 4136904.4060201733 -buffers/buffer-tostring.js n=10000000 len=0 arg=false: 22974354.231509723 -buffers/buffer-tostring.js n=10000000 len=1 arg=false: 11485945.656765845 -buffers/buffer-tostring.js n=10000000 len=64 arg=false: 8718280.70650129 -buffers/buffer-tostring.js n=10000000 len=1024 arg=false: 4103857.0726124765 -``` - -Each line represents a single benchmark with parameters specified as -`${variable}=${value}`. Each configuration combination is executed in a separate -process. This ensures that benchmark results aren't affected by the execution -order due to v8 optimizations. **The last number is the rate of operations -measured in ops/sec (higher is better).** - -Furthermore you can specify a subset of the configurations, by setting them in -the process arguments: - -```console -$ node benchmark/buffers/buffer-tostring.js len=1024 - -buffers/buffer-tostring.js n=10000000 len=1024 arg=true: 3498295.68561504 -buffers/buffer-tostring.js n=10000000 len=1024 arg=false: 3783071.1678948295 -``` - -### Running all benchmarks - -Similar to running individual benchmarks, a group of benchmarks can be executed -by using the `run.js` tool. Again this does not provide the statistical -information to make any conclusions. - -```console -$ node benchmark/run.js arrays - -arrays/var-int.js -arrays/var-int.js n=25 type=Array: 71.90148040747789 -arrays/var-int.js n=25 type=Buffer: 92.89648382795582 -... - -arrays/zero-float.js -arrays/zero-float.js n=25 type=Array: 75.46208316171496 -arrays/zero-float.js n=25 type=Buffer: 101.62785630273159 -... - -arrays/zero-int.js -arrays/zero-int.js n=25 type=Array: 72.31023859816062 -arrays/zero-int.js n=25 type=Buffer: 90.49906662339653 -... -``` - -It is possible to execute more groups by adding extra process arguments. -```console -$ node benchmark/run.js arrays buffers -``` - -### Comparing node versions - -To compare the effect of a new node version use the `compare.js` tool. This -will run each benchmark multiple times, making it possible to calculate -statistics on the performance measures. - -As an example on how to check for a possible performance improvement, the -[#5134](https://github.com/nodejs/node/pull/5134) pull request will be used as -an example. This pull request _claims_ to improve the performance of the -`string_decoder` module. - -First build two versions of node, one from the master branch (here called -`./node-master`) and another with the pull request applied (here called -`./node-pr-5135`). - -The `compare.js` tool will then produce a csv file with the benchmark results. - -```console -$ node benchmark/compare.js --old ./node-master --new ./node-pr-5134 string_decoder > compare-pr-5134.csv -``` - -For analysing the benchmark results use the `compare.R` tool. - -```console -$ cat compare-pr-5134.csv | Rscript benchmark/compare.R - - improvement confidence p.value -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=1024 encoding=ascii 12.46 % *** 1.165345e-04 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=1024 encoding=base64-ascii 24.70 % *** 1.820615e-15 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=1024 encoding=base64-utf8 23.60 % *** 2.105625e-12 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=1024 encoding=utf8 14.04 % *** 1.291105e-07 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=128 encoding=ascii 6.70 % * 2.928003e-02 -... -``` - -In the output, _improvement_ is the relative improvement of the new version, -hopefully this is positive. _confidence_ tells if there is enough -statistical evidence to validate the _improvement_. If there is enough evidence -then there will be at least one star (`*`), more stars is just better. **However -if there are no stars, then you shouldn't make any conclusions based on the -_improvement_.** Sometimes this is fine, for example if you are expecting there -to be no improvements, then there shouldn't be any stars. - -**A word of caution:** Statistics is not a foolproof tool. If a benchmark shows -a statistical significant difference, there is a 5% risk that this -difference doesn't actually exists. For a single benchmark this is not an -issue. But when considering 20 benchmarks it's normal that one of them -will show significance, when it shouldn't. A possible solution is to instead -consider at least two stars (`**`) as the threshold, in that case the risk -is 1%. If three stars (`***`) is considered the risk is 0.1%. However this -may require more runs to obtain (can be set with `--runs`). - -_For the statistically minded, the R script performs an [independent/unpaired -2-group t-test][t-test], with the null hypothesis that the performance is the -same for both versions. The confidence field will show a star if the p-value -is less than `0.05`._ - -The `compare.R` tool can also produce a box plot by using the `--plot filename` -option. In this case there are 48 different benchmark combinations, thus you -may want to filter the csv file. This can be done while benchmarking using the -`--set` parameter (e.g. `--set encoding=ascii`) or by filtering results -afterwards using tools such as `sed` or `grep`. In the `sed` case be sure to -keep the first line since that contains the header information. - -```console -$ cat compare-pr-5134.csv | sed '1p;/encoding=ascii/!d' | Rscript benchmark/compare.R --plot compare-plot.png - - improvement confidence p.value -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=1024 encoding=ascii 12.46 % *** 1.165345e-04 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=128 encoding=ascii 6.70 % * 2.928003e-02 -string_decoder/string-decoder.js n=250000 chunk=1024 inlen=32 encoding=ascii 7.47 % *** 5.780583e-04 -string_decoder/string-decoder.js n=250000 chunk=16 inlen=1024 encoding=ascii 8.94 % *** 1.788579e-04 -string_decoder/string-decoder.js n=250000 chunk=16 inlen=128 encoding=ascii 10.54 % *** 4.016172e-05 -... -``` - -![compare tool boxplot](doc_img/compare-boxplot.png) - -### Comparing parameters - -It can be useful to compare the performance for different parameters, for -example to analyze the time complexity. - -To do this use the `scatter.js` tool, this will run a benchmark multiple times -and generate a csv with the results. - -```console -$ node benchmark/scatter.js benchmark/string_decoder/string-decoder.js > scatter.csv -``` - -After generating the csv, a comparison table can be created using the -`scatter.R` tool. Even more useful it creates an actual scatter plot when using -the `--plot filename` option. - -```console -$ cat scatter.csv | Rscript benchmark/scatter.R --xaxis chunk --category encoding --plot scatter-plot.png --log - -aggregating variable: inlen - -chunk encoding mean confidence.interval - 16 ascii 1111933.3 221502.48 - 16 base64-ascii 167508.4 33116.09 - 16 base64-utf8 122666.6 25037.65 - 16 utf8 783254.8 159601.79 - 64 ascii 2623462.9 399791.36 - 64 base64-ascii 462008.3 85369.45 - 64 base64-utf8 420108.4 85612.05 - 64 utf8 1358327.5 235152.03 - 256 ascii 3730343.4 371530.47 - 256 base64-ascii 663281.2 80302.73 - 256 base64-utf8 632911.7 81393.07 - 256 utf8 1554216.9 236066.53 - 1024 ascii 4399282.0 186436.46 - 1024 base64-ascii 730426.6 63806.12 - 1024 base64-utf8 680954.3 68076.33 - 1024 utf8 1554832.5 237532.07 -``` - -Because the scatter plot can only show two variables (in this case _chunk_ and -_encoding_) the rest is aggregated. Sometimes aggregating is a problem, this -can be solved by filtering. This can be done while benchmarking using the -`--set` parameter (e.g. `--set encoding=ascii`) or by filtering results -afterwards using tools such as `sed` or `grep`. In the `sed` case be -sure to keep the first line since that contains the header information. - -```console -$ cat scatter.csv | sed -E '1p;/([^,]+, ){3}128,/!d' | Rscript benchmark/scatter.R --xaxis chunk --category encoding --plot scatter-plot.png --log - -chunk encoding mean confidence.interval - 16 ascii 701285.96 21233.982 - 16 base64-ascii 107719.07 3339.439 - 16 base64-utf8 72966.95 2438.448 - 16 utf8 475340.84 17685.450 - 64 ascii 2554105.08 87067.132 - 64 base64-ascii 330120.32 8551.707 - 64 base64-utf8 249693.19 8990.493 - 64 utf8 1128671.90 48433.862 - 256 ascii 4841070.04 181620.768 - 256 base64-ascii 849545.53 29931.656 - 256 base64-utf8 809629.89 33773.496 - 256 utf8 1489525.15 49616.334 - 1024 ascii 4931512.12 165402.805 - 1024 base64-ascii 863933.22 27766.982 - 1024 base64-utf8 827093.97 24376.522 - 1024 utf8 1487176.43 50128.721 -``` - -![compare tool boxplot](doc_img/scatter-plot.png) - -## Creating a benchmark - -All benchmarks use the `require('../common.js')` module. This contains the -`createBenchmark(main, configs[, options])` method which will setup your -benchmark. - -The arguments of `createBenchmark` are: - -* `main` {Function} The benchmark function, - where the code running operations and controlling timers should go -* `configs` {Object} The benchmark parameters. `createBenchmark` will run all - possible combinations of these parameters, unless specified otherwise. - Each configuration is a property with an array of possible values. - Note that the configuration values can only be strings or numbers. -* `options` {Object} The benchmark options. At the moment only the `flags` - option for specifying command line flags is supported. - -`createBenchmark` returns a `bench` object, which is used for timing -the runtime of the benchmark. Run `bench.start()` after the initialization -and `bench.end(n)` when the benchmark is done. `n` is the number of operations -you performed in the benchmark. - -The benchmark script will be run twice: - -The first pass will configure the benchmark with the combination of -parameters specified in `configs`, and WILL NOT run the `main` function. -In this pass, no flags except the ones directly passed via commands -that you run the benchmarks with will be used. - -In the second pass, the `main` function will be run, and the process -will be launched with: - -* The flags you've passed into `createBenchmark` (the third argument) -* The flags in the command that you run this benchmark with - -Beware that any code outside the `main` function will be run twice -in different processes. This could be troublesome if the code -outside the `main` function has side effects. In general, prefer putting -the code inside the `main` function if it's more than just declaration. - -```js -'use strict'; -const common = require('../common.js'); -const SlowBuffer = require('buffer').SlowBuffer; - -const configs = { - // Number of operations, specified here so they show up in the report. - // Most benchmarks just use one value for all runs. - n: [1024], - type: ['fast', 'slow'], // Custom configurations - size: [16, 128, 1024] // Custom configurations -}; - -const options = { - // Add --expose-internals if you want to require internal modules in main - flags: ['--zero-fill-buffers'] -}; - -// main and configs are required, options is optional. -const bench = common.createBenchmark(main, configs, options); - -// Note that any code outside main will be run twice, -// in different processes, with different command line arguments. - -function main(conf) { - // You will only get the flags that you have passed to createBenchmark - // earlier when main is run. If you want to benchmark the internal modules, - // require them here. For example: - // const URL = require('internal/url').URL - - // Start the timer - bench.start(); - - // Do operations here - const BufferConstructor = conf.type === 'fast' ? Buffer : SlowBuffer; - - for (let i = 0; i < conf.n; i++) { - new BufferConstructor(conf.size); - } - - // End the timer, pass in the number of operations - bench.end(conf.n); -} -``` - -## Creating HTTP benchmark - -The `bench` object returned by `createBenchmark` implements -`http(options, callback)` method. It can be used to run external tool to -benchmark HTTP servers. - -```js -'use strict'; - -const common = require('../common.js'); - -const bench = common.createBenchmark(main, { - kb: [64, 128, 256, 1024], - connections: [100, 500] -}); - -function main(conf) { - const http = require('http'); - const len = conf.kb * 1024; - const chunk = Buffer.alloc(len, 'x'); - const server = http.createServer(function(req, res) { - res.end(chunk); - }); - - server.listen(common.PORT, function() { - bench.http({ - connections: conf.connections, - }, function() { - server.close(); - }); - }); -} -``` - -Supported options keys are: -* `port` - defaults to `common.PORT` -* `path` - defaults to `/` -* `connections` - number of concurrent connections to use, defaults to 100 -* `duration` - duration of the benchmark in seconds, defaults to 10 -* `benchmarker` - benchmarker to use, defaults to -`common.default_http_benchmarker` - -[autocannon]: https://github.com/mcollina/autocannon -[wrk]: https://github.com/wg/wrk -[t-test]: https://en.wikipedia.org/wiki/Student%27s_t-test#Equal_or_unequal_sample_sizes.2C_unequal_variances -[git-for-windows]: http://git-scm.com/download/win diff --git a/benchmark/_benchmark_progress.js b/benchmark/_benchmark_progress.js new file mode 100644 index 00000000000000..4b42248f246858 --- /dev/null +++ b/benchmark/_benchmark_progress.js @@ -0,0 +1,120 @@ +'use strict'; + +const readline = require('readline'); + +function pad(input, minLength, fill) { + var result = input + ''; + return fill.repeat(Math.max(0, minLength - result.length)) + result; +} + +function fraction(numerator, denominator) { + const fdenominator = denominator + ''; + const fnumerator = pad(numerator, fdenominator.length, ' '); + return `${fnumerator}/${fdenominator}`; +} + +function getTime(diff) { + const time = Math.ceil(diff[0] + diff[1] / 1e9); + const hours = pad(Math.floor(time / 3600), 2, '0'); + const minutes = pad(Math.floor((time % 3600) / 60), 2, '0'); + const seconds = pad((time % 3600) % 60, 2, '0'); + return `${hours}:${minutes}:${seconds}`; +} + +// A run is an item in the job queue: { binary, filename, iter } +// A config is an item in the subqueue: { binary, filename, iter, configs } +class BenchmarkProgress { + constructor(queue, benchmarks) { + this.queue = queue; // Scheduled runs. + this.benchmarks = benchmarks; // Filenames of scheduled benchmarks. + this.completedRuns = 0; // Number of completed runs. + this.scheduledRuns = queue.length; // Number of scheduled runs. + // Time when starting to run benchmarks. + this.startTime = process.hrtime(); + // Number of times each file will be run (roughly). + this.runsPerFile = queue.length / benchmarks.length; + this.currentFile = ''; // Filename of current benchmark. + this.currentFileConfig; // Configurations for current file + // Number of configurations already run for the current file. + this.completedConfig = 0; + // Total number of configurations for the current file + this.scheduledConfig = 0; + this.interval = 0; // result of setInterval for updating the elapsed time + } + + startQueue(index) { + this.kStartOfQueue = index; + this.currentFile = this.queue[index].filename; + this.interval = setInterval(() => { + if (this.completedRuns === this.scheduledRuns) { + clearInterval(this.interval); + } else { + this.updateProgress(); + } + }, 1000); + } + + startSubqueue(data, index) { + // This subqueue is generated by a new benchmark + if (data.name !== this.currentFile || index === this.kStartOfQueue) { + this.currentFile = data.name; + this.scheduledConfig = data.queueLength; + } + this.completedConfig = 0; + this.updateProgress(); + } + + completeConfig(data) { + this.completedConfig++; + this.updateProgress(); + } + + completeRun(job) { + this.completedRuns++; + this.updateProgress(); + } + + getProgress() { + // Get time as soon as possible. + const diff = process.hrtime(this.startTime); + + const completedRuns = this.completedRuns; + const scheduledRuns = this.scheduledRuns; + const finished = completedRuns === scheduledRuns; + + // Calculate numbers for fractions. + const runsPerFile = this.runsPerFile; + const completedFiles = Math.floor(completedRuns / runsPerFile); + const scheduledFiles = this.benchmarks.length; + const completedRunsForFile = finished ? runsPerFile : + completedRuns % runsPerFile; + const completedConfig = this.completedConfig; + const scheduledConfig = this.scheduledConfig; + + // Calculate the percentage. + let runRate = 0; // Rate of current incomplete run. + if (completedConfig !== scheduledConfig) { + runRate = completedConfig / scheduledConfig; + } + const completedRate = ((completedRuns + runRate) / scheduledRuns); + const percent = pad(Math.floor(completedRate * 100), 3, ' '); + + const caption = finished ? 'Done\n' : this.currentFile; + return `[${getTime(diff)}|% ${percent}` + + `| ${fraction(completedFiles, scheduledFiles)} files ` + + `| ${fraction(completedRunsForFile, runsPerFile)} runs ` + + `| ${fraction(completedConfig, scheduledConfig)} configs]` + + `: ${caption}`; + } + + updateProgress(finished) { + if (!process.stderr.isTTY || process.stdout.isTTY) { + return; + } + readline.clearLine(process.stderr); + readline.cursorTo(process.stderr, 0); + process.stderr.write(this.getProgress()); + } +} + +module.exports = BenchmarkProgress; diff --git a/benchmark/_cli.js b/benchmark/_cli.js index be2f7ffff83624..17718c4c4d757a 100644 --- a/benchmark/_cli.js +++ b/benchmark/_cli.js @@ -45,13 +45,13 @@ function CLI(usage, settings) { currentOptional = arg.slice(1); } - // Default the value to true - if (!settings.arrayArgs.includes(currentOptional)) { + if (settings.boolArgs && settings.boolArgs.includes(currentOptional)) { this.optional[currentOptional] = true; + mode = 'both'; + } else { + // expect the next value to be option related (either -- or the value) + mode = 'option'; } - - // expect the next value to be option related (either -- or the value) - mode = 'option'; } else if (mode === 'option') { // Optional arguments value diff --git a/benchmark/assert/deepequal-buffer.js b/benchmark/assert/deepequal-buffer.js new file mode 100644 index 00000000000000..2a7d9e3bed7c38 --- /dev/null +++ b/benchmark/assert/deepequal-buffer.js @@ -0,0 +1,40 @@ +'use strict'; +const common = require('../common.js'); +const assert = require('assert'); +const bench = common.createBenchmark(main, { + n: [1e3], + len: [1e2], + method: ['strict', 'nonstrict'] +}); + +function main(conf) { + const n = +conf.n; + const len = +conf.len; + var i; + + const data = Buffer.allocUnsafe(len); + const actual = Buffer.alloc(len); + const expected = Buffer.alloc(len); + data.copy(actual); + data.copy(expected); + + switch (conf.method) { + case 'strict': + bench.start(); + for (i = 0; i < n; ++i) { + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(actual, expected); + } + bench.end(n); + break; + case 'nonstrict': + bench.start(); + for (i = 0; i < n; ++i) { + assert.deepStrictEqual(actual, expected); + } + bench.end(n); + break; + default: + throw new Error('Unsupported method'); + } +} diff --git a/benchmark/assert/deepequal-prims-and-objs-big-array.js b/benchmark/assert/deepequal-prims-and-objs-big-array.js index 1b4802c8ff4ac2..69eda8af087dfa 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-array.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-array.js @@ -1,6 +1,6 @@ 'use strict'; -var common = require('../common.js'); -var assert = require('assert'); +const common = require('../common.js'); +const assert = require('assert'); const primValues = { 'null': null, @@ -13,29 +13,43 @@ const primValues = { 'new-array': new Array([1, 2, 3]) }; -var bench = common.createBenchmark(main, { +const bench = common.createBenchmark(main, { prim: Object.keys(primValues), - n: [25] + n: [25], + len: [1e5], + method: ['strict', 'nonstrict'] }); function main(conf) { - var prim = primValues[conf.prim]; - var n = +conf.n; - var primArray; - var primArrayCompare; - var x; + const prim = primValues[conf.prim]; + const n = +conf.n; + const len = +conf.len; + const actual = []; + const expected = []; + var i; - primArray = new Array(); - primArrayCompare = new Array(); - for (x = 0; x < (1e5); x++) { - primArray.push(prim); - primArrayCompare.push(prim); + for (var x = 0; x < len; x++) { + actual.push(prim); + expected.push(prim); } - bench.start(); - for (x = 0; x < n; x++) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(primArray, primArrayCompare); + switch (conf.method) { + case 'strict': + bench.start(); + for (i = 0; i < n; ++i) { + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(actual, expected); + } + bench.end(n); + break; + case 'nonstrict': + bench.start(); + for (i = 0; i < n; ++i) { + assert.deepStrictEqual(actual, expected); + } + bench.end(n); + break; + default: + throw new Error('Unsupported method'); } - bench.end(n); } diff --git a/benchmark/assert/deepequal-prims-and-objs-big-loop.js b/benchmark/assert/deepequal-prims-and-objs-big-loop.js index dea084bc984126..781c5ad754e723 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-loop.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-loop.js @@ -1,6 +1,6 @@ 'use strict'; -var common = require('../common.js'); -var assert = require('assert'); +const common = require('../common.js'); +const assert = require('assert'); const primValues = { 'null': null, @@ -13,22 +13,37 @@ const primValues = { 'new-array': new Array([1, 2, 3]) }; -var bench = common.createBenchmark(main, { +const bench = common.createBenchmark(main, { prim: Object.keys(primValues), - n: [1e5] + n: [1e6], + method: ['strict', 'nonstrict'] }); function main(conf) { - var prim = primValues[conf.prim]; - var n = +conf.n; - var x; + const prim = primValues[conf.prim]; + const n = +conf.n; + const actual = prim; + const expected = prim; + var i; - bench.start(); - - for (x = 0; x < n; x++) { - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(new Array([prim]), new Array([prim])); + // Creates new array to avoid loop invariant code motion + switch (conf.method) { + case 'strict': + bench.start(); + for (i = 0; i < n; ++i) { + // eslint-disable-next-line no-restricted-properties + assert.deepEqual([actual], [expected]); + } + bench.end(n); + break; + case 'nonstrict': + bench.start(); + for (i = 0; i < n; ++i) { + assert.deepStrictEqual([actual], [expected]); + } + bench.end(n); + break; + default: + throw new Error('Unsupported method'); } - - bench.end(n); } diff --git a/benchmark/assert/deepequal-typedarrays.js b/benchmark/assert/deepequal-typedarrays.js index 1954c57ee59eeb..037cfb2cf1ec3c 100644 --- a/benchmark/assert/deepequal-typedarrays.js +++ b/benchmark/assert/deepequal-typedarrays.js @@ -1,23 +1,41 @@ 'use strict'; -var common = require('../common.js'); -var assert = require('assert'); -var bench = common.createBenchmark(main, { +const common = require('../common.js'); +const assert = require('assert'); +const bench = common.createBenchmark(main, { type: ('Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array ' + 'Float32Array Float64Array Uint8ClampedArray').split(' '), - n: [1] + n: [1], + method: ['strict', 'nonstrict'], + len: [1e6] }); function main(conf) { - var type = conf.type; - var clazz = global[type]; - var n = +conf.n; + const type = conf.type; + const clazz = global[type]; + const n = +conf.n; + const len = +conf.len; - bench.start(); - var actual = new clazz(n * 1e6); - var expected = new clazz(n * 1e6); + const actual = new clazz(len); + const expected = new clazz(len); + var i; - // eslint-disable-next-line no-restricted-properties - assert.deepEqual(actual, expected); - - bench.end(n); + switch (conf.method) { + case 'strict': + bench.start(); + for (i = 0; i < n; ++i) { + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(actual, expected); + } + bench.end(n); + break; + case 'nonstrict': + bench.start(); + for (i = 0; i < n; ++i) { + assert.deepStrictEqual(actual, expected); + } + bench.end(n); + break; + default: + throw new Error('Unsupported method'); + } } diff --git a/benchmark/buffers/buffer-compare-instance-method.js b/benchmark/buffers/buffer-compare-instance-method.js index 0becbeee23a7d7..ff3bc4c1abda98 100644 --- a/benchmark/buffers/buffer-compare-instance-method.js +++ b/benchmark/buffers/buffer-compare-instance-method.js @@ -1,29 +1,79 @@ 'use strict'; const common = require('../common.js'); -const v8 = require('v8'); const bench = common.createBenchmark(main, { size: [16, 512, 1024, 4096, 16386], + args: [1, 2, 3, 4, 5], millions: [1] }); function main(conf) { const iter = (conf.millions >>> 0) * 1e6; const size = (conf.size >>> 0); - const b0 = new Buffer(size).fill('a'); - const b1 = new Buffer(size).fill('a'); + const args = (conf.args >>> 0); + const b0 = Buffer.alloc(size, 'a'); + const b1 = Buffer.alloc(size, 'a'); + const b0Len = b0.length; + const b1Len = b1.length; + var i; b1[size - 1] = 'b'.charCodeAt(0); - // Force optimization before starting the benchmark - b0.compare(b1); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(b0.compare)'); - b0.compare(b1); - - bench.start(); - for (var i = 0; i < iter; i++) { - b0.compare(b1); + switch (args) { + case 2: + b0.compare(b1, 0); + break; + case 3: + b0.compare(b1, 0, b1Len); + break; + case 4: + b0.compare(b1, 0, b1Len, 0); + break; + case 5: + b0.compare(b1, 0, b1Len, 0, b0Len); + break; + default: + b0.compare(b1); + } + switch (args) { + case 2: + b0.compare(b1, 0); + bench.start(); + for (i = 0; i < iter; i++) { + b0.compare(b1, 0); + } + bench.end(iter / 1e6); + break; + case 3: + b0.compare(b1, 0, b1Len); + bench.start(); + for (i = 0; i < iter; i++) { + b0.compare(b1, 0, b1Len); + } + bench.end(iter / 1e6); + break; + case 4: + b0.compare(b1, 0, b1Len, 0); + bench.start(); + for (i = 0; i < iter; i++) { + b0.compare(b1, 0, b1Len, 0); + } + bench.end(iter / 1e6); + break; + case 5: + b0.compare(b1, 0, b1Len, 0, b0Len); + bench.start(); + for (i = 0; i < iter; i++) { + b0.compare(b1, 0, b1Len, 0, b0Len); + } + bench.end(iter / 1e6); + break; + default: + b0.compare(b1); + bench.start(); + for (i = 0; i < iter; i++) { + b0.compare(b1); + } + bench.end(iter / 1e6); } - bench.end(iter / 1e6); } diff --git a/benchmark/buffers/buffer-compare-offset.js b/benchmark/buffers/buffer-compare-offset.js index 17b36f82883426..fd8c96dbce0158 100644 --- a/benchmark/buffers/buffer-compare-offset.js +++ b/benchmark/buffers/buffer-compare-offset.js @@ -1,6 +1,5 @@ 'use strict'; const common = require('../common.js'); -const v8 = require('v8'); const bench = common.createBenchmark(main, { method: ['offset', 'slice'], @@ -9,18 +8,6 @@ const bench = common.createBenchmark(main, { }); function compareUsingSlice(b0, b1, len, iter) { - - // Force optimization before starting the benchmark - Buffer.compare(b0.slice(1, len), b1.slice(1, len)); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(Buffer.compare)'); - eval('%OptimizeFunctionOnNextCall(b0.slice)'); - eval('%OptimizeFunctionOnNextCall(b1.slice)'); - Buffer.compare(b0.slice(1, len), b1.slice(1, len)); - doCompareUsingSlice(b0, b1, len, iter); -} - -function doCompareUsingSlice(b0, b1, len, iter) { var i; bench.start(); for (i = 0; i < iter; i++) @@ -29,16 +16,6 @@ function doCompareUsingSlice(b0, b1, len, iter) { } function compareUsingOffset(b0, b1, len, iter) { - len = len + 1; - // Force optimization before starting the benchmark - b0.compare(b1, 1, len, 1, len); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(b0.compare)'); - b0.compare(b1, 1, len, 1, len); - doCompareUsingOffset(b0, b1, len, iter); -} - -function doCompareUsingOffset(b0, b1, len, iter) { var i; bench.start(); for (i = 0; i < iter; i++) diff --git a/benchmark/buffers/buffer-swap.js b/benchmark/buffers/buffer-swap.js index c6d7db470bc69a..71e08890910843 100644 --- a/benchmark/buffers/buffer-swap.js +++ b/benchmark/buffers/buffer-swap.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common.js'); -const v8 = require('v8'); const bench = common.createBenchmark(main, { aligned: ['true', 'false'], @@ -81,9 +80,7 @@ function main(conf) { const buf = createBuffer(len, aligned === 'true'); const bufferSwap = genMethod(method); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(bufferSwap)'); - + bufferSwap(n, buf); bench.start(); bufferSwap(n, buf); bench.end(n); diff --git a/benchmark/buffers/buffer-tojson.js b/benchmark/buffers/buffer-tojson.js new file mode 100644 index 00000000000000..1be59952c3fe60 --- /dev/null +++ b/benchmark/buffers/buffer-tojson.js @@ -0,0 +1,18 @@ +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [1e4], + len: [0, 10, 256, 4 * 1024] +}); + +function main(conf) { + var n = +conf.n; + var buf = Buffer.allocUnsafe(+conf.len); + + bench.start(); + for (var i = 0; i < n; ++i) + buf.toJSON(); + bench.end(n); +} diff --git a/benchmark/child_process/child-process-params.js b/benchmark/child_process/child-process-params.js new file mode 100644 index 00000000000000..644b2136a0f03f --- /dev/null +++ b/benchmark/child_process/child-process-params.js @@ -0,0 +1,146 @@ +'use strict'; + +const common = require('../common.js'); +const cp = require('child_process'); + +const command = 'echo'; +const args = ['hello']; +const options = {}; +const cb = () => {}; + +const configs = { + n: [1e3], + methodName: [ + 'exec', 'execSync', + 'execFile', 'execFileSync', + 'spawn', 'spawnSync', + ], + params: [1, 2, 3, 4], +}; + +const bench = common.createBenchmark(main, configs); + +function main(conf) { + const n = +conf.n; + const methodName = conf.methodName; + const params = +conf.params; + + const method = cp[methodName]; + + switch (methodName) { + case 'exec': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command).kill(); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, options).kill(); + bench.end(n); + break; + case 3: + bench.start(); + for (let i = 0; i < n; i++) method(command, options, cb).kill(); + bench.end(n); + break; + } + break; + case 'execSync': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, options); + bench.end(n); + break; + } + break; + case 'execFile': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command).kill(); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, args).kill(); + bench.end(n); + break; + case 3: + bench.start(); + for (let i = 0; i < n; i++) method(command, args, options).kill(); + bench.end(n); + break; + case 4: + bench.start(); + for (let i = 0; i < n; i++) method(command, args, options, cb).kill(); + bench.end(n); + break; + } + break; + case 'execFileSync': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, args); + bench.end(n); + break; + case 3: + bench.start(); + for (let i = 0; i < n; i++) method(command, args, options); + bench.end(n); + break; + } + break; + case 'spawn': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command).kill(); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, args).kill(); + bench.end(n); + break; + case 3: + bench.start(); + for (let i = 0; i < n; i++) method(command, args, options).kill(); + bench.end(n); + break; + } + break; + case 'spawnSync': + switch (params) { + case 1: + bench.start(); + for (let i = 0; i < n; i++) method(command); + bench.end(n); + break; + case 2: + bench.start(); + for (let i = 0; i < n; i++) method(command, args); + bench.end(n); + break; + case 3: + bench.start(); + for (let i = 0; i < n; i++) method(command, args, options); + bench.end(n); + break; + } + break; + } +} diff --git a/benchmark/common.js b/benchmark/common.js index 4ce9501dd9cff7..7ce180fdb7ff0a 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -128,6 +128,14 @@ Benchmark.prototype.http = function(options, cb) { Benchmark.prototype._run = function() { const self = this; + // If forked, report to the parent. + if (process.send) { + process.send({ + type: 'config', + name: this.name, + queueLength: this.queue.length + }); + } (function recursive(queueIndex) { const config = self.queue[queueIndex]; @@ -217,20 +225,7 @@ Benchmark.prototype.report = function(rate, elapsed) { name: this.name, conf: this.config, rate: rate, - time: elapsed[0] + elapsed[1] / 1e9 + time: elapsed[0] + elapsed[1] / 1e9, + type: 'report' }); }; - -exports.v8ForceOptimization = function(method) { - if (typeof method !== 'function') - return; - - const v8 = require('v8'); - v8.setFlagsFromString('--allow_natives_syntax'); - - const args = Array.prototype.slice.call(arguments, 1); - method.apply(null, args); - eval('%OptimizeFunctionOnNextCall(method)'); - method.apply(null, args); - return eval('%GetOptimizationStatus(method)'); -}; diff --git a/benchmark/compare.R b/benchmark/compare.R index 3f37cad74ad847..5085f4ea73b71a 100644 --- a/benchmark/compare.R +++ b/benchmark/compare.R @@ -47,7 +47,7 @@ statistics = ddply(dat, "name", function(subdat) { p.value = NA; confidence = 'NA'; - # Check if there is enough data to calulate the calculate the p-value + # Check if there is enough data to calculate the calculate the p-value if (length(old.rate) > 1 && length(new.rate) > 1) { # Perform a statistics test to see of there actually is a difference in # performance. diff --git a/benchmark/compare.js b/benchmark/compare.js index ea431b18cb4cd9..a671bc9f3d7be6 100644 --- a/benchmark/compare.js +++ b/benchmark/compare.js @@ -3,23 +3,26 @@ const fork = require('child_process').fork; const path = require('path'); const CLI = require('./_cli.js'); +const BenchmarkProgress = require('./_benchmark_progress.js'); // // Parse arguments // const cli = CLI(`usage: ./node compare.js [options] [--] ... - Run each benchmark in the directory many times using two diffrent + Run each benchmark in the directory many times using two different node versions. More than one directory can be specified. The output is formatted as csv, which can be processed using for example 'compare.R'. - --new ./new-node-binary new node binary (required) - --old ./old-node-binary old node binary (required) - --runs 30 number of samples - --filter pattern string to filter benchmark scripts - --set variable=value set benchmark variable (can be repeated) + --new ./new-node-binary new node binary (required) + --old ./old-node-binary old node binary (required) + --runs 30 number of samples + --filter pattern string to filter benchmark scripts + --set variable=value set benchmark variable (can be repeated) + --no-progress don't show benchmark progress indicator `, { - arrayArgs: ['set'] + arrayArgs: ['set'], + boolArgs: ['no-progress'] }); if (!cli.optional.new || !cli.optional.old) { @@ -39,6 +42,9 @@ if (benchmarks.length === 0) { // Create queue from the benchmarks list such both node versions are tested // `runs` amount of times each. +// Note: BenchmarkProgress relies on this order to estimate +// how much runs remaining for a file. All benchmarks generated from +// the same file must be run consecutively. const queue = []; for (const filename of benchmarks) { for (let iter = 0; iter < runs; iter++) { @@ -47,10 +53,20 @@ for (const filename of benchmarks) { } } } +// queue.length = binary.length * runs * benchmarks.length // Print csv header console.log('"binary", "filename", "configuration", "rate", "time"'); +const kStartOfQueue = 0; + +const showProgress = !cli.optional['no-progress']; +let progress; +if (showProgress) { + progress = new BenchmarkProgress(queue, benchmarks); + progress.startQueue(kStartOfQueue); +} + (function recursive(i) { const job = queue[i]; @@ -59,18 +75,26 @@ console.log('"binary", "filename", "configuration", "rate", "time"'); }); child.on('message', function(data) { - // Construct configuration string, " A=a, B=b, ..." - let conf = ''; - for (const key of Object.keys(data.conf)) { - conf += ' ' + key + '=' + JSON.stringify(data.conf[key]); - } - conf = conf.slice(1); + if (data.type === 'report') { + // Construct configuration string, " A=a, B=b, ..." + let conf = ''; + for (const key of Object.keys(data.conf)) { + conf += ' ' + key + '=' + JSON.stringify(data.conf[key]); + } + conf = conf.slice(1); + // Escape quotes (") for correct csv formatting + conf = conf.replace(/"/g, '""'); - // Escape quotes (") for correct csv formatting - conf = conf.replace(/"/g, '""'); - - console.log(`"${job.binary}", "${job.filename}", "${conf}", ` + - `${data.rate}, ${data.time}`); + console.log(`"${job.binary}", "${job.filename}", "${conf}", ` + + `${data.rate}, ${data.time}`); + if (showProgress) { + // One item in the subqueue has been completed. + progress.completeConfig(data); + } + } else if (showProgress && data.type === 'config') { + // The child has computed the configurations, ready to run subqueue. + progress.startSubqueue(data, i); + } }); child.once('close', function(code) { @@ -78,10 +102,13 @@ console.log('"binary", "filename", "configuration", "rate", "time"'); process.exit(code); return; } + if (showProgress) { + progress.completeRun(job); + } // If there are more benchmarks execute the next if (i + 1 < queue.length) { recursive(i + 1); } }); -})(0); +})(kStartOfQueue); diff --git a/benchmark/crypto/get-ciphers.js b/benchmark/crypto/get-ciphers.js index 257c9af2fd531e..f6b1767cb4fbcc 100644 --- a/benchmark/crypto/get-ciphers.js +++ b/benchmark/crypto/get-ciphers.js @@ -12,8 +12,11 @@ function main(conf) { const v = conf.v; const method = require(v).getCiphers; var i = 0; - - common.v8ForceOptimization(method); + // first call to getChipers will dominate the results + if (n > 1) { + for (; i < n; i++) + method(); + } bench.start(); for (; i < n; i++) method(); bench.end(n); diff --git a/benchmark/dgram/bind-params.js b/benchmark/dgram/bind-params.js new file mode 100644 index 00000000000000..92e9b7f85b1e12 --- /dev/null +++ b/benchmark/dgram/bind-params.js @@ -0,0 +1,38 @@ +'use strict'; + +const common = require('../common.js'); +const dgram = require('dgram'); + +const configs = { + n: [1e4], + port: ['true', 'false'], + address: ['true', 'false'], +}; + +const bench = common.createBenchmark(main, configs); + +function main(conf) { + const n = +conf.n; + const port = conf.port === 'true' ? 0 : undefined; + const address = conf.address === 'true' ? '0.0.0.0' : undefined; + + if (port !== undefined && address !== undefined) { + bench.start(); + for (let i = 0; i < n; i++) { + dgram.createSocket('udp4').bind(port, address).unref(); + } + bench.end(n); + } else if (port !== undefined) { + bench.start(); + for (let i = 0; i < n; i++) { + dgram.createSocket('udp4').bind(port).unref(); + } + bench.end(n); + } else if (port === undefined && address === undefined) { + bench.start(); + for (let i = 0; i < n; i++) { + dgram.createSocket('udp4').bind().unref(); + } + bench.end(n); + } +} diff --git a/benchmark/domain/domain-fn-args.js b/benchmark/domain/domain-fn-args.js index e9b24811c81689..20f452d67a6f9a 100644 --- a/benchmark/domain/domain-fn-args.js +++ b/benchmark/domain/domain-fn-args.js @@ -12,14 +12,14 @@ var gargs = [1, 2, 3]; function main(conf) { - var args, n = +conf.n; + var n = +conf.n; var myArguments = gargs.slice(0, conf.arguments); bench.start(); bdomain.enter(); for (var i = 0; i < n; i++) { if (myArguments.length >= 2) { - args = Array.prototype.slice.call(myArguments, 1); + const args = Array.prototype.slice.call(myArguments, 1); fn.apply(this, args); } else { fn.call(this); diff --git a/benchmark/es/defaultparams-bench.js b/benchmark/es/defaultparams-bench.js index 1b962cfb39333f..56d04cd95bb454 100644 --- a/benchmark/es/defaultparams-bench.js +++ b/benchmark/es/defaultparams-bench.js @@ -22,8 +22,6 @@ function defaultParams(x = 1, y = 2) { function runOldStyleDefaults(n) { - common.v8ForceOptimization(oldStyleDefaults); - var i = 0; bench.start(); for (; i < n; i++) @@ -33,8 +31,6 @@ function runOldStyleDefaults(n) { function runDefaultParams(n) { - common.v8ForceOptimization(defaultParams); - var i = 0; bench.start(); for (; i < n; i++) diff --git a/benchmark/es/destructuring-bench.js b/benchmark/es/destructuring-bench.js index 0e9b5e93f3b318..3288e009a08515 100644 --- a/benchmark/es/destructuring-bench.js +++ b/benchmark/es/destructuring-bench.js @@ -9,9 +9,9 @@ const bench = common.createBenchmark(main, { }); function runSwapManual(n) { - var i = 0, x, y, r; + var x, y, r; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < n; i++) { x = 1, y = 2; r = x; x = y; @@ -23,9 +23,9 @@ function runSwapManual(n) { } function runSwapDestructured(n) { - var i = 0, x, y; + var x, y; bench.start(); - for (; i < n; i++) { + for (var i = 0; i < n; i++) { x = 1, y = 2; [x, y] = [y, x]; assert.strictEqual(x, 2); diff --git a/benchmark/es/restparams-bench.js b/benchmark/es/restparams-bench.js index 0ff9c48dedc490..f5c49dd969b40a 100644 --- a/benchmark/es/restparams-bench.js +++ b/benchmark/es/restparams-bench.js @@ -35,8 +35,6 @@ function useArguments() { function runCopyArguments(n) { - common.v8ForceOptimization(copyArguments, 1, 2, 'a', 'b'); - var i = 0; bench.start(); for (; i < n; i++) @@ -46,8 +44,6 @@ function runCopyArguments(n) { function runRestArguments(n) { - common.v8ForceOptimization(restArguments, 1, 2, 'a', 'b'); - var i = 0; bench.start(); for (; i < n; i++) @@ -57,8 +53,6 @@ function runRestArguments(n) { function runUseArguments(n) { - common.v8ForceOptimization(useArguments, 1, 2, 'a', 'b'); - var i = 0; bench.start(); for (; i < n; i++) diff --git a/benchmark/es/spread-bench.js b/benchmark/es/spread-bench.js new file mode 100644 index 00000000000000..a9416ad90ef4b3 --- /dev/null +++ b/benchmark/es/spread-bench.js @@ -0,0 +1,59 @@ +'use strict'; + +const common = require('../common.js'); +const assert = require('assert'); + +const bench = common.createBenchmark(main, { + method: ['apply', 'spread', 'call-spread'], + count: [5, 10, 20], + context: ['context', 'null'], + rest: [0, 1], + millions: [5] +}); + +function makeTest(count, rest) { + if (rest) { + return function test(...args) { + assert.strictEqual(count, args.length); + }; + } else { + return function test() { + assert.strictEqual(count, arguments.length); + }; + } +} + +function main(conf) { + const n = +conf.millions * 1e6; + const ctx = conf.context === 'context' ? {} : null; + var fn = makeTest(conf.count, conf.rest); + const args = new Array(conf.count); + var i; + for (i = 0; i < conf.count; i++) + args[i] = i; + + switch (conf.method) { + case 'apply': + bench.start(); + for (i = 0; i < n; i++) + fn.apply(ctx, args); + bench.end(n / 1e6); + break; + case 'spread': + if (ctx !== null) + fn = fn.bind(ctx); + bench.start(); + for (i = 0; i < n; i++) + fn(...args); + bench.end(n / 1e6); + break; + case 'call-spread': + bench.start(); + for (i = 0; i < n; i++) + fn.call(ctx, ...args); + bench.end(n / 1e6); + break; + default: + throw new Error('Unexpected method'); + } +} diff --git a/benchmark/fixtures/url-inputs.js b/benchmark/fixtures/url-inputs.js new file mode 100644 index 00000000000000..7b1983f6faa590 --- /dev/null +++ b/benchmark/fixtures/url-inputs.js @@ -0,0 +1,30 @@ +'use strict'; + +exports.urls = { + long: 'http://nodejs.org:89/docs/latest/api/foo/bar/qua/13949281/0f28b/' + + '/5d49/b3020/url.html#test?payload1=true&payload2=false&test=1' + + '&benchmark=3&foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + + 'key=f5c65e1e98fe07e648249ad41e1cfdb0', + short: 'https://nodejs.org/en/blog/', + idn: 'http://你好你好.在线', + auth: 'https://user:pass@example.com/path?search=1', + file: 'file:///foo/bar/test/node.js', + ws: 'ws://localhost:9229/f46db715-70df-43ad-a359-7f9949f39868', + javascript: 'javascript:alert("node is awesome");', + percent: 'https://%E4%BD%A0/foo', + dot: 'https://example.org/./a/../b/./c' +}; + +exports.searchParams = { + noencode: 'foo=bar&baz=quux&xyzzy=thud', + multicharsep: 'foo=bar&&&&&&&&&&baz=quux&&&&&&&&&&xyzzy=thud', + encodefake: 'foo=%©ar&baz=%A©uux&xyzzy=%©ud', + encodemany: '%66%6F%6F=bar&%62%61%7A=quux&xyzzy=%74h%75d', + encodelast: 'foo=bar&baz=quux&xyzzy=thu%64', + multivalue: 'foo=bar&foo=baz&foo=quux&quuy=quuz', + multivaluemany: 'foo=bar&foo=baz&foo=quux&quuy=quuz&foo=abc&foo=def&' + + 'foo=ghi&foo=jkl&foo=mno&foo=pqr&foo=stu&foo=vwxyz', + manypairs: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z', + manyblankpairs: '&&&&&&&&&&&&&&&&&&&&&&&&', + altspaces: 'foo+bar=baz+quux&xyzzy+thud=quuy+quuz&abc=def+ghi' +}; diff --git a/benchmark/fs/bench-statSync.js b/benchmark/fs/bench-statSync.js index ba1e8168b4aaf5..4bc2ecd65a3624 100644 --- a/benchmark/fs/bench-statSync.js +++ b/benchmark/fs/bench-statSync.js @@ -5,17 +5,35 @@ const fs = require('fs'); const bench = common.createBenchmark(main, { n: [1e4], - kind: ['lstatSync', 'statSync'] + kind: ['fstatSync', 'lstatSync', 'statSync'] }); function main(conf) { const n = conf.n >>> 0; - const fn = fs[conf.kind]; - - bench.start(); - for (var i = 0; i < n; i++) { - fn(__filename); + var fn; + var i; + switch (conf.kind) { + case 'statSync': + case 'lstatSync': + fn = fs[conf.kind]; + bench.start(); + for (i = 0; i < n; i++) { + fn(__filename); + } + bench.end(n); + break; + case 'fstatSync': + fn = fs.fstatSync; + const fd = fs.openSync(__filename, 'r'); + bench.start(); + for (i = 0; i < n; i++) { + fn(fd); + } + bench.end(n); + fs.closeSync(fd); + break; + default: + throw new Error('Invalid kind argument'); } - bench.end(n); } diff --git a/benchmark/misc/console.js b/benchmark/misc/console.js index 9a08a411c51f82..9c5aec0eeeb5fa 100644 --- a/benchmark/misc/console.js +++ b/benchmark/misc/console.js @@ -4,9 +4,6 @@ const common = require('../common.js'); const assert = require('assert'); const Writable = require('stream').Writable; const util = require('util'); -const v8 = require('v8'); - -v8.setFlagsFromString('--allow_natives_syntax'); const methods = [ 'restAndSpread', @@ -51,14 +48,7 @@ function usingArgumentsAndApplyC() { nullStream.write(util.format.apply(null, arguments) + '\n'); } -function optimize(method, ...args) { - method(...args); - eval(`%OptimizeFunctionOnNextCall(${method.name})`); - method(...args); -} - function runUsingRestAndConcat(n) { - optimize(usingRestAndConcat, 'a', 1); var i = 0; bench.start(); @@ -70,7 +60,6 @@ function runUsingRestAndConcat(n) { function runUsingRestAndSpread(n, concat) { const method = concat ? usingRestAndSpreadC : usingRestAndSpreadTS; - optimize(method, 'this is %s of %d', 'a', 1); var i = 0; bench.start(); @@ -82,7 +71,6 @@ function runUsingRestAndSpread(n, concat) { function runUsingRestAndApply(n, concat) { const method = concat ? usingRestAndApplyC : usingRestAndApplyTS; - optimize(method, 'this is %s of %d', 'a', 1); var i = 0; bench.start(); @@ -94,7 +82,6 @@ function runUsingRestAndApply(n, concat) { function runUsingArgumentsAndApply(n, concat) { const method = concat ? usingArgumentsAndApplyC : usingArgumentsAndApplyTS; - optimize(method, 'this is %s of %d', 'a', 1); var i = 0; bench.start(); diff --git a/benchmark/misc/object-property-bench.js b/benchmark/misc/object-property-bench.js new file mode 100644 index 00000000000000..8ac7683cd54d7e --- /dev/null +++ b/benchmark/misc/object-property-bench.js @@ -0,0 +1,81 @@ +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + method: ['property', 'string', 'variable', 'symbol'], + millions: [1000] +}); + +function runProperty(n) { + const object = {}; + var i = 0; + bench.start(); + for (; i < n; i++) { + object.p1 = 21; + object.p2 = 21; + object.p1 += object.p2; + } + bench.end(n / 1e6); +} + +function runString(n) { + const object = {}; + var i = 0; + bench.start(); + for (; i < n; i++) { + object['p1'] = 21; + object['p2'] = 21; + object['p1'] += object['p2']; + } + bench.end(n / 1e6); +} + +function runVariable(n) { + const object = {}; + const var1 = 'p1'; + const var2 = 'p2'; + var i = 0; + bench.start(); + for (; i < n; i++) { + object[var1] = 21; + object[var2] = 21; + object[var1] += object[var2]; + } + bench.end(n / 1e6); +} + +function runSymbol(n) { + const object = {}; + const symbol1 = Symbol('p1'); + const symbol2 = Symbol('p2'); + var i = 0; + bench.start(); + for (; i < n; i++) { + object[symbol1] = 21; + object[symbol2] = 21; + object[symbol1] += object[symbol2]; + } + bench.end(n / 1e6); +} + +function main(conf) { + const n = +conf.millions * 1e6; + + switch (conf.method) { + case 'property': + runProperty(n); + break; + case 'string': + runString(n); + break; + case 'variable': + runVariable(n); + break; + case 'symbol': + runSymbol(n); + break; + default: + throw new Error('Unexpected method'); + } +} diff --git a/benchmark/misc/punycode.js b/benchmark/misc/punycode.js index f4d22557ac5d65..b359fbbff4bbc6 100644 --- a/benchmark/misc/punycode.js +++ b/benchmark/misc/punycode.js @@ -42,8 +42,9 @@ function usingICU(val) { } function runPunycode(n, val) { - common.v8ForceOptimization(usingPunycode, val); var i = 0; + for (; i < n; i++) + usingPunycode(val); bench.start(); for (; i < n; i++) usingPunycode(val); @@ -51,7 +52,6 @@ function runPunycode(n, val) { } function runICU(n, val) { - common.v8ForceOptimization(usingICU, val); var i = 0; bench.start(); for (; i < n; i++) diff --git a/benchmark/misc/util-extend-vs-object-assign.js b/benchmark/misc/util-extend-vs-object-assign.js index caea42ce914cf5..41c15d7d2caa0c 100644 --- a/benchmark/misc/util-extend-vs-object-assign.js +++ b/benchmark/misc/util-extend-vs-object-assign.js @@ -2,7 +2,6 @@ const common = require('../common.js'); const util = require('util'); -const v8 = require('v8'); const bench = common.createBenchmark(main, { type: ['extend', 'assign'], @@ -12,15 +11,11 @@ const bench = common.createBenchmark(main, { function main(conf) { let fn; const n = conf.n | 0; - let v8command; if (conf.type === 'extend') { fn = util._extend; - v8command = '%OptimizeFunctionOnNextCall(util._extend)'; } else if (conf.type === 'assign') { fn = Object.assign; - // Object.assign is built-in, cannot be optimized - v8command = ''; } // Force-optimize the method to test so that the benchmark doesn't @@ -28,9 +23,6 @@ function main(conf) { for (var i = 0; i < conf.type.length * 10; i += 1) fn({}, process.env); - v8.setFlagsFromString('--allow_natives_syntax'); - eval(v8command); - var obj = new Proxy({}, { set: function(a, b, c) { return true; } }); bench.start(); diff --git a/benchmark/os/cpus.js b/benchmark/os/cpus.js new file mode 100644 index 00000000000000..2a8535113c207a --- /dev/null +++ b/benchmark/os/cpus.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common.js'); +const cpus = require('os').cpus; + +const bench = common.createBenchmark(main, { + n: [3e4] +}); + +function main(conf) { + const n = +conf.n; + + bench.start(); + for (var i = 0; i < n; ++i) + cpus(); + bench.end(n); +} diff --git a/benchmark/os/loadavg.js b/benchmark/os/loadavg.js new file mode 100644 index 00000000000000..6e3c57ed44b777 --- /dev/null +++ b/benchmark/os/loadavg.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common.js'); +const loadavg = require('os').loadavg; + +const bench = common.createBenchmark(main, { + n: [5e6] +}); + +function main(conf) { + const n = +conf.n; + + bench.start(); + for (var i = 0; i < n; ++i) + loadavg(); + bench.end(n); +} diff --git a/benchmark/path/basename-posix.js b/benchmark/path/basename-posix.js index 64da9017793440..fc983c8074c940 100644 --- a/benchmark/path/basename-posix.js +++ b/benchmark/path/basename-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { pathext: [ @@ -30,12 +29,6 @@ function main(conf) { input = input.slice(0, extIdx); } - // Force optimization before starting the benchmark - p.basename(input, ext); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.basename)'); - p.basename(input, ext); - bench.start(); for (var i = 0; i < n; i++) { p.basename(input, ext); diff --git a/benchmark/path/basename-win32.js b/benchmark/path/basename-win32.js index a6214598790033..b493beb87c9e94 100644 --- a/benchmark/path/basename-win32.js +++ b/benchmark/path/basename-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { pathext: [ @@ -30,12 +29,6 @@ function main(conf) { input = input.slice(0, extIdx); } - // Force optimization before starting the benchmark - p.basename(input, ext); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.basename)'); - p.basename(input, ext); - bench.start(); for (var i = 0; i < n; i++) { p.basename(input, ext); diff --git a/benchmark/path/dirname-posix.js b/benchmark/path/dirname-posix.js index e7ea80ffa313c8..af77be5ac06559 100644 --- a/benchmark/path/dirname-posix.js +++ b/benchmark/path/dirname-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -21,12 +20,6 @@ function main(conf) { var p = path.posix; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.dirname(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.dirname)'); - p.dirname(input); - bench.start(); for (var i = 0; i < n; i++) { p.dirname(input); diff --git a/benchmark/path/dirname-win32.js b/benchmark/path/dirname-win32.js index 5cb0829437c2ed..01d97d08e2ae05 100644 --- a/benchmark/path/dirname-win32.js +++ b/benchmark/path/dirname-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -21,12 +20,6 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.dirname(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.dirname)'); - p.dirname(input); - bench.start(); for (var i = 0; i < n; i++) { p.dirname(input); diff --git a/benchmark/path/extname-posix.js b/benchmark/path/extname-posix.js index 61a1073158f8d3..50c4e8f7927ba6 100644 --- a/benchmark/path/extname-posix.js +++ b/benchmark/path/extname-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -24,12 +23,6 @@ function main(conf) { var p = path.posix; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.extname(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.extname)'); - p.extname(input); - bench.start(); for (var i = 0; i < n; i++) { p.extname(input); diff --git a/benchmark/path/extname-win32.js b/benchmark/path/extname-win32.js index 67e53eab85817f..9c0df13ab46105 100644 --- a/benchmark/path/extname-win32.js +++ b/benchmark/path/extname-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -24,12 +23,6 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.extname(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.extname)'); - p.extname(input); - bench.start(); for (var i = 0; i < n; i++) { p.extname(input); diff --git a/benchmark/path/format-posix.js b/benchmark/path/format-posix.js index b30b58be4118f0..ee78a6d5f30980 100644 --- a/benchmark/path/format-posix.js +++ b/benchmark/path/format-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { props: [ @@ -22,12 +21,6 @@ function main(conf) { name: props[4] || '', }; - // Force optimization before starting the benchmark - p.format(obj); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.format)'); - p.format(obj); - bench.start(); for (var i = 0; i < n; i++) { p.format(obj); diff --git a/benchmark/path/format-win32.js b/benchmark/path/format-win32.js index 7404f2e93e6868..9ec981d6310ed6 100644 --- a/benchmark/path/format-win32.js +++ b/benchmark/path/format-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { props: [ @@ -22,12 +21,6 @@ function main(conf) { name: props[4] || '', }; - // Force optimization before starting the benchmark - p.format(obj); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.format)'); - p.format(obj); - bench.start(); for (var i = 0; i < n; i++) { p.format(obj); diff --git a/benchmark/path/isAbsolute-posix.js b/benchmark/path/isAbsolute-posix.js index fb8956c073b9db..22db751100ceee 100644 --- a/benchmark/path/isAbsolute-posix.js +++ b/benchmark/path/isAbsolute-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -19,12 +18,6 @@ function main(conf) { var p = path.posix; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.isAbsolute(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.isAbsolute)'); - p.isAbsolute(input); - bench.start(); for (var i = 0; i < n; i++) { p.isAbsolute(input); diff --git a/benchmark/path/isAbsolute-win32.js b/benchmark/path/isAbsolute-win32.js index 57fb8b8999e838..a565da8e566f8f 100644 --- a/benchmark/path/isAbsolute-win32.js +++ b/benchmark/path/isAbsolute-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -20,12 +19,6 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.isAbsolute(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.isAbsolute)'); - p.isAbsolute(input); - bench.start(); for (var i = 0; i < n; i++) { p.isAbsolute(input); diff --git a/benchmark/path/join-posix.js b/benchmark/path/join-posix.js index 1222f4050aa6ab..a7cf3772522daa 100644 --- a/benchmark/path/join-posix.js +++ b/benchmark/path/join-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -15,12 +14,6 @@ function main(conf) { var p = path.posix; var args = ('' + conf.paths).split('|'); - // Force optimization before starting the benchmark - p.join.apply(null, args); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.join)'); - p.join.apply(null, args); - bench.start(); for (var i = 0; i < n; i++) { p.join.apply(null, args); diff --git a/benchmark/path/join-win32.js b/benchmark/path/join-win32.js index 86801859d56c3b..18c1e802a6bff1 100644 --- a/benchmark/path/join-win32.js +++ b/benchmark/path/join-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -15,12 +14,6 @@ function main(conf) { var p = path.win32; var args = ('' + conf.paths).split('|'); - // Force optimization before starting the benchmark - p.join.apply(null, args); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.join)'); - p.join.apply(null, args); - bench.start(); for (var i = 0; i < n; i++) { p.join.apply(null, args); diff --git a/benchmark/path/makeLong-win32.js b/benchmark/path/makeLong-win32.js index d4b29d7e709b3e..fe5da425a5cd73 100644 --- a/benchmark/path/makeLong-win32.js +++ b/benchmark/path/makeLong-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -18,12 +17,6 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p._makeLong(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p._makeLong)'); - p._makeLong(input); - bench.start(); for (var i = 0; i < n; i++) { p._makeLong(input); diff --git a/benchmark/path/normalize-posix.js b/benchmark/path/normalize-posix.js index 19d6461ca51dcf..aec703cbe21242 100644 --- a/benchmark/path/normalize-posix.js +++ b/benchmark/path/normalize-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -20,12 +19,6 @@ function main(conf) { var p = path.posix; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.normalize(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.normalize)'); - p.normalize(input); - bench.start(); for (var i = 0; i < n; i++) { p.normalize(input); diff --git a/benchmark/path/normalize-win32.js b/benchmark/path/normalize-win32.js index 119f9797681113..356d399c3513ab 100644 --- a/benchmark/path/normalize-win32.js +++ b/benchmark/path/normalize-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -20,12 +19,6 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.normalize(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.normalize)'); - p.normalize(input); - bench.start(); for (var i = 0; i < n; i++) { p.normalize(input); diff --git a/benchmark/path/parse-posix.js b/benchmark/path/parse-posix.js index ee4306fcd27496..997eec0452b74a 100644 --- a/benchmark/path/parse-posix.js +++ b/benchmark/path/parse-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -21,15 +20,12 @@ function main(conf) { var p = path.posix; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.parse(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.parse)'); - p.parse(input); - - bench.start(); for (var i = 0; i < n; i++) { p.parse(input); } + bench.start(); + for (i = 0; i < n; i++) { + p.parse(input); + } bench.end(n); } diff --git a/benchmark/path/parse-win32.js b/benchmark/path/parse-win32.js index 5a7b80f0ddb3da..2a95f758665377 100644 --- a/benchmark/path/parse-win32.js +++ b/benchmark/path/parse-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { path: [ @@ -22,15 +21,12 @@ function main(conf) { var p = path.win32; var input = '' + conf.path; - // Force optimization before starting the benchmark - p.parse(input); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.parse)'); - p.parse(input); - - bench.start(); for (var i = 0; i < n; i++) { p.parse(input); } + bench.start(); + for (i = 0; i < n; i++) { + p.parse(input); + } bench.end(n); } diff --git a/benchmark/path/relative-posix.js b/benchmark/path/relative-posix.js index 7544fb2dc67e7d..492b73c3e89f8a 100644 --- a/benchmark/path/relative-posix.js +++ b/benchmark/path/relative-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -26,15 +25,12 @@ function main(conf) { to = from.slice(delimIdx + 1); from = from.slice(0, delimIdx); } - - // Force optimization before starting the benchmark - p.relative(from, to); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.relative)'); - p.relative(from, to); + for (var i = 0; i < n; i++) { + p.relative(from, to); + } bench.start(); - for (var i = 0; i < n; i++) { + for (i = 0; i < n; i++) { p.relative(from, to); } bench.end(n); diff --git a/benchmark/path/relative-win32.js b/benchmark/path/relative-win32.js index 92531959c1c3aa..7e7620299eb16c 100644 --- a/benchmark/path/relative-win32.js +++ b/benchmark/path/relative-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -25,14 +24,13 @@ function main(conf) { from = from.slice(0, delimIdx); } - // Force optimization before starting the benchmark - p.relative(from, to); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.relative)'); - p.relative(from, to); + // Warmup + for (var i = 0; i < n; i++) { + p.relative(from, to); + } bench.start(); - for (var i = 0; i < n; i++) { + for (i = 0; i < n; i++) { p.relative(from, to); } bench.end(n); diff --git a/benchmark/path/resolve-posix.js b/benchmark/path/resolve-posix.js index 93e5b82191a23a..d1364a8ac256c9 100644 --- a/benchmark/path/resolve-posix.js +++ b/benchmark/path/resolve-posix.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -18,12 +17,6 @@ function main(conf) { var p = path.posix; var args = ('' + conf.paths).split('|'); - // Force optimization before starting the benchmark - p.resolve.apply(null, args); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.resolve)'); - p.resolve.apply(null, args); - bench.start(); for (var i = 0; i < n; i++) { p.resolve.apply(null, args); diff --git a/benchmark/path/resolve-win32.js b/benchmark/path/resolve-win32.js index dc0eb30e930049..6dfb38167c96bd 100644 --- a/benchmark/path/resolve-win32.js +++ b/benchmark/path/resolve-win32.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var path = require('path'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { paths: [ @@ -18,12 +17,6 @@ function main(conf) { var p = path.win32; var args = ('' + conf.paths).split('|'); - // Force optimization before starting the benchmark - p.resolve.apply(null, args); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(p.resolve)'); - p.resolve.apply(null, args); - bench.start(); for (var i = 0; i < n; i++) { p.resolve.apply(null, args); diff --git a/benchmark/process/bench-hrtime.js b/benchmark/process/bench-hrtime.js index 661dff43b0103c..8a2920a238d042 100644 --- a/benchmark/process/bench-hrtime.js +++ b/benchmark/process/bench-hrtime.js @@ -1,18 +1,32 @@ 'use strict'; const common = require('../common'); +const assert = require('assert'); const bench = common.createBenchmark(main, { - n: [1e6] + n: [1e6], + type: ['raw', 'diff'] }); - function main(conf) { - const n = conf.n >>> 0; + const n = conf.n | 0; + const hrtime = process.hrtime; + var noDead = hrtime(); + var i; - bench.start(); - for (var i = 0; i < n; i++) { - process.hrtime(); + if (conf.type === 'raw') { + bench.start(); + for (i = 0; i < n; i++) { + noDead = hrtime(); + } + bench.end(n); + } else { + bench.start(); + for (i = 0; i < n; i++) { + noDead = hrtime(noDead); + } + bench.end(n); } - bench.end(n); + + assert.ok(Array.isArray(noDead)); } diff --git a/benchmark/process/memoryUsage.js b/benchmark/process/memoryUsage.js new file mode 100644 index 00000000000000..d68ef339b4d10b --- /dev/null +++ b/benchmark/process/memoryUsage.js @@ -0,0 +1,16 @@ +'use strict'; + +var common = require('../common.js'); +var bench = common.createBenchmark(main, { + n: [1e5] +}); + +function main(conf) { + var n = +conf.n; + + bench.start(); + for (var i = 0; i < n; i++) { + process.memoryUsage(); + } + bench.end(n); +} diff --git a/benchmark/querystring/querystring-parse.js b/benchmark/querystring/querystring-parse.js index d78ef99f84f3d4..eacbd7f92aa337 100644 --- a/benchmark/querystring/querystring-parse.js +++ b/benchmark/querystring/querystring-parse.js @@ -1,62 +1,35 @@ 'use strict'; var common = require('../common.js'); var querystring = require('querystring'); -var v8 = require('v8'); - -var types = [ - 'noencode', - 'multicharsep', - 'encodemany', - 'encodelast', - 'multivalue', - 'multivaluemany', - 'manypairs' -]; +var inputs = require('../fixtures/url-inputs.js').searchParams; var bench = common.createBenchmark(main, { - type: types, + type: Object.keys(inputs), n: [1e6], }); function main(conf) { var type = conf.type; var n = conf.n | 0; - - var inputs = { - noencode: 'foo=bar&baz=quux&xyzzy=thud', - multicharsep: 'foo=bar&&&&&&&&&&baz=quux&&&&&&&&&&xyzzy=thud', - encodemany: '%66%6F%6F=bar&%62%61%7A=quux&xyzzy=%74h%75d', - encodelast: 'foo=bar&baz=quux&xyzzy=thu%64', - multivalue: 'foo=bar&foo=baz&foo=quux&quuy=quuz', - multivaluemany: 'foo=bar&foo=baz&foo=quux&quuy=quuz&foo=abc&foo=def&' + - 'foo=ghi&foo=jkl&foo=mno&foo=pqr&foo=stu&foo=vwxyz', - manypairs: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z' - }; var input = inputs[type]; - - // Force-optimize querystring.parse() so that the benchmark doesn't get - // disrupted by the optimizer kicking in halfway through. - v8.setFlagsFromString('--allow_natives_syntax'); - if (type !== 'multicharsep') { - querystring.parse(input); - eval('%OptimizeFunctionOnNextCall(querystring.parse)'); - querystring.parse(input); - } else { - querystring.parse(input, '&&&&&&&&&&'); - eval('%OptimizeFunctionOnNextCall(querystring.parse)'); - querystring.parse(input, '&&&&&&&&&&'); - } - var i; - if (type !== 'multicharsep') { + // Execute the function a "sufficient" number of times before the timed + // loop to ensure the function is optimized just once. + if (type === 'multicharsep') { + for (i = 0; i < n; i += 1) + querystring.parse(input, '&&&&&&&&&&'); + bench.start(); for (i = 0; i < n; i += 1) - querystring.parse(input); + querystring.parse(input, '&&&&&&&&&&'); bench.end(n); } else { + for (i = 0; i < n; i += 1) + querystring.parse(input); + bench.start(); for (i = 0; i < n; i += 1) - querystring.parse(input, '&&&&&&&&&&'); + querystring.parse(input); bench.end(n); } } diff --git a/benchmark/querystring/querystring-stringify.js b/benchmark/querystring/querystring-stringify.js index 5870a690555a0a..7e31a49e99e54c 100644 --- a/benchmark/querystring/querystring-stringify.js +++ b/benchmark/querystring/querystring-stringify.js @@ -1,7 +1,6 @@ 'use strict'; var common = require('../common.js'); var querystring = require('querystring'); -var v8 = require('v8'); var bench = common.createBenchmark(main, { type: ['noencode', 'encodemany', 'encodelast'], @@ -36,10 +35,6 @@ function main(conf) { for (var name in inputs) querystring.stringify(inputs[name]); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(querystring.stringify)'); - querystring.stringify(input); - bench.start(); for (var i = 0; i < n; i += 1) querystring.stringify(input); diff --git a/benchmark/querystring/querystring-unescapebuffer.js b/benchmark/querystring/querystring-unescapebuffer.js new file mode 100644 index 00000000000000..fe48a6f149bc6a --- /dev/null +++ b/benchmark/querystring/querystring-unescapebuffer.js @@ -0,0 +1,23 @@ +'use strict'; +var common = require('../common.js'); +var querystring = require('querystring'); + +var bench = common.createBenchmark(main, { + input: [ + 'there is nothing to unescape here', + 'there%20are%20several%20spaces%20that%20need%20to%20be%20unescaped', + 'there%2Qare%0-fake%escaped values in%%%%this%9Hstring', + '%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%30%31%32%33%34%35%36%37' + ], + n: [10e6], +}); + +function main(conf) { + var input = conf.input; + var n = conf.n | 0; + + bench.start(); + for (var i = 0; i < n; i += 1) + querystring.unescapeBuffer(input); + bench.end(n); +} diff --git a/benchmark/run.js b/benchmark/run.js index c04824866710a8..cb4f8cc00487fe 100644 --- a/benchmark/run.js +++ b/benchmark/run.js @@ -44,6 +44,9 @@ if (format === 'csv') { } child.on('message', function(data) { + if (data.type !== 'report') { + return; + } // Construct configuration string, " A=a, B=b, ..." let conf = ''; for (const key of Object.keys(data.conf)) { diff --git a/benchmark/scatter.js b/benchmark/scatter.js index 3003616b58eee4..65d1a5f604877d 100644 --- a/benchmark/scatter.js +++ b/benchmark/scatter.js @@ -42,6 +42,10 @@ function csvEncodeValue(value) { const child = fork(path.resolve(__dirname, filepath), cli.optional.set); child.on('message', function(data) { + if (data.type !== 'report') { + return; + } + // print csv header if (printHeader) { const confHeader = Object.keys(data.conf) diff --git a/benchmark/streams/readable-bigread.js b/benchmark/streams/readable-bigread.js index 50f10c44119141..34d478fb478478 100644 --- a/benchmark/streams/readable-bigread.js +++ b/benchmark/streams/readable-bigread.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common'); -const v8 = require('v8'); const Readable = require('stream').Readable; const bench = common.createBenchmark(main, { @@ -15,13 +14,6 @@ function main(conf) { function noop() {} s._read = noop; - // Force optimization before starting the benchmark - s.push(b); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(s.read)'); - s.push(b); - while (s.read(128)); - bench.start(); for (var k = 0; k < n; ++k) { for (var i = 0; i < 1e4; ++i) diff --git a/benchmark/streams/readable-bigunevenread.js b/benchmark/streams/readable-bigunevenread.js index ce6e41c5d30eac..d176166ae4f432 100644 --- a/benchmark/streams/readable-bigunevenread.js +++ b/benchmark/streams/readable-bigunevenread.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common'); -const v8 = require('v8'); const Readable = require('stream').Readable; const bench = common.createBenchmark(main, { @@ -15,13 +14,6 @@ function main(conf) { function noop() {} s._read = noop; - // Force optimization before starting the benchmark - s.push(b); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(s.read)'); - s.push(b); - while (s.read(106)); - bench.start(); for (var k = 0; k < n; ++k) { for (var i = 0; i < 1e4; ++i) diff --git a/benchmark/streams/readable-boundaryread.js b/benchmark/streams/readable-boundaryread.js index 93a6616361ba18..1a0b7eb7ac9ddc 100644 --- a/benchmark/streams/readable-boundaryread.js +++ b/benchmark/streams/readable-boundaryread.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common'); -const v8 = require('v8'); const Readable = require('stream').Readable; const bench = common.createBenchmark(main, { @@ -15,14 +14,6 @@ function main(conf) { function noop() {} s._read = noop; - // Force optimization before starting the benchmark - s.push(b); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(s.push)'); - eval('%OptimizeFunctionOnNextCall(s.read)'); - s.push(b); - while (s.read(32)); - bench.start(); for (var k = 0; k < n; ++k) { for (var i = 0; i < 1e4; ++i) diff --git a/benchmark/streams/readable-readall.js b/benchmark/streams/readable-readall.js index 07626fd7978b9a..be34afbeabc090 100644 --- a/benchmark/streams/readable-readall.js +++ b/benchmark/streams/readable-readall.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common'); -const v8 = require('v8'); const Readable = require('stream').Readable; const bench = common.createBenchmark(main, { @@ -15,13 +14,6 @@ function main(conf) { function noop() {} s._read = noop; - // Force optimization before starting the benchmark - s.push(b); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(s.read)'); - s.push(b); - while (s.read()); - bench.start(); for (var k = 0; k < n; ++k) { for (var i = 0; i < 1e4; ++i) diff --git a/benchmark/streams/readable-unevenread.js b/benchmark/streams/readable-unevenread.js index 4a69bd97a94bcf..ebbc727ad23ec3 100644 --- a/benchmark/streams/readable-unevenread.js +++ b/benchmark/streams/readable-unevenread.js @@ -1,7 +1,6 @@ 'use strict'; const common = require('../common'); -const v8 = require('v8'); const Readable = require('stream').Readable; const bench = common.createBenchmark(main, { @@ -15,13 +14,6 @@ function main(conf) { function noop() {} s._read = noop; - // Force optimization before starting the benchmark - s.push(b); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(s.read)'); - s.push(b); - while (s.read(12)); - bench.start(); for (var k = 0; k < n; ++k) { for (var i = 0; i < 1e4; ++i) diff --git a/benchmark/misc/set-immediate-breadth-args.js b/benchmark/timers/set-immediate-breadth-args.js similarity index 100% rename from benchmark/misc/set-immediate-breadth-args.js rename to benchmark/timers/set-immediate-breadth-args.js diff --git a/benchmark/misc/set-immediate-breadth.js b/benchmark/timers/set-immediate-breadth.js similarity index 100% rename from benchmark/misc/set-immediate-breadth.js rename to benchmark/timers/set-immediate-breadth.js diff --git a/benchmark/misc/set-immediate-depth-args.js b/benchmark/timers/set-immediate-depth-args.js similarity index 100% rename from benchmark/misc/set-immediate-depth-args.js rename to benchmark/timers/set-immediate-depth-args.js diff --git a/benchmark/misc/set-immediate-depth.js b/benchmark/timers/set-immediate-depth.js similarity index 100% rename from benchmark/misc/set-immediate-depth.js rename to benchmark/timers/set-immediate-depth.js diff --git a/benchmark/timers/timers-cancel-pooled.js b/benchmark/timers/timers-cancel-pooled.js new file mode 100644 index 00000000000000..47c9fea2cb5b61 --- /dev/null +++ b/benchmark/timers/timers-cancel-pooled.js @@ -0,0 +1,32 @@ +'use strict'; +var common = require('../common.js'); +var assert = require('assert'); + +var bench = common.createBenchmark(main, { + thousands: [500], +}); + +function main(conf) { + var iterations = +conf.thousands * 1e3; + + var timer = setTimeout(() => {}, 1); + for (var i = 0; i < iterations; i++) { + setTimeout(cb, 1); + } + var next = timer._idlePrev; + clearTimeout(timer); + + bench.start(); + + for (var j = 0; j < iterations; j++) { + timer = next; + next = timer._idlePrev; + clearTimeout(timer); + } + + bench.end(iterations / 1e3); +} + +function cb() { + assert(false, 'Timer should not call callback'); +} diff --git a/benchmark/timers/timers-cancel-unpooled.js b/benchmark/timers/timers-cancel-unpooled.js new file mode 100644 index 00000000000000..a040fad69e1c66 --- /dev/null +++ b/benchmark/timers/timers-cancel-unpooled.js @@ -0,0 +1,26 @@ +'use strict'; +var common = require('../common.js'); +var assert = require('assert'); + +var bench = common.createBenchmark(main, { + thousands: [100], +}); + +function main(conf) { + var iterations = +conf.thousands * 1e3; + + var timersList = []; + for (var i = 0; i < iterations; i++) { + timersList.push(setTimeout(cb, i + 1)); + } + + bench.start(); + for (var j = 0; j < iterations + 1; j++) { + clearTimeout(timersList[j]); + } + bench.end(iterations / 1e3); +} + +function cb() { + assert(false, 'Timer ' + this._idleTimeout + ' should not call callback'); +} diff --git a/benchmark/timers/timers-insert-pooled.js b/benchmark/timers/timers-insert-pooled.js new file mode 100644 index 00000000000000..11c35319b11d69 --- /dev/null +++ b/benchmark/timers/timers-insert-pooled.js @@ -0,0 +1,18 @@ +'use strict'; +var common = require('../common.js'); + +var bench = common.createBenchmark(main, { + thousands: [500], +}); + +function main(conf) { + var iterations = +conf.thousands * 1e3; + + bench.start(); + + for (var i = 0; i < iterations; i++) { + setTimeout(() => {}, 1); + } + + bench.end(iterations / 1e3); +} diff --git a/benchmark/timers/timers-insert-unpooled.js b/benchmark/timers/timers-insert-unpooled.js new file mode 100644 index 00000000000000..91eabeb04e9d4f --- /dev/null +++ b/benchmark/timers/timers-insert-unpooled.js @@ -0,0 +1,27 @@ +'use strict'; +var common = require('../common.js'); +var assert = require('assert'); + +var bench = common.createBenchmark(main, { + thousands: [100], +}); + +function main(conf) { + var iterations = +conf.thousands * 1e3; + + var timersList = []; + + bench.start(); + for (var i = 0; i < iterations; i++) { + timersList.push(setTimeout(cb, i + 1)); + } + bench.end(iterations / 1e3); + + for (var j = 0; j < iterations + 1; j++) { + clearTimeout(timersList[j]); + } +} + +function cb() { + assert(false, 'Timer ' + this._idleTimeout + ' should not call callback'); +} diff --git a/benchmark/timers/timers-timeout-pooled.js b/benchmark/timers/timers-timeout-pooled.js new file mode 100644 index 00000000000000..feaec23237f13d --- /dev/null +++ b/benchmark/timers/timers-timeout-pooled.js @@ -0,0 +1,23 @@ +'use strict'; +var common = require('../common.js'); + +var bench = common.createBenchmark(main, { + thousands: [500], +}); + +function main(conf) { + var iterations = +conf.thousands * 1e3; + var count = 0; + + for (var i = 0; i < iterations; i++) { + setTimeout(cb, 1); + } + + bench.start(); + + function cb() { + count++; + if (count === iterations) + bench.end(iterations / 1e3); + } +} diff --git a/benchmark/tls/convertprotocols.js b/benchmark/tls/convertprotocols.js index 32da0fe6fde271..5d561455051a0c 100644 --- a/benchmark/tls/convertprotocols.js +++ b/benchmark/tls/convertprotocols.js @@ -12,8 +12,11 @@ function main(conf) { var i = 0; var m = {}; - common.v8ForceOptimization( - tls.convertNPNProtocols, ['ABC', 'XYZ123', 'FOO'], m); + // First call dominates results + if (n > 1) { + tls.convertNPNProtocols(['ABC', 'XYZ123', 'FOO'], m); + m = {}; + } bench.start(); for (; i < n; i++) tls.convertNPNProtocols(['ABC', 'XYZ123', 'FOO'], m); bench.end(n); diff --git a/benchmark/url/legacy-vs-whatwg-url-get-prop.js b/benchmark/url/legacy-vs-whatwg-url-get-prop.js index f703b75b16f6f7..ffc8b4995df3de 100644 --- a/benchmark/url/legacy-vs-whatwg-url-get-prop.js +++ b/benchmark/url/legacy-vs-whatwg-url-get-prop.js @@ -3,19 +3,7 @@ const common = require('../common.js'); const url = require('url'); const URL = url.URL; const assert = require('assert'); - -const inputs = { - long: 'http://nodejs.org:89/docs/latest/api/url.html#test?' + - 'payload1=true&payload2=false&test=1&benchmark=3&' + - 'foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + - 'key=f5c65e1e98fe07e648249ad41e1cfdb0', - short: 'https://nodejs.org/en/blog/', - idn: 'http://你好你好', - auth: 'https://user:pass@example.com/path?search=1', - special: 'file:///foo/bar/test/node.js', - percent: 'https://%E4%BD%A0/foo', - dot: 'https://example.org/./a/../b/./c' -}; +const inputs = require('../fixtures/url-inputs.js').urls; const bench = common.createBenchmark(main, { type: Object.keys(inputs), diff --git a/benchmark/url/legacy-vs-whatwg-url-parse.js b/benchmark/url/legacy-vs-whatwg-url-parse.js index ca7a48466c7dc3..ec386b7b85597d 100644 --- a/benchmark/url/legacy-vs-whatwg-url-parse.js +++ b/benchmark/url/legacy-vs-whatwg-url-parse.js @@ -3,19 +3,7 @@ const common = require('../common.js'); const url = require('url'); const URL = url.URL; const assert = require('assert'); - -const inputs = { - long: 'http://nodejs.org:89/docs/latest/api/url.html#test?' + - 'payload1=true&payload2=false&test=1&benchmark=3&' + - 'foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + - 'key=f5c65e1e98fe07e648249ad41e1cfdb0', - short: 'https://nodejs.org/en/blog/', - idn: 'http://你好你好', - auth: 'https://user:pass@example.com/path?search=1', - special: 'file:///foo/bar/test/node.js', - percent: 'https://%E4%BD%A0/foo', - dot: 'https://example.org/./a/../b/./c' -}; +const inputs = require('../fixtures/url-inputs.js').urls; const bench = common.createBenchmark(main, { type: Object.keys(inputs), @@ -34,7 +22,7 @@ function useLegacy(n, input) { } function useWHATWG(n, input) { - var noDead = url.parse(input); + var noDead = new URL(input); bench.start(); for (var i = 0; i < n; i += 1) { noDead = new URL(input); diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js new file mode 100644 index 00000000000000..86714df6c196a7 --- /dev/null +++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js @@ -0,0 +1,51 @@ +'use strict'; +const common = require('../common.js'); +const { URLSearchParams } = require('url'); +const querystring = require('querystring'); +const inputs = require('../fixtures/url-inputs.js').searchParams; + +const bench = common.createBenchmark(main, { + type: Object.keys(inputs), + method: ['legacy', 'whatwg'], + n: [1e5] +}); + +function useLegacy(n, input) { + querystring.parse(input); + bench.start(); + for (var i = 0; i < n; i += 1) { + querystring.parse(input); + } + bench.end(n); +} + +function useWHATWG(n, input) { + new URLSearchParams(input); + bench.start(); + for (var i = 0; i < n; i += 1) { + new URLSearchParams(input); + } + bench.end(n); +} + +function main(conf) { + const type = conf.type; + const n = conf.n | 0; + const method = conf.method; + + const input = inputs[type]; + if (!input) { + throw new Error('Unknown input type'); + } + + switch (method) { + case 'legacy': + useLegacy(n, input); + break; + case 'whatwg': + useWHATWG(n, input); + break; + default: + throw new Error('Unknown method'); + } +} diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js new file mode 100644 index 00000000000000..7e56b5fba6e4f8 --- /dev/null +++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js @@ -0,0 +1,53 @@ +'use strict'; +const common = require('../common.js'); +const { URLSearchParams } = require('url'); +const querystring = require('querystring'); +const inputs = require('../fixtures/url-inputs.js').searchParams; + +const bench = common.createBenchmark(main, { + type: Object.keys(inputs), + method: ['legacy', 'whatwg'], + n: [1e5] +}); + +function useLegacy(n, input, prop) { + const obj = querystring.parse(input); + querystring.stringify(obj); + bench.start(); + for (var i = 0; i < n; i += 1) { + querystring.stringify(obj); + } + bench.end(n); +} + +function useWHATWG(n, input, prop) { + const obj = new URLSearchParams(input); + obj.toString(); + bench.start(); + for (var i = 0; i < n; i += 1) { + obj.toString(); + } + bench.end(n); +} + +function main(conf) { + const type = conf.type; + const n = conf.n | 0; + const method = conf.method; + + const input = inputs[type]; + if (!input) { + throw new Error('Unknown input type'); + } + + switch (method) { + case 'legacy': + useLegacy(n, input); + break; + case 'whatwg': + useWHATWG(n, input); + break; + default: + throw new Error('Unknown method'); + } +} diff --git a/benchmark/url/legacy-vs-whatwg-url-serialize.js b/benchmark/url/legacy-vs-whatwg-url-serialize.js index c0b7f5a6ce1565..911e79794b84fb 100644 --- a/benchmark/url/legacy-vs-whatwg-url-serialize.js +++ b/benchmark/url/legacy-vs-whatwg-url-serialize.js @@ -3,19 +3,7 @@ const common = require('../common.js'); const url = require('url'); const URL = url.URL; const assert = require('assert'); - -const inputs = { - long: 'http://nodejs.org:89/docs/latest/api/url.html#test?' + - 'payload1=true&payload2=false&test=1&benchmark=3&' + - 'foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + - 'key=f5c65e1e98fe07e648249ad41e1cfdb0', - short: 'https://nodejs.org/en/blog/', - idn: 'http://你好你好', - auth: 'https://user:pass@example.com/path?search=1', - special: 'file:///foo/bar/test/node.js', - percent: 'https://%E4%BD%A0/foo', - dot: 'https://example.org/./a/../b/./c' -}; +const inputs = require('../fixtures/url-inputs.js').urls; const bench = common.createBenchmark(main, { type: Object.keys(inputs), diff --git a/benchmark/url/url-format.js b/benchmark/url/url-format.js index 3f7df8a0bc4536..771786d3350513 100644 --- a/benchmark/url/url-format.js +++ b/benchmark/url/url-format.js @@ -1,10 +1,14 @@ 'use strict'; const common = require('../common.js'); const url = require('url'); -const v8 = require('v8'); + +const inputs = { + slashes: {slashes: true, host: 'localhost'}, + file: {protocol: 'file:', pathname: '/foo'}, +}; const bench = common.createBenchmark(main, { - type: 'one two'.split(' '), + type: Object.keys(inputs), n: [25e6] }); @@ -12,10 +16,6 @@ function main(conf) { const type = conf.type; const n = conf.n | 0; - const inputs = { - one: {slashes: true, host: 'localhost'}, - two: {protocol: 'file:', pathname: '/foo'}, - }; const input = inputs[type] || ''; // Force-optimize url.format() so that the benchmark doesn't get @@ -23,9 +23,6 @@ function main(conf) { for (const name in inputs) url.format(inputs[name]); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(url.format)'); - bench.start(); for (var i = 0; i < n; i += 1) url.format(input); diff --git a/benchmark/url/url-parse.js b/benchmark/url/url-parse.js deleted file mode 100644 index 89679548b8f193..00000000000000 --- a/benchmark/url/url-parse.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; -var common = require('../common.js'); -var url = require('url'); -var v8 = require('v8'); - -var bench = common.createBenchmark(main, { - type: 'one two three four five six'.split(' '), - n: [25e4] -}); - -function main(conf) { - var type = conf.type; - var n = conf.n | 0; - - var inputs = { - one: 'http://nodejs.org/docs/latest/api/url.html#url_url_format_urlobj', - two: 'http://blog.nodejs.org/', - three: 'https://encrypted.google.com/search?q=url&q=site:npmjs.org&hl=en', - four: 'javascript:alert("node is awesome");', - five: 'some.ran/dom/url.thing?oh=yes#whoo', - six: 'https://user:pass@example.com/', - }; - var input = inputs[type] || ''; - - // Force-optimize url.parse() so that the benchmark doesn't get - // disrupted by the optimizer kicking in halfway through. - for (var name in inputs) - url.parse(inputs[name]); - - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(url.parse)'); - - bench.start(); - for (var i = 0; i < n; i += 1) - url.parse(input); - bench.end(n); -} diff --git a/benchmark/url/url-resolve.js b/benchmark/url/url-resolve.js index 8372132e4d269e..421a70ef6d59f1 100644 --- a/benchmark/url/url-resolve.js +++ b/benchmark/url/url-resolve.js @@ -1,42 +1,27 @@ 'use strict'; -var common = require('../common.js'); -var url = require('url'); -var v8 = require('v8'); +const common = require('../common.js'); +const url = require('url'); +const hrefs = require('../fixtures/url-inputs.js').urls; +hrefs.noscheme = 'some.ran/dom/url.thing?oh=yes#whoo'; -var hrefs = [ - 'http://example.com/', - 'http://nodejs.org/docs/latest/api/url.html#url_url_format_urlobj', - 'http://blog.nodejs.org/', - 'https://encrypted.google.com/search?q=url&q=site:npmjs.org&hl=en', - 'javascript:alert("node is awesome");', - 'some.ran/dom/url.thing?oh=yes#whoo' -]; +const paths = { + 'up': '../../../../../etc/passwd', + 'sibling': '../foo/bar?baz=boom', + 'foo/bar': 'foo/bar', + 'withscheme': 'http://nodejs.org', + 'down': './foo/bar?baz' +}; - -var paths = [ - '../../../../../etc/passwd', - '../foo/bar?baz=boom', - 'foo/bar', - 'http://nodejs.org', - './foo/bar?baz' -]; - -var bench = common.createBenchmark(main, { +const bench = common.createBenchmark(main, { href: Object.keys(hrefs), path: Object.keys(paths), n: [1e5] }); function main(conf) { - var n = conf.n | 0; - var href = hrefs[conf.href]; - var path = paths[conf.path]; - - // Force-optimize url.resolve() so that the benchmark doesn't get - // disrupted by the optimizer kicking in halfway through. - url.resolve(href, path); - v8.setFlagsFromString('--allow_natives_syntax'); - eval('%OptimizeFunctionOnNextCall(url.resolve)'); + const n = conf.n | 0; + const href = hrefs[conf.href]; + const path = paths[conf.path]; bench.start(); for (var i = 0; i < n; i += 1) diff --git a/benchmark/url/url-searchparams-iteration.js b/benchmark/url/url-searchparams-iteration.js index caa4e45c41247e..833271ef306309 100644 --- a/benchmark/url/url-searchparams-iteration.js +++ b/benchmark/url/url-searchparams-iteration.js @@ -1,7 +1,7 @@ 'use strict'; const common = require('../common.js'); const assert = require('assert'); -const URLSearchParams = new (require('url').URL)('a:').searchParams.constructor; +const { URLSearchParams } = require('url'); const bench = common.createBenchmark(main, { method: ['forEach', 'iterator'], diff --git a/benchmark/url/url-searchparams-parse.js b/benchmark/url/url-searchparams-parse.js deleted file mode 100644 index 61796a7d327bd4..00000000000000 --- a/benchmark/url/url-searchparams-parse.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; -const common = require('../common.js'); -const URLSearchParams = new (require('url').URL)('a:').searchParams.constructor; - -const inputs = { - noencode: 'foo=bar&baz=quux&xyzzy=thud', - // multicharsep: 'foo=bar&&&&&&&&&&baz=quux&&&&&&&&&&xyzzy=thud', - multicharsep: '&&&&&&&&&&&&&&&&&&&&&&&&&&&&', - encodemany: '%66%6F%6F=bar&%62%61%7A=quux&xyzzy=%74h%75d', - encodelast: 'foo=bar&baz=quux&xyzzy=thu%64', - multivalue: 'foo=bar&foo=baz&foo=quux&quuy=quuz', - multivaluemany: 'foo=bar&foo=baz&foo=quux&quuy=quuz&foo=abc&foo=def&' + - 'foo=ghi&foo=jkl&foo=mno&foo=pqr&foo=stu&foo=vwxyz', - manypairs: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z' -}; - -const bench = common.createBenchmark(main, { - type: Object.keys(inputs), - n: [1e5] -}); - -function main(conf) { - const input = inputs[conf.type]; - const n = conf.n | 0; - - var i; - bench.start(); - for (i = 0; i < n; i++) - new URLSearchParams(input); - bench.end(n); -} diff --git a/benchmark/url/url-searchparams-read.js b/benchmark/url/url-searchparams-read.js index 4cee49c74d2baa..94ddaf1cfa4072 100644 --- a/benchmark/url/url-searchparams-read.js +++ b/benchmark/url/url-searchparams-read.js @@ -1,6 +1,6 @@ 'use strict'; const common = require('../common.js'); -const URLSearchParams = new (require('url').URL)('a:').searchParams.constructor; +const { URLSearchParams } = require('url'); const bench = common.createBenchmark(main, { method: ['get', 'getAll', 'has'], diff --git a/benchmark/url/url-searchparams-sort.js b/benchmark/url/url-searchparams-sort.js new file mode 100644 index 00000000000000..677ce511cf3ea2 --- /dev/null +++ b/benchmark/url/url-searchparams-sort.js @@ -0,0 +1,48 @@ +'use strict'; +const common = require('../common.js'); +const URLSearchParams = require('url').URLSearchParams; + +const inputs = { + empty: '', + sorted: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z', + almostsorted: 'a&b&c&d&e&f&g&i&h&j&k&l&m&n&o&p&q&r&s&t&u&w&v&x&y&z', + reversed: 'z&y&x&w&v&u&t&s&r&q&p&o&n&m&l&k&j&i&h&g&f&e&d&c&b&a', + random: 'm&t&d&c&z&v&a&n&p&y&u&o&h&l&f&j&e&q&b&i&s&x&k&w&r&g', + // 8 parameters + short: 'm&t&d&c&z&v&a&n', + // 88 parameters + long: 'g&r&t&h&s&r&d&w&b&n&h&k&x&m&k&h&o&e&x&c&c&g&e&b&p&p&s&n&j&b&y&z&' + + 'u&l&o&r&w&a&u&l&m&f&j&q&p&f&e&y&e&n&e&l&m&w&u&w&t&n&t&q&v&y&c&o&' + + 'k&f&j&i&l&m&g&j&d&i&z&q&p&x&q&q&d&n&y&w&g&i&v&r' +}; + +function getParams(str) { + const out = []; + for (const key of str.split('&')) { + out.push(key, ''); + } + return out; +} + +const bench = common.createBenchmark(main, { + type: Object.keys(inputs), + n: [1e6] +}, { + flags: ['--expose-internals'] +}); + +function main(conf) { + const searchParams = require('internal/url').searchParamsSymbol; + const input = inputs[conf.type]; + const n = conf.n | 0; + const params = new URLSearchParams(); + const array = getParams(input); + + var i; + bench.start(); + for (i = 0; i < n; i++) { + params[searchParams] = array.slice(); + params.sort(); + } + bench.end(n); +} diff --git a/benchmark/url/url-searchparams-stringifier.js b/benchmark/url/url-searchparams-stringifier.js deleted file mode 100644 index 2979064b322592..00000000000000 --- a/benchmark/url/url-searchparams-stringifier.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; -const common = require('../common.js'); -const Buffer = require('buffer').Buffer; -const URLSearchParams = new (require('url').URL)('a:').searchParams.constructor; - -const inputs = { - noencode: 'foo=bar&baz=quux&xyzzy=thud', - // multicharsep: 'foo=bar&&&&&&&&&&baz=quux&&&&&&&&&&xyzzy=thud', - multicharsep: '&&&&&&&&&&&&&&&&&&&&&&&&&&&&', - encodemany: '%66%6F%6F=bar&%62%61%7A=quux&xyzzy=%74h%75d', - encodelast: 'foo=bar&baz=quux&xyzzy=thu%64', - multivalue: 'foo=bar&foo=baz&foo=quux&quuy=quuz', - multivaluemany: 'foo=bar&foo=baz&foo=quux&quuy=quuz&foo=abc&foo=def&' + - 'foo=ghi&foo=jkl&foo=mno&foo=pqr&foo=stu&foo=vwxyz', - manypairs: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z' -}; - -const bench = common.createBenchmark(main, { - type: Object.keys(inputs), - n: [1e5] -}); - -function main(conf) { - const input = inputs[conf.type]; - const n = conf.n | 0; - - const params = new URLSearchParams(input); - - bench.start(); - // Using Buffer.from to prevent JS version from cheating with ropes instead - // of strings - for (var i = 0; i < n; i += 1) - Buffer.from(params.toString()); - bench.end(n); -} diff --git a/benchmark/url/usvstring.js b/benchmark/url/usvstring.js new file mode 100644 index 00000000000000..40a945037385cf --- /dev/null +++ b/benchmark/url/usvstring.js @@ -0,0 +1,28 @@ +'use strict'; +const common = require('../common.js'); + +const inputs = { + valid: 'adsfadsfadsf', + validsurr: '\uda23\ude23\uda1f\udfaa\ud800\udfff\uda23\ude23\uda1f\udfaa' + + '\ud800\udfff', + someinvalid: 'asasfdfasd\uda23', + allinvalid: '\udc45\uda23 \udf00\udc00 \udfaa\uda12 \udc00\udfaa', + nonstring: { toString() { return 'asdf'; } } +}; +const bench = common.createBenchmark(main, { + input: Object.keys(inputs), + n: [5e7] +}, { + flags: ['--expose-internals'] +}); + +function main(conf) { + const { toUSVString } = require('internal/url'); + const str = inputs[conf.input]; + const n = conf.n | 0; + + bench.start(); + for (var i = 0; i < n; i++) + toUSVString(str); + bench.end(n); +} diff --git a/benchmark/url/whatwg-url-idna.js b/benchmark/url/whatwg-url-idna.js new file mode 100644 index 00000000000000..41b4c639de97b6 --- /dev/null +++ b/benchmark/url/whatwg-url-idna.js @@ -0,0 +1,47 @@ +'use strict'; +const common = require('../common.js'); +const { domainToASCII, domainToUnicode } = require('url'); + +const inputs = { + empty: { + ascii: '', + unicode: '' + }, + none: { + ascii: 'passports', + unicode: 'passports' + }, + some: { + ascii: 'Paßstraße', + unicode: 'xn--Pastrae-1vae' + }, + all: { + ascii: '他们不说中文', + unicode: 'xn--ihqwczyycu19kkg2c' + }, + nonstring: { + ascii: { toString() { return ''; } }, + unicode: { toString() { return ''; } } + } +}; + +const bench = common.createBenchmark(main, { + input: Object.keys(inputs), + to: ['ascii', 'unicode'], + n: [5e6] +}); + +function main(conf) { + const n = conf.n | 0; + const to = conf.to; + const input = inputs[conf.input][to]; + const method = to === 'ascii' ? domainToASCII : domainToUnicode; + + common.v8ForceOptimization(method, input); + + bench.start(); + for (var i = 0; i < n; i++) { + method(input); + } + bench.end(n); +} diff --git a/benchmark/url/whatwg-url-properties.js b/benchmark/url/whatwg-url-properties.js index 375939c601d363..9bdc9778a8c922 100644 --- a/benchmark/url/whatwg-url-properties.js +++ b/benchmark/url/whatwg-url-properties.js @@ -1,16 +1,11 @@ 'use strict'; +const common = require('../common.js'); +const URL = require('url').URL; +const inputs = require('../fixtures/url-inputs.js').urls; -var common = require('../common.js'); -var URL = require('url').URL; - -var bench = common.createBenchmark(main, { - url: [ - 'http://example.com/', - 'https://encrypted.google.com/search?q=url&q=site:npmjs.org&hl=en', - 'javascript:alert("node is awesome");', - 'http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test' - ], - prop: ['toString', 'href', 'origin', 'protocol', +const bench = common.createBenchmark(main, { + input: Object.keys(inputs), + prop: ['href', 'origin', 'protocol', 'username', 'password', 'host', 'hostname', 'port', 'pathname', 'search', 'searchParams', 'hash'], n: [1e4] @@ -34,14 +29,6 @@ function get(n, url, prop) { bench.end(n); } -function stringify(n, url, prop) { - bench.start(); - for (var i = 0; i < n; i += 1) { - url.toString(); - } - bench.end(n); -} - const alternatives = { href: 'http://user:pass@foo.bar.com:21/aaa/zzz?l=25#test', protocol: 'https:', @@ -61,7 +48,8 @@ function getAlternative(prop) { function main(conf) { const n = conf.n | 0; - const url = new URL(conf.url); + const input = inputs[conf.input]; + const url = new URL(input); const prop = conf.prop; switch (prop) { @@ -74,17 +62,13 @@ function main(conf) { case 'pathname': case 'search': case 'hash': + case 'href': setAndGet(n, url, prop, getAlternative(prop)); break; - // TODO: move href to the first group when the setter lands. - case 'href': case 'origin': case 'searchParams': get(n, url, prop); break; - case 'toString': - stringify(n, url); - break; default: throw new Error('Unknown prop'); } diff --git a/benchmark/util/format.js b/benchmark/util/format.js index 8040554ba0861a..82e25b4c4c8127 100644 --- a/benchmark/util/format.js +++ b/benchmark/util/format.js @@ -2,7 +2,6 @@ const util = require('util'); const common = require('../common'); -const v8 = require('v8'); const types = [ 'string', 'number', @@ -29,12 +28,6 @@ function main(conf) { const input = inputs[type]; - v8.setFlagsFromString('--allow_natives_syntax'); - - util.format(input[0], input[1]); - eval('%OptimizeFunctionOnNextCall(util.format)'); - util.format(input[0], input[1]); - bench.start(); for (var i = 0; i < n; i++) { util.format(input[0], input[1]); diff --git a/common.gypi b/common.gypi index d87205e5c320cf..a52915d59a7ac4 100644 --- a/common.gypi +++ b/common.gypi @@ -42,12 +42,19 @@ 'os_posix': 1, 'v8_postmortem_support%': 'true', }], - ['GENERATOR == "ninja" or OS== "mac"', { + ['OS== "mac"', { 'OBJ_DIR': '<(PRODUCT_DIR)/obj', 'V8_BASE': '<(PRODUCT_DIR)/libv8_base.a', }, { - 'OBJ_DIR': '<(PRODUCT_DIR)/obj.target', - 'V8_BASE': '<(PRODUCT_DIR)/obj.target/deps/v8/src/libv8_base.a', + 'conditions': [ + ['GENERATOR=="ninja"', { + 'OBJ_DIR': '<(PRODUCT_DIR)/obj', + 'V8_BASE': '<(PRODUCT_DIR)/obj/deps/v8/src/libv8_base.a', + }, { + 'OBJ_DIR': '<(PRODUCT_DIR)/obj.target', + 'V8_BASE': '<(PRODUCT_DIR)/obj.target/deps/v8/src/libv8_base.a', + }], + ], }], ['openssl_fips != ""', { 'OPENSSL_PRODUCT': 'libcrypto.a', @@ -188,6 +195,10 @@ 'BufferSecurityCheck': 'true', 'ExceptionHandling': 0, # /EHsc 'SuppressStartupBanner': 'true', + # Disable "warning C4267: conversion from 'size_t' to 'int', + # possible loss of data". Many originate from our dependencies + # and their sheer number drowns out other, more legitimate warnings. + 'DisableSpecificWarnings': ['4267'], 'WarnAsError': 'false', }, 'VCLibrarianTool': { diff --git a/configure b/configure index d926cec7d5d7ea..31d682575e7a0d 100755 --- a/configure +++ b/configure @@ -2,7 +2,16 @@ import sys if sys.version_info[0] != 2 or sys.version_info[1] not in (6, 7): - sys.stdout.write("Please use either Python 2.6 or 2.7\n") + sys.stderr.write('Please use either Python 2.6 or 2.7') + + from distutils.spawn import find_executable as which + python2 = which('python2') or which('python2.6') or which('python2.7') + + if python2: + sys.stderr.write(':\n\n') + sys.stderr.write(' ' + python2 + ' ' + ' '.join(sys.argv)) + + sys.stderr.write('\n') sys.exit(1) import errno @@ -144,6 +153,11 @@ parser.add_option('--openssl-fips', dest='openssl_fips', help='Build OpenSSL using FIPS canister .o file in supplied folder') +parser.add_option('--openssl-use-def-ca-store', + action='store_true', + dest='use_openssl_ca_store', + help='Use OpenSSL supplied CA store instead of compiled-in Mozilla CA copy.') + shared_optgroup.add_option('--shared-http-parser', action='store_true', dest='shared_http_parser', @@ -469,6 +483,12 @@ parser.add_option('--without-bundled-v8', help='do not use V8 includes from the bundled deps folder. ' + '(This mode is not officially supported for regular applications)') +# Create compile_commands.json in out/Debug and out/Release. +parser.add_option('-C', + action='store_true', + dest='compile_commands_json', + help=optparse.SUPPRESS_HELP) + (options, args) = parser.parse_args() # Expand ~ in the install prefix now, it gets written to multiple files. @@ -483,7 +503,7 @@ def warn(msg): prefix = '\033[1m\033[93mWARNING\033[0m' if os.isatty(1) else 'WARNING' print('%s: %s' % (prefix, msg)) -# track if warnings occured +# track if warnings occurred warn.warned = False def b(value): @@ -556,11 +576,11 @@ def get_version_helper(cc, regexp): def get_llvm_version(cc): return get_version_helper( - cc, r"(^clang version|based on LLVM) ([3-9]\.[0-9]+)") + cc, r"(^(?:FreeBSD )?clang version|based on LLVM) ([3-9]\.[0-9]+)") def get_xcode_version(cc): return get_version_helper( - cc, r"(^Apple LLVM version) ([5-9]\.[0-9]+)") + cc, r"(^Apple LLVM version) ([5-9]\.[0-9]+)") def get_gas_version(cc): try: @@ -706,6 +726,9 @@ def host_arch_cc(): if rtn != 's390': break + if rtn == 'mipsel' and '_LP64' in k: + rtn = 'mips64el' + return rtn @@ -787,7 +810,7 @@ def configure_node(o): if target_arch == 'arm': configure_arm(o) - elif target_arch in ('mips', 'mipsel'): + elif target_arch in ('mips', 'mipsel', 'mips64el'): configure_mips(o) if flavor == 'aix': @@ -940,6 +963,8 @@ def configure_openssl(o): o['variables']['node_use_openssl'] = b(not options.without_ssl) o['variables']['node_shared_openssl'] = b(options.shared_openssl) o['variables']['openssl_no_asm'] = 1 if options.openssl_no_asm else 0 + if options.use_openssl_ca_store: + o['defines'] += ['NODE_OPENSSL_CERT_STORE'] if options.openssl_fips: o['variables']['openssl_fips'] = options.openssl_fips fips_dir = os.path.join(root_dir, 'deps', 'openssl', 'fips') @@ -1258,7 +1283,7 @@ def configure_inspector(o): disable_inspector = (options.without_inspector or options.with_intl in (None, 'none') or options.without_ssl) - o['variables']['v8_inspector'] = b(not disable_inspector) + o['variables']['v8_enable_inspector'] = 0 if disable_inspector else 1 output = { 'variables': {}, @@ -1350,6 +1375,9 @@ elif flavor == 'win' and sys.platform != 'msys': else: gyp_args += ['-f', 'make-' + flavor] +if options.compile_commands_json: + gyp_args += ['-f', 'compile_commands_json'] + gyp_args += args if warn.warned: diff --git a/deps/node-inspect/.editorconfig b/deps/node-inspect/.editorconfig new file mode 100644 index 00000000000000..beffa3084e7a69 --- /dev/null +++ b/deps/node-inspect/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/deps/node-inspect/.eslintrc b/deps/node-inspect/.eslintrc new file mode 100644 index 00000000000000..c731203df64fd7 --- /dev/null +++ b/deps/node-inspect/.eslintrc @@ -0,0 +1,147 @@ +root: true + +env: + node: true + es6: true + +parserOptions: + ecmaVersion: 2016 + +rules: + # Possible Errors + # http://eslint.org/docs/rules/#possible-errors + comma-dangle: [2, only-multiline] + no-control-regex: 2 + no-debugger: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 2 + no-extra-parens: [2, functions] + no-extra-semi: 2 + no-func-assign: 2 + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-obj-calls: 2 + no-proto: 2 + no-template-curly-in-string: 2 + no-unexpected-multiline: 2 + no-unreachable: 2 + no-unsafe-negation: 2 + use-isnan: 2 + valid-typeof: 2 + + # Best Practices + # http://eslint.org/docs/rules/#best-practices + dot-location: [2, property] + no-fallthrough: 2 + no-global-assign: 2 + no-multi-spaces: 2 + no-octal: 2 + no-redeclare: 2 + no-self-assign: 2 + no-unused-labels: 2 + no-useless-call: 2 + no-useless-escape: 2 + no-void: 2 + no-with: 2 + + # Strict Mode + # http://eslint.org/docs/rules/#strict-mode + strict: [2, global] + + # Variables + # http://eslint.org/docs/rules/#variables + no-delete-var: 2 + no-undef: 2 + no-unused-vars: [2, {args: none}] + + # Node.js and CommonJS + # http://eslint.org/docs/rules/#nodejs-and-commonjs + no-mixed-requires: 2 + no-new-require: 2 + no-path-concat: 2 + no-restricted-modules: [2, sys, _linklist] + no-restricted-properties: [2, { + object: assert, + property: deepEqual, + message: Please use assert.deepStrictEqual(). + }, { + property: __defineGetter__, + message: __defineGetter__ is deprecated. + }, { + property: __defineSetter__, + message: __defineSetter__ is deprecated. + }] + + # Stylistic Issues + # http://eslint.org/docs/rules/#stylistic-issues + brace-style: [2, 1tbs, {allowSingleLine: true}] + comma-spacing: 2 + comma-style: 2 + computed-property-spacing: 2 + eol-last: 2 + func-call-spacing: 2 + func-name-matching: 2 + indent: [2, 2, {SwitchCase: 1, MemberExpression: 1}] + key-spacing: [2, {mode: minimum}] + keyword-spacing: 2 + linebreak-style: [2, unix] + max-len: [2, 80, 2] + new-parens: 2 + no-mixed-spaces-and-tabs: 2 + no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] + no-tabs: 2 + no-trailing-spaces: 2 + quotes: [2, single, avoid-escape] + semi: 2 + semi-spacing: 2 + space-before-blocks: [2, always] + space-before-function-paren: [2, never] + space-in-parens: [2, never] + space-infix-ops: 2 + space-unary-ops: 2 + + # ECMAScript 6 + # http://eslint.org/docs/rules/#ecmascript-6 + arrow-parens: [2, always] + arrow-spacing: [2, {before: true, after: true}] + constructor-super: 2 + no-class-assign: 2 + no-confusing-arrow: 2 + no-const-assign: 2 + no-dupe-class-members: 2 + no-new-symbol: 2 + no-this-before-super: 2 + prefer-const: [2, {ignoreReadBeforeAssign: true}] + rest-spread-spacing: 2 + template-curly-spacing: 2 + + # Custom rules in tools/eslint-rules + align-function-arguments: 2 + align-multiline-assignment: 2 + assert-fail-single-argument: 2 + new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError] + +# Global scoped method and vars +globals: + COUNTER_HTTP_CLIENT_REQUEST: false + COUNTER_HTTP_CLIENT_RESPONSE: false + COUNTER_HTTP_SERVER_REQUEST: false + COUNTER_HTTP_SERVER_RESPONSE: false + COUNTER_NET_SERVER_CONNECTION: false + COUNTER_NET_SERVER_CONNECTION_CLOSE: false + DTRACE_HTTP_CLIENT_REQUEST: false + DTRACE_HTTP_CLIENT_RESPONSE: false + DTRACE_HTTP_SERVER_REQUEST: false + DTRACE_HTTP_SERVER_RESPONSE: false + DTRACE_NET_SERVER_CONNECTION: false + DTRACE_NET_STREAM_END: false + LTTNG_HTTP_CLIENT_REQUEST: false + LTTNG_HTTP_CLIENT_RESPONSE: false + LTTNG_HTTP_SERVER_REQUEST: false + LTTNG_HTTP_SERVER_RESPONSE: false + LTTNG_NET_SERVER_CONNECTION: false + LTTNG_NET_STREAM_END: false diff --git a/deps/node-inspect/.gitignore b/deps/node-inspect/.gitignore new file mode 100644 index 00000000000000..72e2c8c18012a8 --- /dev/null +++ b/deps/node-inspect/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +npm-debug.log +/tmp +/.vs diff --git a/deps/node-inspect/.npmrc b/deps/node-inspect/.npmrc new file mode 100644 index 00000000000000..38f11c645a0019 --- /dev/null +++ b/deps/node-inspect/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org diff --git a/deps/node-inspect/.travis.yml b/deps/node-inspect/.travis.yml new file mode 100644 index 00000000000000..07418a91eb7986 --- /dev/null +++ b/deps/node-inspect/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +node_js: + - '6.8' +before_deploy: + - git config --global user.email "jan.krems@gmail.com" + - git config --global user.name "Jan Krems" +deploy: + provider: script + script: ./node_modules/.bin/nlm release + skip_cleanup: true + 'on': + branch: master + node: '6.8' diff --git a/deps/node-inspect/CHANGELOG.md b/deps/node-inspect/CHANGELOG.md new file mode 100644 index 00000000000000..0a7ba1be94fb50 --- /dev/null +++ b/deps/node-inspect/CHANGELOG.md @@ -0,0 +1,212 @@ +### 1.10.4 + +* [`1c31bf7`](https://github.com/buggerjs/node-inspect/commit/1c31bf7d1b3ea1b424ae0662526596670cb506c9) **chore:** Support embedded mode + + +### 1.10.3 + +* [`7b20379`](https://github.com/buggerjs/node-inspect/commit/7b20379069af692a9038a31a4465f72db9eb532f) **chore:** Mark .eslintrc as root + + +### 1.10.2 + +* Run tests on windows - **[@jkrems](https://github.com/jkrems)** [#16](https://github.com/buggerjs/node-inspect/pull/16) + - [`5a57f98`](https://github.com/buggerjs/node-inspect/commit/5a57f9865e02eef0763c2a7f26236c34a632ccdd) **chore:** Run tests on windows + - [`0a04b50`](https://github.com/buggerjs/node-inspect/commit/0a04b50cc8b4dc6ce868927c635c479d75ce71f4) **chore:** Bump nlm to get rid of postinstall + - [`4a8b27c`](https://github.com/buggerjs/node-inspect/commit/4a8b27cea814a37895effd2a0c1b85dbfee3a7f4) **test:** Remove unix path assumptions + + +### 1.10.1 + +* [`4ba3c72`](https://github.com/buggerjs/node-inspect/commit/4ba3c72270fae9a71343ddca11aa27980678a67c) **refactor:** Undo weird bundling into one file + + +### 1.10.0 + +* [`3e1a66a`](https://github.com/buggerjs/node-inspect/commit/3e1a66a489bef19beaa5f859e99e027274ff43cb) **feat:** Support CPU & heap profiles + + +### 1.9.3 + +* Move back to single file - **[@jkrems](https://github.com/jkrems)** [#15](https://github.com/buggerjs/node-inspect/pull/15) + - [`9877660`](https://github.com/buggerjs/node-inspect/commit/9877660a73ff0ec0885ad7f939ba62020a46b4b6) **refactor:** Wrap client in IIFE + - [`7795c53`](https://github.com/buggerjs/node-inspect/commit/7795c533f0605eb128db610a5874b27e555251ef) **refactor:** Move more code in createRepl scope + - [`be34a39`](https://github.com/buggerjs/node-inspect/commit/be34a398e823612bdf5ac90bad5222af27035a00) **refactor:** Move back to single file + - [`ab45b62`](https://github.com/buggerjs/node-inspect/commit/ab45b6273dc0d3a49d3cf46a80cb48ab79d1caf8) **refactor:** Remove single-use functions + - [`37a711e`](https://github.com/buggerjs/node-inspect/commit/37a711ed5334c06ed4d85f995e567a9f176a68d5) **style:** Stop using `new Buffer` + - [`d669dc5`](https://github.com/buggerjs/node-inspect/commit/d669dc593f5ad5ca7a48f19f0905ef66ec0e540d) **chore:** Switch to node eslint rules + - [`15e7917`](https://github.com/buggerjs/node-inspect/commit/15e79177918d96dcffd2384715faf0308e97a26c) **style:** Use var in classical for loops + + +### 1.9.2 + +* [`c9dc4be`](https://github.com/buggerjs/node-inspect/commit/c9dc4beb08236e33d64f19417682cf5b3f5aeed6) **doc:** Link directly to GOVERNANCE file + + +### 1.9.1 + +* Handle big ws frames correctly - **[@jkrems](https://github.com/jkrems)** [#14](https://github.com/buggerjs/node-inspect/pull/14) + - [`f80100e`](https://github.com/buggerjs/node-inspect/commit/f80100e932710d232d074b239cbf8fefa564c789) **fix:** Handle big ws frames correctly - see: [#10](https://github.com/buggerjs/node-inspect/issues/10) + + +### 1.9.0 + +* Support for low-level agent access - **[@jkrems](https://github.com/jkrems)** [#13](https://github.com/buggerjs/node-inspect/pull/13) + - [`90ed431`](https://github.com/buggerjs/node-inspect/commit/90ed4310c62d130637c12f8ecdb752075c43ac36) **feat:** Support for low-level agent access + + +### 1.8.4 + +* Use proper path for websocket - **[@jkrems](https://github.com/jkrems)** [#12](https://github.com/buggerjs/node-inspect/pull/12) + - [`3405225`](https://github.com/buggerjs/node-inspect/commit/3405225979dfc2058bcc6d1b90f41c060dbd1f92) **fix:** Use proper path for websocket - see: [#11](https://github.com/buggerjs/node-inspect/issues/11) + + +### 1.8.3 + +* [`6f9883d`](https://github.com/buggerjs/node-inspect/commit/6f9883d4b29419831133988981b83e891b19739a) **fix:** Breakpoints & scripts work when not paused +* [`ecb1362`](https://github.com/buggerjs/node-inspect/commit/ecb1362c842e6ed5bc28c091a32bfd540742db75) **chore:** Pin node to 6.8 + + +### 1.8.2 + +* [`4219a98`](https://github.com/buggerjs/node-inspect/commit/4219a98d6514f1068feabce2945c21a0d5ba6561) **refactor:** Decouple source snippet from repl + + +### 1.8.1 + +* [`95402ee`](https://github.com/buggerjs/node-inspect/commit/95402ee5dff04057f074677d39db2f61ec74c151) **refactor:** Move `list` into CallFrame + + +### 1.8.0 + +* [`d0e6499`](https://github.com/buggerjs/node-inspect/commit/d0e6499084f5d656ef0c5fd470d3ab21f2e9a6b4) **feat:** `exec .scope` + + +### 1.7.0 + +* `breakOn{Exception,Uncaught,None}` - **[@jkrems](https://github.com/jkrems)** [#8](https://github.com/buggerjs/node-inspect/pull/8) + - [`fa8c4c7`](https://github.com/buggerjs/node-inspect/commit/fa8c4c7d7bb6972733c92da4d04fdd62c02b0e3b) **feat:** `breakOn{Exception,Uncaught,None}` - see: [#6](https://github.com/buggerjs/node-inspect/issues/6) + + +### 1.6.0 + +* Add `help` command - **[@jkrems](https://github.com/jkrems)** [#7](https://github.com/buggerjs/node-inspect/pull/7) + - [`09b37a0`](https://github.com/buggerjs/node-inspect/commit/09b37a02e04e16a38ce27f69538d3b098548b47c) **feat:** Add `help` command - see: [#5](https://github.com/buggerjs/node-inspect/issues/5) + + +### 1.5.0 + +* [`7e0fd99`](https://github.com/buggerjs/node-inspect/commit/7e0fd99fcfc65d8b647a2259df78f4cabf1d3d63) **feat:** Add `r` shortcut for `run` + + +### 1.4.1 + +* [`484d098`](https://github.com/buggerjs/node-inspect/commit/484d0983f06d6ff9639ab5197ba0a58313f532df) **chore:** Remove old implementation + + +### 1.4.0 + +* Properly tested implementation - **[@jkrems](https://github.com/jkrems)** [#4](https://github.com/buggerjs/node-inspect/pull/4) + - [`ba060d3`](https://github.com/buggerjs/node-inspect/commit/ba060d3ef65ae84df2a3a9b9f16d563f3c4b29be) **feat:** Error handling w/o args + - [`b39b3bc`](https://github.com/buggerjs/node-inspect/commit/b39b3bc07c13adc48fc8bb720889285c51e62548) **feat:** Launch child + - [`481693f`](https://github.com/buggerjs/node-inspect/commit/481693f676ee099b7787cd2426b980858e973602) **feat:** Connect debug client + - [`3bba0f2`](https://github.com/buggerjs/node-inspect/commit/3bba0f2416b2e3b4e6010de675003fcc328b16e8) **chore:** Disable lint for inactive code + - [`cc7bdfc`](https://github.com/buggerjs/node-inspect/commit/cc7bdfcf7f21ef5cd5c32c7800407238b0d4f100) **feat:** Properly fail with invalid host:port + - [`73f34f9`](https://github.com/buggerjs/node-inspect/commit/73f34f902634e9778597e129f46895aa8b643d72) **refactor:** Remove unused field + - [`6a23e0c`](https://github.com/buggerjs/node-inspect/commit/6a23e0cf3179f43ca6fc5a0fa2b1dd18ebc044b5) **refactor:** Better debug output & support node 6.6 + - [`63b0f9b`](https://github.com/buggerjs/node-inspect/commit/63b0f9b6ef8bd9af0f7cb14a5938a45838731fc9) **test:** Add timeout to waitFor(pattern) + - [`cfa197b`](https://github.com/buggerjs/node-inspect/commit/cfa197bf8325a1a4ca1b296f8d6971d368bfbfbb) **refactor:** Move REPL setup into own file + - [`3f46c2c`](https://github.com/buggerjs/node-inspect/commit/3f46c2c43f836e1135b66871087aa74969f6b330) **feat:** Working repl eval + - [`6911eb1`](https://github.com/buggerjs/node-inspect/commit/6911eb1a00b964bc5683506d433fa4f665f5a82c) **feat:** Enter repeats last command + - [`7d20b7d`](https://github.com/buggerjs/node-inspect/commit/7d20b7deadf1b251ea8cf2cc9167c175624932c4) **chore:** Add missing license header + - [`23c62f8`](https://github.com/buggerjs/node-inspect/commit/23c62f8375ca7c8b71d032047e728dace02f4efa) **feat:** Print break context + - [`5dbc83d`](https://github.com/buggerjs/node-inspect/commit/5dbc83df31171f9c38a974c99340bde26f2e24ec) **feat:** Stepping and breakpoints + - [`8deb8cc`](https://github.com/buggerjs/node-inspect/commit/8deb8cc36b9fca432ab8df63a82e9de7ab5adaf0) **feat:** list for printing source + - [`1ed2ec9`](https://github.com/buggerjs/node-inspect/commit/1ed2ec9937070652be611dbb6b11dfb42cb840f8) **chore:** Disable verbose output on CI + - [`625a435`](https://github.com/buggerjs/node-inspect/commit/625a435925dd8fd980bed2dc9e3fd73dd27df4ef) **fix:** Gracefully handle delayed scriptParsed + - [`8823c60`](https://github.com/buggerjs/node-inspect/commit/8823c60d347600b2313cfdd8cb5e96fe02419a8a) **chore:** Run all the tests + - [`00506f7`](https://github.com/buggerjs/node-inspect/commit/00506f763928cc440505a81030167a11b9a84e00) **feat:** backtrace/bt + - [`e1ee02d`](https://github.com/buggerjs/node-inspect/commit/e1ee02d5cc389916489d387d07d5dd161230427a) **refactor:** Leverage util.inspect.custom + - [`5dcc319`](https://github.com/buggerjs/node-inspect/commit/5dcc31922d40f56c7435319d1538390a442e8e4b) **feat:** scripts and scripts(true) + - [`085cd5a`](https://github.com/buggerjs/node-inspect/commit/085cd5a76a961edfcaa342fff5eb09bf2f9c8983) **refactor:** Consistent import style + - [`1c60f91`](https://github.com/buggerjs/node-inspect/commit/1c60f91f233848c05d865617dc7f5aacb36270b6) **feat:** Set breakpoint before file is loaded + - [`bc82ecc`](https://github.com/buggerjs/node-inspect/commit/bc82eccb2a1a7c0f5332371254f6584e748216aa) **feat:** breakpoints to list breakpoints + - [`7f48c95`](https://github.com/buggerjs/node-inspect/commit/7f48c9510696ec400d51afaca8d23a9c292640f8) **feat:** watchers & exec + - [`0f8cd13`](https://github.com/buggerjs/node-inspect/commit/0f8cd13a092e5dbeb395ff04cbe2ed97cb986423) **feat:** clearBreakpoint + - [`0d31560`](https://github.com/buggerjs/node-inspect/commit/0d315603bdcb9f4da42fab24dc569c325151269e) **feat:** version to print v8 version + - [`df6b89d`](https://github.com/buggerjs/node-inspect/commit/df6b89df580a9afcb3b8883b0e4224cbcebb384f) **feat:** Paused & global exec + - [`9e97d73`](https://github.com/buggerjs/node-inspect/commit/9e97d73073ceffd70974d45887c84fadb9159d5c) **feat:** repl to enter exec mode + - [`9ee9f90`](https://github.com/buggerjs/node-inspect/commit/9ee9f903d6202f54ed2b3b3559da4006b65d39b5) **feat:** run & restart +* [`3a752aa`](https://github.com/buggerjs/node-inspect/commit/3a752aaa773968bfe16c5f543bd739feed598bea) **feat:** kill +* [`a67e470`](https://github.com/buggerjs/node-inspect/commit/a67e47018b20d46aeeaa7abd27eb8e7770fd0b8f) **feat:** Restore breakpoints on restart + + +### 1.3.3 + +* [`eb7a54c`](https://github.com/buggerjs/node-inspect/commit/eb7a54c6fa731ed3276072c72034046fc5ffbac6) **chore:** Switch to tap for tests + + +### 1.3.2 + +* Add notes about governance - **[@jkrems](https://github.com/jkrems)** [#3](https://github.com/buggerjs/node-inspect/pull/3) + - [`e94089d`](https://github.com/buggerjs/node-inspect/commit/e94089d93689cacf5c953e94563463d1e174452d) **chore:** Add notes about governance + + +### 1.3.1 + +* [`8767137`](https://github.com/buggerjs/node-inspect/commit/8767137c53a2f6b1d36970074ea95be9871e50e3) **style:** Remove rogue console.log + + +### 1.3.0 + +* [`3ac6232`](https://github.com/buggerjs/node-inspect/commit/3ac623219ba44b0af40ef66826610a26a46c7966) **feat:** Add `version` command + + +### 1.2.0 + +* [`86b5812`](https://github.com/buggerjs/node-inspect/commit/86b581218ccab44e6bde259a17ad1e71645a6137) **feat:** scripts & listScripts(true) + + +### 1.1.1 + +* [`feaea38`](https://github.com/buggerjs/node-inspect/commit/feaea385a981e6b72a8d99277fbf575c54e15fc6) **style:** Typo in comment + + +### 1.1.0 + +* [`c64155f`](https://github.com/buggerjs/node-inspect/commit/c64155faa552f71463842a26330aa5bcbfc31670) **feat:** repl command + + +### 1.0.0 + +* [`44c4c79`](https://github.com/buggerjs/node-inspect/commit/44c4c79af5a228ccfd8906f11409b2a33390b878) **chore:** Initial commit +* [`985873c`](https://github.com/buggerjs/node-inspect/commit/985873cfb97146b38480080f9907219c473f1f6f) **feat:** Launching the example works +* [`3d92d05`](https://github.com/buggerjs/node-inspect/commit/3d92d05cca152a2c2647aa64eefc80432638bc4d) **chore:** Proper license and passing tests +* [`b3f99d9`](https://github.com/buggerjs/node-inspect/commit/b3f99d981038b17663fcfd984d2f5d6d9b51ee18) **feat:** Futile attempts to send a valid ws frame +* [`465cfb7`](https://github.com/buggerjs/node-inspect/commit/465cfb7b295aebb48b285c26f6de9c4657fe590d) **feat:** Working ws connection +* [`da9f011`](https://github.com/buggerjs/node-inspect/commit/da9f01118e2b144f2da8cd370113a608526774a1) **fix:** Fix remote connect +* [`5ef33d7`](https://github.com/buggerjs/node-inspect/commit/5ef33d7892cc49becb4c66098fc7927bc74b014a) **feat:** Working step-by-step +* [`534e1e4`](https://github.com/buggerjs/node-inspect/commit/534e1e46b307d61d51eb4c0aab4a3b17c17aea3d) **chore:** Add bin entry +* [`8cff9cf`](https://github.com/buggerjs/node-inspect/commit/8cff9cfb0138b5ecff0f5f6a7839dbfddc0684fd) **style:** Use simpler key thingy +* [`720ec53`](https://github.com/buggerjs/node-inspect/commit/720ec53a5b251ab3caf27f06b60924efb9e03a92) **doc:** Add instructions +* [`b89ad60`](https://github.com/buggerjs/node-inspect/commit/b89ad601b885a417e6433b1609477d8453f498a1) **doc:** More helpful docs +* [`de9243c`](https://github.com/buggerjs/node-inspect/commit/de9243c95eabe733d05952229340808c3cebf129) **feat:** Watchers +* [`e16978f`](https://github.com/buggerjs/node-inspect/commit/e16978ff8e4b2b2bdccf88fd7d3905f525822981) **docs:** Working usage hints +* [`2dbc204`](https://github.com/buggerjs/node-inspect/commit/2dbc2042145fd97169fc7536186a449715e27810) **refactor:** Use proxies +* [`b8c9b14`](https://github.com/buggerjs/node-inspect/commit/b8c9b147713f63181396d5a7fe4c2f737b733b4c) **style:** Remove unused var +* [`f6b4b20`](https://github.com/buggerjs/node-inspect/commit/f6b4b20a1d28d91cfe452b995f7dbe5f7c749e89) **feat:** Nicer inspect of remote values +* [`36887c6`](https://github.com/buggerjs/node-inspect/commit/36887c66bbf26d540f087f80ddfec38462a33bdf) **fix:** Properly print watchers +* [`7729442`](https://github.com/buggerjs/node-inspect/commit/77294426157a28cc76e339cb13916a205182641e) **feat:** Add pause command +* [`e39a713`](https://github.com/buggerjs/node-inspect/commit/e39a7134873f06da37baaa9b6252cede4ad38d7a) **fix:** Properly format boolean properties +* [`f8f51d7`](https://github.com/buggerjs/node-inspect/commit/f8f51d7a01e8d74023306a08a3d6e2da63d123e1) **fix:** Properly format numeric properties +* [`89e6e08`](https://github.com/buggerjs/node-inspect/commit/89e6e087220f3c3cb628ac7541c44298485a2e04) **feat:** Add backtrace command +* [`82362ac`](https://github.com/buggerjs/node-inspect/commit/82362acfc7ce22b4cccc64889ec136dedc8895ec) **feat:** Add setBreakpoint() +* [`7064cce`](https://github.com/buggerjs/node-inspect/commit/7064ccec3b103683088d532abfe5b4e7c066948b) **feat:** Add `setBreakpoint(line)` +* [`360580e`](https://github.com/buggerjs/node-inspect/commit/360580eba4353e81311e56df018eec0ca233da11) **feat:** Add run/kill/restart +* [`b1b576e`](https://github.com/buggerjs/node-inspect/commit/b1b576e2645723a8575df544e0bfb672d60d9d91) **feat:** Add `help` command +* [`2db4660`](https://github.com/buggerjs/node-inspect/commit/2db46609cd1c8543d31ebd5dc47e4c27ec254841) **feat:** Add remaining sb() variants +* [`f2ad1ae`](https://github.com/buggerjs/node-inspect/commit/f2ad1aeedafb154043d70bb9195b10986d311d26) **fix:** Display breakpoints set into the future +* [`73272f9`](https://github.com/buggerjs/node-inspect/commit/73272f9ace1f8546f8cad1d53627dbffba50bb4e) **refactor:** Make breakpoints more inspect friendly +* [`507a71d`](https://github.com/buggerjs/node-inspect/commit/507a71de345a3de7fe144517e9f5ea264ff993e3) **feat:** Add breakpoints command +* [`5fb3e5d`](https://github.com/buggerjs/node-inspect/commit/5fb3e5d17bbcfd45b264431547b3cf0b781c7640) **docs:** Link to Command Line API docs +* [`81af501`](https://github.com/buggerjs/node-inspect/commit/81af501bbf85397e2078310c7f24a9ac5b7f02dc) **chore:** Fix license field diff --git a/deps/node-inspect/CONTRIBUTING.md b/deps/node-inspect/CONTRIBUTING.md new file mode 100644 index 00000000000000..08d333cce8321f --- /dev/null +++ b/deps/node-inspect/CONTRIBUTING.md @@ -0,0 +1,183 @@ +# Contributing + +🎉🏅 Thanks for helping us improve this project! 🙏 + +This document outlines some of the practices we care about. +If you have any questions or suggestions about the process, +feel free to [open an issue](#reporting-issues) +. + +## Code of Conduct + +The [Node.js Code of Conduct][] applies to this repo. + +[Node.js Code of Conduct]: https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md + +## Code Contributions + +The nodereport project falls under the governance of the diagnostics +working group which is documented in: +https://github.com/nodejs/diagnostics/blob/master/GOVERNANCE.md. + +## Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +* (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +* (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +* (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +* (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +## How Can I Contribute? + +### Reporting Issues + +If you find any mistakes in the docs or a bug in the code, +please [open an issue in Github](https://github.com/nodejs/node-inspect/issues/new) so we can look into it. +You can also [create a PR](#contributing-code) fixing it yourself, or course. + +If you report a bug, please follow these guidelines: + +* Make sure the bug exists in the latest version. +* Include instructions on how to reproduce the issue. + The instructions should be as minimal as possible + and answer the three big questions: + 1. What are the exact steps you took? This includes the exact versions of node, npm, and any packages involved. + 1. What result are you expecting? + 1. What is the actual result? + +### Improving Documentation + +For small documentation changes, you can use [Github's editing feature](https://help.github.com/articles/editing-files-in-another-user-s-repository/). +The only thing to keep in mind is to prefix the commit message with "docs: ". +The detault commit message generated by Github will lead to a failing CI build. + +For larger updates to the documentation +it might be better to follow the [instructions for contributing code below](#contributing-code). + +### Contributing Code + +**Note:** If you're planning on making substantial changes, +please [open an issue first to discuss your idea](#reporting-issues). +Otherwise you might end up investing a lot of work +only to discover that it conflicts with plans the maintainers might have. + +The general steps for creating a pull request are: + +1. Create a branch for your change. + Always start your branch from the latest `master`. + We often prefix the branch name with our initials, e.g. `jk-a-change`. +1. Run `npm install` to install the dependencies. +1. If you're fixing a bug, be sure to write a test *first*. + That way you can validate that the test actually catches the bug and doesn't pass. +1. Make your changes to the code. + Remember to update the tests if you add new features or change behavior. +1. Run the tests via `npm test`. This will also run style checks and other validations. + You might see errors about uncommitted files. + This is expected until you commit your changes. +1. Once you're done, `git add .` and `git commit`. + Please follow the [commit message conventions](#commits--commit-messages) described below. +1. Push your branch to Github & create a PR. + +#### Code Style + +In addition to any linting rules the project might include, +a few general rules of thumb: + +* Try to match the style of the rest of the code. +* We prefer simple code that is easy to understand over terse, expressive code. +* We try to structure projects by semantics instead of role. + E.g. we'd rather have a `tree.js` module that contains tree traversal-related helpers + than a `helpers.js` module. +* Actually, if you create helpers you might want to put those into a separate package. + That way it's easier to reuse them. + +#### Commits & Commit Messages + +Please follow the [angular commit message conventions](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#-git-commit-guidelines). +We use an automated tool for generating releases +that depends on the conventions to determine the next version and the content of the changelog. +Commit messages that don't follow the conventions will cause `npm test` (and thus CI) to fail. + +The short summary - a commit message should look like this: + +``` +: + + + + + +