Skip to content

Commit 6047fdd

Browse files
committed
Optimise Flow.copy with Buf_read.as_flow
By default, Flow.copy creates a 4KB buffer and copies the data through that. However, if the source of the copy is a buffered reader then it is much more efficient to use its buffer directly. This updates the flow you get from `Buf_read.as_flow` to offer this optimisation, and also updates the eio_posix backend's flow to use this optimisation when available (eio_linux already supported this). Detected in a benchmark by Leandro Ostera.
1 parent fbe8a71 commit 6047fdd

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

lib_eio/buf_read.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ module F = struct
140140
consume t len;
141141
len
142142

143-
let read_methods = []
143+
let rsb t fn =
144+
ensure t 1;
145+
let data = peek t in
146+
let sent = fn [data] in
147+
consume t sent
148+
149+
let read_methods = [Flow.Read_source_buffer rsb]
144150
end
145151

146152
let as_flow =

lib_eio_posix/flow.ml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,22 @@ module Impl = struct
6464
with Unix.Unix_error (code, name, arg) ->
6565
raise (Err.wrap code name arg)
6666

67-
let copy t ~src = Eio.Flow.Pi.simple_copy ~single_write t ~src
67+
(* Copy using the [Read_source_buffer] optimisation.
68+
Avoids a copy if the source already has the data. *)
69+
let copy_with_rsb rsb dst =
70+
try
71+
while true do rsb (single_write dst) done
72+
with End_of_file -> ()
73+
74+
let copy t ~src =
75+
let Eio.Resource.T (src_t, ops) = src in
76+
let module Src = (val (Eio.Resource.get ops Eio.Flow.Pi.Source)) in
77+
let rec aux = function
78+
| Eio.Flow.Read_source_buffer rsb :: _ -> copy_with_rsb (rsb src_t) t
79+
| _ :: xs -> aux xs
80+
| [] -> Eio.Flow.Pi.simple_copy ~single_write t ~src
81+
in
82+
aux Src.read_methods
6883

6984
let single_read t buf =
7085
match Low_level.readv t [| buf |] with

0 commit comments

Comments
 (0)