Avoid needless buffer copy in Cronet*OutputStream |
||||
Issue descriptionVersion: ToT OS: Android Normally Cronet*OutputStream classes copy from byte[] provided by caller into an internal ByteBuffer and then pass this to Cronet to upload. If the incoming byte[] is fairly large (which I assume it generally is) then we could just wrap it in a ByteBuffer and pass in to Cronet to upload directly thus avoiding the memory copy. I should mention that Android's ByteBuffer put(byte[]) may be excruciatingly slow: it loops over each byte calling put(byte)... http://androidxref.com/6.0.0_r1/xref/libcore/luni/src/main/java/java/nio/ByteBuffer.java#751
,
Oct 5 2016
I don't propose holding onto it beyond the write() call. This is a blocking API, so if passed a large buffer, we're expected to block until we've uploaded it I believe.
,
Oct 5 2016
Ah, I see. But for the different type of OutputStream, the upload behavior is a bit different. - ChunkedOutputStream: we need to hold on the byte[] until |chunked| bytes are written by clients. We can then try to upload. - FixedModeOutputStream: We can try eliminating the buffer. My concern is that if client tries to write one byte at a time, we will have no choice but to buffer so as to avoid multiple thread hops. - BufferedOutputStream: this is where client didn't set the chunked mode or the fixed streaming mode. In this case, we have to buffer because it's not guaranteed that client has passed us the Content-Length header -- we have to wait until all bytes have been written.
,
Oct 6 2016
For ChunkedOutputStream, I propose my optimization only if the user passes in a buffer at least as big as |chunked| bytes. For FixedModeOutputStream, as I described in my description, I'm only proposing my optimization when "the incoming byte[] is fairly large"; it's not worth doing if they're passing in lots of small buffers. For BufferedOutputStream, I think we can do the optimization if Content-Length header is set and this is the last buffer passed in; again it's only worth it if the buffer is fairly large.
,
Oct 6 2016
I see. That makes sense. I will mark this as available and lower this to P3. Please adjust this accordingly if needed. Thanks.
,
Oct 6 2016
How do we ensure that byte[] is backed by *direct* byte buffer?
,
Oct 6 2016
That's a problem. Can a byte[] be backed by direct memory?
,
Oct 6 2016
Good question, AFAIK direct byte buffers don't have byte[] array (hasArray() return false), but I don't know about opposite. Actually, I might've misunderstood the suggestion, it seems that we don't need direct byte buffer here, as it gets copied into cronet-supplied direct byte buffer in UploadDataProviderImpl.read(): https://cs.chromium.org/chromium/src/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java?rcl=0&l=156
,
Oct 6 2016
Ah ya, it doesn't have to be direct.
,
Nov 7 2016
#8, direct buffers can hasArray() on android, if you obtain it via ByteBuffer.allocateDirect().
,
Nov 7 2016
Also, false alarm over the "excruciatingly slow" implementation - the put method is overridden in both the heap and direct implementations, to use System.arrayCopy or memmove.
,
Nov 8 2017
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. If you change it back, also remove the "Hotlist-Recharge-Cold" label. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Jan 3
|
||||
►
Sign in to add a comment |
||||
Comment 1 by xunji...@chromium.org
, Oct 5 2016