Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stat benchmark: report cleanup time and optimise #692

Merged
merged 2 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions bench/bench_stat.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,19 @@ module Bench_dir = struct
| File { name; size; perm } ->
Fmt.pf ppf "file %s (0o%o) %Lu" name perm size

let make random fs t =
let limit = Eio.Semaphore.make 32 in (* Prevent FD exhaustion *)
let rec aux fs = function
let make fs t =
let rec aux iter fs = function
| Dir { name; perm; children } ->
let dir = fs / name in
Eio.Semaphore.acquire limit;
Path.mkdir ~perm dir;
Eio.Semaphore.release limit;
Fiber.List.iter (aux dir) children
iter (aux List.iter dir) children
| File { name; size; perm } ->
Eio.Semaphore.acquire limit;
let buf = Cstruct.create (Int64.to_int size) in
Eio.Flow.read_exact random buf;
Path.with_open_out ~create:(`If_missing perm) (fs / name) (fun oc ->
Eio.Flow.write oc [ buf ]
);
Eio.Semaphore.release limit
)
in
aux fs t
aux Fiber.List.iter fs t
end

let with_tmp_dir ~fs prefix suffix fn =
Expand All @@ -66,30 +60,27 @@ let with_tmp_dir ~fs prefix suffix fn =
fn dir

let bench_stat root =
let limit = Eio.Semaphore.make 32 in (* Prevent FD exhaustion *)
let rec aux dir =
Eio.Semaphore.acquire limit;
let rec aux level dir =
let { Eio.File.Stat.kind; perm; size; _ } = Path.stat ~follow:false dir in
match kind with
| `Directory ->
let items = Path.read_dir dir in
Eio.Semaphore.release limit;
let children = items |> Fiber.List.map (fun f -> aux (dir / f)) in
let map = if level > 3 then List.map else Fiber.List.map ?max_fibers:None in
let children = items |> map (fun f -> aux (level + 1) (dir / f)) in
let name = Path.native_exn dir |> Filename.basename in
Bench_dir.Dir { name; perm; children }
| `Regular_file ->
Eio.Semaphore.release limit;
let name = Path.native_exn dir |> Filename.basename in
File { name; perm; size = Optint.Int63.to_int64 size }
| _ -> assert false
in
aux root
aux 1 root

let file name = Bench_dir.File { name; perm = 0o644; size = 128L }
let dir name children = Bench_dir.Dir { name; perm = 0o700; children }

let random_bench_dir ~n ~levels =
if levels < 0 then invalid_arg "Levels should be > 0";
if levels < 1 then invalid_arg "Levels should be >= 1";
let rec loop root = function
| 1 -> (
match root with
Expand All @@ -109,16 +100,16 @@ let random_bench_dir ~n ~levels =
in
loop (dir "root" []) levels

let run_bench ~n ~levels ~random ~root ~clock =
let run_bench ~n ~levels ~root ~clock =
let dir = random_bench_dir ~levels ~n |> Bench_dir.sort in
traceln "Going to create %i files and directories" (Bench_dir.size dir);
let create_time =
let t0 = Eio.Time.now clock in
Bench_dir.make random root dir;
Bench_dir.make root dir;
let t1 = Eio.Time.now clock in
t1 -. t0
in
traceln "Created %i files and directories in %.2f s" (Bench_dir.size dir) create_time;
traceln "Created in %.2f s" create_time;
let bench () =
Gc.full_major ();
let stat0 = Gc.stat () in
Expand All @@ -136,16 +127,26 @@ let run_bench ~n ~levels ~random ~root ~clock =
| _ -> failwith "Stat not the same as the spec"
in
let time, minor, major = bench () in
traceln "Statted in %.2f s" time;
let remove_time =
let t0 = Eio.Time.now clock in
let root = root / "root" in
Eio.Path.read_dir root |> Fiber.List.iter (fun item -> Eio.Path.rmtree (root / item));
Eio.Path.rmdir root;
let t1 = Eio.Time.now clock in
t1 -. t0
in
traceln "Removed in %.2f s" remove_time;
[
Metric.create "create-time" (`Float (1e3 *. create_time)) "ms" (Fmt.str "Time to create %i files and directories" (Bench_dir.size dir));
Metric.create "stat-time" (`Float (1e3 *. time)) "ms" (Fmt.str "Time to stat %i files and directories" (Bench_dir.size dir));
Metric.create "stat-minor" (`Float (1e-3 *. minor)) "kwords" (Fmt.str "Minor words allocated to stat %i files and directories" (Bench_dir.size dir));
Metric.create "stat-major" (`Float (1e-3 *. major)) "kwords" (Fmt.str "Major words allocated %i files and directories" (Bench_dir.size dir))
Metric.create "stat-major" (`Float (1e-3 *. major)) "kwords" (Fmt.str "Major words allocated %i files and directories" (Bench_dir.size dir));
Metric.create "remove-time" (`Float (1e3 *. remove_time)) "ms" "Time to remove everything";
]

let run env =
let fs = Eio.Stdenv.fs env in
let random = Eio.Stdenv.secure_random env in
let clock = Eio.Stdenv.clock env in
with_tmp_dir ~fs "eio-bench-" "-stat" @@ fun root ->
run_bench ~n:20 ~levels:4 ~root ~random ~clock
run_bench ~n:20 ~levels:4 ~root ~clock
5 changes: 4 additions & 1 deletion bench/main.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
open Eio.Std

let benchmarks = [
"Promise", Bench_promise.run;
"Cancel", Bench_cancel.run;
Expand All @@ -22,6 +24,7 @@ let usage_error () =

let () =
Eio_main.run @@ fun env ->
traceln "Using %s backend" env#backend_id;
let benchmarks =
match Array.to_list Sys.argv with
| [_] -> benchmarks
Expand All @@ -35,7 +38,7 @@ let () =
| _ -> usage_error ()
in
let run (name, fn) =
Eio.traceln "Running %s..." name;
traceln "Running %s..." name;
let metrics = fn env in
`Assoc [
"name", `String name;
Expand Down
Loading