Beispiel #1
0
    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
Beispiel #2
0
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