Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

napi_create_string_utf8() performance issue #26437

Closed
anthony-tuininga opened this issue Mar 4, 2019 · 7 comments
Closed

napi_create_string_utf8() performance issue #26437

anthony-tuininga opened this issue Mar 4, 2019 · 7 comments
Labels
node-api Issues and PRs related to the Node-API.

Comments

@anthony-tuininga
Copy link
Contributor

anthony-tuininga commented Mar 4, 2019

  • Version: v12.0.0-pre
  • Platform: Linux
  • Subsystem: N-API

In working on the N-API implementation for the node-oracledb driver for Oracle Database it was discovered that the performance between the original V8/NAN implementation and the N-API implementation is dramatically different in some situations. I tracked it down to the fact that the napi_create_string_utf8() uses string type kInternalized instead of kNormal. For my example, creating strings of length 4 MB resulted in almost 4x more time required to create the string than with the original implementation. If I make the following change:

diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc
index 022ce104eb..9da9bb2b2a 100644
--- a/src/js_native_api_v8.cc
+++ b/src/js_native_api_v8.cc
@@ -23,7 +23,7 @@
         (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
         napi_invalid_arg);                                               \
     auto str_maybe = v8::String::NewFromUtf8(                            \
-        (env)->isolate, (str), v8::NewStringType::kInternalized,         \
+        (env)->isolate, (str), v8::NewStringType::kNormal,         \
         static_cast<int>(len));                                          \
     CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
     (result) = str_maybe.ToLocalChecked();                               \

the performance becomes indistinguishable.

So, can this be patched? Or is there a particular reason for using the string type kInternalized? Since this is only particularly noticeable for large strings, the other possibility would be to check the length and only use kNormal if the length is greater than a particular size -- not sure if that would be better?

I tried creating a buffer and converting that to a string by using napi_create_buffer() and napi_coerce_to_string(). That works better but is still more than 2x slower.

@anthony-tuininga
Copy link
Contributor Author

anthony-tuininga commented Mar 4, 2019

An additional note: strings < 100 bytes in length are virtually indistinguishable. The performance decrease become somewhat noticeable around 1,000 bytes and at about 10,000 bytes is very noticeable at about 2x slower. Past 30,000 bytes the performance is around 4x slower and seems to stay at about that ratio after that -- at least up to 16 MB in size.

@addaleax addaleax added the node-api Issues and PRs related to the Node-API. label Mar 4, 2019
@addaleax
Copy link
Member

addaleax commented Mar 4, 2019

Generally, your suggested patch makes sense. It should be applied for all of the napi_create_string_* methods, and it would be great if you could open a pull request.

One issue is that CHECK_NEW_FROM_UTF8() or CHECK_NEW_FROM_UTF8_LEN() are used in quite a number of places, and it actually does make sense to use kInternalized for a lot of its call sites.

So, I would suggest to have napi_create_string_utf8() look more like napi_create_string_latin1(), with the NewStringType inline in the function’s source code (and changed to kNormal), and to leave the macro itself as it is for now?

@anthony-tuininga
Copy link
Contributor Author

Sure. I'm not that familiar with the Node.js internals so took the easiest route. I'll take a closer look now and create a pull request on which you can comment further.

@anthony-tuininga
Copy link
Contributor Author

Ok. Take a look and let me know if that more closely aligns to what you were expecting? Let me know if any changes are required.

@anthony-tuininga
Copy link
Contributor Author

I'm not sure what the process is for getting this fix backported to v10.x and v8.x. If it would help to have PRs created for each branch, please let me know.

@BridgeAR
Copy link
Member

BridgeAR commented Mar 9, 2019

@anthony-tuininga the PRs are pulled in the other released automatically, if they have no conflict with the target branch. If there are conflicts, the releasing person is going to leave a comment that a manual backport is required.

@anthony-tuininga
Copy link
Contributor Author

Ok. Thanks for the explanation!

BridgeAR pushed a commit to BridgeAR/node that referenced this issue Mar 13, 2019
Improve performance creating strings using N-API by ensuring that the
strings are not internalized.

Added test cases for latin-1 and utf-16 strings.

PR-URL: nodejs#26439
Fixes: nodejs#26437
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
BridgeAR pushed a commit that referenced this issue Mar 14, 2019
Improve performance creating strings using N-API by ensuring that the
strings are not internalized.

Added test cases for latin-1 and utf-16 strings.

PR-URL: #26439
Fixes: #26437
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this issue Apr 5, 2019
Improve performance creating strings using N-API by ensuring that the
strings are not internalized.

Added test cases for latin-1 and utf-16 strings.

PR-URL: #26439
Fixes: #26437
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this issue Apr 5, 2019
Improve performance creating strings using N-API by ensuring that the
strings are not internalized.

Added test cases for latin-1 and utf-16 strings.

PR-URL: #26439
Fixes: #26437
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this issue Apr 16, 2019
Improve performance creating strings using N-API by ensuring that the
strings are not internalized.

Added test cases for latin-1 and utf-16 strings.

PR-URL: #26439
Fixes: #26437
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
node-api Issues and PRs related to the Node-API.
Projects
None yet
Development

No branches or pull requests

3 participants