def __init__(self, list_headers=None, device_tree=None, version_desc=None, pci_classes=None): self.device_tree = device_tree self.list_headers = list_headers self.version_desc = version_desc # Create source tree container self.stc = SourceTreeContainer() self.pci_c = PCIClassification( ) if pci_classes is None else pci_classes
class QemuVersionCache(object): current = None def __init__(self, list_headers=None, device_tree=None, known_targets=None, version_desc=None, pci_classes=None): self.device_tree = device_tree self.known_targets = known_targets self.list_headers = list_headers self.version_desc = version_desc # Create source tree container self.stc = SourceTreeContainer() self.pci_c = PCIClassification( ) if pci_classes is None else pci_classes def co_computing_parameters(self, repo, version): print("Build QEMU Git graph ...") self.commit_desc_nodes = {} yield QemuCommitDesc.co_build_git_graph(repo, self.commit_desc_nodes) print("QEMU Git graph was built") yield self.co_propagate_param() c = self.commit_desc_nodes[repo.commit(version).hexsha] param = self.version_desc = QVHDict() for k, v in c.param_nval.items(): param[k] = v for k, v in c.param_oval.items(): param[k] = v def co_propagate_param(self): vd = qemu_heuristic_db vd_list = [] unknown_vd_keys = set() for k in vd.keys(): if k in self.commit_desc_nodes: vd_list.append((k, self.commit_desc_nodes[k].num)) else: unknown_vd_keys.add(k) print("WARNING: Unknown SHA1 %s in QEMU heuristic database" % k) sorted_tuple = sorted(vd_list, key=lambda x: x[1]) sorted_vd_keys = [t[0] for t in sorted_tuple] yield True # first, need to propagate the new labels print("Propagation params in graph of commit's description ...") yield self.co_propagate_new_param(sorted_vd_keys, vd) yield self.co_propagate_old_param(sorted_vd_keys, unknown_vd_keys, vd) print("Params in graph of commit's description were propagated") def co_propagate_new_param(self, sorted_vd_keys, vd): """ This method propagate QEMUVersionParameterDescription.new_value in graph of commits. It must be called before old_value propagation. :param sorted_vd_keys: keys of qemu_heuristic_db sorted in ascending order by num of QemuCommitDesc. It's necessary to optimize the graph traversal. :param vd: qemu_heuristic_db """ # iterations to yield i2y = QVD_HP_IBY for key in sorted_vd_keys: cur_vd = vd[key] cur_node = self.commit_desc_nodes[key] for vpd in cur_vd: cur_node.param_nval[vpd.name] = vpd.new_value if i2y == 0: yield True i2y = QVD_HP_IBY else: i2y -= 1 # vd_keys_set is used to accelerate propagation vd_keys_set = set(sorted_vd_keys) # old_val contains all old_value that are in ancestors old_val = {} for key in sorted_vd_keys: stack = [self.commit_desc_nodes[key]] for vpd in vd[key]: try: old_val[vpd.name].append(vpd.old_value) except KeyError: old_val[vpd.name] = [vpd.old_value] while stack: cur_node = stack.pop() for c in cur_node.children: if c.sha in vd_keys_set: # if the child is vd, only the parameters that are not # in vd's param_nval are added for p in cur_node.param_nval: if p not in c.param_nval: c.param_nval[p] = cur_node.param_nval[p] # no need to add element to stack, as it's in the sorted_vd_keys else: # the child is't vd for p in cur_node.param_nval: if p in c.param_nval: if cur_node.param_nval[p] != c.param_nval[p]: exc_raise = False if p in old_val: if cur_node.param_nval[ p] not in old_val[p]: if c.param_nval[p] in old_val[p]: c.param_nval[ p] = cur_node.param_nval[p] stack.append(c) else: exc_raise = True else: exc_raise = True if exc_raise: raise Exception("Contradictory definition of param " \ "'%s' in commit %s (%s != %s)" % (p, c.sha, cur_node.param_nval[p], c.param_nval[p]) ) else: c.param_nval[p] = cur_node.param_nval[p] stack.append(c) if i2y == 0: yield True i2y = QVD_HP_IBY else: i2y -= 1 def co_propagate_old_param(self, sorted_vd_keys, unknown_vd_keys, vd): """ This method propagate QEMUVersionParameterDescription.old_value in graph of commits. It must be called after new_value propagation. :param sorted_vd_keys: keys of qemu_heuristic_db sorted in ascending order by num of QemuCommitDesc. It's necessary to optimize the graph traversal. :param unknown_vd_keys: set of keys which are not in commit_desc_nodes. :param vd: qemu_heuristic_db """ # message for exceptions msg = "Conflict with param '%s' in commit %s (old_val (%s) != old_val (%s))" # iterations to yield i2y = QVD_HP_IBY # Assume unknown SHA1 corresponds to an ancestor of a known node. # Therefore, old value must be used for all commits. for commit in self.commit_desc_nodes.values(): for vd_keys in unknown_vd_keys: self.init_commit_old_val(commit, vd[vd_keys]) i2y -= 1 if not i2y: yield True i2y = QVD_HP_IBY vd_keys_set = set(sorted_vd_keys) visited_vd = set() for key in sorted_vd_keys[::-1]: stack = [] # used to avoid multiple processing of one node visited_nodes = set([key]) visited_vd.add(key) node = self.commit_desc_nodes[key] for p in node.parents: stack.append(p) # propagate old_val from node to their parents p.param_oval.update() for param, oval in node.param_oval.items(): try: other = p.param_oval[param] except KeyError: p.param_oval[param] = oval else: if other != oval: raise Exception(msg % (param, p.sha, oval, other)) # init old_val of nodes that consist of vd's parents # and check conflicts self.init_commit_old_val(p, vd[key]) i2y -= 1 if not i2y: yield True i2y = QVD_HP_IBY while stack: cur_node = stack.pop() visited_nodes.add(cur_node.sha) for commit in cur_node.parents + cur_node.children: if commit.sha in visited_nodes: continue for param_name in cur_node.param_oval: if param_name in commit.param_nval: continue elif param_name in commit.param_oval: if commit.param_oval[ param_name] != cur_node.param_oval[ param_name]: raise Exception( msg % (param_name, commit.sha, commit.param_oval[param_name], cur_node.param_oval[param_name])) else: commit.param_oval[ param_name] = cur_node.param_oval[param_name] if commit.sha not in vd_keys_set: stack.append(commit) # if we have visited vd before, it is necessary # to propagate the param, otherwise we do it # in the following iterations of the outer loop elif commit.sha in visited_vd: stack.append(commit) i2y -= 1 if not i2y: yield True i2y = QVD_HP_IBY def init_commit_old_val(self, commit, vd): # messages for exceptions msg1 = "Conflict with param '%s' in commit %s (old_val (%s) != new_val (%s))" msg2 = "Conflict with param '%s' in commit %s (old_val (%s) != old_val (%s))" for param in vd: if param.name in commit.param_nval: if commit.param_nval[param.name] != param.old_value: raise Exception(msg1 % (param.name, commit.sha, param.old_value, commit.param_nval[param.name])) elif param.name in commit.param_oval: if commit.param_oval[param.name] != param.old_value: raise Exception(msg2 % (param.name, commit.sha, param.old_value, commit.param_oval[param.name])) else: commit.param_oval[param.name] = param.old_value __pygen_deps__ = ("pci_c", "device_tree") def __gen_code__(self, gen): gen.reset_gen(self) gen.gen_field("device_tree = ") gen.pprint(self.device_tree) gen.gen_field("known_targets = ") gen.pprint(self.known_targets) gen.gen_field("list_headers = ") gen.pprint(self.list_headers) gen.gen_field("version_desc = ") gen.pprint(self.version_desc) gen.gen_field("pci_classes = " + gen.nameof(self.pci_c)) gen.gen_end() # The method made the cache active. def use(self): self.stc.set_cur_stc() PCIId.db = self.pci_c previous = QemuVersionCache.current QemuVersionCache.current = self return previous