perf(http3): eliminate allocations with zero-copy Bytes#3010
Conversation
Fixes issue mozilla#2854 by implementing a zero-copy alternative to the closed PR mozilla#2988. Instead of using the `Bytes` crate (which has `Arc` overhead), this introduces a lightweight `DatagramPayload` wrapper that stores the original `Vec<u8>` with a payload offset, avoiding both memory allocations and memory copies. Key improvements: - WebTransport datagrams: 0 allocations, 0 copies (was 1 allocation via `to_vec()`) - Connect UDP datagrams: 0 allocations, 0 copies (was 1 allocation via `to_vec()`) - No external dependencies or `Arc` overhead - Efficient slice access via offset calculation - Maintains API compatibility through trait implementations CC @mxinden
There was a problem hiding this comment.
Pull Request Overview
This PR implements a zero-copy DatagramPayload wrapper to eliminate memory allocations when handling HTTP/3 datagrams for WebTransport and Connect UDP sessions. The change replaces Vec<u8> with a custom DatagramPayload struct that stores the original data buffer with a payload offset, avoiding the need for to_vec() calls.
Key changes:
- Introduces
DatagramPayloadstruct with offset-based payload access - Updates all datagram-related APIs to use
DatagramPayloadinstead ofVec<u8> - Modifies datagram handling to pass ownership of the original buffer with offset information
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| neqo-http3/src/lib.rs | Adds the new DatagramPayload struct with comprehensive trait implementations |
| neqo-http3/src/connection.rs | Updates datagram handling to pass owned Vec with offset instead of copying |
| neqo-http3/src/features/extended_connect/session.rs | Replaces datagram() with datagram_owned() to handle owned data with offset |
| neqo-http3/src/server_events.rs | Updates event structs and methods to use DatagramPayload |
| neqo-http3/src/client_events.rs | Updates client event structs and methods to use DatagramPayload |
| neqo-http3/src/server_connection_events.rs | Updates server connection events to use DatagramPayload |
| neqo-http3/src/features/extended_connect/mod.rs | Updates trait signature to use DatagramPayload |
| neqo-http3/src/connection_server.rs | Removes reference when passing datagram to handler |
| neqo-http3/src/connection_client.rs | Removes reference when passing datagram to handler |
| neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs | Updates test assertions to use as_ref() for comparison |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3010 +/- ##
==========================================
- Coverage 93.37% 93.35% -0.03%
==========================================
Files 123 124 +1
Lines 35887 35967 +80
Branches 35887 35967 +80
==========================================
+ Hits 33511 33578 +67
- Misses 1533 1546 +13
Partials 843 843
|
DatagramPayload`DatagramPayload
|
| Branch | fix-2854-v2 |
| Testbed | On-prem |
🚨 1 Alert
| Benchmark | Measure Units | View | Benchmark Result (Result Δ%) | Upper Boundary (Limit %) |
|---|---|---|---|---|
| decode 4096 bytes, mask 3f | Latency microseconds (µs) | 📈 plot 🚷 threshold 🚨 alert (🔔) | 8.38 µs(+1.05%)Baseline: 8.30 µs | 8.35 µs (100.44%) |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result nanoseconds (ns) (Result Δ%) | Upper Boundary nanoseconds (ns) (Limit %) |
|---|---|---|---|
| 1-conn/1-100mb-req/mtu-1504 (aka. Upload)/client | 📈 view plot 🚷 view threshold | 199,620,000.00 ns(-4.49%)Baseline: 209,009,375.00 ns | 218,003,224.46 ns (91.57%) |
| 1-conn/1-100mb-resp/mtu-1504 (aka. Download)/client | 📈 view plot 🚷 view threshold | 193,950,000.00 ns(-4.47%)Baseline: 203,033,465.91 ns | 212,898,570.27 ns (91.10%) |
| 1-conn/1-1b-resp/mtu-1504 (aka. HPS)/client | 📈 view plot 🚷 view threshold | 28,423,000.00 ns(+0.04%)Baseline: 28,412,869.32 ns | 28,869,091.75 ns (98.45%) |
| 1-conn/10_000-parallel-1b-resp/mtu-1504 (aka. RPS)/client | 📈 view plot 🚷 view threshold | 287,430,000.00 ns(-2.50%)Baseline: 294,794,772.73 ns | 306,070,236.30 ns (93.91%) |
| 1-streams/each-1000-bytes/simulated-time | 📈 view plot 🚷 view threshold | 119,040,000.00 ns(+0.62%)Baseline: 118,310,056.82 ns | 120,887,916.37 ns (98.47%) |
| 1-streams/each-1000-bytes/wallclock-time | 📈 view plot 🚷 view threshold | 586,670.00 ns(-1.96%)Baseline: 598,389.38 ns | 623,192.47 ns (94.14%) |
| 1000-streams/each-1-bytes/simulated-time | 📈 view plot 🚷 view threshold | 14,994,000,000.00 ns(+0.01%)Baseline: 14,991,823,863.64 ns | 15,010,334,126.88 ns (99.89%) |
| 1000-streams/each-1-bytes/wallclock-time | 📈 view plot 🚷 view threshold | 13,663,000.00 ns(-3.91%)Baseline: 14,219,079.55 ns | 14,990,431.89 ns (91.14%) |
| 1000-streams/each-1000-bytes/simulated-time | 📈 view plot 🚷 view threshold | 19,049,000,000.00 ns(+0.74%)Baseline: 18,909,653,409.09 ns | 19,156,534,875.56 ns (99.44%) |
| 1000-streams/each-1000-bytes/wallclock-time | 📈 view plot 🚷 view threshold | 48,923,000.00 ns(-6.49%)Baseline: 52,316,011.36 ns | 58,757,035.26 ns (83.26%) |
| RxStreamOrderer::inbound_frame() | 📈 view plot 🚷 view threshold | 108,490,000.00 ns(-1.23%)Baseline: 109,846,363.64 ns | 112,004,019.57 ns (96.86%) |
| coalesce_acked_from_zero 1+1 entries | 📈 view plot 🚷 view threshold | 88.56 ns(-0.08%)Baseline: 88.63 ns | 89.31 ns (99.17%) |
| coalesce_acked_from_zero 10+1 entries | 📈 view plot 🚷 view threshold | 105.56 ns(-0.51%)Baseline: 106.10 ns | 107.09 ns (98.57%) |
| coalesce_acked_from_zero 1000+1 entries | 📈 view plot 🚷 view threshold | 88.87 ns(-1.07%)Baseline: 89.84 ns | 94.49 ns (94.06%) |
| coalesce_acked_from_zero 3+1 entries | 📈 view plot 🚷 view threshold | 106.14 ns(-0.45%)Baseline: 106.62 ns | 107.58 ns (98.67%) |
| decode 1048576 bytes, mask 3f | 📈 view plot 🚷 view threshold | 1,593,300.00 ns(+0.05%)Baseline: 1,592,547.73 ns | 1,599,591.84 ns (99.61%) |
| decode 1048576 bytes, mask 7f | 📈 view plot 🚷 view threshold | 5,053,300.00 ns(-0.08%)Baseline: 5,057,278.98 ns | 5,077,128.25 ns (99.53%) |
| decode 1048576 bytes, mask ff | 📈 view plot 🚷 view threshold | 3,036,500.00 ns(+0.16%)Baseline: 3,031,650.57 ns | 3,043,537.16 ns (99.77%) |
| decode 4096 bytes, mask 3f | 📈 view plot 🚷 view threshold 🚨 view alert (🔔) | 8,383.90 ns(+1.05%)Baseline: 8,297.09 ns | 8,347.38 ns (100.44%) |
| decode 4096 bytes, mask 7f | 📈 view plot 🚷 view threshold | 19,994.00 ns(-0.07%)Baseline: 20,007.75 ns | 20,086.37 ns (99.54%) |
| decode 4096 bytes, mask ff | 📈 view plot 🚷 view threshold | 11,636.00 ns(-0.82%)Baseline: 11,732.65 ns | 11,977.40 ns (97.15%) |
| sent::Packets::take_ranges | 📈 view plot 🚷 view threshold | 4,571.20 ns(-3.70%)Baseline: 4,746.71 ns | 4,990.23 ns (91.60%) |
| transfer/pacing-false/same-seed/simulated-time/run | 📈 view plot 🚷 view threshold | 25,710,000,000.00 ns(+1.84%)Baseline: 25,245,000,000.00 ns | 25,733,296,634.69 ns (99.91%) |
| transfer/pacing-false/same-seed/wallclock-time/run | 📈 view plot 🚷 view threshold | 25,638,000.00 ns(-1.50%)Baseline: 26,028,500.00 ns | 27,081,526.02 ns (94.67%) |
| transfer/pacing-false/varying-seeds/simulated-time/run | 📈 view plot 🚷 view threshold | 25,185,000,000.00 ns(+0.07%)Baseline: 25,166,844,827.59 ns | 25,211,663,017.04 ns (99.89%) |
| transfer/pacing-false/varying-seeds/wallclock-time/run | 📈 view plot 🚷 view threshold | 25,049,000.00 ns(-4.64%)Baseline: 26,268,856.32 ns | 27,610,125.20 ns (90.72%) |
| transfer/pacing-true/same-seed/simulated-time/run | 📈 view plot 🚷 view threshold | 25,675,000,000.00 ns(+0.28%)Baseline: 25,602,500,000.00 ns | 25,678,632,271.00 ns (99.99%) |
| transfer/pacing-true/same-seed/wallclock-time/run | 📈 view plot 🚷 view threshold | 26,570,000.00 ns(-3.24%)Baseline: 27,460,000.00 ns | 28,771,349.63 ns (92.35%) |
| transfer/pacing-true/varying-seeds/simulated-time/run | 📈 view plot 🚷 view threshold | 25,009,000,000.00 ns(+0.06%)Baseline: 24,994,063,218.39 ns | 25,043,698,696.08 ns (99.86%) |
| transfer/pacing-true/varying-seeds/wallclock-time/run | 📈 view plot 🚷 view threshold | 25,554,000.00 ns(-4.65%)Baseline: 26,799,793.10 ns | 28,176,607.47 ns (90.69%) |
Co-authored-by: Copilot <[email protected]> Signed-off-by: Lars Eggert <[email protected]>
Co-authored-by: Copilot <[email protected]> Signed-off-by: Lars Eggert <[email protected]>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
| Branch | fix-2854-v2 |
| Testbed | On-prem |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| google vs. neqo (cubic, paced) | 📈 view plot 🚷 view threshold | 278.80 ms(+0.40%)Baseline: 277.69 ms | 280.28 ms (99.47%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| msquic vs. neqo (cubic, paced) | 📈 view plot 🚷 view threshold | 182.69 ms(-5.60%)Baseline: 193.53 ms | 226.60 ms (80.62%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. google (cubic, paced) | 📈 view plot 🚷 view threshold | 751.91 ms(-0.75%)Baseline: 757.57 ms | 764.92 ms (98.30%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. msquic (cubic, paced) | 📈 view plot 🚷 view threshold | 159.17 ms(+1.26%)Baseline: 157.20 ms | 159.51 ms (99.79%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. neqo (cubic) | 📈 view plot 🚷 view threshold | 90.53 ms(-0.17%)Baseline: 90.69 ms | 94.49 ms (95.81%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. neqo (cubic, paced) | 📈 view plot 🚷 view threshold | 92.62 ms(+0.78%)Baseline: 91.91 ms | 95.61 ms (96.88%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. neqo (reno) | 📈 view plot 🚷 view threshold | 89.38 ms(-1.36%)Baseline: 90.61 ms | 94.00 ms (95.08%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. neqo (reno, paced) | 📈 view plot 🚷 view threshold | 91.54 ms(-0.33%)Baseline: 91.84 ms | 95.51 ms (95.84%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. quiche (cubic, paced) | 📈 view plot 🚷 view threshold | 193.64 ms(-0.06%)Baseline: 193.76 ms | 197.21 ms (98.19%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| neqo vs. s2n (cubic, paced) | 📈 view plot 🚷 view threshold | 219.63 ms(-0.53%)Baseline: 220.81 ms | 223.63 ms (98.21%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| quiche vs. neqo (cubic, paced) | 📈 view plot 🚷 view threshold | 152.44 ms(-0.06%)Baseline: 152.54 ms | 158.23 ms (96.34%) |
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| s2n vs. neqo (cubic, paced) | 📈 view plot 🚷 view threshold | 174.02 ms(+0.05%)Baseline: 173.94 ms | 178.09 ms (97.72%) |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]> Signed-off-by: Lars Eggert <[email protected]>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
martinthomson
left a comment
There was a problem hiding this comment.
I think that I found a bug, not exactly in your code, but highlighted by it. Still, this seems like a good change.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
mxinden
left a comment
There was a problem hiding this comment.
Other than these minor comments, this looks good to me.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Co-authored-by: Copilot <[email protected]> Signed-off-by: Lars Eggert <[email protected]>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Failed Interop TestsQUIC Interop Runner, client vs. server neqo-latest as client
neqo-latest as server
All resultsSucceeded Interop TestsQUIC Interop Runner, client vs. server neqo-latest as client
neqo-latest as server
Unsupported Interop TestsQUIC Interop Runner, client vs. server neqo-latest as client
neqo-latest as server
|
Client/server transfer resultsPerformance differences relative to 3d2948d. Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.
Download data for |
Benchmark resultsPerformance differences relative to 3d2948d. 1-conn/1-100mb-resp/mtu-1504 (aka. Download)/client: Change within noise threshold. time: [193.67 ms 193.95 ms 194.23 ms]
thrpt: [514.84 MiB/s 515.60 MiB/s 516.35 MiB/s]
change:
time: [−0.8738% −0.6331% −0.4200%] (p = 0.00 < 0.05)
thrpt: [+0.4218% +0.6372% +0.8815%]
1-conn/10_000-parallel-1b-resp/mtu-1504 (aka. RPS)/client: No change in performance detected. time: [285.77 ms 287.43 ms 289.13 ms]
thrpt: [34.587 Kelem/s 34.791 Kelem/s 34.993 Kelem/s]
change:
time: [−1.2586% −0.4841% +0.3170%] (p = 0.23 > 0.05)
thrpt: [−0.3160% +0.4864% +1.2746%]
1-conn/1-1b-resp/mtu-1504 (aka. HPS)/client: No change in performance detected. time: [28.352 ms 28.423 ms 28.501 ms]
thrpt: [35.086 B/s 35.183 B/s 35.271 B/s]
change:
time: [−0.4448% +0.0369% +0.5069%] (p = 0.88 > 0.05)
thrpt: [−0.5043% −0.0369% +0.4468%]
1-conn/1-100mb-req/mtu-1504 (aka. Upload)/client: No change in performance detected. time: [199.27 ms 199.62 ms 200.05 ms]
thrpt: [499.88 MiB/s 500.95 MiB/s 501.82 MiB/s]
change:
time: [−0.2852% −0.0198% +0.2459%] (p = 0.89 > 0.05)
thrpt: [−0.2453% +0.0198% +0.2860%]
decode 4096 bytes, mask ff: No change in performance detected. time: [11.597 µs 11.636 µs 11.679 µs]
change: [−0.5655% −0.1027% +0.3064%] (p = 0.66 > 0.05)
decode 1048576 bytes, mask ff: No change in performance detected. time: [3.0231 ms 3.0365 ms 3.0535 ms]
change: [−0.4249% +0.1564% +0.7337%] (p = 0.62 > 0.05)
decode 4096 bytes, mask 7f: No change in performance detected. time: [19.943 µs 19.994 µs 20.050 µs]
change: [−0.7023% −0.1380% +0.4892%] (p = 0.66 > 0.05)
decode 1048576 bytes, mask 7f: No change in performance detected. time: [5.0423 ms 5.0533 ms 5.0650 ms]
change: [−0.4083% −0.0736% +0.2237%] (p = 0.67 > 0.05)
decode 4096 bytes, mask 3f: No change in performance detected. time: [8.2735 µs 8.3839 µs 8.5931 µs]
change: [−3.2234% −0.4227% +2.2355%] (p = 0.80 > 0.05)
decode 1048576 bytes, mask 3f: No change in performance detected. time: [1.5865 ms 1.5933 ms 1.6004 ms]
change: [−0.2760% +0.2505% +0.7841%] (p = 0.38 > 0.05)
1-streams/each-1000-bytes/wallclock-time: No change in performance detected. time: [584.00 µs 586.67 µs 589.62 µs]
change: [−0.7850% −0.2494% +0.3293%] (p = 0.40 > 0.05)
1000-streams/each-1-bytes/wallclock-time: No change in performance detected. time: [13.616 ms 13.663 ms 13.721 ms]
change: [−0.0720% +0.3384% +0.7826%] (p = 0.13 > 0.05)
1000-streams/each-1000-bytes/wallclock-time: No change in performance detected. time: [48.752 ms 48.923 ms 49.094 ms]
change: [−0.3027% +0.1962% +0.7040%] (p = 0.45 > 0.05)
coalesce_acked_from_zero 1+1 entries: No change in performance detected. time: [88.050 ns 88.563 ns 89.270 ns]
change: [−0.3826% +0.2811% +1.0626%] (p = 0.48 > 0.05)
coalesce_acked_from_zero 3+1 entries: No change in performance detected. time: [105.82 ns 106.14 ns 106.49 ns]
change: [−0.6431% −0.1753% +0.2647%] (p = 0.46 > 0.05)
coalesce_acked_from_zero 10+1 entries: No change in performance detected. time: [105.21 ns 105.56 ns 106.00 ns]
change: [−0.4737% −0.0516% +0.4260%] (p = 0.82 > 0.05)
coalesce_acked_from_zero 1000+1 entries: No change in performance detected. time: [88.752 ns 88.872 ns 89.015 ns]
change: [−0.6650% +0.1796% +1.1427%] (p = 0.71 > 0.05)
RxStreamOrderer::inbound_frame(): Change within noise threshold. time: [108.42 ms 108.49 ms 108.56 ms]
change: [−1.0062% −0.7124% −0.5013%] (p = 0.00 < 0.05)
sent::Packets::take_ranges: No change in performance detected. time: [4.4988 µs 4.5712 µs 4.6306 µs]
change: [−5.6252% −2.2346% +1.0580%] (p = 0.20 > 0.05)
transfer/pacing-false/varying-seeds/wallclock-time/run: No change in performance detected. time: [25.005 ms 25.049 ms 25.104 ms]
change: [−0.1686% +0.0520% +0.2935%] (p = 0.69 > 0.05)
transfer/pacing-false/varying-seeds/simulated-time/run: No change in performance detected. time: [25.154 s 25.185 s 25.216 s]
thrpt: [162.44 KiB/s 162.64 KiB/s 162.84 KiB/s]
change:
time: [−0.0799% +0.1115% +0.3030%] (p = 0.25 > 0.05)
thrpt: [−0.3021% −0.1114% +0.0800%]
transfer/pacing-true/varying-seeds/wallclock-time/run: No change in performance detected. time: [25.491 ms 25.554 ms 25.618 ms]
change: [−0.2540% +0.1091% +0.4740%] (p = 0.56 > 0.05)
transfer/pacing-true/varying-seeds/simulated-time/run: No change in performance detected. time: [24.972 s 25.009 s 25.047 s]
thrpt: [163.53 KiB/s 163.78 KiB/s 164.03 KiB/s]
change:
time: [−0.1066% +0.0973% +0.2930%] (p = 0.36 > 0.05)
thrpt: [−0.2921% −0.0972% +0.1067%]
transfer/pacing-false/same-seed/wallclock-time/run: Change within noise threshold. time: [25.618 ms 25.638 ms 25.658 ms]
change: [+0.6091% +0.8101% +0.9669%] (p = 0.00 < 0.05)
transfer/pacing-false/same-seed/simulated-time/run: No change in performance detected. time: [25.710 s 25.710 s 25.710 s]
thrpt: [159.31 KiB/s 159.31 KiB/s 159.31 KiB/s]
change:
time: [+0.0000% +0.0000% +0.0000%] (p = NaN > 0.05)
thrpt: [+0.0000% +0.0000% +0.0000%]
transfer/pacing-true/same-seed/wallclock-time/run: Change within noise threshold. time: [26.545 ms 26.570 ms 26.600 ms]
change: [+0.4713% +0.6253% +0.7668%] (p = 0.00 < 0.05)
transfer/pacing-true/same-seed/simulated-time/run: No change in performance detected. time: [25.675 s 25.675 s 25.675 s]
thrpt: [159.53 KiB/s 159.53 KiB/s 159.53 KiB/s]
change:
time: [+0.0000% +0.0000% +0.0000%] (p = NaN > 0.05)
thrpt: [+0.0000% +0.0000% +0.0000%]
Download data for |
Fixes issue #2854 by implementing a zero-copy alternative to the closed PR #2988.
Alternative to #2988
CC @mxinden