Skip to content

Commit 6ccaf7b

Browse files
authored
Update feature/perf with latest blocker fixes (#6237)
2 parents b892c6e + 1e5114c commit 6ccaf7b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+647
-400
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ jobs:
2020
python-version: "3.x"
2121

2222
- name: Install build dependencies
23-
run: |
24-
pip install build
25-
sudo apt-get install ocaml dune libfindlib-ocaml-dev libdune-ocaml-dev libcmdliner-ocaml-dev
23+
run: pip install build
2624

2725
- name: Generate python package for XenAPI
2826
run: |
29-
./configure --xapi_version=${{ github.ref_name }}
27+
echo "export XAPI_VERSION=${{ github.ref_name }}" > config.mk
3028
make python
3129
3230
- name: Store python distribution artifacts

doc/content/design/coverage/index.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ revision: 2
88

99
We would like to add optional coverage profiling to existing [OCaml]
1010
projects in the context of [XenServer] and [XenAPI]. This article
11-
presents how we do it.
11+
presents how we do it.
1212

1313
Binaries instrumented for coverage profiling in the XenServer project
1414
need to run in an environment where several services act together as
@@ -21,7 +21,7 @@ isolation.
2121
To build binaries with coverage profiling, do:
2222

2323
./configure --enable-coverage
24-
make
24+
make
2525

2626
Binaries will log coverage data to `/tmp/bisect*.out` from which a
2727
coverage report can be generated in `coverage/`:
@@ -38,7 +38,7 @@ and logs during execution data to in-memory data structures. Before an
3838
instrumented binary terminates, it writes the logged data to a file.
3939
This data can then be analysed with the `bisect-ppx-report` tool, to
4040
produce a summary of annotated code that highlights what part of a
41-
codebase was executed.
41+
codebase was executed.
4242

4343
[BisectPPX] has several desirable properties:
4444

@@ -65,13 +65,13 @@ abstracted by OCamlfind (OCaml's library manager) and OCamlbuild
6565

6666
# build it with instrumentation from bisect_ppx
6767
ocamlbuild -use-ocamlfind -pkg bisect_ppx -pkg unix example.native
68-
68+
6969
# execute it - generates files ./bisect*.out
7070
./example.native
71-
71+
7272
# generate report
7373
bisect-ppx-report -I _build -html coverage bisect000*
74-
74+
7575
# view coverage/index.html
7676

7777
Summary:
@@ -86,7 +86,7 @@ will be instrumented during compilation. Behind the scenes `ocamlfind`
8686
makes sure that the compiler uses a preprocessing step that instruments
8787
the code.
8888

89-
## Signal Handling
89+
## Signal Handling
9090

9191
During execution the code instrumentation leads to the collection of
9292
data. This code registers a function with `at_exit` that writes the data
@@ -98,7 +98,7 @@ terminated by receiving the `TERM` signal, a signal handler must be
9898
installed:
9999

100100
let stop signal =
101-
printf "caught signal %d\n" signal;
101+
printf "caught signal %a\n" Debug.Pp.signal signal;
102102
exit 0
103103

104104
Sys.set_signal Sys.sigterm (Sys.Signal_handle stop)
@@ -149,8 +149,8 @@ environment variable. This can happen on the command line:
149149

150150
BISECT_FILE=/tmp/example ./example.native
151151

152-
In the context of XenServer we could do this in startup scripts.
153-
However, we added a bit of code
152+
In the context of XenServer we could do this in startup scripts.
153+
However, we added a bit of code
154154

155155
val Coverage.init: string -> unit
156156

@@ -176,12 +176,12 @@ Goals for instrumentation are:
176176

177177
* what files are instrumented should be obvious and easy to manage
178178
* instrumentation must be optional, yet easy to activate
179-
* avoid methods that require to keep several files in sync like multiple
179+
* avoid methods that require to keep several files in sync like multiple
180180
`_oasis` files
181181
* avoid separate Git branches for instrumented and non-instrumented
182182
code
183183

184-
In the ideal case, we could introduce a configuration switch
184+
In the ideal case, we could introduce a configuration switch
185185
`./configure --enable-coverage` that would prepare compilation for
186186
coverage instrumentation. While [Oasis] supports the creation of such
187187
switches, they cannot be used to control build dependencies like
@@ -196,7 +196,7 @@ rules in file `_tags.coverage` that cause files to be instrumented:
196196

197197
leads to the execution of this code during preparation:
198198

199-
coverage: _tags _tags.coverage
199+
coverage: _tags _tags.coverage
200200
test ! -f _tags.orig && mv _tags _tags.orig || true
201201
cat _tags.coverage _tags.orig > _tags
202202

@@ -207,7 +207,7 @@ could be tweaked to instrument only some files:
207207
<**/*.native>: pkg_bisect_ppx
208208

209209
When `make coverage` is not called, these rules are not active and
210-
hence, code is not instrumented for coverage. We believe that this
210+
hence, code is not instrumented for coverage. We believe that this
211211
solution to control instrumentation meets the goals from above. In
212212
particular, what files are instrumented and when is controlled by very
213213
few lines of declarative code that lives in the main repository of a
@@ -226,14 +226,14 @@ coverage analysis are:
226226
The `_oasis` file bundles the files under `profiling/` into an internal
227227
library which executables then depend on:
228228

229-
# Support files for profiling
229+
# Support files for profiling
230230
Library profiling
231231
CompiledObject: best
232232
Path: profiling
233233
Install: false
234234
Findlibname: profiling
235235
Modules: Coverage
236-
BuildDepends:
236+
BuildDepends:
237237

238238
Executable set_domain_uuid
239239
CompiledObject: best
@@ -243,16 +243,16 @@ library which executables then depend on:
243243
MainIs: set_domain_uuid.ml
244244
Install: false
245245
BuildDepends:
246-
xenctrl,
247-
uuidm,
246+
xenctrl,
247+
uuidm,
248248
cmdliner,
249249
profiling # <-- here
250250

251251
The `Makefile` target `coverage` primes the project for a profiling build:
252252

253253
# make coverage - prepares for building with coverage analysis
254254

255-
coverage: _tags _tags.coverage
255+
coverage: _tags _tags.coverage
256256
test ! -f _tags.orig && mv _tags _tags.orig || true
257257
cat _tags.coverage _tags.orig > _tags
258258

ocaml/forkexecd/lib/dune

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
(wrapped false)
55
(libraries
66
astring
7+
clock
78
fd-send-recv
9+
mtime
810
rpclib.core
911
rpclib.json
1012
rpclib.xml

ocaml/forkexecd/lib/forkhelpers.ml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ let safe_close_and_exec ?tracing ?env stdin stdout stderr
315315
close_fds
316316

317317
let execute_command_get_output_inner ?tracing ?env ?stdin
318-
?(syslog_stdout = NoSyslogging) ?(redirect_stderr_to_stdout = false)
319-
?(timeout = -1.0) cmd args =
318+
?(syslog_stdout = NoSyslogging) ?(redirect_stderr_to_stdout = false) timeout
319+
cmd args =
320320
let to_close = ref [] in
321321
let close fd =
322322
if List.mem fd !to_close then (
@@ -354,8 +354,13 @@ let execute_command_get_output_inner ?tracing ?env ?stdin
354354
close wr
355355
)
356356
stdinandpipes ;
357-
if timeout > 0. then
358-
Unix.setsockopt_float sock Unix.SO_RCVTIMEO timeout ;
357+
( match timeout with
358+
| Some span ->
359+
let timeout = Clock.Timer.span_to_s span in
360+
Unix.setsockopt_float sock Unix.SO_RCVTIMEO timeout
361+
| None ->
362+
()
363+
) ;
359364
with_tracing ~tracing ~name:"Forkhelpers.waitpid" @@ fun _ ->
360365
try waitpid (sock, pid)
361366
with Unix.(Unix_error ((EAGAIN | EWOULDBLOCK), _, _)) ->
@@ -380,12 +385,12 @@ let execute_command_get_output_inner ?tracing ?env ?stdin
380385
let execute_command_get_output ?tracing ?env ?(syslog_stdout = NoSyslogging)
381386
?(redirect_stderr_to_stdout = false) ?timeout cmd args =
382387
with_tracing ~tracing ~name:__FUNCTION__ @@ fun tracing ->
383-
execute_command_get_output_inner ?tracing ?env ?stdin:None ?timeout
384-
~syslog_stdout ~redirect_stderr_to_stdout cmd args
388+
execute_command_get_output_inner ?tracing ?env ?stdin:None ~syslog_stdout
389+
~redirect_stderr_to_stdout timeout cmd args
385390

386391
let execute_command_get_output_send_stdin ?tracing ?env
387392
?(syslog_stdout = NoSyslogging) ?(redirect_stderr_to_stdout = false)
388393
?timeout cmd args stdin =
389394
with_tracing ~tracing ~name:__FUNCTION__ @@ fun tracing ->
390395
execute_command_get_output_inner ?tracing ?env ~stdin ~syslog_stdout
391-
~redirect_stderr_to_stdout ?timeout cmd args
396+
~redirect_stderr_to_stdout timeout cmd args

ocaml/forkexecd/lib/forkhelpers.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ val execute_command_get_output :
4848
-> ?env:string array
4949
-> ?syslog_stdout:syslog_stdout
5050
-> ?redirect_stderr_to_stdout:bool
51-
-> ?timeout:float
51+
-> ?timeout:Mtime.Span.t
5252
-> string
5353
-> string list
5454
-> string * string
@@ -61,7 +61,7 @@ val execute_command_get_output_send_stdin :
6161
-> ?env:string array
6262
-> ?syslog_stdout:syslog_stdout
6363
-> ?redirect_stderr_to_stdout:bool
64-
-> ?timeout:float
64+
-> ?timeout:Mtime.Span.t
6565
-> string
6666
-> string list
6767
-> string

ocaml/forkexecd/src/child.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ let report_child_exit comms_sock args child_pid status =
111111
Fe.WEXITED n
112112
| Unix.WSIGNALED n ->
113113
log_failure args child_pid
114-
(Printf.sprintf "exited with signal: %s" (Unixext.string_of_signal n)) ;
114+
(Printf.sprintf "exited with signal: %a" Debug.Pp.signal n) ;
115115
Fe.WSIGNALED n
116116
| Unix.WSTOPPED n ->
117117
log_failure args child_pid
118-
(Printf.sprintf "stopped with signal: %s" (Unixext.string_of_signal n)) ;
118+
(Printf.sprintf "stopped with signal: %a" Debug.Pp.signal n) ;
119119
Fe.WSTOPPED n
120120
in
121121
let result = Fe.Finished pr in

ocaml/forkexecd/test/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(executable
22
(modes exe)
33
(name fe_test)
4-
(libraries forkexec uuid xapi-stdext-unix fd-send-recv))
4+
(libraries fmt forkexec mtime clock mtime.clock.os uuid xapi-stdext-unix fd-send-recv))
55

66
(rule
77
(alias runtest)

ocaml/forkexecd/test/fe_test.ml

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,6 @@ let one fds x =
115115
:: string_of_int (fds - (x.max_extra - number_of_extra))
116116
:: shuffle cmdline_names
117117
in
118-
(* Printf.fprintf stderr "stdin = %s\n" (if x.stdin then "Some" else "None");
119-
Printf.fprintf stderr "stdout = %s\n" (if x.stdout then "Some" else "None");
120-
Printf.fprintf stderr "stderr = %s\n" (if x.stderr then "Some" else "None");
121-
List.iter (fun (uuid, _) -> Printf.fprintf stderr "uuid %s -> stdin\n" uuid) table;
122-
Printf.fprintf stderr "%s %s\n" exe (String.concat " " args);
123-
*)
124118
Forkhelpers.waitpid_fail_if_bad_exit
125119
(Forkhelpers.safe_close_and_exec
126120
(if x.stdin then Some fd else None)
@@ -129,26 +123,43 @@ let one fds x =
129123
table exe args
130124
)
131125

126+
type in_range = In_range | Longer | Shorter
127+
128+
let in_range ~e:leeway ~around span =
129+
let upper = Mtime.Span.add around leeway in
130+
if Clock.Timer.span_is_shorter ~than:around span then
131+
Shorter
132+
else if Clock.Timer.span_is_longer ~than:upper span then
133+
Longer
134+
else
135+
In_range
136+
132137
let test_delay () =
133-
let start = Unix.gettimeofday () in
138+
let start = Mtime_clock.counter () in
134139
let args = ["sleep"] in
135140
(* Need to have fractional part because some internal usage split integer
136141
and fractional and do computation.
137142
Better to have a high fractional part (> 0.5) to more probably exceed
138143
the unit.
139144
*)
140-
let timeout = 1.7 in
145+
let timeout = Mtime.Span.(1700 * ms) in
141146
try
142147
Forkhelpers.execute_command_get_output ~timeout exe args |> ignore ;
143148
fail "Failed to timeout"
144149
with
145-
| Forkhelpers.Subprocess_timeout ->
146-
let elapsed = Unix.gettimeofday () -. start in
147-
Printf.printf "Caught timeout exception after %f seconds\n%!" elapsed ;
148-
if elapsed < timeout then
149-
failwith "Process exited too soon" ;
150-
if elapsed > timeout +. 0.2 then
151-
failwith "Excessive time elapsed"
150+
| Forkhelpers.Subprocess_timeout -> (
151+
let elapsed = Mtime_clock.count start in
152+
Printf.printf "Caught timeout exception after %s seconds\n%!"
153+
Fmt.(to_to_string Mtime.Span.pp elapsed) ;
154+
155+
match in_range ~e:Mtime.Span.(200 * ms) ~around:timeout elapsed with
156+
| In_range ->
157+
()
158+
| Shorter ->
159+
failwith "Process exited too soon"
160+
| Longer ->
161+
failwith "Process took too long to exit"
162+
)
152163
| e ->
153164
fail "Failed with unexpected exception: %s" (Printexc.to_string e)
154165

@@ -289,9 +300,6 @@ let slave = function
289300
)
290301
fds ;
291302
(* Check that we have the expected number *)
292-
(*
293-
Printf.fprintf stderr "%s %d\n" total_fds (List.length present - 1)
294-
*)
295303
if total_fds <> List.length filtered then
296304
fail "Expected %d fds; /proc/self/fd has %d: %s" total_fds
297305
(List.length filtered) ls

0 commit comments

Comments
 (0)