Buffer.byteLength is important for speed because it is called whenever a
new Buffer is created from a string.
This commit optimizes Buffer.byteLength execution by:
- moving base64 length calculation into JS-land, which is now much
faster
- remove redundant code and streamline the UTF8 length calculation
It also adds a benchmark and better tests.
PR-URL: https://github.com/nodejs/io.js/pull/1713
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit uses separate functions to isolate deopts caused by
try-catches and avoids fn.apply() for callbacks with small numbers
of arguments.
These changes improve performance by ~1-40% in the various
nextTick benchmarks.
PR-URL: https://github.com/iojs/io.js/pull/1571
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
When running a non-http benchmark, there is no need the check for the
wrk tool so move the wrk check into the http method.
PR-URL: https://github.com/iojs/io.js/pull/1368
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit fixes a few things for this benchmark:
1. Ensures the temporary directory for the unix socket exists.
2. Prevents the client code from being run directly because the
server script is the one that calls out the client code.
3. Ensures the server is closed once the client benchmarks have
finished.
4. Since this is an http benchmark, it should be moved to the http
benchmarks subdirectory.
PR-URL: https://github.com/iojs/io.js/pull/1257
Reviewed-By: Roman Reiss <me@silverwind.io>
By limiting property getting/setting to only where they are
absolutely necessary, we can achieve greater performance
especially with small utf8 inputs and any size base64 inputs.
PR-URL: https://github.com/iojs/io.js/pull/1209
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Nicu Micleușanu <micnic90@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
This commit adds an `OUTPUT_FORMAT` environment variable option for
all benchmark tests that allow either 'csv' or 'default' output. Default
output has been left unchanged, and csv output prints out the csv
headers along with the csv formatted per-test output, each test also
seperated by a newline.
It can be used like the following:
$ OUTPUT_FORMAT=csv iojs benchmark/common.js http
Not specifying the OUTPUT_FORMAT env var will default to 'default'.
Specifying a bad value will throw an error.
PR-URL: https://github.com/iojs/io.js/pull/777
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit adds a graphing script (in R) for graphing the CSV output
of a benchmark. It can be run like this:
```
$ OUTPUT_FORMAT=csv iojs benchmark/http/client-request-body.js >
data.csv
$ ./benchmark/plot_csv.R data.csv graph.png bytes type
```
This will graph the output to `graph.png`, using the output's `bytes`
value as X and the result value for each as Y. Output will be grouped
by `type`.
Running as the example yields a beautiful graph like this:
http://pbrd.co/1vBhUfy.
PR-URL: https://github.com/iojs/io.js/pull/777
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
wrk is an optional tool that some of the http benchmarks uses. The removal
doesn't affect any users. Developers are assumed to install it before running
the tests.
This change reduces the tarball by 5%
PR-URL: https://github.com/iojs/io.js/pull/982
Reviewed-By: Rod Vagg <rod@vagg.org>
Benchmarker should pass exec flags (e.g. --no-crankshaft,
--turbofan-filter, --trace-opt etc) to the benchmarking process
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
PR-URL: https://github.com/iojs/io.js/pull/928
Some of the benchmarks that were added in commit 847b9d2 complete too
quickly to draw meaningful conclusions from. Increase the number of
iterations to make them run longer.
PR-URL: https://github.com/iojs/io.js/pull/746
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Before this commit, only benchmark targets defined in Makefile could
be used. This commit allows execution of common.js directly and
passing of filter arguments directly, allowing you to run either a
subset of benchmarks or a single specific benchmark for comparison.
PR-URL: https://github.com/iojs/io.js/pull/711
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
When running benchmark/compare.js, it is typical to run a version of
node that does not support template strings. This provides backwards
compatibility for comparing benchmarks using older versions of node.
PR-URL: https://github.com/iojs/io.js/pull/714
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
This commit cleans up `benchmark/common.js` with a few generic changes
such as the following:
- declare all `require()`'d libraries at the top instead of in the
middle
- add some empty whitespace where it helps readability
- changes ambiguous variable names
- standardizes most if / else blocks
- missing semicolons
PR-URL: https://github.com/iojs/io.js/pull/662
Reviewed-By: Nicu Micleușanu <micnic90@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
This commit removes the benchmark spacing modification in
`client-request-body.js` and `end-vs-write-end.js` which adds two spaces
to the end of some variables to make sure the lines line up.
The reason behind this is that its totally pointless (the lines don't
actually line up with it) and it disallows you to parse the output with
a tool like awk, or at least makes it a lot harder.
PR-URL: https://github.com/iojs/io.js/pull/650
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Adds info on the `wrk` prerequisite for http benchmarks and how to
run benchmarks with options.
PR-URL: https://github.com/iojs/io.js/pull/629
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Evan Lucas <evanlucas@me.com>
This makes possible to use `for..of` loop with
buffers. Also related `keys`, `values` and `entries`
methods are added for feature parity with `Uint8Array`.
PR-URL: https://github.com/iojs/io.js/pull/525
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Fix up the tcp raw benchmarks after an internal API change.
PR-URL: https://github.com/iojs/io.js/pull/495
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
deps/v8/benchmarks/regexp.js clobbers the RegExp global, breaking
util.format() and console.log(). Unclobber it to keep the other
benchmarks working.
Fixes the following error when running benchmark/misc/v8-bench.js:
$ out/Release/iojs benchmark/misc/v8-bench.js
util.js:84
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
^
TypeError: object is not a function
at Object.exports.debuglog (util.js:84:9)
at timers.js:12:29
at NativeModule.compile (node.js:800:5)
at NativeModule.require (node.js:769:18)
at net.js:5:14
at NativeModule.compile (node.js:800:5)
at NativeModule.require (node.js:769:18)
at tty.js:4:11
at NativeModule.compile (node.js:800:5)
at Function.NativeModule.require (node.js:769:18)
This could alternatively be addressed by caching the RegExp global
in lib/util.js. That's not a bad approach and I considered it but
doing it for just RegExp and not other globals would be half-baked.
Maybe the more thorough approach where we cache all globals at
start-up is something for a follow-up pull request.
Fixes: https://github.com/iojs/io.js/pull/475
PR-URL: https://github.com/iojs/io.js/pull/489
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Yosuke Furukawa <yosuke.furukawa@gmail.com>
Before:
# common.js executes all tests in net directory.
$ ./iojs common.js net
After:
# common.js executes only "dgram" tests in net directory.
$ ./iojs common.js net dgram
PR-URL: https://github.com/iojs/io.js/pull/488
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
The copyright and license notice is already in the LICENSE file. There
is no justifiable reason to also require that it be included in every
file, since the individual files are not individually distributed except
as part of the entire package.
Replace the call to Array#splice() with a faster open-coded version
that creates less garbage.
Add a new benchmark to prove it. With the change applied, it scores
about 5% higher and that is nothing to sneeze at.
PR-URL: https://github.com/iojs/io.js/pull/184
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Rename the url.parse() benchmark from url.js to url-parse.js.
A follow-up commit is going to add another one for url.resolve().
PR-URL: https://github.com/iojs/io.js/pull/184
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Replace the call to Array#splice() with a faster open-coded version
that creates less garbage.
Add a new benchmark to prove it. With the change applied, it scores
a whopping 40% higher.
PR-URL: https://github.com/iojs/io.js/pull/185
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Don't use Number#toPrecision(), it switches to scientific notation for
numbers with more digits than the precision; use Number#toFixed().
PR-URL: https://github.com/iojs/io.js/pull/185
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Force V8 to optimize url.parse() before starting the actual benchmark.
Tries to minimize variance between successive runs caused by the
optimizer kicking in at different points.
It does not seem to have much impact, CPU times are roughly the same
before and afterwards; url.parse() quickly plateaus at a local optimum
where most time is spent in V8 builtins, notably Runtime_StringSplit()
and Object::GetElementWithReceiver() calls originating from
deps/v8/src/uri.js, with no recurring optimize/deoptimize cycles that
I could spot.
Still, I don't see any downsides to pre-optimizing the function being
benchmarked so in it goes.
PR-URL: https://github.com/iojs/io.js/pull/132
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Reviewed-By: Fedor Indutny <fedor@indutny.com>
Adds the feature to define arguments for the function called in
domain.run(), this is supposed to be useful when a function is called from
another context and some values from the current context are needed as
arguments, it's similar to the callback from setTimeout or setInterval.
PR-URL: https://github.com/iojs/io.js/pull/15
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Based on the ad-hoc benchmark from joyent/node#8638 plus an additional
benchmark for user:pass auth URLs.
PR-URL: https://github.com/iojs/io.js/pull/102
Reviewed-by: Chris Dickinson <christopher.s.dickinson@gmail.com>
Adds a test for benchmarking the module loader, needed for benchmarking
changes / refacortings in the module loader.
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
Reviewed-by: Timothy J Fontaine <tjfontaine@gmail.com>
The test is supposed to measure the performance of the base64 encoder
so move the Buffer#write() calls out of the benchmark section.
The overhead of the calls isn't terrible (about 1-3%) but having
unrelated activity in a micro-benchmark is never a good idea.
Signed-off-by: Trevor Norris <trev.norris@gmail.com>
compare() works like String.localeCompare such that:
Buffer.compare(a, b) === a.compare(b);
equals() does a native check to see if two buffers are equal.
Signed-off-by: Trevor Norris <trev.norris@gmail.com>
Increase the performance and simplify the logic of Buffer#write{U}Int*
and Buffer#read{U}Int* methods by placing the byte manipulation code
directly inline.
Also improve the speed of buffer-write benchmarks by creating a new
call directly to each method by using Function() instead of calling by
buff[fn].
Signed-off-by: Trevor Norris <trev.norris@gmail.com>
Since the SlabAllocator was removed the buffer length/offset is no
longer sent to the onread callback. The benchmarks have been updated to
reflect that.
This commit adds an optimization to the HTTP client that makes it
possible to:
* Pack the headers and the first chunk of the request body into a
single write().
* Pack the chunk header and the chunk itself into a single write().
Because only one write() system call is issued instead of several,
the chances of data ending up in a single TCP packet are phenomenally
higher: the benchmark with `type=buf size=32` jumps from 50 req/s to
7,500 req/s, a 150-fold increase.
This commit removes the check from e4b716ef that pushes binary encoded
strings into the slow path. The commit log mentions that:
We were assuming that any string can be concatenated safely to
CRLF. However, for hex, base64, or binary encoded writes, this
is not the case, and results in sending the incorrect response.
For hex and base64 strings that's certainly true but binary strings
are 'das Ding an sich': string.length is the same before and after
decoding.
Fixes #5528.
The benchmark compare would drop the last run of the binary pairs. So
when they were only run once an error would arise because no data was
generated for the second binary.
The benefits of the hot-path optimization below start to fall off when
the buffer size gets up near 128KB, because the cost of the copy is more
than the cost of the extra write() call. Switch to the write/end method
at that point.
Heuristics and magic numbers are awful, but slow http responses are
worse.
Fix #4975
This will run the benchmarks the number of times specified by NODE_BENCH_RUNS,
to attempt to reduce variability.
If the number of runs is high enough, it'll also throw out the top and bottom
quartiles, since that's where the outliers will be.
It's not very fancy statistics-fu, but it's better than nothing.
Also, linted this file. It had tabs in it. TABS!
For throughput benchmarks, run with just 5s durations rather than 1s and 3s.
For startup benchmark, run with just a single 1s duration, since it's very
consistent anyway.
This increases fs.WriteStream throughput dramatically by removing the
"higher default water marks" for fs.WriteStream.
Also includes a benchmark. Current performance is significantly higher
than v0.8 for strings at all tested levels except size=1. Buffer
performance is still lackluster.
Further improvement in the stream.Writable base class is required, but
this is a start.
Improvements:
* floating point operations are approx 4x's faster
* Now write quiet NaN's
* all read/write on floating point now done in C, so no more need for
lib/buffer_ieee754.js
* float values have more accurate min/max value checks
* add additional benchmarks for buffers read/write
* created benchmark/_bench_timer.js which is a simple library that
can be included into any benchmark and provides an intelligent tracker
for sync and async tests
* add benchmarks for DataView set methods
* add checks and tests to make sure offset is greater than 0
Remove a lot of branches from the inner loop. Speeds up buf.toString('base64')
by about 20%.
Before:
$ time out/Release/node benchmark/buffer-base64-encode.js
real 0m6.607s
user 0m5.508s
sys 0m1.088s
After:
$ time out/Release/node benchmark/buffer-base64-encode.js
real 0m5.520s
user 0m4.520s
sys 0m0.992s
This is very similar to http.sh, but generates a flamegraph
with dtrace, pruning off the single-hit stacks so that we can
more easily see the places where relevant amounts of time are
spent.
Just sends a buffer to a server, which echoes it back, and then measures
the Gbits/second. Very similar to throughput.js, but using a single
process, so that it's possible to dtrace and get the jsstack frames for
profile comparison.
Use static buffers. Most clock ticks were spent in malloc() and free() instead
of read() and write().
Fix measurements. Really fast runs would result in bogus results like:
Wrote 1048576000 bytes in -0.731630s using 8192 byte buffers: -1366.811093mB/s
Change the http.Client API so that it provides a single request() method
taking an optional parameter to specify the HTTP method (defaulting to
"GET"), instead of the five methods get(), head(), post(), del() and put().
include() should not be used by libraries because it will pollute the global
namespace. To discourage this behavior and bring Node more in-line with
the current CommonJS module system, include() is removed.
Small scripts like unit tests often times do want to pollute the global
namespace for ease. To avoid the boiler plate code of
var x = require("/x.js");
var foo = x.foo;
var bar = x.bar;
The function node.mixin() is stolen from jQuery's jQuery.extend. So that it
can be written:
node.mixin(require("/x.js"));
Reference:
http://docs.jquery.com/Utilities/jQuery.extendhttp://groups.google.com/group/nodejs/browse_thread/thread/f9ac83e5c11e7e87
To use the benchmarks:
node benchmarks/run.js
or:
make benchmark
The numbers reported are the elapsed milliseconds the script took to
complete. Currently only benching HTTP code and timers.
This is a rather large refactor! Mostly for the better side. I've had to
remove some functionality like req.interrupt(). A lot of other work is left
messy or incomplete.