140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
540681896Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
640681896Sopenharmony_ci# you may not use this file except in compliance with the License.
740681896Sopenharmony_ci# You may obtain a copy of the License at
840681896Sopenharmony_ci#
940681896Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
1040681896Sopenharmony_ci#
1140681896Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
1240681896Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
1340681896Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1440681896Sopenharmony_ci# See the License for the specific language governing permissions and
1540681896Sopenharmony_ci# limitations under the License.
1640681896Sopenharmony_cifrom collections import OrderedDict
1740681896Sopenharmony_ci
1840681896Sopenharmony_cifrom log_exception import UPDATE_LOGGER
1940681896Sopenharmony_ci
2040681896Sopenharmony_ci# 50% of the data partition, in KB x 1024.
2140681896Sopenharmony_ciDATA_SIZE = 1374024 * 1024
2240681896Sopenharmony_ci
2340681896Sopenharmony_ci
2440681896Sopenharmony_ciclass GigraphProcess(object):
2540681896Sopenharmony_ci    def __init__(self, actions_list, src_image, tgt_image):
2640681896Sopenharmony_ci        self.actions_list = actions_list
2740681896Sopenharmony_ci        if len(self.actions_list) == 0:
2840681896Sopenharmony_ci            raise RuntimeError
2940681896Sopenharmony_ci        self.size_of_source_list = 0
3040681896Sopenharmony_ci        self.src_img_obj = src_image
3140681896Sopenharmony_ci        self.tgt_img_obj = tgt_image
3240681896Sopenharmony_ci        self.vertices = len(self.actions_list)
3340681896Sopenharmony_ci        self.data_size = DATA_SIZE
3440681896Sopenharmony_ci
3540681896Sopenharmony_ci        self.generate_digraph()
3640681896Sopenharmony_ci        self.stash_process()
3740681896Sopenharmony_ci
3840681896Sopenharmony_ci    def generate_digraph(self):
3940681896Sopenharmony_ci        """
4040681896Sopenharmony_ci        Start correlation lookup.
4140681896Sopenharmony_ci        """
4240681896Sopenharmony_ci        source_ranges = []
4340681896Sopenharmony_ci        source_ranges = \
4440681896Sopenharmony_ci            self.get_source_ranges(self.actions_list, source_ranges)
4540681896Sopenharmony_ci
4640681896Sopenharmony_ci        self.get_intersections_dict(source_ranges)
4740681896Sopenharmony_ci        # Start ordering.
4840681896Sopenharmony_ci        topo_logical = TopoLogical(self)
4940681896Sopenharmony_ci        action_stack = topo_logical.stack()
5040681896Sopenharmony_ci        new_action_list = []
5140681896Sopenharmony_ci        for action in action_stack:
5240681896Sopenharmony_ci            action.order = len(new_action_list)
5340681896Sopenharmony_ci            new_action_list.append(action)
5440681896Sopenharmony_ci        self.actions_list = new_action_list
5540681896Sopenharmony_ci
5640681896Sopenharmony_ci    def get_intersections_dict(self, source_ranges):
5740681896Sopenharmony_ci        """
5840681896Sopenharmony_ci        Get the intersections_dict.
5940681896Sopenharmony_ci        :param source_ranges: source blocks
6040681896Sopenharmony_ci        :return:
6140681896Sopenharmony_ci        """
6240681896Sopenharmony_ci        for each_action in self.actions_list:
6340681896Sopenharmony_ci            intersections = OrderedDict()
6440681896Sopenharmony_ci            for start_value, end_value in each_action.tgt_block_set:
6540681896Sopenharmony_ci                for i in range(start_value, end_value):
6640681896Sopenharmony_ci                    if i >= len(source_ranges):
6740681896Sopenharmony_ci                        break
6840681896Sopenharmony_ci                    if source_ranges[i] is not None:
6940681896Sopenharmony_ci                        for j in source_ranges[i]:
7040681896Sopenharmony_ci                            intersections[j] = None
7140681896Sopenharmony_ci
7240681896Sopenharmony_ci            self.update_goes_before_and_after(each_action, intersections)
7340681896Sopenharmony_ci
7440681896Sopenharmony_ci    @staticmethod
7540681896Sopenharmony_ci    def update_goes_before_and_after(each_action, intersections):
7640681896Sopenharmony_ci        """
7740681896Sopenharmony_ci        Update "goes before" and "goes after".
7840681896Sopenharmony_ci        :param each_action: action to be processed
7940681896Sopenharmony_ci        :param intersections: intersections dict
8040681896Sopenharmony_ci        :return:
8140681896Sopenharmony_ci        """
8240681896Sopenharmony_ci        for each_intersection in intersections:
8340681896Sopenharmony_ci            if each_action is each_intersection:
8440681896Sopenharmony_ci                continue
8540681896Sopenharmony_ci
8640681896Sopenharmony_ci            intersect_range = \
8740681896Sopenharmony_ci                each_action.tgt_block_set.get_intersect_with_other(
8840681896Sopenharmony_ci                    each_intersection.src_block_set)
8940681896Sopenharmony_ci            if intersect_range:
9040681896Sopenharmony_ci                if each_intersection.src_name == "__ZERO":
9140681896Sopenharmony_ci                    size = 0
9240681896Sopenharmony_ci                else:
9340681896Sopenharmony_ci                    size = intersect_range.size()
9440681896Sopenharmony_ci                each_intersection.child[each_action] = size
9540681896Sopenharmony_ci                each_action.parent[each_intersection] = size
9640681896Sopenharmony_ci
9740681896Sopenharmony_ci    @staticmethod
9840681896Sopenharmony_ci    def get_source_ranges(transfers, source_ranges):
9940681896Sopenharmony_ci        """
10040681896Sopenharmony_ci        Update "goes before" and "goes after".
10140681896Sopenharmony_ci        :param transfers: actions list
10240681896Sopenharmony_ci        :param source_ranges: source blocks
10340681896Sopenharmony_ci        :return:
10440681896Sopenharmony_ci        """
10540681896Sopenharmony_ci        for each_action in transfers:
10640681896Sopenharmony_ci            for start_value, end_value in each_action.src_block_set:
10740681896Sopenharmony_ci                if end_value > len(source_ranges):
10840681896Sopenharmony_ci                    source_ranges.extend(
10940681896Sopenharmony_ci                        [None] * (end_value - len(source_ranges)))
11040681896Sopenharmony_ci                for i in range(start_value, end_value):
11140681896Sopenharmony_ci                    if source_ranges[i] is None:
11240681896Sopenharmony_ci                        source_ranges[i] = \
11340681896Sopenharmony_ci                            OrderedDict.fromkeys([each_action])
11440681896Sopenharmony_ci                    else:
11540681896Sopenharmony_ci                        source_ranges[i][each_action] = None
11640681896Sopenharmony_ci        return source_ranges
11740681896Sopenharmony_ci
11840681896Sopenharmony_ci    def stash_process(self):
11940681896Sopenharmony_ci        """
12040681896Sopenharmony_ci        Stash processing
12140681896Sopenharmony_ci        """
12240681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Reversing backward edges...")
12340681896Sopenharmony_ci        stash_raw_id = 0
12440681896Sopenharmony_ci        for each_action in self.actions_list:
12540681896Sopenharmony_ci            each_child_dict = each_action.child.copy()
12640681896Sopenharmony_ci            for each_before in each_child_dict:
12740681896Sopenharmony_ci                if each_action.order >= each_before.order:
12840681896Sopenharmony_ci                    intersect_block_set = \
12940681896Sopenharmony_ci                        each_action.src_block_set.get_intersect_with_other(
13040681896Sopenharmony_ci                            each_before.tgt_block_set)
13140681896Sopenharmony_ci
13240681896Sopenharmony_ci                    each_before.stash_before.append(
13340681896Sopenharmony_ci                        (stash_raw_id, intersect_block_set))
13440681896Sopenharmony_ci                    each_action.use_stash.append(
13540681896Sopenharmony_ci                        (stash_raw_id, intersect_block_set))
13640681896Sopenharmony_ci                    stash_raw_id += 1
13740681896Sopenharmony_ci                    each_action.child.pop(each_before)
13840681896Sopenharmony_ci                    each_before.parent.pop(each_action)
13940681896Sopenharmony_ci                    each_action.parent[each_before] = None
14040681896Sopenharmony_ci                    each_before.child[each_action] = None
14140681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Reversing backward edges completed!")
14240681896Sopenharmony_ci
14340681896Sopenharmony_ci
14440681896Sopenharmony_ciclass DirectedCycle(object):
14540681896Sopenharmony_ci    def __init__(self, graph):
14640681896Sopenharmony_ci        self.graph = graph
14740681896Sopenharmony_ci        self.marked = [False for _ in range(self.graph.vertices)]
14840681896Sopenharmony_ci        self.has_cycle = False
14940681896Sopenharmony_ci        self.ontrack = [False for _ in range(self.graph.vertices)]
15040681896Sopenharmony_ci
15140681896Sopenharmony_ci
15240681896Sopenharmony_ciclass DepthFirstOrder:
15340681896Sopenharmony_ci    def __init__(self, graph):
15440681896Sopenharmony_ci        self.graph = graph
15540681896Sopenharmony_ci        self.marked = {}
15640681896Sopenharmony_ci        self.stack = []
15740681896Sopenharmony_ci
15840681896Sopenharmony_ci        for each_action in self.graph.actions_list:
15940681896Sopenharmony_ci            self.marked[each_action] = False
16040681896Sopenharmony_ci
16140681896Sopenharmony_ci    def dfs(self):
16240681896Sopenharmony_ci        def dfs(index):
16340681896Sopenharmony_ci            self.marked[index] = True
16440681896Sopenharmony_ci            for each_child in index.child:
16540681896Sopenharmony_ci                if not self.marked[each_child]:
16640681896Sopenharmony_ci                    dfs(each_child)
16740681896Sopenharmony_ci            self.stack.insert(0, index)
16840681896Sopenharmony_ci
16940681896Sopenharmony_ci        for each_action in self.graph.actions_list:
17040681896Sopenharmony_ci            if not self.marked[each_action]:
17140681896Sopenharmony_ci                dfs(each_action)
17240681896Sopenharmony_ci        return self.stack
17340681896Sopenharmony_ci
17440681896Sopenharmony_ci    def sort_vertices(self):
17540681896Sopenharmony_ci        return self.dfs()
17640681896Sopenharmony_ci
17740681896Sopenharmony_ci
17840681896Sopenharmony_ciclass TopoLogical(object):
17940681896Sopenharmony_ci    def __init__(self, graph):
18040681896Sopenharmony_ci        self.order = None
18140681896Sopenharmony_ci        self.cycle = DirectedCycle(graph)
18240681896Sopenharmony_ci        if not self.cycle.has_cycle:
18340681896Sopenharmony_ci            dfo = DepthFirstOrder(graph)
18440681896Sopenharmony_ci            self.order = dfo.sort_vertices()
18540681896Sopenharmony_ci
18640681896Sopenharmony_ci    def stack(self):
18740681896Sopenharmony_ci        return self.order
188