## # This module implements Gacks handles ## import sys ## # GacksHandle is an object representing a handle. A handle is the following # tuple: # # (id, unitstart, unitstop, timestart, timestop) # # id is a text identifier for the resource, for example "CPU" # # unitstart and unitstop form an interval [unitstart, unitstop) in unit # space. For example, [0, 10) could represent 10% of a CPU. # # timestart and timestop form an interval [timestart, timestop) in time # space. # # If unitstop==INFINITY, or timestop==INFINITY, then it is treated as infinity # # The GacksHandle also doubles as an RSPEC INFINITY = "inf" #sys.maxint def is_lesser_equal(x, y): if x==y: return True if x==INFINITY: return False if y==INFINITY: return True return (xy) def interval_contains(start1, stop1, start2, stop2): return is_lesser_equal(start1, start2) and is_greater_equal(stop1, stop2) class GacksHandle: def __init__(self, id=None, unitStart=0, unitStop=INFINITY, timeStart=0, timeStop=INFINITY, string=None): self.id = id self.unitStart = unitStart self.unitStop = unitStop self.timeStart = timeStart self.timeStop = timeStop if string: self.load_from_string(string) def as_string(self): return str(self.id) + "#" + \ str(self.unitStart) + "-" + str(self.unitStop) + "#" + \ str(self.timeStart) + "-" + str(self.timeStop) def parse_range(self, str): parts = str.split("-") if len(parts)!=2: raise ValueError if parts[0] != INFINITY: parts[0] = int(parts[0]) if parts[1] != INFINITY: parts[1] = int(parts[1]) return parts def load_from_string(self, str): parts = str.split("#") self.id = parts[0] if len(parts) > 1: (self.unitStart, self.unitStop) = self.parse_range(parts[1]) if len(parts) > 2: (self.timeStart, self.timeStop) = self.parse_range(parts[2]) def get_quantity(self): if self.unitStop == INFINITY: return INFINITY else: return self.unitStop-self.unitStart def get_duration(self): if self.timeStop == INFINITY: return INFINITY else: return self.timeStop-self.timeStart def dump(self): print str(self.id) + ": " + \ "units " + str(self.unitStart) + "-" + str(self.unitStop) + \ "time " + str(self.timeStart) + "-" + str(self.timeStop) def clone(self): return GacksHandle(self.id, self.unitStart, self.unitStop, self.timeStart, self.timeStop) def split_subset(self, suStart, suStop, stStart, stStop): # an arbitrary rectangle can have a subset removed by slicing it into # five pieces: # h1 = top # h2 = left # h3 = right # h4 = bottom # s = subset (middle) that was sliced out h1 = self.clone() h2 = self.clone() h3 = self.clone() h4 = self.clone() s = self.clone() if not suStart: suStart = self.unitStart if not suStop: suStop = self.unitStop if not stStart: stStart = self.timeStart if not stStop: stStop = self.timeStop h1.unitStop = suStart h2.unitStart = suStart h2.unitStop = suStop h2.timeStop = stStart h3.unitStart = suStart h3.unitStop = suStop h3.timeStart = stStop h4.unitStart = suStop s.unitStart = suStart s.unitStop = suStop s.timeStart = stStart s.timeStop = stStop results = [s, h1, h2, h3, h4] valid_results = [] for result in results: if result.get_quantity()>0 and result.get_duration()>0: valid_results.append(result) return valid_results def split_subset_old(self, uStart, uStop, tStart, tStop): results = [self] if uStart: results1 = [] for i in results: results1.extend(i.split_unit(uStart)) results = results1 if uStop: results1 = [] for i in results: results1.extend(i.split_unit(uStop)) results = results1 if tStart: results1 = [] for i in results: results1.extend(i.split_time(tStart)) results = results1 if tStop: results1 = [] for i in results: results1.extend(i.split_time(tStop)) results = results1 return results def split_unit(self, unit): if is_lesser_equal(unit, self.unitStart) or is_greater_equal(unit, self.unitStop): return [self] h2 = self.clone() self.unitStop = unit h2.unitStart = unit return [self, h2] def split_time(self, time): if is_lesser_equal(time, self.timeStart) or is_greater_equal(time, self.timeStop): return [self] h2 = self.clone() self.timeStop = time h2.timeStart = time return [self, h2] def is_superset(self, handle): if self.id != handle.id: return False if not interval_contains(self.timeStart, self.timeStop, handle.timeStart, handle.timeStop): return False if not interval_contains(self.unitStart, self.unitStop, self.timeStart, self.timeStop): return False return True def is_proper_superset(self, handle): return self.is_superset(handle) and (not self.is_same_cell(handle)) def is_same_cell(self, handle): return (self.id == handle.id) and \ (self.unitStart == handle.unitStart) and \ (self.unitStop == handle.unitStop) and \ (self.timeStart == handle.timeStart) and \ (self.timeStop == handle.timeStop) def is_same(self, handle): return self.is_same_cell(handle) def is_in_list(self, handle_list): for handle in handle_list: if is_same(self, handle): return True return False class GacksRecord(GacksHandle): def __init__(self, id=None, unitStart=0, unitStop=INFINITY, timeStart=0, timeStop=INFINITY, allocatorHRNs=[], consumerHRN=None): GacksHandle.__init__(self, id, unitStart, unitStop, timeStart, timeStop) self.allocatorHRNs = allocatorHRNs self.consumerHRN = consumerHRN def dump(self): GacksHandle.dump(self) print " allocators:", ", ".join(self.allocatorHRNs) print " consumer:", self.consumerHRN def clone(self): return GacksRecord(self.id, self.unitStart, self.unitStop, self.timeStart, self.timeStop, self.allocatorHRNs, self.consumerHRN) def set_allocator(self, callerHRN, allocatorHRN, which, where): # build up a list of the positions of callerHRN inside of the # allocator list positions = [] for i, hrn in enumerate(self.allocatorHRNs): if hrn == callerHRN: positions.append(i) pos = positions[which] # truncate the allocator list at the appropriate place. # if where==True, # keep callerHRN in the list and append allocatorHRN after # otherwise, # remove callerHRN and replace with allocatorHRN if where: self.allocatorHRNs = self.allocatorHRNs[:(pos+1)] else: self.allocatorHRNs = self.allocatorHRNs[:pos] self.allocatorHRNs.append(allocatorHRN) def get_allocators(self): return self.allocatorHRNs def contains_allocator(self, allocatorHRN): return (allocatorHRN in self.allocatorHRNs) def set_consumer(self, consumerHRN): self.consumerHRN = consumerHRN def get_consumer(self): return self.consumerHRN def strings_to_handles(strings): # if given a newline-separated list of strings, then expand it into a list if isinstance(strings, str): expanded_strings = strings.split("\n") elif isinstance(strings, list): expanded_strings = strings else: raise TypeError # eliminate any blank strings from the list non_blank_strings = [] for string in expanded_strings: if string: non_blank_strings.append(string) handles = [] for line in non_blank_strings: handle = GacksHandle(string = rspec) handles.append(handle) return handles def handles_to_strings(handles): strings = [] for handle in handles: strings.append(handle.as_string()) return strings def rspec_to_handles(rspec): return strings_to_handles(rspec) def find_handle_in_list(list, uStart, uStop, tStart, tStop): for item in list: if item.unitStart == uStart and \ item.unitStop == uStop and \ item.timeStart == tStart and \ item.timeStop == tStop: return item return None