Add the Cachet.map function which takes the advantage of the cache and align everythings

This commit is contained in:
Calascibetta Romain 2025-01-02 15:54:13 +01:00
parent fa4c04053f
commit e1d191e34d
3 changed files with 54 additions and 1 deletions

View file

@ -478,6 +478,39 @@ let none : slice option = None
let cache_miss t = t.metrics.cache_miss let cache_miss t = t.metrics.cache_miss
let cache_hit t = t.metrics.cache_hit let cache_hit t = t.metrics.cache_hit
let map ({ fd; map; _ } as t) ~pos:logical_address logical_len =
let page = logical_address lsr t.pagesize in
let pos = page lsl t.pagesize in
(* round-down *)
let rem = logical_address - pos in
let len = rem + logical_len in
let len =
(* round-up *)
if ((1 lsl t.pagesize) - 1) land len != 0 then
(len + (1 lsl t.pagesize)) land lnot ((1 lsl t.pagesize) - 1)
else len
in
let off = logical_address land ((t.pagesize lsl 1) - 1) in
if len <= 1 lsl t.pagesize then begin
let hash = hash 0l (page lsl t.pagesize) land ((1 lsl t.cachesize) - 1) in
match t.arr.(hash) with
| Some { offset; length; payload } when offset == page lsl t.pagesize ->
t.metrics.cache_hit <- t.metrics.cache_hit + 1;
let len = Int.min (length - off) logical_len in
Bigarray.Array1.sub payload off len
| Some _ | None ->
t.metrics.cache_miss <- t.metrics.cache_miss + 1;
let { length; payload; _ } = load t logical_address in
let len = Int.min (length - off) logical_len in
Bigarray.Array1.sub payload off len
end
else begin
t.metrics.cache_miss <- t.metrics.cache_miss + 1;
let bstr = map fd ~pos len in
let len = Int.min (Bigarray.Array1.dim bstr - off) logical_len in
Bigarray.Array1.sub bstr off len
end
let load t ?(len = 1) logical_address = let load t ?(len = 1) logical_address =
if len > 1 lsl t.pagesize then if len > 1 lsl t.pagesize then
invalid_arg "Cachet.load: you can not load more than a page"; invalid_arg "Cachet.load: you can not load more than a page";

View file

@ -260,6 +260,18 @@ val fd : 'fd t -> 'fd
val pagesize : 'fd t -> int val pagesize : 'fd t -> int
(** [pagesize t] is the {i page-size} used by [t] (and specified on {!make}). *) (** [pagesize t] is the {i page-size} used by [t] (and specified on {!make}). *)
val map : 'fd t -> pos:int -> int -> Bstr.t
(** [map t ~pos len] returns a {!type:Bstr.t} which corresponds to a slice of
the {i block-device}. If this slice is smaller than or equal to a
{!val:pagesize}, the cache system is used to obtain the page and apply
{!val:Bstr.sub} to it (in other words, only a small allocation is made).
Otherwise, the {i syscall} {!type:map} is used.
Regardless of the expected position [pos] or size [len], this function will
call the {i syscall} {!type:map} as the last analysis, with a position
aligned with the {!val:pagesize} and a size aligned with the
{!val:pagesize}. *)
val cache_hit : 'fd t -> int val cache_hit : 'fd t -> int
(** [cache_hit t] is the number of times a load hit the cache. *) (** [cache_hit t] is the number of times a load hit the cache. *)

View file

@ -36,6 +36,14 @@ let test01 =
let b = Cachet.Bstr.to_string oracle in let b = Cachet.Bstr.to_string oracle in
let a = List.of_seq a in let a = List.of_seq a in
let a = String.concat "" a in let a = String.concat "" a in
Alcotest.(check string) "all" a b Alcotest.(check string) "all" a b;
let a = Cachet.map t ~pos:2 (0x100 - 2) in
let a = Cachet.Bstr.to_string a in
let b = Cachet.Bstr.sub_string oracle ~off:2 ~len:(0x100 - 2) in
Alcotest.(check string) "map (round down)" a b;
let a = Cachet.map t ~pos:2 0x100 in
let a = Cachet.Bstr.to_string a in
let b = Cachet.Bstr.sub_string oracle ~off:2 ~len:0x100 in
Alcotest.(check string) "map (round up)" a b
let () = Alcotest.run "cachet" [ ("simple", [ test01 ]) ] let () = Alcotest.run "cachet" [ ("simple", [ test01 ]) ]