Skip to content

Commit 3c78c0e

Browse files
author
Andrii Sultanov
committed
CP-52225 - poll: Reduce unnecessary allocations
No need to maintain interface compatibility with select anymore, allocate an array of connection's poll status and modify that instead of allocating an array, three lists, and a hash table on each iteration of the main listening loop. Signed-off-by: Andrii Sultanov <[email protected]>
1 parent 403c849 commit 3c78c0e

File tree

4 files changed

+57
-53
lines changed

4 files changed

+57
-53
lines changed

oxenstored/connections.ml

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ module Xeneventchn = Eventchn
2020
let debug fmt = Logging.debug "connections" fmt
2121

2222
type t = {
23-
anonymous: (Unix.file_descr, Connection.t) Hashtbl.t
23+
anonymous: (Unix.file_descr, Connection.t * int) Hashtbl.t
24+
(* (fd -> Connection.t, index) where index maps to the poll_status array *)
25+
; mutable poll_status: (Unix.file_descr * Poll.event) array
2426
; domains: (int, Connection.t) Hashtbl.t
2527
; ports: (Xeneventchn.t, Connection.t) Hashtbl.t
2628
; mutable watches: Connection.watch list Trie.t
@@ -30,6 +32,7 @@ type t = {
3032
let create () =
3133
{
3234
anonymous= Hashtbl.create 37
35+
; poll_status= [||]
3336
; domains= Hashtbl.create 37
3437
; ports= Hashtbl.create 37
3538
; watches= Trie.create ()
@@ -43,11 +46,15 @@ let get_capacity () =
4346
; maxwatchevents= !Define.maxwatchevents
4447
}
4548

49+
let default_poll_status () = (Unix.stdin, Poll.init_event ())
50+
4651
let add_anonymous cons fd =
4752
let capacity = get_capacity () in
4853
let xbcon = Xenbus.Xb.open_fd fd ~capacity in
4954
let con = Connection.create xbcon None in
50-
Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon) con
55+
Hashtbl.add cons.anonymous (Xenbus.Xb.get_fd xbcon)
56+
(con, Array.length cons.poll_status) ;
57+
cons.poll_status <- Array.append cons.poll_status [|default_poll_status ()|]
5158

5259
let add_domain cons dom =
5360
let capacity = get_capacity () in
@@ -60,20 +67,26 @@ let add_domain cons dom =
6067
Hashtbl.add cons.domains (Domain.get_id dom) con ;
6168
Hashtbl.add cons.ports (Domain.get_local_port dom) con
6269

63-
let select ?(only_if = fun _ -> true) cons =
64-
Hashtbl.fold
65-
(fun _ con (ins, outs) ->
66-
if only_if con then
67-
let fd = Connection.get_fd con in
68-
let in_fds = if Connection.can_input con then fd :: ins else ins in
69-
let out_fds = if Connection.has_output con then fd :: outs else outs in
70-
(in_fds, out_fds)
71-
else
72-
(ins, outs)
70+
let refresh_poll_status ?(only_if = fun _ -> true) cons =
71+
Hashtbl.iter
72+
(fun _ (con, index) ->
73+
let only = only_if con in
74+
let fd = Connection.get_fd con in
75+
let open Poll in
76+
let event =
77+
{
78+
read= only && Connection.can_input con
79+
; write= only && Connection.has_output con
80+
; except= false
81+
}
82+
in
83+
cons.poll_status.(index) <- (fd, event)
7384
)
74-
cons.anonymous ([], [])
85+
cons.anonymous
7586
76-
let find cons = Hashtbl.find cons.anonymous
87+
let find cons fd =
88+
let c, _ = Hashtbl.find cons.anonymous fd in
89+
c
7790
7891
let find_domain cons = Hashtbl.find cons.domains
7992
@@ -97,8 +110,19 @@ let del_watches cons con =
97110
let del_anonymous cons con =
98111
try
99112
Hashtbl.remove cons.anonymous (Connection.get_fd con) ;
100-
del_watches cons con ;
101-
Connection.close con
113+
(* Reallocate the poll_status array, update indices pointing to it *)
114+
cons.poll_status <-
115+
Array.make (Hashtbl.length cons.anonymous) (default_poll_status ()) ;
116+
let _ =
117+
Hashtbl.fold
118+
(fun key (con, _) i ->
119+
Hashtbl.replace cons.anonymous key (con, i) ;
120+
i + 1
121+
)
122+
cons.anonymous 0
123+
in
124+
125+
del_watches cons con ; Connection.close con
102126
with exn -> debug "del anonymous %s" (Printexc.to_string exn)
103127
104128
let del_domain cons id =
@@ -116,7 +140,8 @@ let del_domain cons id =
116140
117141
let iter_domains cons fct = Hashtbl.iter (fun _ c -> fct c) cons.domains
118142
119-
let iter_anonymous cons fct = Hashtbl.iter (fun _ c -> fct c) cons.anonymous
143+
let iter_anonymous cons fct =
144+
Hashtbl.iter (fun _ (c, _) -> fct c) cons.anonymous
120145
121146
let iter cons fct = iter_domains cons fct ; iter_anonymous cons fct
122147
@@ -227,7 +252,7 @@ let stats cons =
227252
let debug cons =
228253
let anonymous =
229254
Hashtbl.fold
230-
(fun _ con accu -> Connection.debug con :: accu)
255+
(fun _ (con, _) accu -> Connection.debug con :: accu)
231256
cons.anonymous []
232257
in
233258
let domains =
@@ -258,6 +283,7 @@ let debug_watchevents cons con =
258283
259284
let filter ~f cons =
260285
let fold _ v acc = if f v then v :: acc else acc in
261-
[] |> Hashtbl.fold fold cons.anonymous |> Hashtbl.fold fold cons.domains
286+
let fold_a _ (v, _) acc = if f v then v :: acc else acc in
287+
[] |> Hashtbl.fold fold_a cons.anonymous |> Hashtbl.fold fold cons.domains
262288
263289
let prevents_quit cons = filter ~f:Connection.prevents_live_update cons

oxenstored/poll.ml

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
readfds, writefds, exceptfds concept as in select. *)
1818
type event = {mutable read: bool; mutable write: bool; mutable except: bool}
1919

20+
let init_event () = {read= false; write= false; except= false}
21+
2022
external select_on_poll : (Unix.file_descr * event) array -> int -> int
2123
= "stub_select_on_poll"
2224

@@ -31,33 +33,8 @@ let get_sys_fs_nr_open () =
3133
close_in_noerr ch ; v
3234
with _ -> 1024 * 1024
3335

34-
let init_event () = {read= false; write= false; except= false}
35-
36-
let poll_select in_fds out_fds exc_fds timeout =
37-
let h = Hashtbl.create 57 in
38-
let add_event event_set fd =
39-
let e =
40-
try Hashtbl.find h fd
41-
with Not_found ->
42-
let e = init_event () in
43-
Hashtbl.add h fd e ; e
44-
in
45-
event_set e
46-
in
47-
List.iter (add_event (fun x -> x.read <- true)) in_fds ;
48-
List.iter (add_event (fun x -> x.write <- true)) out_fds ;
49-
List.iter (add_event (fun x -> x.except <- true)) exc_fds ;
50-
(* Unix.stdin and init_event are dummy input as stubs, which will
51-
always be overwritten later on. *)
52-
let a = Array.make (Hashtbl.length h) (Unix.stdin, init_event ()) in
53-
let i = ref (-1) in
54-
Hashtbl.iter
55-
(fun fd event ->
56-
incr i ;
57-
Array.set a !i (fd, event)
58-
)
59-
h ;
60-
let n = select_on_poll a (int_of_float (timeout *. 1000.)) in
36+
let poll_select fdarr timeout =
37+
let n = select_on_poll fdarr (int_of_float (timeout *. 1000.)) in
6138
let r = ([], [], []) in
6239
if n = 0 then
6340
r
@@ -69,6 +46,6 @@ let poll_select in_fds out_fds exc_fds timeout =
6946
, if event.except then fd :: x else x
7047
)
7148
)
72-
a r
49+
fdarr r
7350

7451
let () = set_fd_limit (get_sys_fs_nr_open ())

oxenstored/poll.mli

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
* GNU Lesser General Public License for more details.
1313
*)
1414

15+
type event = {mutable read: bool; mutable write: bool; mutable except: bool}
16+
17+
val init_event : unit -> event
18+
1519
val poll_select :
16-
Unix.file_descr list
17-
-> Unix.file_descr list
18-
-> Unix.file_descr list
20+
(Unix.file_descr * event) array
1921
-> float
2022
-> Unix.file_descr list * Unix.file_descr list * Unix.file_descr list
21-
(** Same interface and semantics as [Unix.select], implemented using poll(3). *)

oxenstored/xenstored.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,9 @@ let () =
681681
in
682682
if peaceful_mw <> [] then 0. else until_next_activity
683683
in
684-
let inset, outset = Connections.select ~only_if:is_peaceful cons in
684+
Connections.refresh_poll_status ~only_if:is_peaceful cons ;
685685
let rset, wset, _ =
686-
try Poll.poll_select (spec_fds @ inset) outset [] timeout
686+
try Poll.poll_select cons.poll_status timeout
687687
with Unix.Unix_error (Unix.EINTR, _, _) -> ([], [], [])
688688
in
689689
let sfds, cfds = List.partition (fun fd -> List.mem fd spec_fds) rset in

0 commit comments

Comments
 (0)