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

mobile: Use direct ByteBuffer to pass data between C++ and Java #32715

Merged
merged 2 commits into from
Mar 6, 2024

Conversation

fredyw
Copy link
Member

@fredyw fredyw commented Mar 5, 2024

This PR updates the JNI code to use direct ByteBuffer to pass the data between C++ and Java. This change helps to reduce the number of copying needed, especially between jbyteArray (C++) and byte[] (Java). The direct ByteBuffer is backed by envoy_data without any copy.

Before:

  1. Buffer:Instance is created by Envoy.
  2. Create envoy_data from Buffer::Instance by copying.
  3. Create jbyteArray from envoy_data by copying.
  4. Pass the jbyteArray (C++) to byte[] (Java). This typically involves a copy, but it's implementation dependent.
  5. Wrap the byte[] into ByteBuffer (no copy, memory managed by the JVM).

After:

  1. Buffer:Instance is created by Envoy.
  2. Create envoy_data from Buffer::Instance by copying.
  3. Wraps the envoy_data into direct ByteBuffer (no copy).
  4. Pass the ByteBuffer directly from C++ to Java (no copy).
  5. Create a copy of the ByteBuffer in the callbacks for further use. This is needed because the direct ByteBuffer backed by envoy_data will be destroyed upon completing the callback. Technically, we could let the user-defined callback create a copy as needed, such as if it needs the data to outlive the callback lifetime. However, doing that would put a burden on the users whether or not a copy is needed and failing to do so could result in garbage data. To make things less error-prone, all data passed into the user-defined callbacks will be a copy.

Reference: https://developer.android.com/training/articles/perf-jni#faq:-how-do-i-share-raw-data-with-native-code

Risk Level: medium
Testing: unit tests
Docs Changes: n/a
Release Notes: n/a
Platform Specific Features: mobile

Copy link

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #32715 was opened by fredyw.

see: more, trace.

@fredyw fredyw force-pushed the byte_buffer branch 3 times, most recently from db9fb33 to f456fdf Compare March 5, 2024 23:02
Signed-off-by: Fredy Wijaya <fredyw@google.com>
Signed-off-by: Fredy Wijaya <fredyw@google.com>
@fredyw fredyw changed the title mobile: Change from byte[] to ByteBuffer mobile: Use ByteBuffer to pass data between C++ and Java Mar 6, 2024
@fredyw fredyw changed the title mobile: Use ByteBuffer to pass data between C++ and Java mobile: Use direct ByteBuffer to pass data between C++ and Java Mar 6, 2024
@fredyw fredyw marked this pull request as ready for review March 6, 2024 01:58
@fredyw
Copy link
Member Author

fredyw commented Mar 6, 2024

/assign @abeyad

@fredyw
Copy link
Member Author

fredyw commented Mar 6, 2024

/retest

Copy link
Contributor

@abeyad abeyad left a comment

Choose a reason for hiding this comment

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

Nice, thanks @fredyw ! The PR description was super helpful too.

Question from that though, you mentioned:

Create a copy of the ByteBuffer in the callbacks for further use. 

So from what I understood, if we actually use the data in a callback (which is the majority case?), then both before and after will result in 2 copies of the data. Is this correct?

@fredyw
Copy link
Member Author

fredyw commented Mar 6, 2024

Nice, thanks @fredyw ! The PR description was super helpful too.

Question from that though, you mentioned:

Create a copy of the ByteBuffer in the callbacks for further use. 

So from what I understood, if we actually use the data in a callback (which is the majority case?), then both before and after will result in 2 copies of the data. Is this correct?

Yes, that's correct. The only thing that this PR will save is between the jByteArray to byte[]. There's another thing that I'm experimenting to reduce the number of copies to just 1, but this is going to be a slightly breaking change and I plan to work on it in the next PR.

@abeyad
Copy link
Contributor

abeyad commented Mar 6, 2024

Sorry, I had missed step #4 in your "Before" description, which usually involves a copy, so before is 3 copies, and after is 2 copies. Awesome!

@abeyad abeyad merged commit 5fc7662 into envoyproxy:main Mar 6, 2024
36 checks passed
@fredyw fredyw deleted the byte_buffer branch March 6, 2024 17:12
mattjo added a commit to mattjo/envoy that referenced this pull request Mar 6, 2024
* origin: (34 commits)
  update CODEOWNER (envoyproxy#32457)
  Delete unused runtime flag. (envoyproxy#32739)
  mobile: Use direct ByteBuffer to pass data between C++ and Java (envoyproxy#32715)
  quic: support cert selection by SNI, non-PEM formats (envoyproxy#32260)
  mobile: Replace std::thread with Envoy::Thread::PosixThread (envoyproxy#32610)
  grpc: Add support for max frame length in gPRC frame decoding (envoyproxy#32511)
  build(deps): bump google.golang.org/protobuf from 1.32.0 to 1.33.0 (envoyproxy#32728)
  build(deps): bump the examples-golang-network group in /examples/golang-network/simple with 1 update (envoyproxy#32732)
  build(deps): bump google.golang.org/protobuf from 1.32.0 to 1.33.0 in /contrib/golang/filters/http/test/test_data/property (envoyproxy#32731)
  build(deps): bump otel/opentelemetry-collector from `246dfe9` to `71ac13c` in /examples/opentelemetry (envoyproxy#32730)
  build(deps): bump the examples-grpc-bridge group in /examples/grpc-bridge/server with 2 updates (envoyproxy#32720)
  build(deps): bump the contrib-golang group in /contrib/golang/router/cluster_specifier/test/test_data/simple with 1 update (envoyproxy#32721)
  build(deps): bump the contrib-golang group in /contrib/golang/filters/http/test/test_data/echo with 1 update (envoyproxy#32722)
  build(deps): bump the examples-ext-authz group in /examples/ext_authz/auth/grpc-service with 1 update (envoyproxy#32723)
  build(deps): bump the contrib-golang group in /contrib/golang/filters/http/test/test_data/routeconfig with 1 update (envoyproxy#32724)
  build(deps): bump the examples-load-reporting group in /examples/load-reporting-service with 1 update (envoyproxy#32726)
  build(deps): bump the contrib-golang group in /contrib/golang/filters/http/test/test_data/buffer with 1 update (envoyproxy#32727)
  build(deps): bump the examples-golang-http group in /examples/golang-http/simple with 1 update (envoyproxy#32729)
  opentelemetrytracer: Add User-Agent header to OTLP trace exporters (envoyproxy#32659)
  build: remove incorrect cc_library after tls code move (envoyproxy#32714)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants