-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src,buffer: allow heap-allocated typed arrays #26301
Conversation
@addaleax sadly an error occured when I tried to trigger a build :( |
This was added in 16f86d6, based on the assumption that otherwise, the memory behind `ArrayBuffer` instances could be moved around on the heap while native code holds references to it. This does not match what V8 actually does (and also did at the time): - The option/build variable was about always only about TypedArrays, not ArrayBuffers. Calls like `new ArrayBuffer(4)` call into C++ regardless of the option value, but calls like `new Uint8Array(4)` would not call into C++ under V8 defaults. - When first accessing a heap-allocated TypedArray’s `ArrayBuffer`, whether that is through the JS `.buffer` getter or the C++ `ArrayBufferView::Buffer()` function, a copy of the contents is created using the ArrayBuffer allocator and stored as the (permanent, unmovable) backing store. As a consequence, the memory returned by `ArrayBuffer::GetContents()` is not moved around, because it is fixed once the `ArrayBuffer` object itself first comes into explicit existence in any way. Removing this build option significantly speeds up creation of typed arrays from JS: $ ./node benchmark/compare.js --new ./node --old ./node-master --runs 10 --filter buffer-creation.js buffers | Rscript benchmark/compare.R confidence improvement accuracy (*) (**) (***) buffers/buffer-creation.js n=1024 len=10 type='buffer()' *** 593.66 % ±28.64% ±41.10% ±60.36% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc-fill' *** 675.42 % ±90.67% ±130.24% ±191.54% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc' *** 663.55 % ±58.41% ±83.87% ±123.29% buffers/buffer-creation.js n=1024 len=10 type='fast-allocUnsafe' 3.10 % ±9.63% ±13.22% ±18.07% buffers/buffer-creation.js n=1024 len=10 type='slow-allocUnsafe' 4.67 % ±5.55% ±7.77% ±10.97% buffers/buffer-creation.js n=1024 len=10 type='slow' -2.48 % ±4.47% ±6.12% ±8.34% buffers/buffer-creation.js n=1024 len=1024 type='buffer()' -1.91 % ±4.71% ±6.45% ±8.79% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc-fill' -1.34 % ±7.53% ±10.33% ±14.10% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc' 0.52 % ±5.00% ±6.87% ±9.40% buffers/buffer-creation.js n=1024 len=1024 type='fast-allocUnsafe' 0.39 % ±5.65% ±7.78% ±10.67% buffers/buffer-creation.js n=1024 len=1024 type='slow-allocUnsafe' -0.13 % ±5.68% ±7.83% ±10.77% buffers/buffer-creation.js n=1024 len=1024 type='slow' -5.07 % ±7.15% ±9.80% ±13.35% buffers/buffer-creation.js n=1024 len=2048 type='buffer()' 0.57 % ±2.70% ±3.74% ±5.16% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc-fill' -1.60 % ±4.96% ±6.79% ±9.25% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc' 1.29 % ±3.79% ±5.20% ±7.09% buffers/buffer-creation.js n=1024 len=2048 type='fast-allocUnsafe' 2.73 % ±8.79% ±12.05% ±16.41% buffers/buffer-creation.js n=1024 len=2048 type='slow-allocUnsafe' -0.99 % ±6.27% ±8.65% ±11.91% buffers/buffer-creation.js n=1024 len=2048 type='slow' -5.98 % ±6.24% ±8.71% ±12.20% buffers/buffer-creation.js n=1024 len=4096 type='buffer()' -1.75 % ±3.48% ±4.78% ±6.56% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc-fill' -3.18 % ±3.97% ±5.45% ±7.45% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc' 2.05 % ±4.05% ±5.58% ±7.65% buffers/buffer-creation.js n=1024 len=4096 type='fast-allocUnsafe' 1.44 % ±5.51% ±7.63% ±10.57% buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' * -4.77 % ±4.30% ±5.90% ±8.06% buffers/buffer-creation.js n=1024 len=4096 type='slow' -3.31 % ±6.38% ±8.86% ±12.34% buffers/buffer-creation.js n=1024 len=8192 type='buffer()' 0.06 % ±2.70% ±3.77% ±5.31% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc-fill' -1.20 % ±3.30% ±4.53% ±6.17% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc' -1.46 % ±2.75% ±3.84% ±5.38% buffers/buffer-creation.js n=1024 len=8192 type='fast-allocUnsafe' 1.27 % ±4.69% ±6.49% ±8.98% buffers/buffer-creation.js n=1024 len=8192 type='slow-allocUnsafe' -1.68 % ±3.30% ±4.62% ±6.49% buffers/buffer-creation.js n=1024 len=8192 type='slow' -2.49 % ±3.24% ±4.44% ±6.07% (Re-running the outlier with 30 runs instead of 10:) buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' 2.06 % ±2.39% ±3.19% ±4.15% The performance gains effect are undone once native code accesses the underlying ArrayBuffer, but then again that a) does not happen for all TypedArrays, and b) it should also make sense to look into using `ArrayBufferView::CopyContents()` in some places, which is made specifically to avoid such a performance impact and allows us to use the benefits of heap-allocated typed arrays. Refs: nodejs@16f86d6 Refs: nodejs#2893 Refs: nodejs@74178a5#commitcomment-13250880 Refs: http://logs.libuv.org/node-dev/2015-09-15
Where appropriate, use a helper that wraps around `ArrayBufferView::Buffer()` or `ArrayBufferView::CopyContents()` rather than `Buffer::Data()`, as that may help to avoid materializing the underlying `ArrayBuffer` when reading small typed arrays from C++. This allows keeping the performance benefits of the faster creation of heap-allocated small typed arrays in many cases.
Do not create an `ArrayBuffer` if the engine’s settings avoid it and we don’t need it.
Check that small typed arrays, including `Buffer`s (unless allocated by `Buffer.allocUnsafe()`), are indeed heap-allocated.
fcb6bb0
to
3f96c4d
Compare
I like it! There are probably a fair few libraries out there creating small typed arrays for things like vector arithmetic e.g. with Float64Array for 3D points or something, the idea of the split on/off-heap worlds is to keep these fast. Each typed array with an off-heap buffer also adds time to the GC as we have to explicitly finalize the off-heap backing store. Thanks for working on this 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I would like a CITGM run to avoid potential regressions on native, 3rd party modules.
@mcollina Sure, will do, but to clarify: This is not an API change. It affects performance, not functionality. |
I agree. However it has been like this forever and some native addon could do something... interesting with it. |
Here's an extract of my conversation with @indutny:
Comment from @jeisinger about this when the implementation first landed: #1451 (comment) |
@trevnorris Yeah, I read that – it sounded like @indutny thought that this option applies to ArrayBuffers, and @jeisinger’s comment was, err, not really going into whether the underlying memory is being moved? Like, I totally understand the line of thought that was behind introducing this option, it’s just that it turns out we don’t actually need it. |
I'm not sure which version of v8 you're using here, but the array buffer implementation changed quite a bit since I did that comment. |
CI: https://ci.nodejs.org/job/node-test-pull-request/21066/ (:white_check_mark:) |
CITGM results are hard to read, but generally there’s nothing that isn’t in https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1752/ which is a directly preceding run for master. Looking for results for native addons seems pointless, though, as Nan currently seems to be incompatible with Given that I would still consider this a low-risk change, for addons or other code, and we run CITGM on releases anyway, I feel comfortable moving forward with this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Landed in b0b370c...adbe3b8 |
This was added in 16f86d6, based on the assumption that otherwise, the memory behind `ArrayBuffer` instances could be moved around on the heap while native code holds references to it. This does not match what V8 actually does (and also did at the time): - The option/build variable was about always only about TypedArrays, not ArrayBuffers. Calls like `new ArrayBuffer(4)` call into C++ regardless of the option value, but calls like `new Uint8Array(4)` would not call into C++ under V8 defaults. - When first accessing a heap-allocated TypedArray’s `ArrayBuffer`, whether that is through the JS `.buffer` getter or the C++ `ArrayBufferView::Buffer()` function, a copy of the contents is created using the ArrayBuffer allocator and stored as the (permanent, unmovable) backing store. As a consequence, the memory returned by `ArrayBuffer::GetContents()` is not moved around, because it is fixed once the `ArrayBuffer` object itself first comes into explicit existence in any way. Removing this build option significantly speeds up creation of typed arrays from JS: $ ./node benchmark/compare.js --new ./node --old ./node-master --runs 10 --filter buffer-creation.js buffers | Rscript benchmark/compare.R confidence improvement accuracy (*) (**) (***) buffers/buffer-creation.js n=1024 len=10 type='buffer()' *** 593.66 % ±28.64% ±41.10% ±60.36% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc-fill' *** 675.42 % ±90.67% ±130.24% ±191.54% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc' *** 663.55 % ±58.41% ±83.87% ±123.29% buffers/buffer-creation.js n=1024 len=10 type='fast-allocUnsafe' 3.10 % ±9.63% ±13.22% ±18.07% buffers/buffer-creation.js n=1024 len=10 type='slow-allocUnsafe' 4.67 % ±5.55% ±7.77% ±10.97% buffers/buffer-creation.js n=1024 len=10 type='slow' -2.48 % ±4.47% ±6.12% ±8.34% buffers/buffer-creation.js n=1024 len=1024 type='buffer()' -1.91 % ±4.71% ±6.45% ±8.79% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc-fill' -1.34 % ±7.53% ±10.33% ±14.10% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc' 0.52 % ±5.00% ±6.87% ±9.40% buffers/buffer-creation.js n=1024 len=1024 type='fast-allocUnsafe' 0.39 % ±5.65% ±7.78% ±10.67% buffers/buffer-creation.js n=1024 len=1024 type='slow-allocUnsafe' -0.13 % ±5.68% ±7.83% ±10.77% buffers/buffer-creation.js n=1024 len=1024 type='slow' -5.07 % ±7.15% ±9.80% ±13.35% buffers/buffer-creation.js n=1024 len=2048 type='buffer()' 0.57 % ±2.70% ±3.74% ±5.16% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc-fill' -1.60 % ±4.96% ±6.79% ±9.25% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc' 1.29 % ±3.79% ±5.20% ±7.09% buffers/buffer-creation.js n=1024 len=2048 type='fast-allocUnsafe' 2.73 % ±8.79% ±12.05% ±16.41% buffers/buffer-creation.js n=1024 len=2048 type='slow-allocUnsafe' -0.99 % ±6.27% ±8.65% ±11.91% buffers/buffer-creation.js n=1024 len=2048 type='slow' -5.98 % ±6.24% ±8.71% ±12.20% buffers/buffer-creation.js n=1024 len=4096 type='buffer()' -1.75 % ±3.48% ±4.78% ±6.56% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc-fill' -3.18 % ±3.97% ±5.45% ±7.45% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc' 2.05 % ±4.05% ±5.58% ±7.65% buffers/buffer-creation.js n=1024 len=4096 type='fast-allocUnsafe' 1.44 % ±5.51% ±7.63% ±10.57% buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' * -4.77 % ±4.30% ±5.90% ±8.06% buffers/buffer-creation.js n=1024 len=4096 type='slow' -3.31 % ±6.38% ±8.86% ±12.34% buffers/buffer-creation.js n=1024 len=8192 type='buffer()' 0.06 % ±2.70% ±3.77% ±5.31% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc-fill' -1.20 % ±3.30% ±4.53% ±6.17% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc' -1.46 % ±2.75% ±3.84% ±5.38% buffers/buffer-creation.js n=1024 len=8192 type='fast-allocUnsafe' 1.27 % ±4.69% ±6.49% ±8.98% buffers/buffer-creation.js n=1024 len=8192 type='slow-allocUnsafe' -1.68 % ±3.30% ±4.62% ±6.49% buffers/buffer-creation.js n=1024 len=8192 type='slow' -2.49 % ±3.24% ±4.44% ±6.07% (Re-running the outlier with 30 runs instead of 10:) buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' 2.06 % ±2.39% ±3.19% ±4.15% The performance gains effect are undone once native code accesses the underlying ArrayBuffer, but then again that a) does not happen for all TypedArrays, and b) it should also make sense to look into using `ArrayBufferView::CopyContents()` in some places, which is made specifically to avoid such a performance impact and allows us to use the benefits of heap-allocated typed arrays. Refs: 16f86d6 Refs: #2893 Refs: 74178a5#commitcomment-13250880 Refs: http://logs.libuv.org/node-dev/2015-09-15 PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Where appropriate, use a helper that wraps around `ArrayBufferView::Buffer()` or `ArrayBufferView::CopyContents()` rather than `Buffer::Data()`, as that may help to avoid materializing the underlying `ArrayBuffer` when reading small typed arrays from C++. This allows keeping the performance benefits of the faster creation of heap-allocated small typed arrays in many cases. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Do not create an `ArrayBuffer` if the engine’s settings avoid it and we don’t need it. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Check that small typed arrays, including `Buffer`s (unless allocated by `Buffer.allocUnsafe()`), are indeed heap-allocated. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Here’s CITGM on v11.x-staging after this has landed on it: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1755/ |
This was added in 16f86d6, based on the assumption that otherwise, the memory behind `ArrayBuffer` instances could be moved around on the heap while native code holds references to it. This does not match what V8 actually does (and also did at the time): - The option/build variable was about always only about TypedArrays, not ArrayBuffers. Calls like `new ArrayBuffer(4)` call into C++ regardless of the option value, but calls like `new Uint8Array(4)` would not call into C++ under V8 defaults. - When first accessing a heap-allocated TypedArray’s `ArrayBuffer`, whether that is through the JS `.buffer` getter or the C++ `ArrayBufferView::Buffer()` function, a copy of the contents is created using the ArrayBuffer allocator and stored as the (permanent, unmovable) backing store. As a consequence, the memory returned by `ArrayBuffer::GetContents()` is not moved around, because it is fixed once the `ArrayBuffer` object itself first comes into explicit existence in any way. Removing this build option significantly speeds up creation of typed arrays from JS: $ ./node benchmark/compare.js --new ./node --old ./node-master --runs 10 --filter buffer-creation.js buffers | Rscript benchmark/compare.R confidence improvement accuracy (*) (**) (***) buffers/buffer-creation.js n=1024 len=10 type='buffer()' *** 593.66 % ±28.64% ±41.10% ±60.36% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc-fill' *** 675.42 % ±90.67% ±130.24% ±191.54% buffers/buffer-creation.js n=1024 len=10 type='fast-alloc' *** 663.55 % ±58.41% ±83.87% ±123.29% buffers/buffer-creation.js n=1024 len=10 type='fast-allocUnsafe' 3.10 % ±9.63% ±13.22% ±18.07% buffers/buffer-creation.js n=1024 len=10 type='slow-allocUnsafe' 4.67 % ±5.55% ±7.77% ±10.97% buffers/buffer-creation.js n=1024 len=10 type='slow' -2.48 % ±4.47% ±6.12% ±8.34% buffers/buffer-creation.js n=1024 len=1024 type='buffer()' -1.91 % ±4.71% ±6.45% ±8.79% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc-fill' -1.34 % ±7.53% ±10.33% ±14.10% buffers/buffer-creation.js n=1024 len=1024 type='fast-alloc' 0.52 % ±5.00% ±6.87% ±9.40% buffers/buffer-creation.js n=1024 len=1024 type='fast-allocUnsafe' 0.39 % ±5.65% ±7.78% ±10.67% buffers/buffer-creation.js n=1024 len=1024 type='slow-allocUnsafe' -0.13 % ±5.68% ±7.83% ±10.77% buffers/buffer-creation.js n=1024 len=1024 type='slow' -5.07 % ±7.15% ±9.80% ±13.35% buffers/buffer-creation.js n=1024 len=2048 type='buffer()' 0.57 % ±2.70% ±3.74% ±5.16% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc-fill' -1.60 % ±4.96% ±6.79% ±9.25% buffers/buffer-creation.js n=1024 len=2048 type='fast-alloc' 1.29 % ±3.79% ±5.20% ±7.09% buffers/buffer-creation.js n=1024 len=2048 type='fast-allocUnsafe' 2.73 % ±8.79% ±12.05% ±16.41% buffers/buffer-creation.js n=1024 len=2048 type='slow-allocUnsafe' -0.99 % ±6.27% ±8.65% ±11.91% buffers/buffer-creation.js n=1024 len=2048 type='slow' -5.98 % ±6.24% ±8.71% ±12.20% buffers/buffer-creation.js n=1024 len=4096 type='buffer()' -1.75 % ±3.48% ±4.78% ±6.56% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc-fill' -3.18 % ±3.97% ±5.45% ±7.45% buffers/buffer-creation.js n=1024 len=4096 type='fast-alloc' 2.05 % ±4.05% ±5.58% ±7.65% buffers/buffer-creation.js n=1024 len=4096 type='fast-allocUnsafe' 1.44 % ±5.51% ±7.63% ±10.57% buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' * -4.77 % ±4.30% ±5.90% ±8.06% buffers/buffer-creation.js n=1024 len=4096 type='slow' -3.31 % ±6.38% ±8.86% ±12.34% buffers/buffer-creation.js n=1024 len=8192 type='buffer()' 0.06 % ±2.70% ±3.77% ±5.31% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc-fill' -1.20 % ±3.30% ±4.53% ±6.17% buffers/buffer-creation.js n=1024 len=8192 type='fast-alloc' -1.46 % ±2.75% ±3.84% ±5.38% buffers/buffer-creation.js n=1024 len=8192 type='fast-allocUnsafe' 1.27 % ±4.69% ±6.49% ±8.98% buffers/buffer-creation.js n=1024 len=8192 type='slow-allocUnsafe' -1.68 % ±3.30% ±4.62% ±6.49% buffers/buffer-creation.js n=1024 len=8192 type='slow' -2.49 % ±3.24% ±4.44% ±6.07% (Re-running the outlier with 30 runs instead of 10:) buffers/buffer-creation.js n=1024 len=4096 type='slow-allocUnsafe' 2.06 % ±2.39% ±3.19% ±4.15% The performance gains effect are undone once native code accesses the underlying ArrayBuffer, but then again that a) does not happen for all TypedArrays, and b) it should also make sense to look into using `ArrayBufferView::CopyContents()` in some places, which is made specifically to avoid such a performance impact and allows us to use the benefits of heap-allocated typed arrays. Refs: 16f86d6 Refs: #2893 Refs: 74178a5#commitcomment-13250880 Refs: http://logs.libuv.org/node-dev/2015-09-15 PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Where appropriate, use a helper that wraps around `ArrayBufferView::Buffer()` or `ArrayBufferView::CopyContents()` rather than `Buffer::Data()`, as that may help to avoid materializing the underlying `ArrayBuffer` when reading small typed arrays from C++. This allows keeping the performance benefits of the faster creation of heap-allocated small typed arrays in many cases. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Do not create an `ArrayBuffer` if the engine’s settings avoid it and we don’t need it. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
Check that small typed arrays, including `Buffer`s (unless allocated by `Buffer.allocUnsafe()`), are indeed heap-allocated. PR-URL: #26301 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
I noticed that the reason we’ve been disabling this has not actually been true, so it seems to make sense to let the engine use its default values. /cc @nodejs/buffer @nodejs/v8
build: remove v8_typed_array_max_size_in_heap option
This was added in 16f86d6, based on
the assumption that otherwise, the memory behind
ArrayBuffer
instances could be moved around on the heap while native code
holds references to it.
This does not match what V8 actually does (and also did at the time):
not ArrayBuffers. Calls like
new ArrayBuffer(4)
call into C++regardless of the option value, but calls like
new Uint8Array(4)
would not call into C++ under V8 defaults.
ArrayBuffer
,whether that is through the JS
.buffer
getter or the C++ArrayBufferView::Buffer()
function, a copy of the contents iscreated using the ArrayBuffer allocator and stored as the
(permanent, unmovable) backing store.
As a consequence, the memory returned by
ArrayBuffer::GetContents()
is not moved around, because it is fixed once the
ArrayBuffer
object itself first comes into explicit existence in any way.
Removing this build option significantly speeds up creation of typed
arrays from JS:
The performance gains effect are undone once native code accesses
the underlying ArrayBuffer, but then again that a) does not happen for
all TypedArrays, and b) it should also make sense to look into using
ArrayBufferView::CopyContents()
in some places, which is madespecifically to avoid such a performance impact and allows us to
use the benefits of heap-allocated typed arrays.
Refs: 16f86d6
Refs: #2893
Refs: 74178a5#commitcomment-13250880
Refs: http://logs.libuv.org/node-dev/2015-09-15
src: allow not materializing ArrayBuffers from C++
Where appropriate, use a helper that wraps around
ArrayBufferView::Buffer()
orArrayBufferView::CopyContents()
rather than
Buffer::Data()
, as that may help to avoid materializingthe underlying
ArrayBuffer
when reading small typed arrays from C++.This allows keeping the performance benefits of the faster creation of
heap-allocated small typed arrays in many cases.
buffer: avoid materializing ArrayBuffer for creation
Do not create an
ArrayBuffer
if the engine’s settings avoid itand we don’t need it.
test: verify heap buffer allocations occur
Check that small typed arrays, including
Buffer
s (unless allocatedby
Buffer.allocUnsafe()
), are indeed heap-allocated.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes