Skip to content

Commit 4c45b8b

Browse files
committed
Further tweaks to reduce stack usage
1 parent a5ea38c commit 4c45b8b

File tree

4 files changed

+84
-68
lines changed

4 files changed

+84
-68
lines changed

lib/picos/bootstrap/picos_bootstrap.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ module Fiber = struct
489489
Sys.opaque_identity (Obj.magic (Array.unsafe_get r.fls key) : a)
490490
else default
491491

492+
let reserve (type a) (Fiber r : fiber) (key : a t) =
493+
let fls = r.fls in
494+
if Array.length fls <= key then r.fls <- grow fls key
495+
492496
let set (type a) (Fiber r : fiber) (key : a t) (value : a) =
493497
let fls = r.fls in
494498
if key < Array.length fls then

lib/picos/picos.mli

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,17 @@ module Fiber : sig
10011001
10021002
⚠️ It is only safe to call [remove] from the fiber itself or when the
10031003
fiber is known not to be running. *)
1004+
1005+
val reserve : fiber -> 'a t -> unit
1006+
(** [reserve fiber key] ensures that sufficient space has been allocated to
1007+
associate a value with the specified [key] such that a subsequent {!set}
1008+
with the [key] will not allocate.
1009+
1010+
ℹ️ This can be used to optimize the population of the FLS and to avoid
1011+
performing memory allocations in critical sections.
1012+
1013+
⚠️ It is only safe to call [reserve] from the fiber itself or when the
1014+
fiber is known not to be running. *)
10041015
end
10051016

10061017
(** {2 Interface for spawning} *)

lib/picos_std.finally/picos_std_finally.ml

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,15 @@ let forbidden release x =
5151
We also do not reraise the exception! *)
5252
release x
5353

54-
(** This helps to reduce CPU stack usage with the native compiler. *)
55-
let[@inline never] release_and_reraise exn release x =
54+
let[@inline never] release_and_reraise exn x release =
5655
let bt = Printexc.get_raw_backtrace () in
5756
forbidden release x;
5857
Printexc.raise_with_backtrace exn bt
5958

59+
let[@inline never] release_and_return value x release =
60+
forbidden release x;
61+
value
62+
6063
(* *)
6164

6265
let rec drop instance =
@@ -70,16 +73,19 @@ let rec drop instance =
7073
end
7174
else drop instance
7275

73-
(** This helps to reduce CPU stack usage with the native compiler. *)
74-
let[@inline never] drop_and_reraise bt instance exn =
76+
let[@inline never] drop_and_reraise_as bt instance exn =
7577
drop instance;
7678
Printexc.raise_with_backtrace exn bt
7779

80+
let[@inline never] drop_and_reraise exn instance =
81+
let bt = Printexc.get_raw_backtrace () in
82+
drop_and_reraise_as bt instance exn
83+
7884
(* *)
7985

80-
let await_transferred_or_dropped instance =
86+
let await_transferred_or_dropped instance result =
8187
match Atomic.get instance with
82-
| Transferred | Dropped -> ()
88+
| Transferred | Dropped -> result
8389
| Borrowed as case ->
8490
(* This should be impossible as [let@ _ = borrow _ in _] should have
8591
restored the state. *)
@@ -88,12 +94,18 @@ let await_transferred_or_dropped instance =
8894
match Trigger.await r.transferred_or_dropped with
8995
| None ->
9096
(* We release in case we could not wait. *)
91-
drop instance
97+
drop instance;
98+
result
9299
| Some (exn, bt) ->
93100
(* We have been canceled, so we release. *)
94-
drop_and_reraise bt instance exn
101+
drop_and_reraise_as bt instance exn
95102
end
96103

104+
let[@inline never] instantiate instance scope =
105+
match scope instance with
106+
| result -> await_transferred_or_dropped instance result
107+
| exception exn -> drop_and_reraise exn instance
108+
97109
let[@inline never] instantiate release acquire scope =
98110
let instance =
99111
Sys.opaque_identity
@@ -108,13 +120,7 @@ let[@inline never] instantiate release acquire scope =
108120
(* After this point there must be no allocations before [acquire ()]. *)
109121
let (Resource r : (_, [ `Resource ]) tdt) = Obj.magic (Atomic.get instance) in
110122
r.resource <- acquire ();
111-
match scope instance with
112-
| result ->
113-
await_transferred_or_dropped instance;
114-
result
115-
| exception exn ->
116-
let bt = Printexc.get_raw_backtrace () in
117-
drop_and_reraise bt instance exn
123+
instantiate instance scope
118124

119125
(* *)
120126

@@ -130,12 +136,8 @@ let[@inline never] rec transfer from scope =
130136
Trigger.signal r.transferred_or_dropped;
131137
scope into
132138
with
133-
| result ->
134-
await_transferred_or_dropped into;
135-
result
136-
| exception exn ->
137-
let bt = Printexc.get_raw_backtrace () in
138-
drop_and_reraise bt into exn
139+
| result -> await_transferred_or_dropped into result
140+
| exception exn -> drop_and_reraise exn into
139141
end
140142
else transfer from scope
141143

@@ -172,25 +174,24 @@ let[@inline never] rec move from scope =
172174
| result ->
173175
forbidden r.release r.resource;
174176
result
175-
| exception exn -> release_and_reraise exn r.release r.resource
177+
| exception exn -> release_and_reraise exn r.resource r.release
176178
end
177179
else move from scope
178180

179181
(* *)
180182

183+
let[@inline never] finally x scope release =
184+
match scope x with
185+
| y -> release_and_return y x release
186+
| exception exn -> release_and_reraise exn x release
187+
181188
let[@inline never] finally release acquire scope =
182189
let x = acquire () in
183-
match scope x with
184-
| y ->
185-
forbidden release x;
186-
y
187-
| exception exn -> release_and_reraise exn release x
190+
finally x scope release
188191

189192
let[@inline never] lastly action scope =
190193
match scope () with
191-
| value ->
192-
forbidden action ();
193-
value
194-
| exception exn -> release_and_reraise exn action ()
194+
| value -> release_and_return value () action
195+
| exception exn -> release_and_reraise exn () action
195196

196197
external ( let@ ) : ('a -> 'b) -> 'a -> 'b = "%apply"

lib/picos_std.structured/bundle.ml

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,43 @@ let get_flock fiber =
5353
| Bundle _ as t -> t
5454
| Nothing -> no_flock ()
5555

56-
let await (type a) (Bundle r as t : t) fiber packed canceler outer
57-
(pass : a pass) =
56+
let await (Bundle r as t : t) fiber packed canceler outer =
5857
decr t;
5958
Fiber.set_computation fiber packed;
6059
let forbid = Fiber.exchange fiber ~forbid:true in
6160
Trigger.await r.finished |> ignore;
6261
Fiber.set fiber ~forbid;
63-
begin
64-
match pass with FLS -> Fiber.FLS.set fiber flock_key outer | Arg -> ()
65-
end;
62+
if Fiber.FLS.get fiber flock_key ~default:Nothing != outer then
63+
Fiber.FLS.set fiber flock_key outer;
6664
let (Packed parent) = packed in
6765
Computation.detach parent canceler;
6866
Control.Errors.check r.errors;
6967
Fiber.check fiber
7068

69+
let[@inline never] raised exn t fiber packed canceler outer =
70+
let bt = Printexc.get_raw_backtrace () in
71+
error t exn bt;
72+
await t fiber packed canceler outer;
73+
Printexc.raise_with_backtrace exn bt
74+
75+
let[@inline never] returned value (Bundle r as t : t) fiber packed canceler
76+
outer =
77+
let config = Atomic.get r.config in
78+
if config land config_terminated_bit <> 0 then begin
79+
let callstack =
80+
let n = (config land config_callstack_mask) lsr config_callstack_shift in
81+
if n = 0 then None else Some n
82+
in
83+
terminate ?callstack t
84+
end;
85+
await t fiber packed canceler outer;
86+
value
87+
88+
let join_after_realloc x fn t fiber packed canceler outer =
89+
match fn x with
90+
| value -> returned value t fiber packed canceler outer
91+
| exception exn -> raised exn t fiber packed canceler outer
92+
7193
let join_after_pass (type a) ?callstack ?on_return (fn : a -> _) (pass : a pass)
7294
=
7395
(* The sequence of operations below ensures that nothing is leaked. *)
@@ -93,38 +115,20 @@ let join_after_pass (type a) ?callstack ?on_return (fn : a -> _) (pass : a pass)
93115
Bundle { config; bundle; errors; finished }
94116
in
95117
let fiber = Fiber.current () in
96-
let outer =
97-
match pass with
98-
| Arg -> Nothing
99-
| FLS -> Fiber.FLS.get fiber flock_key ~default:Nothing
100-
in
118+
let outer = Fiber.FLS.get fiber flock_key ~default:Nothing in
119+
begin
120+
match pass with FLS -> Fiber.FLS.reserve fiber flock_key | Arg -> ()
121+
end;
101122
let (Packed parent as packed) = Fiber.get_computation fiber in
102123
let (Packed bundle) = r.bundle in
103124
let canceler = Computation.attach_canceler ~from:parent ~into:bundle in
104125
(* Ideally there should be no poll point betweem [attach_canceler] and the
105-
[match ... with] below. *)
106-
match
107-
Fiber.set_computation fiber r.bundle;
108-
fn (match pass with FLS -> Fiber.FLS.set fiber flock_key t | Arg -> t)
109-
with
110-
| value ->
111-
let config = Atomic.get r.config in
112-
if config land config_terminated_bit <> 0 then begin
113-
let callstack =
114-
let n =
115-
(config land config_callstack_mask) lsr config_callstack_shift
116-
in
117-
if n = 0 then None else Some n
118-
in
119-
terminate ?callstack t
120-
end;
121-
await t fiber packed canceler outer pass;
122-
value
123-
| exception exn ->
124-
let bt = Printexc.get_raw_backtrace () in
125-
error t exn bt;
126-
await t fiber packed canceler outer pass;
127-
Printexc.raise_with_backtrace exn bt
126+
[match ... with] in [join_after_realloc]. *)
127+
Fiber.set_computation fiber r.bundle;
128+
let x : a =
129+
match pass with FLS -> Fiber.FLS.set fiber flock_key t | Arg -> t
130+
in
131+
join_after_realloc x fn t fiber packed canceler outer
128132

129133
let rec incr (Bundle r as t : t) backoff =
130134
let before = Atomic.get r.config in
@@ -136,14 +140,12 @@ let finish (Bundle { bundle = Packed bundle; _ } as t : t) canceler =
136140
Computation.detach bundle canceler;
137141
decr t
138142

139-
(** This helps to reduce CPU stack usage with the native compiler. *)
140143
let[@inline never] raised exn child t canceler =
141144
let bt = Printexc.get_raw_backtrace () in
142145
Computation.cancel child exn bt;
143146
error t exn bt;
144147
finish t canceler
145148

146-
(** This helps to reduce CPU stack usage with the native compiler. *)
147149
let[@inline never] returned value child t canceler =
148150
Computation.return child value;
149151
finish t canceler
@@ -181,14 +183,12 @@ let fork_as_promise_pass (type a) (Bundle r as t : t) thunk (pass : a pass) =
181183
decr t;
182184
raise canceled_exn
183185

184-
(** This helps to reduce CPU stack usage with the native compiler. *)
185186
let[@inline never] raised_flock exn fiber =
186187
let t = get_flock fiber in
187188
let bt = Printexc.get_raw_backtrace () in
188189
error t exn bt;
189190
decr t
190191

191-
(** This helps to reduce CPU stack usage with the native compiler. *)
192192
let[@inline never] raised_bundle exn t =
193193
error t exn (Printexc.get_raw_backtrace ());
194194
decr t

0 commit comments

Comments
 (0)