diff options
Diffstat (limited to '0058-tools-oxenstored-Use-Map-instead-of-Hashtbl-for-quot.patch')
-rw-r--r-- | 0058-tools-oxenstored-Use-Map-instead-of-Hashtbl-for-quot.patch | 143 |
1 files changed, 0 insertions, 143 deletions
diff --git a/0058-tools-oxenstored-Use-Map-instead-of-Hashtbl-for-quot.patch b/0058-tools-oxenstored-Use-Map-instead-of-Hashtbl-for-quot.patch deleted file mode 100644 index dfc7f5a..0000000 --- a/0058-tools-oxenstored-Use-Map-instead-of-Hashtbl-for-quot.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 7abd305607938b846da1a37dd1bda7bf7d47dba5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Edwin=20T=C3=B6r=C3=B6k?= <edwin.torok@cloud.com> -Date: Wed, 31 Jan 2024 10:52:55 +0000 -Subject: [PATCH 58/67] tools/oxenstored: Use Map instead of Hashtbl for quotas -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -On a stress test running 1000 VMs flamegraphs have shown that -`oxenstored` spends a large amount of time in `Hashtbl.copy` and the GC. - -Hashtable complexity: - * read/write: O(1) average - * copy: O(domains) -- copying the entire table - -Map complexity: - * read/write: O(log n) worst case - * copy: O(1) -- a word copy - -We always perform at least one 'copy' when processing each xenstore -packet (regardless whether it is a readonly operation or inside a -transaction or not), so the actual complexity per packet is: - * Hashtbl: O(domains) - * Map: O(log domains) - -Maps are the clear winner, and a better fit for the immutable xenstore -tree. - -Signed-off-by: Edwin Török <edwin.torok@cloud.com> -Acked-by: Christian Lindig <christian.lindig@cloud.com> -(cherry picked from commit b6cf604207fd0a04451a48f2ce6d05fb66c612ab) ---- - tools/ocaml/xenstored/quota.ml | 65 ++++++++++++++++++---------------- - 1 file changed, 34 insertions(+), 31 deletions(-) - -diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml -index 6e3d6401ae..ee8dd22581 100644 ---- a/tools/ocaml/xenstored/quota.ml -+++ b/tools/ocaml/xenstored/quota.ml -@@ -23,66 +23,69 @@ let activate = ref true - let maxent = ref (1000) - let maxsize = ref (2048) - -+module Domid = struct -+ type t = Xenctrl.domid -+ let compare (a:t) (b:t) = compare a b -+end -+ -+module DomidMap = Map.Make(Domid) -+ - type t = { - maxent: int; (* max entities per domU *) - maxsize: int; (* max size of data store in one node *) -- cur: (Xenctrl.domid, int) Hashtbl.t; (* current domains quota *) -+ mutable cur: int DomidMap.t; (* current domains quota *) - } - - let to_string quota domid = -- if Hashtbl.mem quota.cur domid -- then Printf.sprintf "dom%i quota: %i/%i" domid (Hashtbl.find quota.cur domid) quota.maxent -- else Printf.sprintf "dom%i quota: not set" domid -+ try -+ Printf.sprintf "dom%i quota: %i/%i" domid (DomidMap.find domid quota.cur) quota.maxent -+ with Not_found -> -+ Printf.sprintf "dom%i quota: not set" domid - - let create () = -- { maxent = !maxent; maxsize = !maxsize; cur = Hashtbl.create 100; } -+ { maxent = !maxent; maxsize = !maxsize; cur = DomidMap.empty; } - --let copy quota = { quota with cur = (Hashtbl.copy quota.cur) } -+let copy quota = { quota with cur = quota.cur } - --let del quota id = Hashtbl.remove quota.cur id -+let del quota id = { quota with cur = DomidMap.remove id quota.cur } - - let _check quota id size = - if size > quota.maxsize then ( - warn "domain %u err create entry: data too big %d" id size; - raise Data_too_big - ); -- if id > 0 && Hashtbl.mem quota.cur id then -- let entry = Hashtbl.find quota.cur id in -+ if id > 0 then -+ try -+ let entry = DomidMap.find id quota.cur in - if entry >= quota.maxent then ( - warn "domain %u cannot create entry: quota reached" id; - raise Limit_reached - ) -+ with Not_found -> () - - let check quota id size = - if !activate then - _check quota id size - --let get_entry quota id = Hashtbl.find quota.cur id -+let find_or_zero quota_cur id = -+ try DomidMap.find id quota_cur with Not_found -> 0 - --let set_entry quota id nb = -- if nb = 0 -- then Hashtbl.remove quota.cur id -- else begin -- if Hashtbl.mem quota.cur id then -- Hashtbl.replace quota.cur id nb -- else -- Hashtbl.add quota.cur id nb -- end -+let update_entry quota_cur id diff = -+ let nb = diff + find_or_zero quota_cur id in -+ if nb = 0 then DomidMap.remove id quota_cur -+ else DomidMap.add id nb quota_cur - - let del_entry quota id = -- try -- let nb = get_entry quota id in -- set_entry quota id (nb - 1) -- with Not_found -> () -+ quota.cur <- update_entry quota.cur id (-1) - - let add_entry quota id = -- let nb = try get_entry quota id with Not_found -> 0 in -- set_entry quota id (nb + 1) -- --let add quota diff = -- Hashtbl.iter (fun id nb -> set_entry quota id (get_entry quota id + nb)) diff.cur -+ quota.cur <- update_entry quota.cur id (+1) - - let merge orig_quota mod_quota dest_quota = -- Hashtbl.iter (fun id nb -> let diff = nb - (try get_entry orig_quota id with Not_found -> 0) in -- if diff <> 0 then -- set_entry dest_quota id ((try get_entry dest_quota id with Not_found -> 0) + diff)) mod_quota.cur -+ let fold_merge id nb dest = -+ match nb - find_or_zero orig_quota.cur id with -+ | 0 -> dest (* not modified *) -+ | diff -> update_entry dest id diff (* update with [x=x+diff] *) -+ in -+ dest_quota.cur <- DomidMap.fold fold_merge mod_quota.cur dest_quota.cur -+ (* dest_quota = dest_quota + (mod_quota - orig_quota) *) --- -2.44.0 - |