ia64/xen-unstable

view tools/python/xen/xend/balloon.py @ 17827:4c1e740e392c

xend: minor ballooning cleanup

In xend/balloon.py, there's only one place where dom0_start_alloc_mb
is used. Move its initialization to right before its usage.

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 10 14:53:01 2008 +0100 (2008-06-10)
parents 6143f5bd32a7
children 0bf73f557f41
line source
1 #===========================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 XenSource Ltd
17 #============================================================================
20 import time
22 import xen.lowlevel.xc
24 import XendDomain
25 import XendOptions
26 from XendLogging import log
27 from XendError import VmError
28 import osdep
30 RETRY_LIMIT = 20
31 RETRY_LIMIT_INCR = 5
32 ##
33 # The time to sleep between retries grows linearly, using this value (in
34 # seconds). When the system is lightly loaded, memory should be scrubbed and
35 # returned to the system very quickly, whereas when it is loaded, the system
36 # needs idle time to get the scrubbing done. This linear growth accommodates
37 # such requirements.
38 SLEEP_TIME_GROWTH = 0.1
40 # A mapping between easy-to-remember labels and the more verbose
41 # label actually shown in the PROC_XEN_BALLOON file.
42 labels = { 'current' : 'Current allocation',
43 'target' : 'Requested target',
44 'low-balloon' : 'Low-mem balloon',
45 'high-balloon' : 'High-mem balloon',
46 'limit' : 'Xen hard limit' }
48 def _get_proc_balloon(label):
49 """Returns the value for the named label. Returns None if the label was
50 not found or the value was non-numeric."""
52 return osdep.lookup_balloon_stat(label)
54 def get_dom0_current_alloc():
55 """Returns the current memory allocation (in KiB) of dom0."""
57 kb = _get_proc_balloon(labels['current'])
58 if kb == None:
59 raise VmError('Failed to query current memory allocation of dom0.')
60 return kb
62 def get_dom0_target_alloc():
63 """Returns the target memory allocation (in KiB) of dom0."""
65 kb = _get_proc_balloon(labels['target'])
66 if kb == None:
67 raise VmError('Failed to query target memory allocation of dom0.')
68 return kb
70 def free(need_mem):
71 """Balloon out memory from the privileged domain so that there is the
72 specified required amount (in KiB) free.
73 """
75 # We check whether there is enough free memory, and if not, instruct dom0
76 # to balloon out to free some up. Memory freed by a destroyed domain may
77 # not appear in the free_memory field immediately, because it needs to be
78 # scrubbed before it can be released to the free list, which is done
79 # asynchronously by Xen; ballooning is asynchronous also. Such memory
80 # does, however, need to be accounted for when calculating how much dom0
81 # needs to balloon. No matter where we expect the free memory to come
82 # from, we need to wait for it to become available.
83 #
84 # We are not allowed to balloon below dom0_min_mem, or if dom0_ballooning
85 # is False, we cannot balloon at all. Memory can still become available
86 # through a rebooting domain, however.
87 #
88 # Eventually, we time out (presumably because there really isn't enough
89 # free memory).
90 #
91 # We don't want to set the memory target (triggering a watch) when that
92 # has already been done, but we do want to respond to changing memory
93 # usage, so we recheck the required alloc each time around the loop, but
94 # track the last used value so that we don't trigger too many watches.
96 xoptions = XendOptions.instance()
97 dom0 = XendDomain.instance().privilegedDomain()
98 xc = xen.lowlevel.xc.xc()
100 try:
101 dom0_min_mem = xoptions.get_dom0_min_mem() * 1024
102 dom0_ballooning = xoptions.get_enable_dom0_ballooning()
103 dom0_alloc = get_dom0_current_alloc()
105 retries = 0
106 sleep_time = SLEEP_TIME_GROWTH
107 new_alloc = 0
108 last_new_alloc = None
109 last_free = None
110 rlimit = RETRY_LIMIT
112 # If unreasonable memory size is required, we give up waiting
113 # for ballooning or scrubbing, as if had retried.
114 physinfo = xc.physinfo()
115 free_mem = physinfo['free_memory']
116 scrub_mem = physinfo['scrub_memory']
117 total_mem = physinfo['total_memory']
118 if dom0_ballooning:
119 max_free_mem = total_mem - dom0_min_mem
120 else:
121 max_free_mem = total_mem - dom0_alloc
122 if need_mem >= max_free_mem:
123 retries = rlimit
125 while retries < rlimit:
126 physinfo = xc.physinfo()
127 free_mem = physinfo['free_memory']
128 scrub_mem = physinfo['scrub_memory']
130 if free_mem >= need_mem:
131 log.debug("Balloon: %d KiB free; need %d; done.",
132 free_mem, need_mem)
133 return
135 if retries == 0:
136 rlimit += ((need_mem - free_mem)/1024/1024) * RETRY_LIMIT_INCR
137 log.debug("Balloon: %d KiB free; %d to scrub; need %d; retries: %d.",
138 free_mem, scrub_mem, need_mem, rlimit)
140 if dom0_ballooning:
141 dom0_alloc = get_dom0_current_alloc()
142 new_alloc = dom0_alloc - (need_mem - free_mem - scrub_mem)
144 if free_mem + scrub_mem >= need_mem:
145 if last_new_alloc == None:
146 log.debug("Balloon: waiting on scrubbing")
147 last_new_alloc = dom0_alloc
148 else:
149 if (new_alloc >= dom0_min_mem and
150 new_alloc != last_new_alloc):
151 new_alloc_mb = new_alloc / 1024 # Round down
152 log.debug("Balloon: setting dom0 target to %d MiB.",
153 new_alloc_mb)
154 dom0.setMemoryTarget(new_alloc_mb)
155 last_new_alloc = new_alloc
156 # Continue to retry, waiting for ballooning or scrubbing.
158 time.sleep(sleep_time)
159 if retries < 2 * RETRY_LIMIT:
160 sleep_time += SLEEP_TIME_GROWTH
161 if last_free != None and last_free >= free_mem + scrub_mem:
162 retries += 1
163 last_free = free_mem + scrub_mem
165 # Not enough memory; diagnose the problem.
166 if not dom0_ballooning:
167 raise VmError(('Not enough free memory and enable-dom0-ballooning '
168 'is False, so I cannot release any more. '
169 'I need %d KiB but only have %d.') %
170 (need_mem, free_mem))
171 elif new_alloc < dom0_min_mem:
172 raise VmError(
173 ('I need %d KiB, but dom0_min_mem is %d and shrinking to '
174 '%d KiB would leave only %d KiB free.') %
175 (need_mem, dom0_min_mem, dom0_min_mem,
176 free_mem + scrub_mem + dom0_alloc - dom0_min_mem))
177 else:
178 dom0_start_alloc_mb = get_dom0_current_alloc() / 1024
179 dom0.setMemoryTarget(dom0_start_alloc_mb)
180 raise VmError(
181 ('Not enough memory is available, and dom0 cannot'
182 ' be shrunk any further'))
184 finally:
185 del xc