# HG changeset patch # User David Scott # Date 1259362817 0 # Node ID 895c6ed73dbc4fa98dd9ea351a887ccbaa2c714b # Parent a42ee172122fcfb19efe8fd406ba3c84a120708c CA-35372: the ballooning simulator now checks that target <= maxmem. This patch addes a new scenario to the simulator which triggers a failure. The subsequent patch will fix it. Note that we order updates to target and maxmem to ensure that we don't trivially violate the desired property. Signed-off-by: David Scott diff -r a42ee172122f -r 895c6ed73dbc ocaml/xenops/squeeze_test.ml --- a/ocaml/xenops/squeeze_test.ml Fri Nov 27 23:00:16 2009 +0000 +++ b/ocaml/xenops/squeeze_test.ml Fri Nov 27 23:00:17 2009 +0000 @@ -44,9 +44,17 @@ (** Helper function to change the domain's balloon target *) method set_target new_target_kib = if new_target_kib <> domain.target_kib - then debug "domid %d: target change was %Ld now %Ld" - domain.domid domain.target_kib new_target_kib; + then debug "domid %d: target change was %Ld now %Ld (max %Ld)" + domain.domid domain.target_kib new_target_kib domain.memory_max_kib; + if new_target_kib > domain.memory_max_kib + then failwith (Printf.sprintf "Target set above max_mem domid %d; max_mem = %Ld; target = %Ld" domain.domid domain.memory_max_kib new_target_kib); domain <- { domain with target_kib = new_target_kib } + + (** Helper function to set the domain's maxmem *) + method set_maxmem new_max_kib = + if domain.target_kib > new_max_kib + then failwith (Printf.sprintf "mem_max set below target domid %d; max_mem = %Ld; target = %Ld" domain.domid new_max_kib domain.target_kib); + domain <- { domain with memory_max_kib = new_max_kib } (** Given a number of time units since the last call to 'update', @@ -106,6 +114,20 @@ else minimum_memory -* domain.memory_actual_kib (* this takes us to the minimum *) end + +(** Represents a VM which fails to allocate above a certain threshold *) +class idealised_vm_with_upper_limit initial_domain rate limit = object + inherit vm initial_domain + + method compute_memory_actual_delta time_passed = + let delta = compute_memory_actual_delta domain rate time_passed in + let proposed_new_memory_actual = domain.memory_actual_kib +* delta in + if proposed_new_memory_actual < limit + then delta + else (limit -* domain.memory_actual_kib) +end + + (** Represents a VM whose balloon driver has completely failed *) class stuck_vm initial_domain = object @@ -157,9 +179,9 @@ should_succeed = true; scenario_domains = [ new idealised_vm_with_limit - (domain_make 0 true 1000L 1500L 2000L 1500L 0L 4L) 100L 1250L; + (domain_make 0 true 1000L 1500L 2000L 1500L 1500L 4L) 100L 1250L; new intermittently_stuck_vm - (domain_make 1 true 2500L 3500L 4500L 3500L 0L 4L) 500L 0.25; + (domain_make 1 true 2500L 3500L 4500L 3500L 3500L 4L) 500L 0.25; ]; host_free_mem_kib = 0L; required_mem_kib = 1000L; @@ -173,9 +195,9 @@ should_succeed = true; scenario_domains = [ new intermittently_stuck_vm - (domain_make 1 true 500L 3500L 4500L 3500L 0L 4L) 100L 3.; + (domain_make 1 true 500L 3500L 4500L 3500L 3500L 4L) 100L 3.; new intermittently_stuck_vm - (domain_make 0 true 500L 1500L 2500L 1500L 0L 4L) 100L 1.5; + (domain_make 0 true 500L 1500L 2500L 1500L 1500L 4L) 100L 1.5; ]; host_free_mem_kib = 0L; required_mem_kib = 1000L; @@ -188,8 +210,8 @@ freed"; should_succeed = false; scenario_domains = [ - new idealised_vm (domain_make 0 true 1000L 1500L 2000L 1500L 0L 0L) 100L; - new idealised_vm (domain_make 1 true 2000L 2500L 3000L 2500L 0L 0L) 100L; + new idealised_vm (domain_make 0 true 1000L 1500L 2000L 1500L 1500L 0L) 100L; + new idealised_vm (domain_make 1 true 2000L 2500L 3000L 2500L 2500L 0L) 100L; ]; host_free_mem_kib = 0L; required_mem_kib = 1500L; @@ -203,9 +225,9 @@ should_succeed = false; scenario_domains = [ new idealised_vm - (domain_make 0 true 1000L 1500L 2000L 1500L 0L 0L) 100L; + (domain_make 0 true 1000L 1500L 2000L 1500L 1500L 0L) 100L; new idealised_vm_with_limit - (domain_make 1 true 2000L 2500L 3000L 2500L 0L 0L) 100L 2250L; + (domain_make 1 true 2000L 2500L 3000L 2500L 2500L 0L) 100L 2250L; ]; host_free_mem_kib = 0L; required_mem_kib = 1000L; @@ -222,10 +244,10 @@ scenario_domains = [ (* The stuck domain is using more than it should be if the memory was freed and everything balanced *) new stuck_vm - (domain_make 0 true (*min*)5000L (*target*)7000L (*max*)7000L (*actual*)7000L 0L 0L); + (domain_make 0 true (*min*)5000L (*target*)7000L (*max*)7000L (*actual*)7000L 7000L 0L); (* The working domain is using less than it should be if the memory was freed and everything balanced *) new idealised_vm - (domain_make 1 true (*min*)5000L (*target*)6000L (*max*)11000L (*actual*)6000L 0L 0L) 100L; + (domain_make 1 true (*min*)5000L (*target*)6000L (*max*)11000L (*actual*)6000L 6000L 0L) 100L; ]; host_free_mem_kib = 0L; @@ -262,6 +284,21 @@ domains are both stuck if we don't take this into account. *) } +let scenario_h = { + name = "h"; + description = "a small domain with a hidden upper limit and a perfectly working domain"; + should_succeed = true; + scenario_domains = [ + new idealised_vm_with_upper_limit + (domain_make 0 true 1000L 1500L 2000L 1500L 1500L 4L) 100L 1500L; + new idealised_vm + (domain_make 1 true 1000L 1500L 2000L 1500L 1500L 4L) 100L; (* this one can take up the slack *) + ]; + host_free_mem_kib = 1000L; + required_mem_kib = 0L; + fistpoints = [ ]; +} + (* scenario_a with < 24L after the balancing will fail *) let all_scenarios = [ @@ -272,6 +309,7 @@ scenario_e; scenario_f; scenario_g; + scenario_h; ] (* @@ -313,9 +351,19 @@ (* Update all the recorded balloon targets *) let execute_action (action: action) = let domain = List.assoc action.action_domid domid_to_domain in - domain#set_target action.new_target_kib + if action.new_target_kib > domain#get_domain.memory_max_kib then begin + domain#set_maxmem action.new_target_kib; + domain#set_target action.new_target_kib; + end else begin + domain#set_target action.new_target_kib; + domain#set_maxmem action.new_target_kib; + end in - + let setmaxmem domid kib = + let domain = List.assoc domid domid_to_domain in + debug "setmaxmem domid = %d; kib = %Ld target = %Ld" domid kib (domain#get_domain.target_kib); + domain#set_maxmem kib + in (* Allow the simulated balloon drivers to change memory_actual_kib *) (* and update host_free_memory accordingly. *) let update_balloons time = @@ -353,7 +401,7 @@ let io = { Squeeze.gettimeofday = gettimeofday; make_host = (fun () -> Printf.sprintf "F%Ld" !host_free_mem_kib, make_host ()); - domain_setmaxmem = (fun domid kib -> ()); + domain_setmaxmem = setmaxmem; wait = wait; execute_action = execute_action; target_host_free_mem_kib = scenario.required_mem_kib; diff -r a42ee172122f -r 895c6ed73dbc ocaml/xenops/squeeze_xen.ml --- a/ocaml/xenops/squeeze_xen.ml Fri Nov 27 23:00:16 2009 +0000 +++ b/ocaml/xenops/squeeze_xen.ml Fri Nov 27 23:00:17 2009 +0000 @@ -282,9 +282,15 @@ let target_kib = action.Squeeze.new_target_kib in if target_kib < 0L then failwith "Proposed target is negative (domid %d): %Ld" domid target_kib; - - domain_setmaxmem_noexn xc domid target_kib; - set_target_noexn xs path target_kib + let di = Xc.domain_getinfo xc domid in + let memory_max_kib = Xc.pages_to_kib (Int64.of_nativeint di.Xc.max_memory_pages) in + if target_kib > memory_max_kib then begin + domain_setmaxmem_noexn xc domid target_kib; + set_target_noexn xs path target_kib; + end else begin + set_target_noexn xs path target_kib; + domain_setmaxmem_noexn xc domid target_kib; + end with e -> debug "Failed to reset balloon target (domid: %d) (target: %Ld): %s" action.Squeeze.action_domid action.Squeeze.new_target_kib