Skip to content

buffer: optimize buffer.concat performance#61721

Merged
nodejs-github-bot merged 7 commits intonodejs:mainfrom
mertcanaltin:mert/buffer-concat-optimize-js
Feb 27, 2026
Merged

buffer: optimize buffer.concat performance#61721
nodejs-github-bot merged 7 commits intonodejs:mainfrom
mertcanaltin:mert/buffer-concat-optimize-js

Conversation

@mertcanaltin
Copy link
Member

@mertcanaltin mertcanaltin commented Feb 7, 2026

Removed the _copyActual indirection in the copy loop and called TypedArrayPrototypeSet directly.
Split auto-length and explicit-length paths so the auto-length copy loop is branch free. Replaced Buffer.allocUnsafe with allocate to skip redundant validation.

benchmark results:

➜  node git:(mert/buffer-concat-optimize-js) ✗ node-benchmark-compare ./result.csv
                                                                            confidence improvement accuracy (*)    (**)   (***)
buffers/buffer-concat-fill.js n=800000 extraSize=1                                   *     10.37 %       ±9.47% ±13.37% ±19.13%
buffers/buffer-concat-fill.js n=800000 extraSize=1024                                       2.91 %       ±6.22%  ±8.53% ±11.62%
buffers/buffer-concat-fill.js n=800000 extraSize=256                                 *      7.05 %       ±6.13%  ±8.41% ±11.49%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=1 pieces=16           **      1.76 %       ±1.18%  ±1.64%  ±2.26%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=1 pieces=4           ***      5.20 %       ±1.21%  ±1.65%  ±2.25%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=16 pieces=16          **      1.96 %       ±1.17%  ±1.61%  ±2.21%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=16 pieces=4          ***      3.06 %       ±1.50%  ±2.06%  ±2.84%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=256 pieces=16                 1.93 %       ±8.35% ±11.48% ±15.73%
buffers/buffer-concat.js n=800000 withTotalLength=0 pieceSize=256 pieces=4                  2.37 %       ±6.69%  ±9.34% ±13.12%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=1 pieces=16                  -0.59 %       ±0.99%  ±1.36%  ±1.86%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=1 pieces=4           ***      5.17 %       ±1.25%  ±1.71%  ±2.33%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=16 pieces=16                  0.98 %       ±1.45%  ±2.02%  ±2.81%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=16 pieces=4          ***      4.44 %       ±1.89%  ±2.62%  ±3.62%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=256 pieces=16          *     -1.97 %       ±1.89%  ±2.63%  ±3.67%
buffers/buffer-concat.js n=800000 withTotalLength=1 pieceSize=256 pieces=4         ***      3.55 %       ±1.08%  ±1.49%  ±2.04%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 15 comparisons, you can thus expect the following amount of false-positive results:
  0.75 false positives, when considering a   5% risk acceptance (*, **, ***),
  0.15 false positives, when considering a   1% risk acceptance (**, ***),
  0.01 false positives, when considering a 0.1% risk acceptance (***)
➜  node git:(mert/buffer-concat-optimize-js) ✗ 

@nodejs-github-bot nodejs-github-bot added buffer Issues and PRs related to the buffer subsystem. needs-ci PRs that need a full CI run. labels Feb 7, 2026
@codecov
Copy link

codecov bot commented Feb 7, 2026

Codecov Report

❌ Patch coverage is 90.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.74%. Comparing base (3ab9dd8) to head (4848305).
⚠️ Report is 141 commits behind head on main.

Files with missing lines Patch % Lines
lib/buffer.js 90.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #61721      +/-   ##
==========================================
+ Coverage   89.73%   89.74%   +0.01%     
==========================================
  Files         675      675              
  Lines      204502   204673     +171     
  Branches    39304    39329      +25     
==========================================
+ Hits       183502   183684     +182     
+ Misses      13283    13281       -2     
+ Partials     7717     7708       -9     
Files with missing lines Coverage Δ
lib/buffer.js 99.16% <90.00%> (-0.63%) ⬇️

... and 52 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@ChALkeR ChALkeR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #60399 (comment)

Shouldn't _copyActual be just using TypedArrayPrototypeSet since #60399?
cc @gurgunday

@gurgunday gurgunday added the needs-benchmark-ci PR that need a benchmark CI run. label Feb 7, 2026
Copy link
Member

@gurgunday gurgunday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the ping @ChALkeR

Yeah so other than inlining what we did in _copyActual (#60399), this PR avoids going through _copy even in the non sourceStart === 0 && nb === sourceLen (partial copy) case (I remember that we'd talked about doing this in a follow-up PR anyway)

I like that change

@mertcanaltin
Copy link
Member Author

I updated bench result: #61721 (comment)

Copy link
Member

@gurgunday gurgunday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@anonrig anonrig added the request-ci Add this label to start a Jenkins CI on a PR. label Feb 25, 2026
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Feb 25, 2026
@nodejs-github-bot
Copy link
Collaborator

@gurgunday gurgunday added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Feb 26, 2026
@anonrig anonrig added commit-queue Add this label to land a pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. labels Feb 27, 2026
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Feb 27, 2026
@nodejs-github-bot nodejs-github-bot merged commit cc6c188 into nodejs:main Feb 27, 2026
74 of 75 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in cc6c188

aduh95 pushed a commit that referenced this pull request Feb 28, 2026
PR-URL: #61721
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Mar 11, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [node](https://nodejs.org) ([source](https://github.com/nodejs/node)) | minor | `25.7.0` → `25.8.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>nodejs/node (node)</summary>

### [`v25.8.0`](https://github.com/nodejs/node/releases/tag/v25.8.0): 2026-03-03, Version 25.8.0 (Current), @&#8203;richardlau

[Compare Source](nodejs/node@v25.7.0...v25.8.0)

##### Notable Changes

- \[[`e55eddea2a`](nodejs/node@e55eddea2a)] - **build, doc**: use new api doc tooling (flakey5) [#&#8203;57343](nodejs/node#57343)
- \[[`4c181e2277`](nodejs/node@4c181e2277)] - **(SEMVER-MINOR)** **sqlite**: add limits property to DatabaseSync (Mert Can Altin) [#&#8203;61298](nodejs/node#61298)
- \[[`46ee1eddd7`](nodejs/node@46ee1eddd7)] - **(SEMVER-MINOR)** **src**: add C++ support for diagnostics channels (RafaelGSS) [#&#8203;61869](nodejs/node#61869)
- \[[`9ddd1a9c27`](nodejs/node@9ddd1a9c27)] - **(SEMVER-MINOR)** **src,permission**: add --permission-audit (RafaelGSS) [#&#8203;61869](nodejs/node#61869)
- \[[`0d97ec4044`](nodejs/node@0d97ec4044)] - **(SEMVER-MINOR)** **test\_runner**: expose worker ID for concurrent test execution (Ali Hassan) [#&#8203;61394](nodejs/node#61394)

##### Commits

- \[[`940b58c8c1`](nodejs/node@940b58c8c1)] - **buffer**: optimize buffer.concat performance (Mert Can Altin) [#&#8203;61721](nodejs/node#61721)
- \[[`0589b0e5a1`](nodejs/node@0589b0e5a1)] - **build**: fix GN for new merve dep (Shelley Vohr) [#&#8203;61984](nodejs/node#61984)
- \[[`f3d3968dcd`](nodejs/node@f3d3968dcd)] - ***Revert*** "**build**: add temporal test on GHA windows" (Antoine du Hamel) [#&#8203;61810](nodejs/node#61810)
- \[[`e55eddea2a`](nodejs/node@e55eddea2a)] - **build, doc**: use new api doc tooling (flakey5) [#&#8203;57343](nodejs/node#57343)
- \[[`b7715292f8`](nodejs/node@b7715292f8)] - **child\_process**: add tracing channel for spawn (Marco) [#&#8203;61836](nodejs/node#61836)
- \[[`a32a598748`](nodejs/node@a32a598748)] - **crypto**: fix missing nullptr check on RSA\_new() (ndossche) [#&#8203;61888](nodejs/node#61888)
- \[[`dc384f95b3`](nodejs/node@dc384f95b3)] - **crypto**: fix handling of null BUF\_MEM\* in ToV8Value() (Nora Dossche) [#&#8203;61885](nodejs/node#61885)
- \[[`3337b095db`](nodejs/node@3337b095db)] - **crypto**: fix potential null pointer dereference when BIO\_meth\_new() fails (Nora Dossche) [#&#8203;61788](nodejs/node#61788)
- \[[`51ded81139`](nodejs/node@51ded81139)] - **deps**: update undici to 7.22.0 (Node.js GitHub Bot) [#&#8203;62035](nodejs/node#62035)
- \[[`8aa2fde931`](nodejs/node@8aa2fde931)] - **deps**: update minimatch to 10.2.4 (Node.js GitHub Bot) [#&#8203;62016](nodejs/node#62016)
- \[[`57dc092eaf`](nodejs/node@57dc092eaf)] - **deps**: upgrade npm to 11.11.0 (npm team) [#&#8203;61994](nodejs/node#61994)
- \[[`705bbd60a9`](nodejs/node@705bbd60a9)] - **deps**: update simdjson to 4.3.1 (Node.js GitHub Bot) [#&#8203;61930](nodejs/node#61930)
- \[[`4d411d72e5`](nodejs/node@4d411d72e5)] - **deps**: update acorn-walk to 8.3.5 (Node.js GitHub Bot) [#&#8203;61928](nodejs/node#61928)
- \[[`f53a32ab84`](nodejs/node@f53a32ab84)] - **deps**: update acorn to 8.16.0 (Node.js GitHub Bot) [#&#8203;61925](nodejs/node#61925)
- \[[`9b483fbb27`](nodejs/node@9b483fbb27)] - **deps**: update minimatch to 10.2.2 (Node.js GitHub Bot) [#&#8203;61830](nodejs/node#61830)
- \[[`4e54c103cb`](nodejs/node@4e54c103cb)] - **doc**: separate in-types and out-types in SQLite conversion docs (René) [#&#8203;62034](nodejs/node#62034)
- \[[`ca78ebbeaa`](nodejs/node@ca78ebbeaa)] - **doc**: fix small logic error in DETECT\_MODULE\_SYNTAX (René) [#&#8203;62025](nodejs/node#62025)
- \[[`e6b131f3fe`](nodejs/node@e6b131f3fe)] - **doc**: fix module.stripTypeScriptTypes indentation (René) [#&#8203;61992](nodejs/node#61992)
- \[[`7508540e19`](nodejs/node@7508540e19)] - **doc**: update DEP0040 (punycode) to application type deprecation (Mike McCready) [#&#8203;61916](nodejs/node#61916)
- \[[`33a364cb62`](nodejs/node@33a364cb62)] - **doc**: explicitly mention Slack handle (Rafael Gonzaga) [#&#8203;61986](nodejs/node#61986)
- \[[`46a61922bd`](nodejs/node@46a61922bd)] - **doc**: support toolchain Visual Studio 2022 & 2026 + Windows 11 SDK (Mike McCready) [#&#8203;61864](nodejs/node#61864)
- \[[`dc12a257aa`](nodejs/node@dc12a257aa)] - **doc**: rename invalid `function` parameter (René) [#&#8203;61942](nodejs/node#61942)
- \[[`dafdc0a5b8`](nodejs/node@dafdc0a5b8)] - **http**: validate headers in writeEarlyHints (Richard Clarke) [#&#8203;61897](nodejs/node#61897)
- \[[`3c94b56fa6`](nodejs/node@3c94b56fa6)] - **inspector**: unwrap internal/debugger/inspect imports (René) [#&#8203;61974](nodejs/node#61974)
- \[[`8a24c17648`](nodejs/node@8a24c17648)] - **lib**: improve argument handling in Blob constructor (Ms2ger) [#&#8203;61980](nodejs/node#61980)
- \[[`21d4baf256`](nodejs/node@21d4baf256)] - **meta**: bump github/codeql-action from 4.32.0 to 4.32.4 (dependabot\[bot]) [#&#8203;61911](nodejs/node#61911)
- \[[`59a726a8e3`](nodejs/node@59a726a8e3)] - **meta**: bump step-security/harden-runner from 2.14.1 to 2.14.2 (dependabot\[bot]) [#&#8203;61909](nodejs/node#61909)
- \[[`0072b7f991`](nodejs/node@0072b7f991)] - **meta**: bump actions/stale from 10.1.1 to 10.2.0 (dependabot\[bot]) [#&#8203;61908](nodejs/node#61908)
- \[[`999bf22f47`](nodejs/node@999bf22f47)] - **repl**: keep reference count for `process.on('newListener')` (Anna Henningsen) [#&#8203;61895](nodejs/node#61895)
- \[[`4c181e2277`](nodejs/node@4c181e2277)] - **(SEMVER-MINOR)** **sqlite**: add limits property to DatabaseSync (Mert Can Altin) [#&#8203;61298](nodejs/node#61298)
- \[[`aee2a18257`](nodejs/node@aee2a18257)] - **src**: fix flags argument offset in JSUdpWrap (Weixie Cui) [#&#8203;61948](nodejs/node#61948)
- \[[`46ee1eddd7`](nodejs/node@46ee1eddd7)] - **(SEMVER-MINOR)** **src**: add C++ support for diagnostics channels (RafaelGSS) [#&#8203;61869](nodejs/node#61869)
- \[[`9ddd1a9c27`](nodejs/node@9ddd1a9c27)] - **(SEMVER-MINOR)** **src,permission**: add --permission-audit (RafaelGSS) [#&#8203;61869](nodejs/node#61869)
- \[[`ea2df2a16f`](nodejs/node@ea2df2a16f)] - **stream**: fix pipeTo to defer writes per WHATWG spec (Matteo Collina) [#&#8203;61800](nodejs/node#61800)
- \[[`aa0c7b09e0`](nodejs/node@aa0c7b09e0)] - **test**: remove unnecessary `process.exit` calls from test files (Antoine du Hamel) [#&#8203;62020](nodejs/node#62020)
- \[[`ad96a6578f`](nodejs/node@ad96a6578f)] - **test**: skip `test-url` on `--shared-ada` builds (Antoine du Hamel) [#&#8203;62019](nodejs/node#62019)
- \[[`7c72a31e4b`](nodejs/node@7c72a31e4b)] - **test**: skip strace test with shared openssl (Richard Lau) [#&#8203;61987](nodejs/node#61987)
- \[[`604456c163`](nodejs/node@604456c163)] - **test**: avoid flaky debugger restart waits (Yuya Inoue) [#&#8203;61773](nodejs/node#61773)
- \[[`4890d6bd43`](nodejs/node@4890d6bd43)] - **test\_runner**: run afterEach on runtime skip (Igor Shevelenkov) [#&#8203;61525](nodejs/node#61525)
- \[[`fce2930110`](nodejs/node@fce2930110)] - **test\_runner**: expose expectFailure message (sangwook) [#&#8203;61563](nodejs/node#61563)
- \[[`0d97ec4044`](nodejs/node@0d97ec4044)] - **(SEMVER-MINOR)** **test\_runner**: expose worker ID for concurrent test execution (Ali Hassan) [#&#8203;61394](nodejs/node#61394)
- \[[`243e6b2009`](nodejs/node@243e6b2009)] - **test\_runner**: replace native methods with primordials (Ayoub Mabrouk) [#&#8203;61219](nodejs/node#61219)
- \[[`bf1ed7e647`](nodejs/node@bf1ed7e647)] - **tls**: forward keepAlive, keepAliveInitialDelay, noDelay to socket (Sergey Zelenov) [#&#8203;62004](nodejs/node#62004)
- \[[`0f15079d94`](nodejs/node@0f15079d94)] - **tools**: remove custom logic for skipping `test-strace-openat-openssl` (Antoine du Hamel) [#&#8203;62038](nodejs/node#62038)
- \[[`54a055a59d`](nodejs/node@54a055a59d)] - **tools**: bump minimatch from 3.1.2 to 3.1.3 in `/tools/clang-format` (dependabot\[bot]) [#&#8203;61977](nodejs/node#61977)
- \[[`a28744cb62`](nodejs/node@a28744cb62)] - **tools**: fix permissions for merve update script (Richard Lau) [#&#8203;62023](nodejs/node#62023)
- \[[`31e7936354`](nodejs/node@31e7936354)] - **tools**: revert tools GHA workflow to ubuntu-latest (Richard Lau) [#&#8203;62024](nodejs/node#62024)
- \[[`0a96a16e1f`](nodejs/node@0a96a16e1f)] - **tools**: bump minimatch from 3.1.2 to 3.1.3 in /tools/eslint (dependabot\[bot]) [#&#8203;61976](nodejs/node#61976)
- \[[`f279233412`](nodejs/node@f279233412)] - **tools**: roll back to x86 runner on `scorecard.yml` (Antoine du Hamel) [#&#8203;61944](nodejs/node#61944)
- \[[`192c0382f4`](nodejs/node@192c0382f4)] - **util**: add fast path to stripVTControlCharacters (Hiroki Osame) [#&#8203;61833](nodejs/node#61833)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My40OS4wIiwidXBkYXRlZEluVmVyIjoiNDMuNDkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs that have at least one approval, no pending requests for changes, and a CI started. buffer Issues and PRs related to the buffer subsystem. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. needs-benchmark-ci PR that need a benchmark CI run. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants