123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import string
- def parse_meminfo(meminfo):
- dict = {}
- l1 = string.split(meminfo,"\n")
- for i in l1:
- l2 = string.split(i)
- if len(l2) >= 2:
- dict[string.rstrip(l2[0], ":")] = l2[1]
- try:
- for i in ('MemTotal', 'MemFree', 'Buffers', 'Cached', 'SwapTotal', 'SwapFree'):
- val = int(dict[i])*1024
- if (val < 0):
- return None
- dict[i] = val
- except:
- return None
- if dict['SwapTotal'] < dict['SwapFree']:
- return None
- return dict
- def is_suspicious(dom):
- ret = False
- if dom.meminfo['SwapTotal'] < dom.meminfo['SwapFree']:
- ret = True
- if dom.meminfo['MemTotal'] < dom.meminfo['MemFree'] + dom.meminfo['Cached'] + dom.meminfo['Buffers']:
- ret = True
- if ret:
- print 'suspicious meminfo for domain', dom.id, 'mem actual', dom.memory_actual, dom.meminfo
- return ret
- def refresh_meminfo_for_domain(dom, xenstore_key):
- meminfo = parse_meminfo(xenstore_key)
- dom.meminfo = meminfo
- if meminfo is None:
- return
- if is_suspicious(dom):
- dom.meminfo = None
- dom.mem_used = None
- else:
- dom.mem_used = dom.meminfo['MemTotal'] - dom.meminfo['MemFree'] - dom.meminfo['Cached'] - dom.meminfo['Buffers'] + dom.meminfo['SwapTotal'] - dom.meminfo['SwapFree']
-
- def prefmem(dom):
- CACHE_FACTOR = 1.3
- #dom0 is special, as it must have large cache, for vbds. Thus, give it a special boost
- if dom.id == '0':
- return dom.mem_used*CACHE_FACTOR + 350*1024*1024
- return dom.mem_used*CACHE_FACTOR
- def memneeded(dom):
- #do not change
- #in balance(), "distribute totalsum proportionally to mempref" relies on this exact formula
- ret = prefmem(dom) - dom.memory_actual
- return ret
-
-
- def balloon(memsize, domdict):
- REQ_SAFETY_NET_FACTOR = 1.05
- donors = list()
- request = list()
- available = 0
- for i in domdict.keys():
- if domdict[i].meminfo is None:
- continue
- if domdict[i].no_progress:
- continue
- need = memneeded(domdict[i])
- if need < 0:
- print 'balloon: dom' , i, 'has actual memory', domdict[i].memory_actual
- donors.append((i,-need))
- available-=need
- print 'req=', memsize, 'avail=', available, 'donors', donors
- if available<memsize:
- return ()
- scale = 1.0*memsize/available
- for donors_iter in donors:
- id, mem = donors_iter
- memborrowed = mem*scale*REQ_SAFETY_NET_FACTOR
- print 'borrow' , memborrowed, 'from', id
- memtarget = int(domdict[id].memory_actual - memborrowed)
- request.append((id, memtarget))
- return request
- # REQ_SAFETY_NET_FACTOR is a bit greater that 1. So that if the domain yields a bit less than requested, due
- # to e.g. rounding errors, we will not get stuck. The surplus will return to the VM during "balance" call.
- #redistribute positive "totalsum" of memory between domains, proportionally to prefmem
- def balance_when_enough_memory(domdict, xenfree, total_mem_pref, totalsum):
- donors_rq = list()
- acceptors_rq = list()
- for i in domdict.keys():
- if domdict[i].meminfo is None:
- continue
- #distribute totalsum proportionally to mempref
- scale = 1.0*prefmem(domdict[i])/total_mem_pref
- target_nonint = prefmem(domdict[i]) + scale*totalsum
- #prevent rounding errors
- target = int(0.999*target_nonint)
- if (target < domdict[i].memory_actual):
- donors_rq.append((i, target))
- else:
- acceptors_rq.append((i, target))
- # print 'balance(enough): xenfree=', xenfree, 'requests:', donors_rq + acceptors_rq
- return donors_rq + acceptors_rq
- #when not enough mem to make everyone be above prefmem, make donors be at prefmem, and
- #redistribute anything left between acceptors
- def balance_when_low_on_memory(domdict, xenfree, total_mem_pref_acceptors, donors, acceptors):
- donors_rq = list()
- acceptors_rq = list()
- squeezed_mem = xenfree
- for i in donors:
- avail = -memneeded(domdict[i])
- if avail < 10*1024*1024:
- #probably we have already tried making it exactly at prefmem, give up
- continue
- squeezed_mem -= avail
- donors_rq.append((i, prefmem(domdict[i])))
- #the below can happen if initially xen free memory is below 50M
- if squeezed_mem < 0:
- return donors_rq
- for i in acceptors:
- scale = 1.0*prefmem(domdict[i])/total_mem_pref_acceptors
- target_nonint = domdict[i].memory_actual + scale*squeezed_mem
- acceptors_rq.append((i, int(target_nonint)))
- # print 'balance(low): xenfree=', xenfree, 'requests:', donors_rq + acceptors_rq
- return donors_rq + acceptors_rq
-
- def balance(xenfree, domdict):
- total_memneeded = 0
- total_mem_pref = 0
- total_mem_pref_acceptors = 0
-
- donors = list()
- acceptors = list()
- #pass 1: compute the above "total" values
- for i in domdict.keys():
- if domdict[i].meminfo is None:
- continue
- need = memneeded(domdict[i])
- # print 'domain' , i, 'act/pref', domdict[i].memory_actual, prefmem(domdict[i]), 'need=', need
- if need < 0:
- donors.append(i)
- else:
- acceptors.append(i)
- total_mem_pref_acceptors += prefmem(domdict[i])
- total_memneeded += need
- total_mem_pref += prefmem(domdict[i])
- totalsum = xenfree - total_memneeded
- if totalsum > 0:
- return balance_when_enough_memory(domdict, xenfree, total_mem_pref, totalsum)
- else:
- return balance_when_low_on_memory(domdict, xenfree, total_mem_pref_acceptors, donors, acceptors)
|