Add the Cachet.map function which takes the advantage of the cache and align everythings
This commit is contained in:
parent
fa4c04053f
commit
e1d191e34d
3 changed files with 54 additions and 1 deletions
|
@ -478,6 +478,39 @@ let none : slice option = None
|
|||
let cache_miss t = t.metrics.cache_miss
|
||||
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 =
|
||||
if len > 1 lsl t.pagesize then
|
||||
invalid_arg "Cachet.load: you can not load more than a page";
|
||||
|
|
|
@ -260,6 +260,18 @@ val fd : 'fd t -> 'fd
|
|||
val pagesize : 'fd t -> int
|
||||
(** [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
|
||||
(** [cache_hit t] is the number of times a load hit the cache. *)
|
||||
|
||||
|
|
10
test/test.ml
10
test/test.ml
|
@ -36,6 +36,14 @@ let test01 =
|
|||
let b = Cachet.Bstr.to_string oracle in
|
||||
let a = List.of_seq 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 ]) ]
|
||||
|
|
Loading…
Reference in a new issue