b4c8ab56创建于 2025年1月3日历史提交
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import OrderedDict

from log_exception import UPDATE_LOGGER

# 50% of the data partition, in KB x 1024.
DATA_SIZE = 1374024 * 1024


class GigraphProcess(object):
    def __init__(self, actions_list, src_image, tgt_image):
        self.actions_list = actions_list
        if len(self.actions_list) == 0:
            raise RuntimeError
        self.size_of_source_list = 0
        self.src_img_obj = src_image
        self.tgt_img_obj = tgt_image
        self.vertices = len(self.actions_list)
        self.data_size = DATA_SIZE

        self.generate_digraph()

    def generate_digraph(self):
        """
        Start correlation lookup.
        """
        source_ranges = []
        source_ranges = \
            self.get_source_ranges(self.actions_list, source_ranges)

        self.get_intersections_dict(source_ranges)
        # Start ordering.
        topo_logical = TopoLogical(self)
        action_stack = topo_logical.stack()
        new_action_list = []
        for action in action_stack:
            action.order = len(new_action_list)
            new_action_list.append(action)
        self.actions_list = new_action_list

    def get_intersections_dict(self, source_ranges):
        """
        Get the intersections_dict.
        :param source_ranges: source blocks
        :return:
        """
        for each_action in self.actions_list:
            intersections = OrderedDict()
            for start_value, end_value in each_action.tgt_block_set:
                for i in range(start_value, end_value):
                    if i >= len(source_ranges):
                        break
                    if source_ranges[i] is not None:
                        for j in source_ranges[i]:
                            intersections[j] = None

            self.update_goes_before_and_after(each_action, intersections)

    @staticmethod
    def update_goes_before_and_after(each_action, intersections):
        """
        Update "goes before" and "goes after".
        :param each_action: action to be processed
        :param intersections: intersections dict
        :return:
        """
        for each_intersection in intersections:
            if each_action is each_intersection:
                continue

            intersect_range = \
                each_action.tgt_block_set.get_intersect_with_other(
                    each_intersection.src_block_set)
            if intersect_range:
                if each_intersection.src_name == "__ZERO":
                    size = 0
                else:
                    size = intersect_range.size()
                each_intersection.child[each_action] = size
                each_action.parent[each_intersection] = size

    @staticmethod
    def get_source_ranges(transfers, source_ranges):
        """
        Update "goes before" and "goes after".
        :param transfers: actions list
        :param source_ranges: source blocks
        :return:
        """
        for each_action in transfers:
            for start_value, end_value in each_action.src_block_set:
                if end_value > len(source_ranges):
                    source_ranges.extend(
                        [None] * (end_value - len(source_ranges)))
                for i in range(start_value, end_value):
                    if source_ranges[i] is None:
                        source_ranges[i] = \
                            OrderedDict.fromkeys([each_action])
                    else:
                        source_ranges[i][each_action] = None
        return source_ranges

    def stash_process(self):
        """
        Stash processing
        """
        UPDATE_LOGGER.print_log("Reversing backward edges...")
        stash_raw_id = 0
        for each_action in self.actions_list:
            each_child_dict = each_action.child.copy()
            for each_before in each_child_dict:
                if each_action.order >= each_before.order:
                    intersect_block_set = \
                        each_action.src_block_set.get_intersect_with_other(
                            each_before.tgt_block_set)

                    each_before.stash_before.append(
                        (stash_raw_id, intersect_block_set))
                    each_action.use_stash.append(
                        (stash_raw_id, intersect_block_set))
                    stash_raw_id += 1
                    each_action.child.pop(each_before)
                    each_before.parent.pop(each_action)
                    each_action.parent[each_before] = None
                    each_before.child[each_action] = None
        UPDATE_LOGGER.print_log("Reversing backward edges completed!")


class DirectedCycle(object):
    def __init__(self, graph):
        self.graph = graph
        self.marked = [False for _ in range(self.graph.vertices)]
        self.has_cycle = False
        self.ontrack = [False for _ in range(self.graph.vertices)]


class DepthFirstOrder:
    def __init__(self, graph):
        self.graph = graph
        self.marked = {}
        self.stack = []

        for each_action in self.graph.actions_list:
            self.marked[each_action] = False

    def dfs(self):
        def dfs(index):
            self.marked[index] = True
            for each_child in index.child:
                if not self.marked[each_child]:
                    dfs(each_child)
            self.stack.insert(0, index)

        for each_action in self.graph.actions_list:
            if not self.marked[each_action]:
                dfs(each_action)
        return self.stack

    def sort_vertices(self):
        return self.dfs()


class TopoLogical(object):
    def __init__(self, graph):
        self.order = None
        self.cycle = DirectedCycle(graph)
        if not self.cycle.has_cycle:
            dfo = DepthFirstOrder(graph)
            self.order = dfo.sort_vertices()

    def stack(self):
        return self.order