From d97c106bfce69598cddc120cc286e0bc052419bf Mon Sep 17 00:00:00 2001 From: wuweikang Date: Mon, 10 Aug 2020 19:46:23 +0800 Subject: [PATCH] code sync for C75B100 master --- build.sh | 2 + inc/common/opskernel/ge_task_info.h | 18 + inc/common/opskernel/ops_kernel_info_store.h | 9 +- inc/common/opskernel/ops_kernel_info_types.h | 6 +- inc/common/optimizer/graph_optimizer.h | 2 + inc/common/util/compress/compress.h | 1 + inc/common/util/compress/compress_weight.h | 33 + inc/common/util/error_manager/error_manager.h | 25 +- inc/common/util/platform_info.h | 6 +- inc/common/util/platform_info_def.h | 14 + inc/external/ge/ge_api_error_codes.h | 2 +- inc/external/ge/ge_api_types.h | 20 +- inc/external/graph/attr_value.h | 2 + inc/external/graph/operator.h | 23 +- inc/external/graph/operator_reg.h | 1 + inc/external/graph/tensor.h | 1 + inc/external/graph/types.h | 3 +- inc/external/register/register.h | 4 + inc/framework/common/debug/ge_log.h | 24 - inc/framework/common/debug/log.h | 57 +- inc/framework/common/ge_inner_error_codes.h | 23 +- inc/framework/common/ge_types.h | 8 +- inc/framework/common/helper/model_helper.h | 2 - inc/framework/common/string_util.h | 6 +- inc/framework/common/types.h | 20 + inc/framework/executor/ge_executor.h | 66 +- inc/framework/ge_runtime/model_runner.h | 12 +- inc/framework/ge_runtime/task_info.h | 135 +- inc/framework/generator/ge_generator.h | 1 + inc/framework/memory/memory_api.h | 56 + inc/framework/omg/omg.h | 5 - inc/framework/omg/omg_inner_types.h | 1 + inc/graph/buffer.h | 6 +- inc/graph/compute_graph.h | 21 +- inc/graph/debug/ge_attr_define.h | 50 +- inc/graph/detail/any_map.h | 4 +- inc/graph/detail/attributes_holder.h | 18 +- inc/graph/detail/model_serialize_imp.h | 3 + inc/graph/ge_attr_value.h | 6 +- inc/graph/ge_context.h | 1 + inc/graph/ge_tensor.h | 7 +- inc/graph/model_serialize.h | 1 - inc/graph/node.h | 2 +- inc/graph/op_desc.h | 13 +- inc/graph/shape_refiner.h | 1 + inc/graph/utils/graph_utils.h | 44 +- inc/graph/utils/node_utils.h | 28 + inc/graph/utils/tensor_adapter.h | 1 + inc/graph/utils/tensor_utils.h | 1 + src/common/graph/CMakeLists.txt | 1 + src/common/graph/compute_graph.cc | 134 +- src/common/graph/debug/ge_op_types.h | 4 + src/common/graph/format_refiner.cc | 90 +- src/common/graph/format_refiner.h | 8 +- src/common/graph/ge_attr_define.cc | 50 +- src/common/graph/ge_attr_value.cc | 55 +- src/common/graph/ge_tensor.cc | 11 + src/common/graph/graph.cc | 2 +- src/common/graph/graph.mk | 76 +- src/common/graph/model_serialize.cc | 124 +- src/common/graph/node.cc | 57 +- src/common/graph/op_desc.cc | 201 ++- src/common/graph/operator.cc | 94 +- src/common/graph/opsproto/opsproto_manager.cc | 2 + src/common/graph/option/ge_context.cc | 2 + src/common/graph/ref_relation.cc | 51 +- src/common/graph/runtime_inference_context.cc | 1 + src/common/graph/shape_refiner.cc | 293 ++++- src/common/graph/stub/Makefile | 6 - src/common/graph/stub/gen_stubapi.py | 573 -------- src/common/graph/tensor.cc | 24 +- src/common/graph/utils/graph_utils.cc | 226 +++- src/common/graph/utils/node_utils.cc | 235 +++- src/common/graph/utils/op_desc_utils.cc | 76 +- src/common/graph/utils/tensor_utils.cc | 8 +- src/common/graph/utils/type_utils.cc | 3 +- src/ge/CMakeLists.txt | 30 +- src/ge/client/ge_api.cc | 57 +- src/ge/common/convert/pb2json.cc | 11 +- .../formats/format_transfers/datatype_transfer.cc | 1 - .../formats/format_transfers/datatype_transfer.h | 1 - .../format_transfer_dhwcn_fracz3D.cc | 1 - .../format_transfer_dhwnc_fracz3D_transpose.cc | 1 - .../format_transfers/format_transfer_fractal_nz.cc | 2 +- .../format_transfers/format_transfer_fractal_z.cc | 95 +- .../format_transfer_nchw_fz_c04.cc | 4 +- src/ge/common/formats/utils/formats_definitions.h | 2 - src/ge/common/formats/utils/formats_trans_utils.h | 2 - src/ge/common/fp16_t.h | 2 +- src/ge/common/ge/op_tiling_manager.cc | 81 ++ src/ge/common/ge/op_tiling_manager.h | 38 + src/ge/common/ge/tbe_plugin_manager.cc | 7 +- src/ge/common/ge/tbe_plugin_manager.h | 2 +- src/ge/common/ge_common.mk | 1 + src/ge/common/helper/model_helper.cc | 156 +-- src/ge/common/helper/om_file_helper.cc | 31 +- src/ge/common/math/fp16_math.h | 2 +- src/ge/common/math_util.h | 2 - src/ge/common/model_parser/base.cc | 29 +- src/ge/common/model_parser/graph_parser_util.cc | 501 +++++++ src/ge/common/model_parser/graph_parser_util.h | 62 + src/ge/common/model_saver.cc | 7 +- src/ge/common/profiling/profiling_manager.cc | 20 +- src/ge/common/properties_manager.cc | 320 +++-- src/ge/common/properties_manager.h | 68 +- src/ge/common/tbe_kernel_store.h | 1 - src/ge/common/types.cc | 198 +-- src/ge/common/util.cc | 135 +- src/ge/engine_manager/dnnengine_manager.cc | 44 +- src/ge/engine_manager/dnnengine_manager.h | 3 + src/ge/executor/CMakeLists.txt | 3 +- src/ge/executor/ge_executor.cc | 309 ++++- src/ge/executor/module.mk | 8 +- src/ge/ge_inference.mk | 20 +- .../ops_kernel_store/op/ge_deleted_op.cc | 1 + src/ge/ge_runner.mk | 47 +- src/ge/ge_runtime/model_runner.cc | 50 + src/ge/ge_runtime/output.cc | 2 +- src/ge/ge_runtime/runtime_model.cc | 91 +- src/ge/ge_runtime/runtime_model.h | 11 +- src/ge/ge_runtime/task/aicpu_task.cc | 14 +- src/ge/ge_runtime/task/aicpu_task.h | 6 + src/ge/ge_runtime/task/hccl_task.cc | 1 - src/ge/ge_runtime/task/label_goto_task.cc | 70 + src/ge/ge_runtime/task/label_goto_task.h | 41 + src/ge/ge_runtime/task/label_set_task.cc | 70 + src/ge/ge_runtime/task/label_set_task.h | 41 + src/ge/ge_runtime/task/label_switch_task.cc | 131 ++ src/ge/ge_runtime/task/label_switch_task.h | 44 + src/ge/ge_runtime/task/stream_switch_task.cc | 2 +- src/ge/ge_runtime/task/task.h | 6 + src/ge/ge_runtime/task/tbe_task.cc | 7 +- src/ge/ge_runtime/task/tbe_task.h | 4 + src/ge/ge_train.mk | 333 ----- src/ge/generator/ge_generator.cc | 201 ++- src/ge/graph/build/graph_builder.cc | 111 +- src/ge/graph/build/label_allocator.cc | 2 - src/ge/graph/build/logical_stream_allocator.cc | 62 +- src/ge/graph/build/logical_stream_allocator.h | 4 - src/ge/graph/build/memory/block_mem_assigner.cc | 521 ++++---- src/ge/graph/build/memory/block_mem_assigner.h | 66 +- src/ge/graph/build/memory/graph_mem_assigner.cc | 289 ++-- src/ge/graph/build/memory/graph_mem_assigner.h | 21 +- src/ge/graph/build/memory/var_mem_assign_util.cc | 40 +- src/ge/graph/build/memory/var_mem_assign_util.h | 4 +- src/ge/graph/build/model_builder.cc | 78 +- src/ge/graph/build/model_builder.h | 4 +- src/ge/graph/build/run_context.cc | 1 - src/ge/graph/build/stream_allocator.cc | 270 ++-- src/ge/graph/build/stream_allocator.h | 11 +- src/ge/graph/build/task_generator.cc | 229 +--- src/ge/graph/build/task_generator.h | 18 +- src/ge/graph/common/ge_call_wrapper.h | 50 + src/ge/graph/execute/graph_execute.cc | 48 +- src/ge/graph/execute/graph_execute.h | 21 +- src/ge/graph/label/while_label_maker.cc | 3 +- src/ge/graph/load/graph_loader.cc | 19 +- .../load/new_model_manager/cpu_queue_schedule.cc | 102 +- .../load/new_model_manager/cpu_queue_schedule.h | 3 +- src/ge/graph/load/new_model_manager/data_dumper.cc | 412 ++++-- src/ge/graph/load/new_model_manager/data_dumper.h | 34 +- .../graph/load/new_model_manager/davinci_model.cc | 1391 ++++++++++++-------- .../graph/load/new_model_manager/davinci_model.h | 180 ++- .../graph/load/new_model_manager/model_manager.cc | 232 ++-- .../graph/load/new_model_manager/model_manager.h | 24 +- src/ge/graph/load/new_model_manager/model_utils.cc | 248 ++-- src/ge/graph/load/new_model_manager/model_utils.h | 37 +- .../task_info/end_graph_task_info.cc | 11 +- .../task_info/end_graph_task_info.h | 10 +- .../task_info/event_record_task_info.cc | 2 +- .../task_info/event_wait_task_info.cc | 4 +- .../task_info/fusion_start_task_info.cc | 2 +- .../task_info/fusion_stop_task_info.cc | 2 +- .../new_model_manager/task_info/hccl_task_info.cc | 152 ++- .../new_model_manager/task_info/hccl_task_info.h | 15 +- .../task_info/kernel_ex_task_info.cc | 125 +- .../task_info/kernel_ex_task_info.h | 2 + .../task_info/kernel_task_info.cc | 273 ++-- .../new_model_manager/task_info/kernel_task_info.h | 14 + .../task_info/label_goto_ex_task_info.cc | 2 +- .../task_info/label_set_task_info.cc | 2 +- .../task_info/label_switch_by_index_task_info.cc | 37 +- .../task_info/label_switch_by_index_task_info.h | 7 +- .../task_info/memcpy_addr_async_task_info.cc | 109 +- .../task_info/memcpy_addr_async_task_info.h | 14 +- .../task_info/memcpy_async_task_info.cc | 107 +- .../task_info/memcpy_async_task_info.h | 14 +- .../task_info/profiler_trace_task_info.cc | 2 +- .../task_info/stream_active_task_info.cc | 2 +- .../task_info/stream_switch_task_info.cc | 45 +- .../task_info/stream_switch_task_info.h | 5 + .../task_info/stream_switchn_task_info.cc | 56 +- .../task_info/stream_switchn_task_info.h | 6 +- .../task_info/super_kernel/super_kernel.cc | 10 +- .../task_info/super_kernel/super_kernel.h | 15 +- .../task_info/super_kernel/super_kernel_factory.cc | 115 +- .../task_info/super_kernel/super_kernel_factory.h | 3 +- .../load/new_model_manager/task_info/task_info.h | 2 + .../task_info/task_info_factory.h | 2 +- .../load/new_model_manager/zero_copy_offset.cc | 220 ++++ .../load/new_model_manager/zero_copy_offset.h | 84 ++ .../graph/load/new_model_manager/zero_copy_task.cc | 33 +- .../graph/load/new_model_manager/zero_copy_task.h | 4 +- src/ge/graph/load/output/output.cc | 175 --- src/ge/graph/load/output/output.h | 94 -- src/ge/graph/manager/block_memory.h | 43 + src/ge/graph/manager/graph_caching_allocator.cc | 24 +- src/ge/graph/manager/graph_caching_allocator.h | 12 +- src/ge/graph/manager/graph_manager.cc | 176 ++- src/ge/graph/manager/graph_manager.h | 5 +- src/ge/graph/manager/graph_mem_allocator.h | 2 +- src/ge/graph/manager/graph_var_manager.cc | 7 +- src/ge/graph/manager/graph_var_manager.h | 2 +- src/ge/graph/manager/host_mem_manager.cc | 86 ++ src/ge/graph/manager/host_mem_manager.h | 73 + src/ge/graph/manager/memory_api.cc | 45 + src/ge/graph/manager/model_manager/event_manager.h | 4 +- src/ge/graph/manager/rdma_pool_allocator.cc | 179 +++ src/ge/graph/manager/rdma_pool_allocator.h | 71 + src/ge/graph/manager/trans_var_data_utils.cc | 20 +- src/ge/graph/manager/util/hcom_util.cc | 9 +- src/ge/graph/manager/util/hcom_util.h | 4 +- src/ge/graph/manager/util/rt_context_util.cc | 27 +- src/ge/graph/manager/util/rt_context_util.h | 13 +- src/ge/graph/optimize/graph_optimize.cc | 32 + src/ge/graph/optimize/graph_optimize.h | 11 +- src/ge/graph/optimize/mem_rw_conflict_optimize.cc | 712 ++++++++++ src/ge/graph/optimize/summary_optimize.cc | 3 +- src/ge/graph/partition/dynamic_shape_partition.cc | 124 +- src/ge/graph/partition/dynamic_shape_partition.h | 2 + src/ge/graph/partition/engine_place.cc | 6 +- src/ge/graph/partition/graph_partition.cc | 77 +- src/ge/graph/passes/atomic_addr_clean_pass.cc | 169 ++- src/ge/graph/passes/atomic_addr_clean_pass.h | 11 + src/ge/graph/passes/attach_stream_label_pass.cc | 291 ++++ src/ge/graph/passes/attach_stream_label_pass.h | 89 ++ src/ge/graph/passes/base_pass.cc | 10 +- src/ge/graph/passes/base_pass.h | 6 +- src/ge/graph/passes/bitcast_pass.cc | 148 +++ src/ge/graph/passes/bitcast_pass.h | 41 + src/ge/graph/passes/cast_remove_pass.cc | 1 - src/ge/graph/passes/cast_translate_pass.cc | 2 +- .../common_subexpression_elimination_pass.cc | 1 + src/ge/graph/passes/compile_nodes_pass.cc | 4 +- src/ge/graph/passes/cond_pass.cc | 4 +- src/ge/graph/passes/cond_remove_pass.cc | 19 +- src/ge/graph/passes/constant_folding_pass.cc | 35 + src/ge/graph/passes/constant_folding_pass.h | 6 + src/ge/graph/passes/control_trigger_pass.cc | 9 +- .../passes/end_of_sequence_add_control_pass.cc | 139 ++ .../passes/end_of_sequence_add_control_pass.h | 56 + src/ge/graph/passes/folding_pass.cc | 2 +- src/ge/graph/passes/hccl_memcpy_pass.cc | 26 +- src/ge/graph/passes/hccl_memcpy_pass.h | 2 - src/ge/graph/passes/identify_reference_pass.cc | 52 - src/ge/graph/passes/identity_pass.cc | 39 +- src/ge/graph/passes/infershape_pass.cc | 4 +- .../input_output_connection_identify_pass.cc | 193 +++ .../passes/input_output_connection_identify_pass.h | 75 ++ src/ge/graph/passes/iterator_op_pass.cc | 12 +- src/ge/graph/passes/iterator_op_pass.h | 2 +- src/ge/graph/passes/link_gen_mask_nodes_pass.cc | 7 + .../graph/passes/mark_graph_unknown_status_pass.cc | 35 + ...nce_pass.h => mark_graph_unknown_status_pass.h} | 15 +- src/ge/graph/passes/mark_same_addr_pass.cc | 66 + src/ge/graph/passes/mark_same_addr_pass.h | 32 + src/ge/graph/passes/memcpy_addr_async_pass.cc | 245 ++++ src/ge/graph/passes/memcpy_addr_async_pass.h | 51 + src/ge/graph/passes/merge_pass.cc | 2 +- src/ge/graph/passes/merge_to_stream_merge_pass.cc | 234 ++++ src/ge/graph/passes/merge_to_stream_merge_pass.h | 75 ++ src/ge/graph/passes/multi_batch_pass.cc | 251 ++-- src/ge/graph/passes/multi_batch_pass.h | 20 +- src/ge/graph/passes/net_output_pass.cc | 251 ++-- src/ge/graph/passes/net_output_pass.h | 28 +- src/ge/graph/passes/next_iteration_pass.cc | 110 +- src/ge/graph/passes/next_iteration_pass.h | 57 +- src/ge/graph/passes/pass_manager.cc | 1 + src/ge/graph/passes/permute_pass.cc | 3 - src/ge/graph/passes/print_op_pass.h | 2 +- src/ge/graph/passes/ref_identity_delete_op_pass.cc | 225 ++++ src/ge/graph/passes/ref_identity_delete_op_pass.h | 40 + src/ge/graph/passes/reshape_recovery_pass.cc | 9 +- .../graph/passes/resource_pair_add_control_pass.cc | 16 +- .../passes/resource_pair_remove_control_pass.cc | 16 +- .../passes/same_transdata_breadth_fusion_pass.cc | 33 +- .../passes/same_transdata_breadth_fusion_pass.h | 2 +- .../graph/passes/set_input_output_offset_pass.cc | 285 ++++ src/ge/graph/passes/set_input_output_offset_pass.h | 38 + src/ge/graph/passes/subgraph_pass.cc | 357 ++--- src/ge/graph/passes/subgraph_pass.h | 78 +- .../graph/passes/switch_dead_branch_elimination.cc | 2 +- src/ge/graph/passes/switch_logic_remove_pass.cc | 2 +- src/ge/graph/passes/switch_op_pass.cc | 1227 ----------------- .../graph/passes/switch_to_stream_switch_pass.cc | 755 +++++++++++ ...ch_op_pass.h => switch_to_stream_switch_pass.h} | 200 ++- src/ge/graph/passes/transop_breadth_fusion_pass.cc | 3 - src/ge/graph/passes/transop_depth_fusion_pass.cc | 3 - .../passes/transop_symmetry_elimination_pass.cc | 133 +- .../passes/transop_symmetry_elimination_pass.h | 15 + .../passes/transop_without_reshape_fusion_pass.cc | 3 - src/ge/graph/passes/transpose_transdata_pass.cc | 2 +- src/ge/graph/passes/var_is_initialized_op_pass.cc | 2 +- src/ge/graph/passes/variable_op_pass.cc | 34 +- src/ge/graph/passes/variable_op_pass.h | 1 + src/ge/graph/passes/variable_prepare_op_pass.cc | 319 +++-- src/ge/graph/passes/variable_prepare_op_pass.h | 13 +- src/ge/graph/passes/variable_ref_delete_op_pass.cc | 48 +- ...variable_ref_useless_control_out_delete_pass.cc | 1 - src/ge/graph/preprocess/graph_preprocess.cc | 718 +++------- src/ge/graph/preprocess/graph_preprocess.h | 8 +- src/ge/graph/preprocess/insert_op/ge_aipp_op.cc | 164 +-- .../preprocess/insert_op/util_insert_aipp_op.cc | 3 +- src/ge/graph/preprocess/multi_batch_copy_graph.cc | 130 +- src/ge/graph/preprocess/multi_batch_copy_graph.h | 4 + .../host_aicpu_engine/common/constant/constant.h | 30 + .../host_aicpu_engine/engine/host_aicpu_engine.cc | 74 ++ .../host_aicpu_engine/engine/host_aicpu_engine.h | 111 ++ src/ge/host_aicpu_engine/module.mk | 57 + .../ops_kernel_store/host_aicpu_ops_kernel_info.cc | 132 ++ .../ops_kernel_store/host_aicpu_ops_kernel_info.h | 88 ++ .../ops_kernel_store/op/assign_op.cc | 51 + .../ops_kernel_store/op/assign_op.h | 41 + .../ops_kernel_store/op/host_op.cc | 34 + .../ops_kernel_store/op/host_op.h | 36 + src/ge/host_aicpu_engine/ops_kernel_store/op/op.h | 45 + .../ops_kernel_store/op/op_factory.cc | 55 + .../ops_kernel_store/op/op_factory.h | 94 ++ .../ops_kernel_store/op/random_uniform_op.cc | 104 ++ .../ops_kernel_store/op/random_uniform_op.h | 45 + .../ops_kernel_store/op/variable_op.cc | 46 + .../ops_kernel_store/op/variable_op.h | 41 + src/ge/host_kernels/add_kernel.cc | 11 +- src/ge/host_kernels/broadcast_args_kernel.cc | 1 - src/ge/host_kernels/concat_offset_kernel.cc | 11 +- src/ge/host_kernels/dynamic_stitch_kernel.cc | 10 +- src/ge/host_kernels/empty_kernel.cc | 11 +- src/ge/host_kernels/expanddims_kernel.cc | 2 +- src/ge/host_kernels/floordiv_kernel.cc | 2 +- src/ge/host_kernels/floormod_kernel.cc | 2 +- src/ge/host_kernels/gather_v2_kernel.cc | 28 +- src/ge/host_kernels/identity_kernel.cc | 63 + src/ge/host_kernels/identity_kernel.h | 31 + src/ge/host_kernels/pack_kernel.cc | 9 +- src/ge/host_kernels/permute_kernel.cc | 4 +- src/ge/host_kernels/rank_kernel.cc | 6 +- src/ge/host_kernels/reduce_prod_kernel.cc | 24 +- src/ge/host_kernels/reformat_kernel.cc | 9 +- src/ge/host_kernels/reshape_kernel.cc | 2 +- src/ge/host_kernels/rsqrt_kernel.cc | 6 +- src/ge/host_kernels/slice_d_kernel.cc | 23 +- src/ge/host_kernels/slice_d_kernel.h | 1 + src/ge/host_kernels/slice_kernel.cc | 2 +- src/ge/host_kernels/ssd_prior_box_kernel.cc | 2 +- src/ge/host_kernels/strided_slice_kernel.cc | 39 +- src/ge/host_kernels/strided_slice_kernel.h | 1 + src/ge/host_kernels/sub_kernel.cc | 2 +- src/ge/host_kernels/transdata_kernel.cc | 2 +- src/ge/host_kernels/transpose_kernel.cc | 4 +- src/ge/hybrid/common/npu_memory_allocator.cc | 26 +- src/ge/hybrid/common/npu_memory_allocator.h | 21 +- src/ge/hybrid/common/tensor_value.cc | 4 +- src/ge/hybrid/common/tensor_value.h | 4 +- src/ge/hybrid/executor/hybrid_execution_context.cc | 31 +- src/ge/hybrid/executor/hybrid_execution_context.h | 26 +- .../hybrid/executor/hybrid_model_async_executor.cc | 107 +- .../hybrid/executor/hybrid_model_async_executor.h | 8 +- src/ge/hybrid/executor/hybrid_model_executor.cc | 103 +- src/ge/hybrid/executor/hybrid_model_executor.h | 17 +- src/ge/hybrid/executor/hybrid_profiler.cc | 3 +- src/ge/hybrid/executor/node_done_manager.cc | 41 +- src/ge/hybrid/executor/node_done_manager.h | 5 +- src/ge/hybrid/executor/node_state.cc | 131 +- src/ge/hybrid/executor/node_state.h | 77 +- src/ge/hybrid/executor/rt_callback_manager.cc | 1 - src/ge/hybrid/executor/subgraph_context.cc | 113 ++ src/ge/hybrid/executor/subgraph_context.h | 61 + src/ge/hybrid/executor/subgraph_executor.cc | 373 ++++++ src/ge/hybrid/executor/subgraph_executor.h | 101 ++ src/ge/hybrid/executor/worker/execution_engine.cc | 194 +-- src/ge/hybrid/executor/worker/execution_engine.h | 21 +- .../executor/worker/shape_inference_engine.cc | 236 +--- .../executor/worker/shape_inference_engine.h | 68 +- .../hybrid/executor/worker/task_compile_engine.cc | 170 +-- .../hybrid/executor/worker/task_compile_engine.h | 33 +- src/ge/hybrid/hybrid_davinci_model.cc | 13 +- src/ge/hybrid/hybrid_davinci_model.h | 2 + src/ge/hybrid/hybrid_davinci_model_stub.cc | 2 + src/ge/hybrid/model/graph_item.cc | 63 + src/ge/hybrid/model/graph_item.h | 64 + src/ge/hybrid/model/hybrid_model.cc | 61 +- src/ge/hybrid/model/hybrid_model.h | 48 +- src/ge/hybrid/model/hybrid_model_builder.cc | 587 ++++++--- src/ge/hybrid/model/hybrid_model_builder.h | 22 +- src/ge/hybrid/model/node_item.cc | 65 +- src/ge/hybrid/model/node_item.h | 20 +- .../node_executor/aicore/aicore_node_executor.cc | 304 ++--- .../node_executor/aicore/aicore_node_executor.h | 16 +- .../hybrid/node_executor/aicore/aicore_op_task.cc | 304 ++++- .../hybrid/node_executor/aicore/aicore_op_task.h | 51 +- .../node_executor/aicore/aicore_task_builder.cc | 110 +- .../node_executor/aicore/aicore_task_builder.h | 21 +- .../node_executor/aicore/aicore_task_compiler.cc | 13 +- .../hybrid/node_executor/aicpu/aicpu_ext_info.cc | 1 - src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.h | 1 - .../node_executor/aicpu/aicpu_node_executor.cc | 79 +- .../node_executor/aicpu/aicpu_node_executor.h | 4 +- .../compiledsubgraph/known_node_executor.cc | 32 +- .../node_executor/controlop/control_op_executor.cc | 344 +++++ .../node_executor/controlop/control_op_executor.h | 100 ++ .../node_executor/hccl/hccl_node_executor.cc | 207 +++ .../hybrid/node_executor/hccl/hccl_node_executor.h | 59 + .../hostaicpu/host_aicpu_node_executor.cc | 191 +++ .../hostaicpu/host_aicpu_node_executor.h | 83 ++ .../hostaicpu/kernel/assign_kernel.cc | 61 + .../node_executor/hostaicpu/kernel/assign_kernel.h | 42 + .../hybrid/node_executor/hostaicpu/kernel/kernel.h | 43 + .../node_executor/hostaicpu/kernel/no_op_kernel.cc | 33 + .../node_executor/hostaicpu/kernel/no_op_kernel.h | 42 + .../hostaicpu/kernel/random_uniform_kernel.cc | 145 ++ .../hostaicpu/kernel/random_uniform_kernel.h | 48 + .../hostaicpu/kernel/variable_kernel.cc | 43 + .../hostaicpu/kernel/variable_kernel.h | 42 + .../node_executor/hostaicpu/kernel_factory.cc | 55 + .../node_executor/hostaicpu/kernel_factory.h | 86 ++ .../hostcpu/ge_local_node_executor.cc | 35 +- .../node_executor/hostcpu/ge_local_node_executor.h | 13 +- src/ge/hybrid/node_executor/node_executor.cc | 122 +- src/ge/hybrid/node_executor/node_executor.h | 132 +- .../partitioned_call_node_executor.cc | 81 ++ .../partitioned_call_node_executor.h | 54 + src/ge/hybrid/node_executor/task_context.cc | 144 +- src/ge/hybrid/node_executor/task_context.h | 43 +- src/ge/inc/kernel_factory.h | 2 +- src/ge/init/gelib.cc | 47 +- src/ge/init/gelib.h | 6 +- src/ge/ir_build/atc_ir_common.cc | 277 ++-- src/ge/ir_build/atc_ir_common.h | 17 +- src/ge/ir_build/ge_ir_build.cc | 21 +- src/ge/model/ge_model.h | 2 +- src/ge/offline/main.cc | 252 ++-- src/ge/offline/module.mk | 2 +- src/ge/offline/single_op_parser.cc | 108 +- src/ge/offline/single_op_parser.h | 5 +- src/ge/opskernel_manager/ops_kernel_manager.cc | 6 +- src/ge/opskernel_manager/ops_kernel_manager.h | 2 + src/ge/session/inner_session.cc | 58 +- src/ge/session/omg.cc | 321 +---- src/ge/session/session_manager.cc | 10 +- src/ge/session/session_manager.h | 5 +- src/ge/single_op/single_op.cc | 135 +- src/ge/single_op/single_op.h | 21 + src/ge/single_op/single_op_manager.cc | 116 +- src/ge/single_op/single_op_manager.h | 17 +- src/ge/single_op/single_op_model.cc | 148 ++- src/ge/single_op/single_op_model.h | 10 +- src/ge/single_op/stream_resource.cc | 41 +- src/ge/single_op/stream_resource.h | 13 +- src/ge/single_op/task/aicpu_kernel_task_builder.cc | 56 + src/ge/single_op/task/aicpu_kernel_task_builder.h | 40 + src/ge/single_op/task/aicpu_task_builder.cc | 3 +- src/ge/single_op/task/aicpu_task_builder.h | 2 +- src/ge/single_op/task/build_task_utils.cc | 40 + src/ge/single_op/task/build_task_utils.h | 16 + src/ge/single_op/task/op_task.cc | 182 ++- src/ge/single_op/task/op_task.h | 63 +- src/ge/single_op/task/tbe_task_builder.cc | 70 +- src/ge/single_op/task/tbe_task_builder.h | 6 +- src/ge/stub/Makefile | 6 - src/ge/stub/README | 4 - src/ge/stub/gen_stubapi.py | 573 -------- tests/depends/cce/src/op_kernel_registry.cc | 16 - tests/st/resnet50/common.cc | 0 .../ut/ge/graph/passes/flow_ctrl_pass_unittest.cc | 0 .../folding_kernel/expanddims_kernel_unittest.cc | 0 tests/ut/ge/graph/passes/merge_pass_unittest.cc | 0 .../ut/ge/graph/passes/net_output_pass_unittest.cc | 0 tests/ut/ge/graph/passes/snapshot_pass_unittest.cc | 0 .../ut/ge/single_op/single_op_manager_unittest.cc | 0 tests/ut/ge/single_op/single_op_model_unittest.cc | 0 third_party/fwkacllib/inc/cce/fwk_adpt_struct.h | 9 + third_party/fwkacllib/inc/hccl/base.h | 11 + third_party/fwkacllib/inc/hccl/hcom.h | 6 +- third_party/fwkacllib/inc/mmpa/mmpa_api.h | 4 +- .../fwkacllib/inc/mmpa/sub_inc/mmpa_linux.h | 2 + third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_win.h | 1 + third_party/fwkacllib/inc/ops/all_ops.h | 2 + third_party/fwkacllib/inc/ops/array_ops.h | 37 + third_party/fwkacllib/inc/ops/ctc_ops.h | 72 +- .../fwkacllib/inc/ops/elewise_calculation_ops.h | 141 +- third_party/fwkacllib/inc/ops/hvd_ops.h | 77 ++ third_party/fwkacllib/inc/ops/image_ops.h | 34 + third_party/fwkacllib/inc/ops/internal_ops.h | 61 + third_party/fwkacllib/inc/ops/math_ops.h | 6 +- .../fwkacllib/inc/ops/matrix_calculation_ops.h | 88 +- third_party/fwkacllib/inc/ops/nn_batch_norm_ops.h | 103 +- third_party/fwkacllib/inc/ops/nn_calculation_ops.h | 347 +++-- third_party/fwkacllib/inc/ops/nn_detect_ops.h | 252 +++- third_party/fwkacllib/inc/ops/nn_norm_ops.h | 88 +- third_party/fwkacllib/inc/ops/nn_pooling_ops.h | 352 ++++- third_party/fwkacllib/inc/ops/nn_training_ops.h | 12 +- third_party/fwkacllib/inc/ops/nonlinear_fuc_ops.h | 8 +- third_party/fwkacllib/inc/ops/reduce_ops.h | 187 ++- third_party/fwkacllib/inc/ops/rnn.h | 9 +- third_party/fwkacllib/inc/ops/selection_ops.h | 50 +- .../fwkacllib/inc/ops/split_combination_ops.h | 9 +- third_party/fwkacllib/inc/ops/transformation_ops.h | 53 +- .../fwkacllib/inc/register/op_kernel_registry.h | 1 + third_party/fwkacllib/inc/register/op_registry.h | 15 +- third_party/fwkacllib/inc/register/op_tiling.h | 133 ++ third_party/fwkacllib/inc/runtime/base.h | 22 +- third_party/fwkacllib/inc/runtime/config.h | 4 +- third_party/fwkacllib/inc/runtime/context.h | 42 +- third_party/fwkacllib/inc/runtime/dev.h | 109 +- third_party/fwkacllib/inc/runtime/mem.h | 31 +- third_party/fwkacllib/inc/runtime/rt_model.h | 27 + third_party/fwkacllib/inc/toolchain/slog.h | 85 +- third_party/prebuild/aarch64/liberror_manager.so | Bin 0 -> 888880 bytes third_party/prebuild/aarch64/libslog.so | Bin 0 -> 150360 bytes third_party/prebuild/x86_64/liberror_manager.so | Bin 0 -> 852544 bytes third_party/prebuild/x86_64/libslog.so | Bin 89440 -> 103704 bytes 521 files changed, 23824 insertions(+), 11418 deletions(-) create mode 100644 inc/common/util/compress/compress_weight.h create mode 100644 inc/framework/memory/memory_api.h delete mode 100644 src/common/graph/stub/Makefile delete mode 100644 src/common/graph/stub/gen_stubapi.py create mode 100644 src/ge/common/ge/op_tiling_manager.cc create mode 100644 src/ge/common/ge/op_tiling_manager.h create mode 100644 src/ge/common/model_parser/graph_parser_util.cc create mode 100644 src/ge/common/model_parser/graph_parser_util.h create mode 100644 src/ge/ge_runtime/task/label_goto_task.cc create mode 100644 src/ge/ge_runtime/task/label_goto_task.h create mode 100644 src/ge/ge_runtime/task/label_set_task.cc create mode 100644 src/ge/ge_runtime/task/label_set_task.h create mode 100644 src/ge/ge_runtime/task/label_switch_task.cc create mode 100644 src/ge/ge_runtime/task/label_switch_task.h delete mode 100644 src/ge/ge_train.mk create mode 100644 src/ge/graph/load/new_model_manager/zero_copy_offset.cc create mode 100644 src/ge/graph/load/new_model_manager/zero_copy_offset.h delete mode 100644 src/ge/graph/load/output/output.cc delete mode 100644 src/ge/graph/load/output/output.h create mode 100644 src/ge/graph/manager/block_memory.h create mode 100644 src/ge/graph/manager/host_mem_manager.cc create mode 100644 src/ge/graph/manager/host_mem_manager.h create mode 100644 src/ge/graph/manager/memory_api.cc create mode 100644 src/ge/graph/manager/rdma_pool_allocator.cc create mode 100644 src/ge/graph/manager/rdma_pool_allocator.h create mode 100644 src/ge/graph/optimize/mem_rw_conflict_optimize.cc create mode 100644 src/ge/graph/passes/attach_stream_label_pass.cc create mode 100644 src/ge/graph/passes/attach_stream_label_pass.h create mode 100644 src/ge/graph/passes/bitcast_pass.cc create mode 100644 src/ge/graph/passes/bitcast_pass.h create mode 100644 src/ge/graph/passes/end_of_sequence_add_control_pass.cc create mode 100644 src/ge/graph/passes/end_of_sequence_add_control_pass.h delete mode 100644 src/ge/graph/passes/identify_reference_pass.cc create mode 100644 src/ge/graph/passes/input_output_connection_identify_pass.cc create mode 100644 src/ge/graph/passes/input_output_connection_identify_pass.h create mode 100644 src/ge/graph/passes/mark_graph_unknown_status_pass.cc rename src/ge/graph/passes/{identify_reference_pass.h => mark_graph_unknown_status_pass.h} (67%) create mode 100644 src/ge/graph/passes/mark_same_addr_pass.cc create mode 100644 src/ge/graph/passes/mark_same_addr_pass.h create mode 100644 src/ge/graph/passes/memcpy_addr_async_pass.cc create mode 100644 src/ge/graph/passes/memcpy_addr_async_pass.h create mode 100644 src/ge/graph/passes/merge_to_stream_merge_pass.cc create mode 100644 src/ge/graph/passes/merge_to_stream_merge_pass.h create mode 100644 src/ge/graph/passes/ref_identity_delete_op_pass.cc create mode 100644 src/ge/graph/passes/ref_identity_delete_op_pass.h create mode 100644 src/ge/graph/passes/set_input_output_offset_pass.cc create mode 100644 src/ge/graph/passes/set_input_output_offset_pass.h delete mode 100644 src/ge/graph/passes/switch_op_pass.cc create mode 100644 src/ge/graph/passes/switch_to_stream_switch_pass.cc rename src/ge/graph/passes/{switch_op_pass.h => switch_to_stream_switch_pass.h} (61%) create mode 100644 src/ge/host_aicpu_engine/common/constant/constant.h create mode 100644 src/ge/host_aicpu_engine/engine/host_aicpu_engine.cc create mode 100644 src/ge/host_aicpu_engine/engine/host_aicpu_engine.h create mode 100644 src/ge/host_aicpu_engine/module.mk create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/op.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.h create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.cc create mode 100644 src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.h create mode 100644 src/ge/host_kernels/identity_kernel.cc create mode 100644 src/ge/host_kernels/identity_kernel.h create mode 100644 src/ge/hybrid/executor/subgraph_context.cc create mode 100644 src/ge/hybrid/executor/subgraph_context.h create mode 100644 src/ge/hybrid/executor/subgraph_executor.cc create mode 100644 src/ge/hybrid/executor/subgraph_executor.h create mode 100644 src/ge/hybrid/model/graph_item.cc create mode 100644 src/ge/hybrid/model/graph_item.h create mode 100644 src/ge/hybrid/node_executor/controlop/control_op_executor.cc create mode 100644 src/ge/hybrid/node_executor/controlop/control_op_executor.h create mode 100644 src/ge/hybrid/node_executor/hccl/hccl_node_executor.cc create mode 100644 src/ge/hybrid/node_executor/hccl/hccl_node_executor.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/kernel.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.h create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel_factory.cc create mode 100644 src/ge/hybrid/node_executor/hostaicpu/kernel_factory.h create mode 100644 src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc create mode 100644 src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.h create mode 100644 src/ge/single_op/task/aicpu_kernel_task_builder.cc create mode 100644 src/ge/single_op/task/aicpu_kernel_task_builder.h delete mode 100644 src/ge/stub/Makefile delete mode 100644 src/ge/stub/README delete mode 100644 src/ge/stub/gen_stubapi.py mode change 100755 => 100644 tests/st/resnet50/common.cc mode change 100755 => 100644 tests/ut/ge/graph/passes/flow_ctrl_pass_unittest.cc mode change 100755 => 100644 tests/ut/ge/graph/passes/folding_kernel/expanddims_kernel_unittest.cc mode change 100755 => 100644 tests/ut/ge/graph/passes/merge_pass_unittest.cc mode change 100755 => 100644 tests/ut/ge/graph/passes/net_output_pass_unittest.cc mode change 100755 => 100644 tests/ut/ge/graph/passes/snapshot_pass_unittest.cc mode change 100755 => 100644 tests/ut/ge/single_op/single_op_manager_unittest.cc mode change 100755 => 100644 tests/ut/ge/single_op/single_op_model_unittest.cc create mode 100644 third_party/fwkacllib/inc/ops/hvd_ops.h create mode 100644 third_party/fwkacllib/inc/ops/internal_ops.h create mode 100644 third_party/fwkacllib/inc/register/op_tiling.h create mode 100755 third_party/prebuild/aarch64/liberror_manager.so create mode 100755 third_party/prebuild/aarch64/libslog.so create mode 100755 third_party/prebuild/x86_64/liberror_manager.so diff --git a/build.sh b/build.sh index 0afaa7fb..1871bbb8 100644 --- a/build.sh +++ b/build.sh @@ -174,9 +174,11 @@ echo "---------------- GraphEngine output generated ----------------" # generate output package in tar form, including ut/st libraries/executables cd ${BASEPATH} mkdir -p output/plugin/nnengine/ge_config/ +mkdir -p output/plugin/opskernel/ find output/ -name graphengine_lib.tar -exec rm {} \; cp src/ge/engine_manager/engine_conf.json output/plugin/nnengine/ge_config/ find output/ -maxdepth 1 -name libengine.so -exec mv -f {} output/plugin/nnengine/ \; +find output/ -maxdepth 1 -name libge_local_engine.so -exec mv -f {} output/plugin/opskernel/ \; tar -cf graphengine_lib.tar output/* mv -f graphengine_lib.tar output echo "---------------- GraphEngine package archive generated ----------------" diff --git a/inc/common/opskernel/ge_task_info.h b/inc/common/opskernel/ge_task_info.h index 360f8a5d..9f3c409d 100644 --- a/inc/common/opskernel/ge_task_info.h +++ b/inc/common/opskernel/ge_task_info.h @@ -52,5 +52,23 @@ struct GETaskInfo { std::vector kernelHcclInfo; }; + +struct HcomOpertion { + std::string hcclType; + void *inputPtr; + void *outputPtr; + uint64_t count; + int32_t dataType; + int32_t opType; + int32_t root; +}; + +struct HcomRemoteAccessAddrInfo { + uint32_t remotetRankID; + uint64_t remoteAddr; // host embedding table address + uint64_t localAddr; // device HBM address + uint64_t length; // memory Length in Bytes +}; + } // namespace ge #endif // INC_COMMON_OPSKERNEL_GE_TASK_INFO_H_ diff --git a/inc/common/opskernel/ops_kernel_info_store.h b/inc/common/opskernel/ops_kernel_info_store.h index 46338e45..ce1464d4 100644 --- a/inc/common/opskernel/ops_kernel_info_store.h +++ b/inc/common/opskernel/ops_kernel_info_store.h @@ -43,10 +43,10 @@ class OpsKernelInfoStore { virtual ~OpsKernelInfoStore() {} // initialize opsKernelInfoStore - virtual Status Initialize(const map &options) = 0; + virtual Status Initialize(const map &options) = 0; /*lint -e148*/ // close opsKernelInfoStore - virtual Status Finalize() = 0; + virtual Status Finalize() = 0; /*lint -e148*/ virtual Status CreateSession(const std::map &session_options) { return SUCCESS; } @@ -66,10 +66,11 @@ class OpsKernelInfoStore { virtual void opsFlagCheck(const ge::Node &node, std::string &opsFlag){}; // memory allocation requirement - virtual Status CalcOpRunningParam(Node &node) = 0; + virtual Status CalcOpRunningParam(Node &node) = 0; /*lint -e148*/ // generate task for op。 - virtual Status GenerateTask(const Node &node, RunContext &context, std::vector &tasks) = 0; + virtual Status GenerateTask(const Node &node, RunContext &context, + std::vector &tasks) = 0; /*lint -e148*/ // only call fe engine interface to compile single op virtual Status CompileOp(vector &node_vec) { return SUCCESS; } diff --git a/inc/common/opskernel/ops_kernel_info_types.h b/inc/common/opskernel/ops_kernel_info_types.h index d13840bd..684c1abc 100644 --- a/inc/common/opskernel/ops_kernel_info_types.h +++ b/inc/common/opskernel/ops_kernel_info_types.h @@ -26,6 +26,7 @@ using std::string; namespace ge { +/*lint -e148*/ struct RunContext { rtModel_t model; rtStream_t stream; @@ -40,6 +41,8 @@ struct RunContext { std::vector graphLabelList; // all labels of graph, order by ge label id(0,1,...) }; +/*lint +e148*/ + struct Task { uint32_t id; uint16_t type; @@ -48,7 +51,8 @@ struct Task { }; struct OpInfo { - string engine; // which engin + string engine; // which engin + /*lint -e148*/ string opKernelLib; // which opsKernelStore int computeCost; // compute cost bool flagPartial; // whether to support is related to shape diff --git a/inc/common/optimizer/graph_optimizer.h b/inc/common/optimizer/graph_optimizer.h index 5897842f..c330dd63 100644 --- a/inc/common/optimizer/graph_optimizer.h +++ b/inc/common/optimizer/graph_optimizer.h @@ -27,6 +27,7 @@ using std::map; using std::string; +/*lint -e148*/ namespace ge { class GraphOptimizer { public: @@ -60,4 +61,5 @@ class GraphOptimizer { virtual Status OptimizeStreamGraph(ComputeGraph &graph, const RunContext &context) { return SUCCESS; } }; } // namespace ge +/*lint +e148*/ #endif // INC_COMMON_OPTIMIZER_GRAPH_OPTIMIZER_H_ diff --git a/inc/common/util/compress/compress.h b/inc/common/util/compress/compress.h index 6908fb75..e350f9e5 100644 --- a/inc/common/util/compress/compress.h +++ b/inc/common/util/compress/compress.h @@ -28,6 +28,7 @@ struct CompressConfig { size_t channel; // channels of L2 or DDR. For load balance size_t fractalSize; // size of compressing block bool isTight; // whether compose compressed data tightly + size_t init_offset; }; CmpStatus CompressWeights(char* input, const CompressConfig& compressConfig, char* indexs, char* output, diff --git a/inc/common/util/compress/compress_weight.h b/inc/common/util/compress/compress_weight.h new file mode 100644 index 00000000..34ea47d1 --- /dev/null +++ b/inc/common/util/compress/compress_weight.h @@ -0,0 +1,33 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef COMPRESS_WEIGHT_H +#define COMPRESS_WEIGHT_H + +#include "compress.h" + +const int SHAPE_SIZE_WEIGHT = 4; + +struct CompressOpConfig { + int64_t wShape[SHAPE_SIZE_WEIGHT]; + size_t compressTilingK; + size_t compressTilingN; + struct CompressConfig compressConfig; +}; + +extern "C" CmpStatus CompressWeightsConv2D(const char *const input, char *const zipBuffer, char *const infoBuffer, + CompressOpConfig *const param); +#endif // COMPRESS_WEIGHT_H diff --git a/inc/common/util/error_manager/error_manager.h b/inc/common/util/error_manager/error_manager.h index 76d5ce33..438e68a7 100644 --- a/inc/common/util/error_manager/error_manager.h +++ b/inc/common/util/error_manager/error_manager.h @@ -31,27 +31,37 @@ class ErrorManager { /// /// @brief init - /// @param [in] path current so path + /// @param [in] path: current so path /// @return int 0(success) -1(fail) /// int Init(std::string path); /// /// @brief Report error message - /// @param [in] errCode error code - /// @param [in] mapArgs parameter map + /// @param [in] error_code: error code + /// @param [in] args_map: parameter map /// @return int 0(success) -1(fail) /// int ReportErrMessage(std::string error_code, const std::map &args_map); + /// /// @brief output error message - /// @param [in] handle print handle + /// @param [in] handle: print handle /// @return int 0(success) -1(fail) /// int OutputErrMessage(int handle); + /// + /// @brief output message + /// @param [in] handle: print handle + /// @return int 0(success) -1(fail) + /// + int OutputMessage(int handle); + + /// /// @brief Report error message - /// @param [in] vector parameter key, vector parameter value + /// @param [in] key: vector parameter key + /// @param [in] value: vector parameter value /// void ATCReportErrMessage(std::string error_code, const std::vector &key = {}, const std::vector &value = {}); @@ -60,7 +70,7 @@ class ErrorManager { struct ErrorInfo { std::string error_id; std::string error_message; - std::vector arglist; + std::vector arg_list; }; ErrorManager() {} @@ -77,7 +87,8 @@ class ErrorManager { bool is_init_ = false; std::map error_map_; - std::vector error_message_evc_; + std::vector error_messages_; + std::vector warning_messages_; }; #endif // ERROR_MANAGER_H_ diff --git a/inc/common/util/platform_info.h b/inc/common/util/platform_info.h index cd143fcc..8d2a0579 100644 --- a/inc/common/util/platform_info.h +++ b/inc/common/util/platform_info.h @@ -27,7 +27,6 @@ using std::string; using std::vector; namespace fe { - class PlatformInfoManager { public: PlatformInfoManager(const PlatformInfoManager &) = delete; @@ -39,6 +38,8 @@ class PlatformInfoManager { uint32_t GetPlatformInfo(const string SoCVersion, PlatformInfo &platformInfo, OptionalInfo &optiCompilationInfo); + uint32_t GetPlatformInfoWithOutSocVersion(PlatformInfo &platformInfo, OptionalInfo &optiCompilationInfo); + void SetOptionalCompilationInfo(OptionalInfo &optiCompilationInfo); private: @@ -81,6 +82,8 @@ class PlatformInfoManager { void ParseVectorCoreMemoryRates(map &vectorCoreMemoryRatesMap, PlatformInfo &platformInfoTemp); + void ParseCPUCache(map &CPUCacheMap, PlatformInfo &platformInfoTemp); + void ParseVectorCoreintrinsicDtypeMap(map &vectorCoreintrinsicDtypeMap, PlatformInfo &platformInfoTemp); @@ -94,6 +97,5 @@ class PlatformInfoManager { map platformInfoMap_; OptionalInfo optiCompilationInfo_; }; - } // namespace fe #endif diff --git a/inc/common/util/platform_info_def.h b/inc/common/util/platform_info_def.h index e840a8b9..c660e8f1 100644 --- a/inc/common/util/platform_info_def.h +++ b/inc/common/util/platform_info_def.h @@ -73,6 +73,8 @@ typedef struct tagAiCoreSpec { typedef struct tagAiCoreMemoryRates { double ddrRate; + double ddrReadRate; + double ddrWriteRate; double l2Rate; double l2ReadRate; double l2WriteRate; @@ -86,6 +88,7 @@ typedef struct tagAiCoreMemoryRates { } AiCoreMemoryRates; typedef struct tagVectorCoreSpec { + double vecFreq; uint64_t vecCalcSize; uint64_t smaskBuffer; uint64_t ubSize; @@ -94,10 +97,15 @@ typedef struct tagVectorCoreSpec { uint64_t ubbankNum; uint64_t ubburstInOneBlock; uint64_t ubbankGroupNum; + uint64_t vectorRegSize; + uint64_t predicateRegSize; + uint64_t addressRegSize; } VectorCoreSpec; typedef struct tagVectorCoreMemoryRates { double ddrRate; + double ddrReadRate; + double ddrWriteRate; double l2Rate; double l2ReadRate; double l2WriteRate; @@ -105,6 +113,11 @@ typedef struct tagVectorCoreMemoryRates { double ubToDdrRate; } VectorCoreMemoryRates; +typedef struct tagCPUCache { + uint32_t AICPUSyncBySW; + uint32_t TSCPUSyncBySW; +} CPUCache; + typedef struct tagPlatformInfo { StrInfo strInfo; SoCInfo socInfo; @@ -113,6 +126,7 @@ typedef struct tagPlatformInfo { map> aiCoreIntrinsicDtypeMap; VectorCoreSpec vectorCoreSpec; VectorCoreMemoryRates vectorCoreMemoryRates; + CPUCache cpucache; map> vectorCoreIntrinsicDtypeMap; } PlatformInfo; diff --git a/inc/external/ge/ge_api_error_codes.h b/inc/external/ge/ge_api_error_codes.h index e7f52724..7b045d54 100644 --- a/inc/external/ge/ge_api_error_codes.h +++ b/inc/external/ge/ge_api_error_codes.h @@ -70,7 +70,7 @@ using Status = uint32_t; // General error code GE_ERRORNO(0, 0, 0, 0, 0, SUCCESS, 0, "success"); -GE_ERRORNO(0b11, 0b11, 0b111, 0xFF, 0b11111, FAILED, 0xFFF, "failed"); +GE_ERRORNO(0b11, 0b11, 0b111, 0xFF, 0b11111, FAILED, 0xFFF, "failed"); /*lint !e401*/ } // namespace ge #endif // INC_EXTERNAL_GE_GE_API_ERROR_CODES_H_ diff --git a/inc/external/ge/ge_api_types.h b/inc/external/ge/ge_api_types.h index 1632f11c..619812d7 100644 --- a/inc/external/ge/ge_api_types.h +++ b/inc/external/ge/ge_api_types.h @@ -44,8 +44,11 @@ const char *const OPTION_EXEC_ENABLE_DUMP = "ge.exec.enableDump"; const char *const OPTION_EXEC_DUMP_PATH = "ge.exec.dumpPath"; const char *const OPTION_EXEC_DUMP_STEP = "ge.exec.dumpStep"; const char *const OPTION_EXEC_DUMP_MODE = "ge.exec.dumpMode"; +const char *const OPTION_EXEC_ENABLE_DUMP_DEBUG = "ge.exec.enableDumpDebug"; +const char *const OPTION_EXEC_DUMP_DEBUG_MODE = "ge.exec.dumpDebugMode"; const char *const OPTION_EXEC_ENABLE_INCRE_BUILD = "ge.exec.enableIncreBuild"; const char *const OPTION_EXEC_INCRE_BUILD_CACHE_PATH = "ge.exec.increBuildCachePath"; +const char *const OPTION_EXEC_ENABLE_SCOPE_FUSION_PASSES = "ge.exec.enableScopeFusionPasses"; // profiling flag const char *const OPTION_EXEC_PROFILING_MODE = "ge.exec.profilingMode"; const char *const OPTION_EXEC_PROFILING_OPTIONS = "ge.exec.profilingOptions"; @@ -170,6 +173,9 @@ const char *const kDynamicBatchSize = "ge.dynamicBatchSize"; // configure whether to use dynamic image size const char *const kDynamicImageSize = "ge.dynamicImageSize"; +// Configure whether to use dynamic dims +const char *const kDynamicDims = "ge.dynamicDims"; + // Configure auto tune mode, this option only take effect while AUTO_TUNE_FLAG is Y, // example: GA|RL, support configure multiple, split by | const std::string AUTO_TUNE_MODE = "ge.autoTuneMode"; @@ -219,6 +225,10 @@ const char *const ENABLE_SINGLE_STREAM = "ge.enableSingleStream"; // Configure input fp16 nodes const std::string INPUT_FP16_NODES = "ge.INPUT_NODES_SET_FP16"; +// Configure debug level, its value should be 0(default), 1 or 2. +// 0: close debug; 1: open TBE compiler; 2: open ccec compiler +const std::string OP_DEBUG_LEVEL = "ge.opDebugLevel"; + // Graph run mode enum GraphRunMode { PREDICTION = 0, TRAIN }; @@ -261,6 +271,7 @@ static const char *const INPUT_SHAPE = "input_shape"; static const char *const OP_NAME_MAP = "op_name_map"; static const char *const DYNAMIC_BATCH_SIZE = kDynamicBatchSize; static const char *const DYNAMIC_IMAGE_SIZE = kDynamicImageSize; +static const char *const DYNAMIC_DIMS = kDynamicDims; static const char *const INSERT_OP_FILE = ge::INSERT_OP_FILE.c_str(); static const char *const PRECISION_MODE = ge::PRECISION_MODE.c_str(); static const char *const EXEC_DISABLE_REUSED_MEMORY = ge::OPTION_EXEC_DISABLE_REUSED_MEMORY; @@ -283,10 +294,11 @@ static const char *const OPTYPELIST_FOR_IMPLMODE = ge::OPTYPELIST_FOR_IMPLMODE.c // for interface: aclgrphBuildModel const std::set ir_builder_suppported_options = { - INPUT_FORMAT, INPUT_SHAPE, OP_NAME_MAP, DYNAMIC_BATCH_SIZE, - DYNAMIC_IMAGE_SIZE, INSERT_OP_FILE, PRECISION_MODE, EXEC_DISABLE_REUSED_MEMORY, - AUTO_TUNE_MODE, OUTPUT_TYPE, OUT_NODES, INPUT_FP16_NODES, - LOG_LEVEL}; + INPUT_FORMAT, INPUT_SHAPE, OP_NAME_MAP, + DYNAMIC_BATCH_SIZE, DYNAMIC_IMAGE_SIZE, DYNAMIC_DIMS, + INSERT_OP_FILE, PRECISION_MODE, EXEC_DISABLE_REUSED_MEMORY, + AUTO_TUNE_MODE, OUTPUT_TYPE, OUT_NODES, + INPUT_FP16_NODES, LOG_LEVEL}; // for interface: aclgrphBuildInitialize const std::set global_options = {CORE_TYPE, SOC_VERSION, diff --git a/inc/external/graph/attr_value.h b/inc/external/graph/attr_value.h index 32fce04c..af430f9b 100644 --- a/inc/external/graph/attr_value.h +++ b/inc/external/graph/attr_value.h @@ -34,6 +34,7 @@ using std::vector; namespace ge { class AttrValueImpl; +/*lint -e148*/ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AttrValue { public: using INT = int64_t; @@ -69,5 +70,6 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AttrValue { VALUE_SET_GET_DEC(AttrValue::FLOAT) #undef VALUE_SET_GET_DEC }; +/*lint +e148*/ } // namespace ge #endif // INC_EXTERNAL_GRAPH_ATTR_VALUE_H_ diff --git a/inc/external/graph/operator.h b/inc/external/graph/operator.h index 4f837b9d..2dcdb773 100644 --- a/inc/external/graph/operator.h +++ b/inc/external/graph/operator.h @@ -61,6 +61,7 @@ using std::function; using std::shared_ptr; using std::string; +/*lint -e148*/ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { public: friend class OperatorImpl; @@ -88,7 +89,7 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { explicit Operator(const string &type); - Operator(const string &name, const string &type); + Operator(const string &name, const string &type); // lint !e148 virtual ~Operator() = default; @@ -101,7 +102,7 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { // Only has one output index = 0 Operator &SetInput(const string &dst_name, const Operator &src_oprt); - Operator &SetInput(const string &dst_name, const Operator &src_oprt, const string &name); + Operator &SetInput(const string &dst_name, const Operator &src_oprt, const string &name); // lint !e148 Operator &AddControlInput(const Operator &src_oprt); @@ -123,22 +124,22 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { TensorDesc GetOutputDesc(uint32_t index) const; - graphStatus UpdateOutputDesc(const string &name, const TensorDesc &tensor_desc); + graphStatus UpdateOutputDesc(const string &name, const TensorDesc &tensor_desc); // lint !e148 TensorDesc GetDynamicInputDesc(const string &name, uint32_t index) const; - graphStatus UpdateDynamicInputDesc(const string &name, uint32_t index, const TensorDesc &tensor_desc); + graphStatus UpdateDynamicInputDesc(const string &name, uint32_t index, const TensorDesc &tensor_desc); // lint !e148 TensorDesc GetDynamicOutputDesc(const string &name, uint32_t index) const; - graphStatus UpdateDynamicOutputDesc(const string &name, uint32_t index, const TensorDesc &tensor_desc); + graphStatus UpdateDynamicOutputDesc(const string &name, uint32_t index, const TensorDesc &tensor_desc); // lint !e148 - graphStatus InferShapeAndType(); + graphStatus InferShapeAndType(); // lint !e148 void SetInferenceContext(const InferenceContextPtr &inference_context); InferenceContextPtr GetInferenceContext() const; - graphStatus VerifyAllAttr(bool disable_common_verifier = false); + graphStatus VerifyAllAttr(bool disable_common_verifier = false); // lint !e148 size_t GetInputsSize() const; @@ -251,19 +252,20 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { void RequiredAttrRegister(const string &name); - graphStatus VerifyAll(); + graphStatus VerifyAll(); // lint !e148 // Only has one output index = 0 Operator &SetInput(const string &dst_name, uint32_t dst_index, const Operator &src_oprt); - Operator &SetInput(const string &dst_name, uint32_t dst_index, const Operator &src_oprt, const string &name); + Operator &SetInput(const string &dst_name, uint32_t dst_index, const Operator &src_oprt, + const string &name); // lint !e148 void SubgraphRegister(const string &ir_name, bool dynamic); void SubgraphCountRegister(const string &ir_name, uint32_t count); void SetSubgraphBuilder(const string &ir_name, uint32_t index, const SubgraphBuilder &builder); private: - Operator &SetInput(const string &dst_name, const OutHandler &out_handler); + Operator &SetInput(const string &dst_name, const OutHandler &out_handler); // lint !e148 OutHandler GetOutput(const string &name) const; @@ -273,6 +275,7 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Operator { graphStatus GetInputConstDataOut(const string &dst_name, Tensor &data) const; }; +/*lint +e148*/ } // namespace ge #endif // INC_EXTERNAL_GRAPH_OPERATOR_H_ diff --git a/inc/external/graph/operator_reg.h b/inc/external/graph/operator_reg.h index dfa21acf..d155f4bd 100644 --- a/inc/external/graph/operator_reg.h +++ b/inc/external/graph/operator_reg.h @@ -343,6 +343,7 @@ class OpReg { auto x_type = op.GetInputDesc(in_name).GetDataType(); \ TensorDesc op_output_desc = op.GetOutputDesc(out_name); \ op_output_desc.SetShape(ge::Shape(x_shape)); \ + op_output_desc.SetOriginShape(ge::Shape(x_shape)); \ op_output_desc.SetDataType(x_type); \ return op.UpdateOutputDesc(out_name, op_output_desc); \ } diff --git a/inc/external/graph/tensor.h b/inc/external/graph/tensor.h index 5174c248..800e1037 100644 --- a/inc/external/graph/tensor.h +++ b/inc/external/graph/tensor.h @@ -126,5 +126,6 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Tensor { friend class TensorAdapter; }; } // namespace ge +/*lint +e148*/ #endif // INC_EXTERNAL_GRAPH_TENSOR_H_ diff --git a/inc/external/graph/types.h b/inc/external/graph/types.h index 4cd9ba91..a1245c9d 100644 --- a/inc/external/graph/types.h +++ b/inc/external/graph/types.h @@ -145,7 +145,8 @@ enum Format { FORMAT_FRACTAL_ZN_LSTM, FORMAT_FRACTAL_Z_G, FORMAT_RESERVED, - FORMAT_ALL + FORMAT_ALL, + FORMAT_NULL }; // for unknown shape op type diff --git a/inc/external/register/register.h b/inc/external/register/register.h index a8421511..e905e8d4 100644 --- a/inc/external/register/register.h +++ b/inc/external/register/register.h @@ -40,6 +40,7 @@ using std::to_string; using std::unique_ptr; using std::vector; +/*lint -e148*/ namespace ge { class Operator; class TensorDesc; @@ -98,6 +99,8 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY OpRegistrationData { OpRegistrationData &DelInputWithOriginalType(int input_idx, const std::string &ori_type); + OpRegistrationData &InputReorderVector(const vector &input_order); + domi::ImplyType GetImplyType() const; std::string GetOmOptype() const; std::set GetOriginOpTypeSet() const; @@ -130,4 +133,5 @@ namespace ge { using OpRegistrationData = domi::OpRegistrationData; using OpReceiver = domi::OpReceiver; } // namespace ge +/*lint +e148*/ #endif // INC_EXTERNAL_REGISTER_REGISTER_H_ diff --git a/inc/framework/common/debug/ge_log.h b/inc/framework/common/debug/ge_log.h index e2023cb8..6ac00037 100644 --- a/inc/framework/common/debug/ge_log.h +++ b/inc/framework/common/debug/ge_log.h @@ -51,30 +51,6 @@ inline pid_t GetTid() { return tid; } -#define GE_TIMESTAMP_START(stage) uint64_t startUsec_##stage = ge::GetCurrentTimestap() - -#define GE_TIMESTAMP_END(stage, stage_name) \ - do { \ - uint64_t endUsec_##stage = ge::GetCurrentTimestap(); \ - GEEVENT("[GEPERFTRACE] The time cost of %s is [%lu] micro second.", (stage_name), \ - (endUsec_##stage - startUsec_##stage)); \ - } while (0); - -#define GE_TIMESTAMP_CALLNUM_START(stage) \ - uint64_t startUsec_##stage = ge::GetCurrentTimestap(); \ - uint64_t call_num_of##stage = 0; \ - uint64_t time_of##stage = 0 - -#define GE_TIMESTAMP_RESTART(stage) (startUsec_##stage = ge::GetCurrentTimestap()) - -#define GE_TIMESTAMP_ADD(stage) \ - time_of##stage += ge::GetCurrentTimestap() - startUsec_##stage; \ - call_num_of##stage++ - -#define GE_TIMESTAMP_CALLNUM_END(stage, stage_name) \ - GEEVENT("[GEPERFTRACE] The time cost of %s is [%lu] micro second, call num is %lu", (stage_name), time_of##stage, \ - call_num_of##stage) - #define GE_LOG_ERROR(MOD_NAME, ERROR_CODE, fmt, ...) \ dlog_error(MOD_NAME, "%lu %s: ErrorNo: %d(%s) " fmt, GetTid(), __FUNCTION__, ERROR_CODE, \ ((GE_GET_ERRORNO_STR(ERROR_CODE)).c_str()), ##__VA_ARGS__) diff --git a/inc/framework/common/debug/log.h b/inc/framework/common/debug/log.h index 28c6585e..dbf22ead 100644 --- a/inc/framework/common/debug/log.h +++ b/inc/framework/common/debug/log.h @@ -19,15 +19,12 @@ #include -#include "cce/cce_def.hpp" +#include "runtime/rt.h" #include "common/string_util.h" #include "common/util.h" #include "framework/common/debug/ge_log.h" #include "ge/ge_api_error_codes.h" -using cce::CC_STATUS_SUCCESS; -using cce::ccStatus_t; - #if !defined(__ANDROID__) && !defined(ANDROID) #define DOMI_LOGE(...) GE_LOG_ERROR(GE_MODULE_NAME, ge::FAILED, __VA_ARGS__) #else @@ -102,17 +99,13 @@ using cce::ccStatus_t; } while (0); // If expr is not true, print the log and return the specified status -#define GE_CHK_BOOL_RET_STATUS(expr, _status, ...) \ - do { \ - bool b = (expr); \ - if (!b) { \ - std::string msg; \ - (void)msg.append(ge::StringUtils::FormatString(__VA_ARGS__)); \ - (void)msg.append( \ - ge::StringUtils::FormatString(" Error Code:0x%X(%s)", _status, GET_ERRORNO_STR(_status).c_str())); \ - DOMI_LOGE("%s", msg.c_str()); \ - return _status; \ - } \ +#define GE_CHK_BOOL_RET_STATUS(expr, _status, ...) \ + do { \ + bool b = (expr); \ + if (!b) { \ + GELOGE(_status, __VA_ARGS__); \ + return _status; \ + } \ } while (0); // If expr is not true, print the log and return the specified status @@ -132,7 +125,7 @@ using cce::ccStatus_t; DOMI_LOGE(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is not true, print the log and execute a custom statement #define GE_CHK_BOOL_EXEC_WARN(expr, exec_expr, ...) \ @@ -142,7 +135,7 @@ using cce::ccStatus_t; GELOGW(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is not true, print the log and execute a custom statement #define GE_CHK_BOOL_EXEC_INFO(expr, exec_expr, ...) \ { \ @@ -151,7 +144,7 @@ using cce::ccStatus_t; GELOGI(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is not true, print the log and execute a custom statement #define GE_CHK_BOOL_TRUE_EXEC_INFO(expr, exec_expr, ...) \ @@ -161,7 +154,7 @@ using cce::ccStatus_t; GELOGI(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is true, print logs and execute custom statements #define GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(expr, exec_expr, ...) \ @@ -171,7 +164,7 @@ using cce::ccStatus_t; DOMI_LOGE(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is true, print the Information log and execute a custom statement #define GE_CHK_TRUE_EXEC_INFO(expr, exec_expr, ...) \ { \ @@ -180,7 +173,7 @@ using cce::ccStatus_t; GELOGI(__VA_ARGS__); \ exec_expr; \ } \ - }; + } // If expr is not SUCCESS, print the log and execute the expression + return #define GE_CHK_BOOL_TRUE_RET_VOID(expr, exec_expr, ...) \ @@ -191,7 +184,7 @@ using cce::ccStatus_t; exec_expr; \ return; \ } \ - }; + } // If expr is not SUCCESS, print the log and execute the expression + return _status #define GE_CHK_BOOL_TRUE_EXEC_RET_STATUS(expr, _status, exec_expr, ...) \ @@ -202,7 +195,7 @@ using cce::ccStatus_t; exec_expr; \ return _status; \ } \ - }; + } // If expr is not true, execute a custom statement #define GE_CHK_BOOL_EXEC_NOLOG(expr, exec_expr) \ @@ -211,7 +204,7 @@ using cce::ccStatus_t; if (!b) { \ exec_expr; \ } \ - }; + } // -----------------runtime related macro definitions------------------------------- // If expr is not RT_ERROR_NONE, print the log @@ -231,7 +224,7 @@ using cce::ccStatus_t; DOMI_LOGE("Call rt api failed, ret: 0x%X", _rt_ret); \ exec_expr; \ } \ - }; + } // If expr is not RT_ERROR_NONE, print the log and return #define GE_CHK_RT_RET(expr) \ @@ -239,27 +232,17 @@ using cce::ccStatus_t; rtError_t _rt_ret = (expr); \ if (_rt_ret != RT_ERROR_NONE) { \ DOMI_LOGE("Call rt api failed, ret: 0x%X", _rt_ret); \ - return ge::RT_FAILED; \ + return RT_ERROR_TO_GE_STATUS(_rt_ret); \ } \ } while (0); -// ------------------------cce related macro definitions---------------------------- -// If expr is not CC_STATUS_SUCCESS, print the log -#define GE_CHK_CCE(expr) \ - do { \ - ccStatus_t _cc_ret = (expr); \ - if (_cc_ret != CC_STATUS_SUCCESS) { \ - DOMI_LOGE("Call cce api failed, ret: 0x%X", _cc_ret); \ - } \ - } while (0); - // If expr is true, execute exec_expr without printing logs #define GE_IF_BOOL_EXEC(expr, exec_expr) \ { \ if (expr) { \ exec_expr; \ } \ - }; + } // If make_shared is abnormal, print the log and execute the statement #define GE_MAKE_SHARED(exec_expr0, exec_expr1) \ diff --git a/inc/framework/common/ge_inner_error_codes.h b/inc/framework/common/ge_inner_error_codes.h index c4a36597..ca727589 100644 --- a/inc/framework/common/ge_inner_error_codes.h +++ b/inc/framework/common/ge_inner_error_codes.h @@ -14,6 +14,7 @@ * limitations under the License. */ +/*lint -e* */ #ifndef INC_FRAMEWORK_COMMON_GE_INNER_ERROR_CODES_H_ #define INC_FRAMEWORK_COMMON_GE_INNER_ERROR_CODES_H_ @@ -280,8 +281,24 @@ GE_ERRORNO_RUNTIME(GE_RTI_CALL_HCCL_REDUCE_SCATTER_FAILED, 47, "call hccl hcom r // Executor module error code definition GE_ERRORNO_EXECUTOR(GE_EXEC_NOT_INIT, 1, "GE Executor is not yet initialized."); -GE_ERRORNO_EXECUTOR(GE_AIPP_NOT_EXIST, 2, "GE AIPP is not exist."); -GE_ERRORNO_EXECUTOR(GE_DYNAMIC_AIPP_NOT_SUPPORT_QUERY, 3, "GE Dynamic AIPP is not support to query temporarily."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_PATH_INVALID, 2, "Model file path is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_KEY_PATH_INVALID, 3, "Key file path of model is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_ID_INVALID, 4, "Model id is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_DATA_SIZE_INVALID, 5, "Data size of model is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_PARTITION_NUM_INVALID, 6, "Partition number of model is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_QUEUE_ID_INVALID, 7, "Queue id of model is invalid."); +GE_ERRORNO_EXECUTOR(GE_EXEC_MODEL_NOT_SUPPORT_ENCRYPTION, 8, "Model does not support encryption."); +GE_ERRORNO_EXECUTOR(GE_EXEC_READ_MODEL_FILE_FAILED, 9, "Failed to read model file."); +GE_ERRORNO_EXECUTOR(GE_EXEC_LOAD_MODEL_REPEATED, 10, "The model is loaded repeatedly."); +GE_ERRORNO_EXECUTOR(GE_EXEC_LOAD_MODEL_PARTITION_FAILED, 11, "Failed to load model partition."); +GE_ERRORNO_EXECUTOR(GE_EXEC_LOAD_WEIGHT_PARTITION_FAILED, 12, "Failed to load weight partition."); +GE_ERRORNO_EXECUTOR(GE_EXEC_LOAD_TASK_PARTITION_FAILED, 13, "Failed to load task partition."); +GE_ERRORNO_EXECUTOR(GE_EXEC_LOAD_KERNEL_PARTITION_FAILED, 14, "Failed to load kernel partition."); +GE_ERRORNO_EXECUTOR(GE_EXEC_ALLOC_FEATURE_MAP_MEM_FAILED, 15, "Failed to allocate feature map memory."); +GE_ERRORNO_EXECUTOR(GE_EXEC_ALLOC_WEIGHT_MEM_FAILED, 16, "Failed to allocate weight memory."); +GE_ERRORNO_EXECUTOR(GE_EXEC_ALLOC_VAR_MEM_FAILED, 17, "Failed to allocate variable memory."); +GE_ERRORNO_EXECUTOR(GE_AIPP_NOT_EXIST, 18, "GE AIPP is not exist."); +GE_ERRORNO_EXECUTOR(GE_DYNAMIC_AIPP_NOT_SUPPORT_QUERY, 19, "GE Dynamic AIPP is not support to query temporarily."); // Generator module error code definition GE_ERRORNO_GENERATOR(GE_GENERATOR_GRAPH_MANAGER_INIT_FAILED, 1, "Graph manager initialize failed."); @@ -289,6 +306,8 @@ GE_ERRORNO_GENERATOR(GE_GENERATOR_GRAPH_MANAGER_ADD_GRAPH_FAILED, 2, "Graph mana GE_ERRORNO_GENERATOR(GE_GENERATOR_GRAPH_MANAGER_BUILD_GRAPH_FAILED, 3, "Graph manager build graph failed."); GE_ERRORNO_GENERATOR(GE_GENERATOR_GRAPH_MANAGER_FINALIZE_FAILED, 4, "Graph manager finalize failed."); GE_ERRORNO_GENERATOR(GE_GENERATOR_GRAPH_MANAGER_SAVE_MODEL_FAILED, 5, "Graph manager save model failed."); + +#define RT_ERROR_TO_GE_STATUS(RT_ERROR) static_cast(RT_ERROR) } // namespace ge #endif // INC_FRAMEWORK_COMMON_GE_INNER_ERROR_CODES_H_ diff --git a/inc/framework/common/ge_types.h b/inc/framework/common/ge_types.h index 27ae28ee..00bfa301 100644 --- a/inc/framework/common/ge_types.h +++ b/inc/framework/common/ge_types.h @@ -54,9 +54,9 @@ const char *const GE_ENGINE_ATTR_MEM_TYPE_HBM = "HBM"; struct DataBuffer { public: void *data; // Data address - uint32_t length; // Data length + uint64_t length; // Data length bool isDataSupportMemShare = false; - DataBuffer(void *dataIn, uint32_t len, bool isSupportMemShare) + DataBuffer(void *dataIn, uint64_t len, bool isSupportMemShare) : data(dataIn), length(len), isDataSupportMemShare(isSupportMemShare) {} DataBuffer() : data(nullptr), length(0), isDataSupportMemShare(false) {} @@ -106,7 +106,7 @@ struct ShapeDescription { // Definition of input and output description information struct InputOutputDescInfo { std::string name; - uint32_t size; + uint64_t size; uint32_t data_type; ShapeDescription shape_info; }; @@ -231,6 +231,7 @@ struct Options { // Profiling info of task struct TaskDescInfo { + std::string model_name; std::string op_name; uint32_t block_dim; uint32_t task_id; @@ -239,6 +240,7 @@ struct TaskDescInfo { // Profiling info of graph struct ComputeGraphDescInfo { + std::string model_name; std::string op_name; std::string op_type; std::vector input_format; diff --git a/inc/framework/common/helper/model_helper.h b/inc/framework/common/helper/model_helper.h index 3c9de891..3671f970 100644 --- a/inc/framework/common/helper/model_helper.h +++ b/inc/framework/common/helper/model_helper.h @@ -44,8 +44,6 @@ class ModelHelper { void SetSaveMode(bool val) { is_offline_ = val; } bool GetSaveMode(void) const { return is_offline_; } - static Status TransModelToGeModel(const ModelPtr& model, GeModelPtr& ge_model); - static Status TransGeModelToModel(const GeModelPtr& geModelPtr, ModelPtr& modelPtr); Status GetBaseNameFromFileName(const std::string& file_name, std::string& base_name); Status GetModelNameFromMergedGraphName(const std::string& graph_name, std::string& model_name); diff --git a/inc/framework/common/string_util.h b/inc/framework/common/string_util.h index b74eddcf..918a3950 100644 --- a/inc/framework/common/string_util.h +++ b/inc/framework/common/string_util.h @@ -36,8 +36,8 @@ class StringUtils { #endif return s; } - - static std::string &Rtrim(std::string &s) { + // lint -esym(551,*) + static std::string &Rtrim(std::string &s) { /*lint !e618*/ #if __cplusplus >= 201103L (void)s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) { return !std::isspace(c); })); #else @@ -45,7 +45,7 @@ class StringUtils { #endif return s; } - + // lint -esym(551,*) /// /// @ingroup domi_common /// @brief delete spaces at the beginning and end of a string diff --git a/inc/framework/common/types.h b/inc/framework/common/types.h index e3844a61..db692c36 100644 --- a/inc/framework/common/types.h +++ b/inc/framework/common/types.h @@ -48,6 +48,9 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string DUMP_S FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string DUMP_LAYER; FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string DUMP_FILE_PATH; FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string DUMP_MODE; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string OP_DEBUG_AICORE; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string OP_DEBUG_ATOMIC; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string OP_DEBUG_ALL; // Supported public properties name FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string PROP_OME_START_TIME; // Start time @@ -335,6 +338,8 @@ REGISTER_OPTYPE_DECLARE(BASICLSTMCELL, "BasicLSTMCell"); REGISTER_OPTYPE_DECLARE(GETNEXT, "GetNext"); REGISTER_OPTYPE_DECLARE(INITDATA, "InitData"); REGISTER_OPTYPE_DECLARE(TRANSSHAPE, "TransShape") +REGISTER_OPTYPE_DECLARE(REFIDENTITY, "RefIdentity"); +REGISTER_OPTYPE_DECLARE(BITCAST, "Bitcast"); // ANN dedicated operator REGISTER_OPTYPE_DECLARE(ANN_MEAN, "AnnMean"); @@ -428,6 +433,8 @@ REGISTER_OPTYPE_DECLARE(HCOMALLREDUCE, "HcomAllReduce"); REGISTER_OPTYPE_DECLARE(HCOMREDUCESCATTER, "HcomReduceScatter"); REGISTER_OPTYPE_DECLARE(HCOMSEND, "HcomSend"); REGISTER_OPTYPE_DECLARE(HCOMRECEIVE, "HcomReceive"); +REGISTER_OPTYPE_DECLARE(HCOMREMOTEREAD, "HcomRemoteRead"); +REGISTER_OPTYPE_DECLARE(HCOMREMOTEWRITE, "HcomRemoteWrite"); REGISTER_OPTYPE_DECLARE(VARASSIGN, "VarAssign"); REGISTER_OPTYPE_DECLARE(VARISINITIALIZEDOP, "VarIsInitializedOp"); @@ -555,6 +562,16 @@ enum ModelCheckType { }; /// +/// @brief dynamic input type +/// +enum DynamicInputType { + FIXED = 0, // default mode + DYNAMIC_BATCH = 1, + DYNAMIC_IMAGE = 2, + DYNAMIC_DIMS = 3 +}; + +/// /// @brief magic number of the model file /// FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const uint32_t MODEL_FILE_MAGIC_NUM; @@ -631,6 +648,9 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string NODE_N FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string NODE_NAME_END_GRAPH; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string NODE_NAME_OP_DEBUG; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string OP_TYPE_OP_DEBUG; + // convolution node type FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY extern const std::string OP_TYPE_CONVOLUTION; // adds a convolutional node name for the hard AIPP diff --git a/inc/framework/executor/ge_executor.h b/inc/framework/executor/ge_executor.h index 91b50311..129b8613 100644 --- a/inc/framework/executor/ge_executor.h +++ b/inc/framework/executor/ge_executor.h @@ -21,28 +21,31 @@ #include #include +#include "common/dynamic_aipp.h" #include "common/ge_inner_error_codes.h" #include "common/ge_types.h" #include "common/types.h" #include "graph/tensor.h" +#include "graph/ge_tensor.h" #include "runtime/base.h" -#include "common/dynamic_aipp.h" namespace ge { class ModelListenerAdapter; class SingleOp; +class DynamicSingleOp; struct RunModelData { uint32_t index; // Data index uint32_t modelId; - std::vector blobs; // All input/output data buffer - uint32_t timestamp; // Data creation time - uint32_t timeout; // Processing timeout - uint64_t request_id = 0; // Request ID - uint64_t dynamic_batch_size = 0; // Dynamic batch size scene, set dynamic size, not supported by default:0 - uint64_t dynamic_image_height = 0; // Dynamic image size scene, set image height, not supported by default:0 - uint64_t dynamic_image_width = 0; // Dynamic image size scene, set image width, not supported by default:0 + std::vector blobs; // All input/output data buffer + uint32_t timestamp; // Data creation time + uint32_t timeout; // Processing timeout + uint64_t request_id = 0; // Request ID + uint64_t dynamic_batch_size = 0; // Dynamic batch size scene, set dynamic size, not supported by default:0 + uint64_t dynamic_image_height = 0; // Dynamic image size scene, set image height, not supported by default:0 + uint64_t dynamic_image_width = 0; // Dynamic image size scene, set image width, not supported by default:0 + std::vector dynamic_dims; // Dynamic dims scene, set dynamic dims, not supported by default:empty }; class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeExecutor { @@ -87,16 +90,52 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeExecutor { /// ge::Status SetDynamicImageSize(uint32_t model_id, void *dynamic_input_addr, uint64_t length, uint64_t image_height, uint64_t image_width); + + /// + /// @ingroup ge + /// @brief Set dynamic dims info + /// @param [in] model_id: model id allocate from manager + /// @param [in] dynamic_input_addr: dynamic input addr created by user + /// @param [in] length: length of dynamic input addr + /// @param [in] dynamic_dim_num: number of dynamic dimension + /// @param [in] dynamic_dims: array of dynamic dimensions + /// @return execute result + /// + ge::Status SetDynamicDims(uint32_t model_id, void *dynamic_input_addr, uint64_t length, + const std::vector &dynamic_dims); + + /// + /// @ingroup ge + /// @brief Get current dynamic dims info by combined dims + /// @param [in] model_id: model id allocate from manager + /// @param [in] combined_dims: array of combined dimensions + /// @param [out] cur_dynamic_dims: current dynamic dims + /// @return execute result + /// + ge::Status GetCurDynamicDims(uint32_t model_id, const std::vector &combined_dims, + std::vector &cur_dynamic_dims); + /// /// @ingroup ge /// @brief Get dynamic batch_info /// @param [in] model_id /// @param [out] batch_info + /// @param [out] dynamic_type /// @return execute result /// - ge::Status GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info); + ge::Status GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type); - ge::Status GetCurShape(const uint32_t model_id, std::vector &batch_info); + /// + /// @ingroup ge + /// @brief Get combined dynamic dims info + /// @param [in] model_id + /// @param [out] batch_info + /// @return execute result + /// + ge::Status GetCombinedDynamicDims(uint32_t model_id, std::vector> &batch_info); + + ge::Status GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type); /// /// @ingroup ge @@ -209,6 +248,13 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeExecutor { static ge::Status ExecuteAsync(SingleOp *executor, const std::vector &inputs, std::vector &outputs); + static ge::Status LoadDynamicSingleOp(const std::string &model_name, const ge::ModelData &modelData, void *stream, + DynamicSingleOp **single_op); + + static ge::Status ExecuteAsync(DynamicSingleOp *executor, const std::vector &input_desc, + const std::vector &inputs, std::vector &output_desc, + std::vector &outputs); + static ge::Status ReleaseSingleOpResource(void *stream); ge::Status GetBatchInfoSize(uint32_t model_id, size_t &shape_count); diff --git a/inc/framework/ge_runtime/model_runner.h b/inc/framework/ge_runtime/model_runner.h index 6e7abcb9..e495dfdf 100644 --- a/inc/framework/ge_runtime/model_runner.h +++ b/inc/framework/ge_runtime/model_runner.h @@ -28,7 +28,7 @@ namespace ge { namespace model_runner { class RuntimeModel; - +using RuntimeInfo = std::tuple; class ModelRunner { public: static ModelRunner &Instance(); @@ -36,8 +36,18 @@ class ModelRunner { bool LoadDavinciModel(uint32_t device_id, uint64_t session_id, uint32_t model_id, std::shared_ptr davinci_model, std::shared_ptr listener); + bool DistributeTask(uint32_t model_id); + + bool LoadModelComplete(uint32_t model_id); + const std::vector &GetTaskIdList(uint32_t model_id) const; + const std::vector &GetStreamIdList(uint32_t model_id) const; + + const std::map> &GetRuntimeInfoMap(uint32_t model_id) const; + + void *GetModelHandle(uint32_t model_id) const; + bool UnloadModel(uint32_t model_id); bool RunModel(uint32_t model_id, const InputData &input_data, OutputData *output_data); diff --git a/inc/framework/ge_runtime/task_info.h b/inc/framework/ge_runtime/task_info.h index a48ed68b..68d71870 100644 --- a/inc/framework/ge_runtime/task_info.h +++ b/inc/framework/ge_runtime/task_info.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "cce/taskdown_api.h" @@ -52,21 +53,27 @@ class TaskInfo { virtual ~TaskInfo() {} uint32_t stream_id() const { return stream_id_; } TaskInfoType type() const { return type_; } + std::string op_name() const { return op_name_; } + bool dump_flag() const { return dump_flag_; } protected: - TaskInfo(uint32_t stream_id, TaskInfoType type) : stream_id_(stream_id), type_(type) {} + TaskInfo(const std::string &op_name, uint32_t stream_id, TaskInfoType type, bool dump_flag) + : op_name_(op_name), stream_id_(stream_id), type_(type), dump_flag_(dump_flag) {} private: + std::string op_name_; uint32_t stream_id_; TaskInfoType type_; + bool dump_flag_; }; class CceTaskInfo : public TaskInfo { public: - CceTaskInfo(uint32_t stream_id, const cce::ccOpContext &ctx, const std::string &stub_func, uint32_t block_dim, - const std::vector &args, uint32_t args_size, const std::vector &sm_desc, - const std::vector &flow_table, const std::vector &args_offset, bool is_flowtable) - : TaskInfo(stream_id, TaskInfoType::CCE), + CceTaskInfo(const std::string &op_name, uint32_t stream_id, const cce::ccOpContext &ctx, const std::string &stub_func, + uint32_t block_dim, const std::vector &args, uint32_t args_size, + const std::vector &sm_desc, const std::vector &flow_table, + const std::vector &args_offset, bool is_flowtable) + : TaskInfo(op_name, stream_id, TaskInfoType::CCE, false), ctx_(ctx), stub_func_(stub_func), block_dim_(block_dim), @@ -102,11 +109,11 @@ class CceTaskInfo : public TaskInfo { class TbeTaskInfo : public TaskInfo { public: - TbeTaskInfo(uint32_t stream_id, const std::string &stub_func, uint32_t block_dim, const std::vector &args, - uint32_t args_size, const std::vector &sm_desc, void *binary, uint32_t binary_size, - const std::vector &meta_data, const std::vector &input_data_addrs, - const std::vector &output_data_addrs, const std::vector &workspace_addrs) - : TaskInfo(stream_id, TaskInfoType::TBE), + TbeTaskInfo(const std::string &op_name, uint32_t stream_id, const std::string &stub_func, uint32_t block_dim, + const std::vector &args, uint32_t args_size, const std::vector &sm_desc, void *binary, + uint32_t binary_size, const std::vector &meta_data, const std::vector &input_data_addrs, + const std::vector &output_data_addrs, const std::vector &workspace_addrs, bool dump_flag) + : TaskInfo(op_name, stream_id, TaskInfoType::TBE, dump_flag), stub_func_(stub_func), block_dim_(block_dim), args_(args), @@ -153,9 +160,10 @@ class TbeTaskInfo : public TaskInfo { class AicpuTaskInfo : public TaskInfo { public: - AicpuTaskInfo(uint32_t stream_id, const string &so_name, const std::string &kernel_name, const std::string &node_def, - const std::vector &input_data_addrs, const std::vector &output_data_addrs) - : TaskInfo(stream_id, TaskInfoType::AICPU), + AicpuTaskInfo(const std::string &op_name, uint32_t stream_id, const string &so_name, const std::string &kernel_name, + const std::string &node_def, const std::vector &input_data_addrs, + const std::vector &output_data_addrs, bool dump_flag) + : TaskInfo(op_name, stream_id, TaskInfoType::AICPU, dump_flag), so_name_(so_name), kernel_name_(kernel_name), node_def_(node_def), @@ -177,37 +185,45 @@ class AicpuTaskInfo : public TaskInfo { std::vector output_data_addrs_; }; -class LabelTaskInfo : public TaskInfo { +class LabelSetTaskInfo : public TaskInfo { public: + LabelSetTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t label_id) + : TaskInfo(op_name, stream_id, TaskInfoType::LABEL_SET, false), label_id_(label_id) {} + ~LabelSetTaskInfo() override {} uint32_t label_id() const { return label_id_; } - protected: - LabelTaskInfo(uint32_t stream_id, TaskInfoType type, uint32_t label_id) - : TaskInfo(stream_id, type), label_id_(label_id) {} - virtual ~LabelTaskInfo() override {} - + private: uint32_t label_id_; }; -class LabelSetTaskInfo : public LabelTaskInfo { +class LabelGotoTaskInfo : public TaskInfo { public: - LabelSetTaskInfo(uint32_t stream_id, uint32_t label_id) - : LabelTaskInfo(stream_id, TaskInfoType::LABEL_SET, label_id) {} - ~LabelSetTaskInfo() override {} + LabelGotoTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t label_id) + : TaskInfo(op_name, stream_id, TaskInfoType::LABEL_GOTO, false), label_id_(label_id) {} + ~LabelGotoTaskInfo() override {} + uint32_t label_id() const { return label_id_; } + + private: + uint32_t label_id_; }; -class LabelSwitchTaskInfo : public LabelTaskInfo { +class LabelSwitchTaskInfo : public TaskInfo { public: - LabelSwitchTaskInfo(uint32_t stream_id, uint32_t label_id) - : LabelTaskInfo(stream_id, TaskInfoType::LABEL_SWITCH, label_id) {} + LabelSwitchTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t label_size, + const std::vector &label_list, void *cond) + : TaskInfo(op_name, stream_id, TaskInfoType::LABEL_SWITCH, false), + label_size_(label_size), + label_list_(label_list), + cond_(cond) {} ~LabelSwitchTaskInfo() override {} -}; + uint32_t label_size() { return label_size_; }; + const std::vector &label_list() { return label_list_; }; + void *cond() { return cond_; }; -class LabelGotoTaskInfo : public LabelTaskInfo { - public: - LabelGotoTaskInfo(uint32_t stream_id, uint32_t label_id) - : LabelTaskInfo(stream_id, TaskInfoType::LABEL_GOTO, label_id) {} - ~LabelGotoTaskInfo() override {} + private: + uint32_t label_size_; + std::vector label_list_; + void *cond_; }; class EventTaskInfo : public TaskInfo { @@ -215,8 +231,8 @@ class EventTaskInfo : public TaskInfo { uint32_t event_id() const { return event_id_; } protected: - EventTaskInfo(uint32_t stream_id, TaskInfoType type, uint32_t event_id) - : TaskInfo(stream_id, type), event_id_(event_id) {} + EventTaskInfo(const std::string &op_name, uint32_t stream_id, TaskInfoType type, uint32_t event_id) + : TaskInfo(op_name, stream_id, type, false), event_id_(event_id) {} virtual ~EventTaskInfo() override {} uint32_t event_id_; @@ -224,39 +240,41 @@ class EventTaskInfo : public TaskInfo { class EventRecordTaskInfo : public EventTaskInfo { public: - EventRecordTaskInfo(uint32_t stream_id, uint32_t event_id) - : EventTaskInfo(stream_id, TaskInfoType::EVENT_RECORD, event_id) {} + EventRecordTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t event_id) + : EventTaskInfo(op_name, stream_id, TaskInfoType::EVENT_RECORD, event_id) {} ~EventRecordTaskInfo() override {} }; class EventWaitTaskInfo : public EventTaskInfo { public: - EventWaitTaskInfo(uint32_t stream_id, uint32_t event_id) - : EventTaskInfo(stream_id, TaskInfoType::EVENT_WAIT, event_id) {} + EventWaitTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t event_id) + : EventTaskInfo(op_name, stream_id, TaskInfoType::EVENT_WAIT, event_id) {} ~EventWaitTaskInfo() override {} }; class FusionStartTaskInfo : public TaskInfo { public: - explicit FusionStartTaskInfo(uint32_t stream_id) : TaskInfo(stream_id, TaskInfoType::FUSION_START) {} + explicit FusionStartTaskInfo(const std::string &op_name, uint32_t stream_id) + : TaskInfo(op_name, stream_id, TaskInfoType::FUSION_START, false) {} ~FusionStartTaskInfo() override {} }; class FusionEndTaskInfo : public TaskInfo { public: - explicit FusionEndTaskInfo(uint32_t stream_id) : TaskInfo(stream_id, TaskInfoType::FUSION_END) {} + explicit FusionEndTaskInfo(const std::string &op_name, uint32_t stream_id) + : TaskInfo(op_name, stream_id, TaskInfoType::FUSION_END, false) {} ~FusionEndTaskInfo() override {} }; class HcclTaskInfo : public TaskInfo { public: - HcclTaskInfo(uint32_t stream_id, const std::string hccl_type, void *input_data_addr, void *output_data_addr, - void *workspace_addr, int64_t workspace_size, int64_t hccl_stream_num, + HcclTaskInfo(const std::string &op_name, uint32_t stream_id, const std::string hccl_type, void *input_data_addr, + void *output_data_addr, void *workspace_addr, int64_t workspace_size, int64_t hccl_stream_num, const std::vector &private_def, void *ops_kernel_store, int32_t count, int64_t root_id, - int64_t op_type, int64_t data_type, std::function hcom_bind_model, - std::function hcom_unbind_model, - std::function, void *)> hcom_distribute_task) - : TaskInfo(stream_id, TaskInfoType::HCCL), + int64_t op_type, int64_t data_type, const std::string &group, + std::function hcom_bind_model, std::function hcom_unbind_model, + std::function, void *)> hcom_distribute_task, bool dump_flag) + : TaskInfo(op_name, stream_id, TaskInfoType::HCCL, dump_flag), hccl_type_(hccl_type), input_data_addr_(input_data_addr), output_data_addr_(output_data_addr), @@ -269,6 +287,7 @@ class HcclTaskInfo : public TaskInfo { root_id_(root_id), op_type_(op_type), data_type_(data_type), + group_(group), hcom_bind_model_(hcom_bind_model), hcom_unbind_model_(hcom_unbind_model), hcom_distribute_task_(hcom_distribute_task) {} @@ -286,6 +305,7 @@ class HcclTaskInfo : public TaskInfo { int64_t root_id() const { return root_id_; } int64_t op_type() const { return op_type_; } int64_t data_type() const { return data_type_; } + const std::string &group() const { return group_; } std::function hcom_bind_model() const { return hcom_bind_model_; } std::function hcom_unbind_model() const { return hcom_unbind_model_; } std::function, void *)> hcom_distribute_task() const { @@ -305,6 +325,7 @@ class HcclTaskInfo : public TaskInfo { int64_t root_id_; int64_t op_type_; int64_t data_type_; + std::string group_; std::function hcom_bind_model_; std::function hcom_unbind_model_; std::function, void *)> hcom_distribute_task_; @@ -312,8 +333,11 @@ class HcclTaskInfo : public TaskInfo { class ProfilerTraceTaskInfo : public TaskInfo { public: - ProfilerTraceTaskInfo(uint32_t stream_id, uint64_t log_id, bool notify, uint32_t flat) - : TaskInfo(stream_id, TaskInfoType::PROFILER_TRACE), log_id_(log_id), notify_(notify), flat_(flat) {} + ProfilerTraceTaskInfo(const std::string &op_name, uint32_t stream_id, uint64_t log_id, bool notify, uint32_t flat) + : TaskInfo(op_name, stream_id, TaskInfoType::PROFILER_TRACE, false), + log_id_(log_id), + notify_(notify), + flat_(flat) {} ~ProfilerTraceTaskInfo() override {} uint64_t log_id() const { return log_id_; } @@ -328,8 +352,9 @@ class ProfilerTraceTaskInfo : public TaskInfo { class MemcpyAsyncTaskInfo : public TaskInfo { public: - MemcpyAsyncTaskInfo(uint32_t stream_id, void *dst, uint64_t dst_max, void *src, uint64_t count, uint32_t kind) - : TaskInfo(stream_id, TaskInfoType::MEMCPY_ASYNC), + MemcpyAsyncTaskInfo(const std::string &op_name, uint32_t stream_id, void *dst, uint64_t dst_max, void *src, + uint64_t count, uint32_t kind, bool dump_flag) + : TaskInfo(op_name, stream_id, TaskInfoType::MEMCPY_ASYNC, dump_flag), dst_(dst), dst_max_(dst_max), src_(src), @@ -353,9 +378,9 @@ class MemcpyAsyncTaskInfo : public TaskInfo { class StreamSwitchTaskInfo : public TaskInfo { public: - StreamSwitchTaskInfo(uint32_t stream_id, int64_t true_stream_id, void *input_addr, void *value_addr, int64_t cond, - int64_t data_type) - : TaskInfo(stream_id, TaskInfoType::STREAM_SWITCH), + StreamSwitchTaskInfo(const std::string &op_name, uint32_t stream_id, int64_t true_stream_id, void *input_addr, + void *value_addr, int64_t cond, int64_t data_type) + : TaskInfo(op_name, stream_id, TaskInfoType::STREAM_SWITCH, false), true_stream_id_(true_stream_id), input_addr_(input_addr), value_addr_(value_addr), @@ -379,8 +404,8 @@ class StreamSwitchTaskInfo : public TaskInfo { class StreamActiveTaskInfo : public TaskInfo { public: - StreamActiveTaskInfo(uint32_t stream_id, uint32_t active_stream_id) - : TaskInfo(stream_id, TaskInfoType::STREAM_ACTIVE), active_stream_id_(active_stream_id) {} + StreamActiveTaskInfo(const std::string &op_name, uint32_t stream_id, uint32_t active_stream_id) + : TaskInfo(op_name, stream_id, TaskInfoType::STREAM_ACTIVE, false), active_stream_id_(active_stream_id) {} ~StreamActiveTaskInfo() override {} uint32_t active_stream_id() const { return active_stream_id_; } diff --git a/inc/framework/generator/ge_generator.h b/inc/framework/generator/ge_generator.h index f0707c67..d3f472e9 100644 --- a/inc/framework/generator/ge_generator.h +++ b/inc/framework/generator/ge_generator.h @@ -27,6 +27,7 @@ #include "graph/ge_tensor.h" #include "graph/graph.h" #include "graph/op_desc.h" +#include "graph/detail/attributes_holder.h" namespace ge { class GeGenerator { diff --git a/inc/framework/memory/memory_api.h b/inc/framework/memory/memory_api.h new file mode 100644 index 00000000..656e4710 --- /dev/null +++ b/inc/framework/memory/memory_api.h @@ -0,0 +1,56 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef INC_FRAMEWORK_MEMORY_MEMORY_API_H_ +#define INC_FRAMEWORK_MEMORY_MEMORY_API_H_ + +#include +#include + +#include "ge/ge_api_error_codes.h" +#include "runtime/mem.h" + +namespace ge { +enum MemStorageType { + HBM = 0, + RDMA_HBM, +}; + +struct HostVarInfo { + uint64_t base_addr; + uint64_t var_size; +}; + +/// +/// \param size [in] rdma pool memory size to be allocated. +/// \param mem_type [in] memory type for rdma pool. +/// \return Status result of function +Status InitRdmaPool(size_t size, rtMemType_t mem_type = RT_MEMORY_HBM); + +/// +/// \param var_info [in] host variable addr infos. +/// \param mem_type [in] memory type for rdma pool. +/// \return Status result of function +Status RdmaRemoteRegister(const std::vector &var_info, rtMemType_t mem_type = RT_MEMORY_HBM); + +/// +/// \param var_name [in] var_name name of host variable. +/// \param base_addr [out] base_addr vase addr of host variable. +/// \param var_size [out] var_size memory_size of host variable. +/// \return Status result of function +Status GetVarBaseAddrAndSize(const std::string &var_name, uint64_t &base_addr, uint64_t &var_size); +} // namespace ge +#endif // INC_FRAMEWORK_MEMORY_MEMORY_API_H_ diff --git a/inc/framework/omg/omg.h b/inc/framework/omg/omg.h index c7dbdd5b..6a120439 100644 --- a/inc/framework/omg/omg.h +++ b/inc/framework/omg/omg.h @@ -96,17 +96,12 @@ Status CheckCustomAiCpuOpLib(); Status DumpInfershapeJson(const ge::Graph &graph, const char *json_file); -Status SetOutputNodeInfo(ge::Graph &graph, const std::string &output_type, const std::string &output_format); - -Status GetOutputLeaf(ge::NodePtr node, std::vector> &output_nodes_info); - void GetOutputNodesNameAndIndex(std::vector> &output_nodes_info, std::vector &output_nodes_name); void UpdateOmgCtxWithParserCtx(); void UpdateParserCtxWithOmgCtx(); - } // namespace ge namespace domi { diff --git a/inc/framework/omg/omg_inner_types.h b/inc/framework/omg/omg_inner_types.h index 70d59c2f..80361232 100644 --- a/inc/framework/omg/omg_inner_types.h +++ b/inc/framework/omg/omg_inner_types.h @@ -120,6 +120,7 @@ struct OmgContext { bool is_dynamic_input = false; std::string dynamic_batch_size; std::string dynamic_image_size; + std::string dynamic_dims; }; } // namespace ge diff --git a/inc/graph/buffer.h b/inc/graph/buffer.h index e6be3daa..ca4355a7 100644 --- a/inc/graph/buffer.h +++ b/inc/graph/buffer.h @@ -57,11 +57,11 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Buffer { // For compatibility inline const std::uint8_t *data() const { return GetData(); } - inline std::uint8_t *data() { return GetData(); } + inline std::uint8_t *data() { return GetData(); } // lint !e659 inline std::size_t size() const { return GetSize(); } inline void clear() { return ClearBuffer(); } - uint8_t operator[](size_t index) const { - if (buffer_ != nullptr && index < buffer_->size()) { + uint8_t operator[](size_t index) const { // lint !e1022 !e1042 + if (buffer_ != nullptr && index < buffer_->size()) { // lint !e574 return (uint8_t)(*buffer_)[index]; } return 0xff; diff --git a/inc/graph/compute_graph.h b/inc/graph/compute_graph.h index 4f865f12..8d3db43c 100644 --- a/inc/graph/compute_graph.h +++ b/inc/graph/compute_graph.h @@ -74,6 +74,9 @@ class ComputeGraph : public std::enable_shared_from_this, public A size_t GetAllNodesSize() const; Vistor GetAllNodes() const; + // is_unknown_shape: false, same with GetAllNodes func + // is_unknown_shape: true, same with GetDirectNodes func + Vistor GetNodes(bool is_unknown_shape) const; size_t GetDirectNodesSize() const; Vistor GetDirectNode() const; Vistor GetInputNodes() const; @@ -81,14 +84,18 @@ class ComputeGraph : public std::enable_shared_from_this, public A NodePtr FindNode(const std::string &name) const; NodePtr FindFirstNodeMatchType(const std::string &name) const; + /*lint -e504*/ // AddNode with NodePtr NodePtr AddNode(NodePtr node); NodePtr AddNode(OpDescPtr op); - NodePtr AddNode(OpDescPtr op, int64_t id); // for unserialize. + NodePtr AddNode(OpDescPtr op, int64_t id); // for unserialize NodePtr AddNodeFront(NodePtr node); NodePtr AddNodeFront(const OpDescPtr &op); NodePtr AddInputNode(NodePtr node); NodePtr AddOutputNode(NodePtr node); + // insert node with specific pre_node + NodePtr AddNodeAfter(OpDescPtr &op, const NodePtr &pre_node); + NodePtr AddNodeAfter(NodePtr node, const NodePtr &pre_node); graphStatus RemoveNode(const NodePtr &node); graphStatus RemoveInputNode(const NodePtr &node); @@ -133,6 +140,8 @@ class ComputeGraph : public std::enable_shared_from_this, public A bool IsValid() const; void Dump() const; + void Swap(ComputeGraph &graph); + graphStatus IsolateNode(const NodePtr &node); graphStatus Verify(); graphStatus InferShape(); @@ -141,6 +150,7 @@ class ComputeGraph : public std::enable_shared_from_this, public A graphStatus InsertEventNodes(); bool operator==(const ComputeGraph &r_compute_graph) const; + /*lint +e504*/ const std::map, std::vector> &GetShareParamLayer() const { return params_share_map_; } @@ -174,6 +184,10 @@ class ComputeGraph : public std::enable_shared_from_this, public A void SetInputSize(uint32_t size) { input_size_ = size; } uint32_t GetInputSize() const { return input_size_; } + // false: known shape true: unknow shape + bool GetGraphUnknownFlag() const { return is_unknown_shape_graph_; } + void SetGraphUnknownFlag(bool flag) { is_unknown_shape_graph_ = flag; } + /// /// Set is need train iteration. /// If set true, it means this graph need to be run iteration some @@ -249,6 +263,8 @@ class ComputeGraph : public std::enable_shared_from_this, public A bool VectorInputNodePtrIsEqual(const std::vector &r_node_ptr_vector, const std::vector &l_node_ptr_vector) const; + void SetNodesOwner(); + friend class ModelSerializeImp; friend class GraphDebugImp; friend class OnnxUtils; @@ -282,7 +298,8 @@ class ComputeGraph : public std::enable_shared_from_this, public A std::map op_name_map_; uint64_t session_id_ = 0; ge::Format data_format_ = ge::FORMAT_ND; + // unknown graph indicator, default is false, mean known shape + bool is_unknown_shape_graph_ = false; }; } // namespace ge - #endif // INC_GRAPH_COMPUTE_GRAPH_H_ diff --git a/inc/graph/debug/ge_attr_define.h b/inc/graph/debug/ge_attr_define.h index 5db047c0..57e389e8 100644 --- a/inc/graph/debug/ge_attr_define.h +++ b/inc/graph/debug/ge_attr_define.h @@ -14,6 +14,7 @@ * limitations under the License. */ +/*lint -e618*/ #ifndef INC_GRAPH_DEBUG_GE_ATTR_DEFINE_H_ #define INC_GRAPH_DEBUG_GE_ATTR_DEFINE_H_ @@ -185,6 +186,9 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAM GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_INPUT_ORIGIN_SIZE; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_NODE_CONNECT_INPUT; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_NODE_CONNECT_OUTPUT; + // to be deleted GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_TO_BE_DELETED; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string PERMUTE_RESHAPE_FUSION; @@ -778,6 +782,10 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_MOD GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_MODEL_CORE_TYPE; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_MODEL_ATC_VERSION; + +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_MODEL_OPP_VERSION; + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string QUANTIZE_SCALE_MODE; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string QUANTIZE_SCALE_VALUE; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string QUANTIZE_SCALE_OFFSET; @@ -930,12 +938,14 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAM GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_PRED_VALUE; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_BATCH_NUM; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_BATCH_LABEL; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_COMBINED_BATCH; // Control flow GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_STREAM_SWITCH_COND; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_ACTIVE_STREAM_LIST; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SWITCHN_PRED_VALUE; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SUBGRAPH_FIRST_ACTIVE; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_COMBINED_DYNAMIC_DIMS; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SWITCH_BRANCH_NODE_LABEL; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG; @@ -979,6 +989,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NEE // For mutil-batch GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_INSERT_BY_MBATCH; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_MBATCH_ORIGIN_INPUT_DIMS; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_DYNAMIC_TYPE; // For inserted op GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_INSERTED_BY_GE; @@ -996,7 +1007,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAM GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_DATA_DUMP_ORIGIN_FORMAT; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_DATA_DUMP_ORIGIN_DATA_TYPE; -// used for l1 fusion and other fusion in future +// used for lX fusion GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_L1_FUSION_GROUP_ID; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_L1_FUSION_GROUP_KEY; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_FUSION_GROUP_KEY; @@ -1010,9 +1021,21 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAM GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SWITCH_FOR_L1_FUSION; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_N_BATCH_SPILT; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NO_TASK_AND_DUMP_NEEDED; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_DATA_DUMP_REF; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_OUTPUT_OFFSET_FOR_BUFFER_FUSION; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_L2_FUSION_GROUP_ID; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_SWITCH_FOR_L2_FUSION; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_OP_INPUT_L1_FLAG; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_OP_INPUT_L1_ADDR; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_OP_INPUT_L1_VALID_SIZE; + +// for unregistered op +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_UNREGST_OPPATH; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_UNREGST_ATTRLIST; + +// op overflow dump +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_OP_DEBUG_FLAG; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_OP_DEBUG_MODE; // functional ops attr GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_IF_THEN_BRANCH; @@ -1058,6 +1081,31 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_HOR // for gradient group GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_HCCL_FUSED_GROUP; GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_HCCL_FUSED_FLAG; + +// dynamic shape attrs +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_DYNAMIC_SHAPE_FIXED_ADDR; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_DYNAMIC_SHAPE_FIXED_ADDR_INDEX; + +// atc user def dtype&format +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_ATC_USER_DEFINE_DATATYPE; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_ATC_USER_DEFINE_FORMAT; + +// for fusion op plugin +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_FUSIONOP_ORIGINAL_TYPE; + +// graph partition for aicpu +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_PLD_FRONT_NODE_ENGINE_NAME; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_NAME_END_REAR_NODE_ENGINE_NAME; + +// input and output memory type +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_VARIABLE_PLACEMENT; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_INPUT_MEMORY_TYPE; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_OUTPUT_MEMORY_TYPE; + +// input_output_offset +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_ZERO_COPY_BASIC_OFFSET; +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY extern const std::string ATTR_ZERO_COPY_RELATIVE_OFFSET; } // namespace ge #endif // INC_GRAPH_DEBUG_GE_ATTR_DEFINE_H_ +/*lint +e618*/ diff --git a/inc/graph/detail/any_map.h b/inc/graph/detail/any_map.h index c417c6a9..70533ea1 100644 --- a/inc/graph/detail/any_map.h +++ b/inc/graph/detail/any_map.h @@ -38,7 +38,7 @@ class TypeID { bool operator==(const TypeID &__arg) const { return type_ == __arg.type_; } private: - explicit TypeID(string type) : type_(std::move(type)) {} + explicit TypeID(string type) : type_(std::move(type)) {} // lint !e30 !e32 string type_; }; @@ -53,6 +53,8 @@ class AnyMap { bool Has(const string &name) const { return anyValues_.find(name) != anyValues_.end(); } + void Swap(AnyMap &other) { anyValues_.swap(other.anyValues_); } + private: class Placeholder { public: diff --git a/inc/graph/detail/attributes_holder.h b/inc/graph/detail/attributes_holder.h index bb26dec5..49741143 100644 --- a/inc/graph/detail/attributes_holder.h +++ b/inc/graph/detail/attributes_holder.h @@ -50,7 +50,7 @@ class OpDef; class GraphDef; } // namespace proto -using ProtoAttrMap = ::google::protobuf::Map<::std::string, ::ge::proto::AttrDef>; +using ProtoAttrMap = ::google::protobuf::Map<::std::string, ::ge::proto::AttrDef>; // lint !e1073 using ProtoMsgOwner = std::shared_ptr<::google::protobuf::Message>; template @@ -95,6 +95,14 @@ class GeIrProtoHelper { } } + void Swap(GeIrProtoHelper &other) { + protoOwner_.swap(other.protoOwner_); + + ProtoType *temp = protoMsg_; + protoMsg_ = other.protoMsg_; + other.protoMsg_ = temp; + } + // protoMsg_ is part of protoOwner_, they have the same runtime ProtoMsgOwner protoOwner_ = nullptr; ProtoType *protoMsg_ = nullptr; @@ -120,6 +128,11 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AttrHolder { void CopyAttrsFrom(const AttrHolder &holder); + void Swap(AttrHolder &holder) { + requiredAttrs_.swap(holder.requiredAttrs_); + extAttrs_.Swap(holder.extAttrs_); + } + template bool SetExtAttr(const string &name, const T &value) { return extAttrs_.Set(name, value); @@ -134,7 +147,7 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AttrHolder { protected: graphStatus AddRequiredAttr(const std::string &name); const std::unordered_set GetAllAttrNames() const; - const std::map GetAllAttrs() const; + const std::map GetAllAttrs() const; // lint !e1073 virtual ProtoAttrMapHelper MutableAttrMap() = 0; virtual ConstProtoAttrMapHelper GetAttrMap() const = 0; @@ -149,5 +162,4 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AttrHolder { AnyMap extAttrs_; }; } // namespace ge - #endif // INC_GRAPH_DETAIL_ATTRIBUTES_HOLDER_H_ diff --git a/inc/graph/detail/model_serialize_imp.h b/inc/graph/detail/model_serialize_imp.h index b8b3916a..ff27335a 100644 --- a/inc/graph/detail/model_serialize_imp.h +++ b/inc/graph/detail/model_serialize_imp.h @@ -67,6 +67,9 @@ class ModelSerializeImp { bool HandleNodeNameRef(); bool UnserializeOpDesc(OpDescPtr &opDesc, proto::OpDef &opDefProto); + void AttrDefToOpDesc(OpDescPtr &op_desc, std::vector &key_in, std::vector &key_out, + std::vector &value_in, std::vector &value_out, std::vector &opt); + void OpDescToAttrDef(const ConstOpDescPtr &op_desc, proto::OpDef *op_def_proto); bool UnserializeNode(ComputeGraphPtr &graph, proto::OpDef &opDefProto); diff --git a/inc/graph/ge_attr_value.h b/inc/graph/ge_attr_value.h index b665beba..0c265c20 100644 --- a/inc/graph/ge_attr_value.h +++ b/inc/graph/ge_attr_value.h @@ -310,7 +310,7 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeAttrValue { VALUE_SET_GET_DEC(GeAttrValue::GRAPH) VALUE_SET_GET_DEC(BYTES) VALUE_SET_GET_DEC(NamedAttrs) - VALUE_SET_GET_DEC(ge::DataType) + VALUE_SET_GET_DEC(ge::DataType) // lint !e665 VALUE_SET_GET_DEC(vector) VALUE_SET_GET_DEC(vector) VALUE_SET_GET_DEC(vector) @@ -320,8 +320,8 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeAttrValue { VALUE_SET_GET_DEC(vector) VALUE_SET_GET_DEC(vector) VALUE_SET_GET_DEC(vector) - VALUE_SET_GET_DEC(vector>) - VALUE_SET_GET_DEC(vector) + VALUE_SET_GET_DEC(vector>) // lint !e665 + VALUE_SET_GET_DEC(vector) // lint !e665 #undef VALUE_SET_GET_DEC GeIrProtoHelper value_; diff --git a/inc/graph/ge_context.h b/inc/graph/ge_context.h index b1ccd5b9..af6b35bc 100644 --- a/inc/graph/ge_context.h +++ b/inc/graph/ge_context.h @@ -28,6 +28,7 @@ class GEContext { uint32_t DeviceId(); uint64_t TraceId(); void Init(); + void SetSessionId(uint64_t session_id); void SetCtxDeviceId(uint32_t device_id); private: diff --git a/inc/graph/ge_tensor.h b/inc/graph/ge_tensor.h index 29a315d6..834dca0b 100644 --- a/inc/graph/ge_tensor.h +++ b/inc/graph/ge_tensor.h @@ -25,6 +25,7 @@ #include "graph/buffer.h" #include "graph/ge_error_codes.h" #include "graph/types.h" + namespace ge { class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeShape { public: @@ -108,8 +109,11 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDesc : public AttrH DataType GetDataType() const; void SetDataType(DataType dt); - void SetOriginDataType(DataType originDataType); DataType GetOriginDataType() const; + void SetOriginDataType(DataType originDataType); + + std::vector GetRefPortIndex() const; + void SetRefPortByIndex(const std::vector &index); GeTensorDesc Clone() const; GeTensorDesc &operator=(const GeTensorDesc &desc); @@ -186,5 +190,4 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensor { GeTensorDesc &DescReference() const; }; } // namespace ge - #endif // INC_GRAPH_GE_TENSOR_H_ diff --git a/inc/graph/model_serialize.h b/inc/graph/model_serialize.h index 3f7d65a9..16529512 100644 --- a/inc/graph/model_serialize.h +++ b/inc/graph/model_serialize.h @@ -49,5 +49,4 @@ class ModelSerialize { friend class GraphDebugImp; }; } // namespace ge - #endif // INC_GRAPH_MODEL_SERIALIZE_H_ diff --git a/inc/graph/node.h b/inc/graph/node.h index 74aaf72f..2629f525 100644 --- a/inc/graph/node.h +++ b/inc/graph/node.h @@ -190,7 +190,7 @@ class Node : public std::enable_shared_from_this { vector out_data_anchors_; InControlAnchorPtr in_control_anchor_; OutControlAnchorPtr out_control_anchor_; - map attrs_; + map attrs_; // lint !e1073 bool has_init_{false}; bool anchor_status_updated_{false}; std::vector send_event_id_list_; diff --git a/inc/graph/op_desc.h b/inc/graph/op_desc.h index faca2d99..1457aa15 100644 --- a/inc/graph/op_desc.h +++ b/inc/graph/op_desc.h @@ -105,6 +105,8 @@ class OpDesc : public std::enable_shared_from_this, public AttrHolder { GeTensorDescPtr MutableInputDesc(uint32_t index) const; + GeTensorDescPtr MutableInputDesc(const string &name) const; + Vistor GetAllInputsDesc() const; Vistor GetAllInputsDescPtr() const; @@ -127,6 +129,8 @@ class OpDesc : public std::enable_shared_from_this, public AttrHolder { GeTensorDescPtr MutableOutputDesc(uint32_t index) const; + GeTensorDescPtr MutableOutputDesc(const string &name) const; + uint32_t GetAllOutputsDescSize() const; Vistor GetAllOutputsDesc() const; @@ -149,16 +153,15 @@ class OpDesc : public std::enable_shared_from_this, public AttrHolder { graphStatus AddDynamicOutputDesc(const string &name, const unsigned int num, bool isPushBack = true); + void RemoveInputDesc(uint32_t index); + void RemoveOutputDesc(uint32_t index); + bool IsOptionalInput(const string &name) const; bool IsOptionalInput(uint32_t index) const; std::map GetAllInputName() const; - void SetAllInputName(const std::map &input_name_idx); - - std::vector GetAllOptionalInputName() const; - std::map GetAllOutputName(); bool UpdateInputName(std::map inputNameIdx); @@ -296,6 +299,8 @@ class OpDesc : public std::enable_shared_from_this, public AttrHolder { std::map subgraph_ir_names_to_type_; vector inputs_desc_{}; + map input_name_idx_{}; + std::unordered_set optional_input_names_{}; vector outputs_desc_{}; map output_name_idx_{}; std::function infer_func_ = nullptr; diff --git a/inc/graph/shape_refiner.h b/inc/graph/shape_refiner.h index 65664615..4f8783a3 100644 --- a/inc/graph/shape_refiner.h +++ b/inc/graph/shape_refiner.h @@ -31,6 +31,7 @@ class ShapeRefiner { static graphStatus InferShapeAndType(const NodePtr &node, bool before_subgraph); static graphStatus InferShapeAndType(const NodePtr &node); static graphStatus InferShapeAndType(const ConstNodePtr &node, Operator &op); + static void ClearContextMap(); private: static void PrintInOutTensorShape(const ge::NodePtr &node, const std::string &phase); diff --git a/inc/graph/utils/graph_utils.h b/inc/graph/utils/graph_utils.h index 6c344435..5f627ea4 100644 --- a/inc/graph/utils/graph_utils.h +++ b/inc/graph/utils/graph_utils.h @@ -23,6 +23,8 @@ #include #include #include +#include + #include "graph/anchor.h" #include "graph/node.h" #include "graph/compute_graph.h" @@ -130,7 +132,7 @@ struct NodeIndexIO { IOType io_type_ = kOut; std::string value_; - std::string ToString() const { return value_; } + const std::string &ToString() const { return value_; } }; class GraphUtils { @@ -188,8 +190,8 @@ class GraphUtils { /// @param [in] output_index /// @return graphStatus /// - static graphStatus InsertNodeBefore(const OutDataAnchorPtr &src, const std::vector &dsts, - const NodePtr &insert_node, uint32_t input_index = 0, uint32_t output_index = 0); + static graphStatus InsertNodeAfter(const OutDataAnchorPtr &src, const std::vector &dsts, + const NodePtr &insert_node, uint32_t input_index = 0, uint32_t output_index = 0); static graphStatus RemoveJustNode(ComputeGraphPtr compute_graph, const NodePtr &node); @@ -303,8 +305,33 @@ class GraphUtils { /// static graphStatus MoveOutCtrlEdges(NodePtr &src_node, NodePtr &dst_node); + /// + /// Copy all in-data edges from `src_node` to `dst_node` + /// @param src_node + /// @param dst_node + /// @return + /// + static graphStatus CopyInDataEdges(const NodePtr &src_node, NodePtr &dst_node); + static ComputeGraphPtr FindRootGraph(ComputeGraphPtr graph); + /// + /// Make a copy of ComputeGraph. + /// @param graph: original graph. + /// @param prefix: node name prefix of new graph. + /// @return ComputeGraphPtr + /// + static ComputeGraphPtr CloneGraph(const ComputeGraphPtr &graph, const string &prefix, + std::vector &input_nodes, std::vector &output_nodes); + + /// + /// Copy tensor attribute to new node. + /// @param [in] dst_desc: cloned node. + /// @param [in] src_node: original node. + /// @return success: GRAPH_SUCESS + /// + static graphStatus CopyTensorAttrs(const OpDescPtr &dst_desc, const NodePtr &src_node); + static graphStatus TopologicalSortingByName(const ge::ComputeGraphPtr &compute_graph, vector &node_vec); /// @@ -393,6 +420,16 @@ class GraphUtils { std::map &anchor_to_symbol); /// + /// Relink all edges for cloned ComputeGraph. + /// @param [in] node: original node. + /// @param [in] prefix: node name prefix of new node. + /// @param [in] all_nodes: all nodes in new graph. + /// @return success: GRAPH_SUCESS + /// + static graphStatus RelinkGraphEdges(const NodePtr &node, const string &prefix, + const std::unordered_map &all_nodes); + + /// /// Union ref-mapping /// @param [in] exist_node_info1 /// @param [in] exist_node_info2 @@ -728,5 +765,4 @@ class PartialGraphBuilder : public ComputeGraphBuilder { std::vector exist_nodes_; }; } // namespace ge - #endif // INC_GRAPH_UTILS_GRAPH_UTILS_H_ diff --git a/inc/graph/utils/node_utils.h b/inc/graph/utils/node_utils.h index 6e0e655d..019bb3a7 100644 --- a/inc/graph/utils/node_utils.h +++ b/inc/graph/utils/node_utils.h @@ -63,6 +63,9 @@ class NodeUtils { static void UnlinkAll(const Node &node); static graphStatus UpdatePeerNodeInputDesc(const NodePtr &node_ptr); + static graphStatus AppendInputAnchor(const NodePtr &node, uint32_t index); + static graphStatus RemoveInputAnchor(const NodePtr &node, uint32_t index); + static bool IsInNodesEmpty(const Node &node); static GeTensorDesc GetOutputDesc(const Node &node, uint32_t index); static GeTensorDesc GetInputDesc(const Node &node, uint32_t index); @@ -100,6 +103,13 @@ class NodeUtils { static NodePtr GetParentInput(const NodePtr &node); /// + /// @brief Check is varying_input for while node + /// @param [in] node: Data node for subgraph + /// @return bool + /// + static bool IsWhileVaryingInput(const ge::NodePtr &node); + + /// /// @brief Get subgraph input is constant. /// @param [in] node /// @param [out] string @@ -114,6 +124,24 @@ class NodeUtils { /// static graphStatus RemoveSubgraphsOnNode(const NodePtr &node); + /// + /// @brief Get subgraph input data node by index. + /// @param [in] node + /// @return Node + /// + static vector GetSubgraphDataNodesByIndex(const Node &node, int index); + + /// + /// @brief Get subgraph input data node by index. + /// @param [in] node + /// @return Node + /// + static vector GetSubgraphOutputNodes(const Node &node); + + static NodePtr GetInDataNodeByIndex(const Node &node, int index); + + static vector GetOutDataNodesByIndex(const Node &node, int index); + private: static std::map> map_send_info_; static std::map> map_recv_info_; diff --git a/inc/graph/utils/tensor_adapter.h b/inc/graph/utils/tensor_adapter.h index f9993606..a7355553 100644 --- a/inc/graph/utils/tensor_adapter.h +++ b/inc/graph/utils/tensor_adapter.h @@ -20,6 +20,7 @@ #include #include "graph/ge_tensor.h" #include "graph/tensor.h" + namespace ge { using GeTensorPtr = std::shared_ptr; using ConstGeTensorPtr = std::shared_ptr; diff --git a/inc/graph/utils/tensor_utils.h b/inc/graph/utils/tensor_utils.h index 2fa398db..caa80dcf 100644 --- a/inc/graph/utils/tensor_utils.h +++ b/inc/graph/utils/tensor_utils.h @@ -21,6 +21,7 @@ #include "graph/def_types.h" #include "graph/ge_error_codes.h" #include "graph/ge_tensor.h" + namespace ge { class TensorUtils { public: diff --git a/src/common/graph/CMakeLists.txt b/src/common/graph/CMakeLists.txt index 43f5b597..f041e4b6 100755 --- a/src/common/graph/CMakeLists.txt +++ b/src/common/graph/CMakeLists.txt @@ -71,5 +71,6 @@ target_link_libraries(graph PRIVATE ${PROTOBUF_LIBRARY} ${c_sec} ${slog} + ${error_manager} rt dl) diff --git a/src/common/graph/compute_graph.cc b/src/common/graph/compute_graph.cc index b73cf939..52953fb2 100644 --- a/src/common/graph/compute_graph.cc +++ b/src/common/graph/compute_graph.cc @@ -62,18 +62,10 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY string ComputeGraph::GetName() co GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void ComputeGraph::SetName(const string &name) { name_ = name; } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY size_t ComputeGraph::GetAllNodesSize() const { - size_t s = nodes_.size(); - for (const auto &sub_graph : sub_graph_) { - s += sub_graph->GetAllNodesSize(); - } - return s; + return GetAllNodes().size(); } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ComputeGraph::Vistor ComputeGraph::GetAllNodes() const { - if (sub_graph_.empty()) { - return Vistor(shared_from_this(), nodes_); - } - std::vector> subgraphs; return AllGraphNodes(subgraphs); } @@ -106,6 +98,15 @@ ComputeGraph::Vistor ComputeGraph::AllGraphNodes(std::vector(shared_from_this(), all_nodes); } +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ComputeGraph::Vistor ComputeGraph::GetNodes( + bool is_unknown_shape) const { + if (is_unknown_shape) { + return GetDirectNode(); + } else { + return GetAllNodes(); + } +} + size_t ComputeGraph::GetDirectNodesSize() const { return nodes_.size(); } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ComputeGraph::Vistor ComputeGraph::GetDirectNode() const { @@ -268,7 +269,7 @@ NodePtr ComputeGraph::AddNodeFront(NodePtr node) { NodePtr ComputeGraph::AddNodeFront(const OpDescPtr &op) { if (op == nullptr) { - GELOGE(GRAPH_FAILED, "The OpDesc ptr should be not null."); + GELOGE(GRAPH_FAILED, "The OpDesc ptr should not be null."); return nullptr; } op->SetId(nodes_.size()); @@ -278,9 +279,38 @@ NodePtr ComputeGraph::AddNodeFront(const OpDescPtr &op) { return AddNodeFront(node_ptr); } +NodePtr ComputeGraph::AddNodeAfter(NodePtr node, const NodePtr &pre_node) { + if (node == nullptr || node->GetOpDesc() == nullptr || pre_node == nullptr) { + GELOGE(GRAPH_FAILED, "The node ptr or op desc should not be null."); + return nullptr; + } + node->GetOpDesc()->SetId(nodes_.size()); + auto node_iter = std::find(nodes_.begin(), nodes_.end(), pre_node); + if (node_iter != nodes_.end()) { + nodes_.insert(node_iter + 1, node); + } else { + GELOGE(GRAPH_FAILED, "Cannot find pre_node in nodes_."); + return nullptr; + } + + return node; +} + +NodePtr ComputeGraph::AddNodeAfter(OpDescPtr &op, const NodePtr &pre_node) { + if (op == nullptr) { + GELOGE(GRAPH_FAILED, "The OpDesc ptr should not be null."); + return nullptr; + } + op->SetId(nodes_.size()); + NodePtr node_ptr = shared_ptr(new (std::nothrow) Node(op, shared_from_this())); + GE_IF_BOOL_EXEC(node_ptr == nullptr, GELOGE(GRAPH_FAILED, "node_ptr is NULL!!!"); return nullptr); + GE_IF_BOOL_EXEC(node_ptr->Init() != GRAPH_SUCCESS, GELOGE(GRAPH_FAILED, "node init failed."); return nullptr); + return AddNodeAfter(node_ptr, pre_node); +} + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY NodePtr ComputeGraph::AddNode(NodePtr node) { if (node == nullptr || node->GetOpDesc() == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr should not be null."); return nullptr; } node->GetOpDesc()->SetId((int64_t)GetDirectNodesSize()); @@ -290,7 +320,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY NodePtr ComputeGraph::AddNode(Nod GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY NodePtr ComputeGraph::AddNode(OpDescPtr op) { if (op == nullptr) { - GELOGE(GRAPH_FAILED, "The OpDesc ptr should be not null."); + GELOGE(GRAPH_FAILED, "The OpDesc ptr should not be null."); return nullptr; } op->SetId(GetDirectNodesSize()); @@ -302,7 +332,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY NodePtr ComputeGraph::AddNode(OpD NodePtr ComputeGraph::AddNode(OpDescPtr op, int64_t id) { // for unserialize. if (op == nullptr) { - GELOGE(GRAPH_FAILED, "The OpDesc ptr should be not null."); + GELOGE(GRAPH_FAILED, "The OpDesc ptr should not be null."); return nullptr; } op->SetId(id); @@ -315,7 +345,7 @@ NodePtr ComputeGraph::AddNode(OpDescPtr op, int64_t id) { // for unserialize. NodePtr ComputeGraph::AddInputNode(NodePtr node) { if (node == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr should not be null."); return nullptr; } input_nodes_.push_back(node); @@ -327,7 +357,7 @@ NodePtr ComputeGraph::AddInputNode(NodePtr node) { NodePtr ComputeGraph::AddOutputNode(NodePtr node) { if (node == nullptr || node->GetOpDesc() == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr or opdesc should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr or opdesc should not be null."); return nullptr; } @@ -363,7 +393,7 @@ graphStatus ComputeGraph::RemoveConstInput(const NodePtr &node) { if (out_anchor->GetOwnerNode()->GetType() == CONSTANT || out_anchor->GetOwnerNode()->GetType() == CONSTANTOP) { GE_CHK_BOOL_RET_STATUS(GraphUtils::RemoveEdge(out_anchor, in_anchor) == GRAPH_SUCCESS, GRAPH_FAILED, "Remove edge from const op failed."); - if (out_anchor->GetOwnerNode()->GetOutDataNodes().size() == 0) { + if (out_anchor->GetOwnerNode()->GetOutNodes().size() == 0) { GELOGI("Remove const op %s.", out_anchor->GetOwnerNode()->GetName().c_str()); auto iter = find(nodes_.begin(), nodes_.end(), out_anchor->GetOwnerNode()); if (iter != nodes_.end()) { @@ -377,7 +407,7 @@ graphStatus ComputeGraph::RemoveConstInput(const NodePtr &node) { GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ComputeGraph::RemoveNode(const NodePtr &node) { if (node == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr should not be null."); return GRAPH_FAILED; } @@ -406,7 +436,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ComputeGraph::RemoveN // Used in sub_graph scenes graphStatus ComputeGraph::RemoveInputNode(const NodePtr &node) { if (node == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr should not be null."); return GRAPH_FAILED; } @@ -421,7 +451,7 @@ graphStatus ComputeGraph::RemoveInputNode(const NodePtr &node) { // Used in sub_graph scenes graphStatus ComputeGraph::RemoveOutputNode(const NodePtr &node) { if (node == nullptr) { - GELOGE(GRAPH_FAILED, "The node ptr should be not null."); + GELOGE(GRAPH_FAILED, "The node ptr should not be null."); return GRAPH_FAILED; } @@ -442,7 +472,7 @@ graphStatus ComputeGraph::RemoveOutputNode(const NodePtr &node) { std::shared_ptr ComputeGraph::AddSubGraph(std::shared_ptr sub_graph) { if (sub_graph == nullptr) { - GELOGE(GRAPH_FAILED, "The graph ptr should be not null."); + GELOGE(GRAPH_FAILED, "The graph ptr should not be null."); return nullptr; } sub_graph_.push_back(sub_graph); @@ -452,7 +482,7 @@ std::shared_ptr ComputeGraph::AddSubGraph(std::shared_ptr &sub_graph) { if (sub_graph == nullptr) { - GELOGE(GRAPH_FAILED, "The graph ptr should be not null."); + GELOGE(GRAPH_FAILED, "The graph ptr should not be null."); return GRAPH_FAILED; } @@ -491,12 +521,15 @@ ComputeGraph::AddSubgraph(const std::string &name, const std::shared_ptrparent_graph_.expired()) { - GE_LOGE("The subgraphs can only be added to the root graph"); - return GRAPH_PARAM_INVALID; + GELOGW("The subgraphs should only be added to the root graph"); } if (name != subgraph->GetName()) { GELOGW("The subgraph name %s is different with input %s", subgraph->GetName().c_str(), name.c_str()); } + if (names_to_subgraph_.find(name) != names_to_subgraph_.end()) { + GE_LOGE("The subgraph %s existed", name.c_str()); + return GRAPH_PARAM_INVALID; + } sub_graph_.push_back(subgraph); names_to_subgraph_[name] = subgraph; return GRAPH_SUCCESS; @@ -640,7 +673,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ComputeGraph::InsertE GELOGW("node or OpDescPtr is nullptr."); continue; } - GE_IF_BOOL_EXEC(node == nullptr, GELOGE(GRAPH_FAILED, "The node should be not null."); return GRAPH_FAILED); + GE_IF_BOOL_EXEC(node == nullptr, GELOGE(GRAPH_FAILED, "The node should not be null."); return GRAPH_FAILED); if (node->GetOpDesc()->GetType() == RECV) { auto iter = find(node_vec.begin(), node_vec.end(), node); if (iter == node_vec.end()) { @@ -786,7 +819,8 @@ graphStatus ComputeGraph::CollectBreadthOutNode(const NodePtr &node, std::mapAttrHolder::Swap(graph); + + origGraph_.swap(graph.origGraph_); + + name_.swap(graph.name_); + std::swap(graph_id_, graph.graph_id_); + attrs_.Swap(graph.attrs_); + nodes_.swap(graph.nodes_); + all_nodes_infos_.swap(graph.all_nodes_infos_); + target_nodes_info_.swap(graph.target_nodes_info_); + + input_nodes_.swap(graph.input_nodes_); + inputs_order_.swap(graph.inputs_order_); + std::swap(input_size_, graph.input_size_); + out_nodes_map_.swap(graph.out_nodes_map_); + std::swap(output_size_, graph.output_size_); + output_nodes_info_.swap(graph.output_nodes_info_); + + sub_graph_.swap(graph.sub_graph_); + names_to_subgraph_.swap(graph.names_to_subgraph_); + parent_graph_.swap(graph.parent_graph_); + parent_node_.swap(graph.parent_node_); + + // the members followed should not in the ComputeGraph class + std::swap(is_valid_flag_, graph.is_valid_flag_); + std::swap(is_summary_graph_, graph.is_summary_graph_); + std::swap(need_iteration_, graph.need_iteration_); + params_share_map_.swap(graph.params_share_map_); + op_name_map_.swap(graph.op_name_map_); + std::swap(session_id_, graph.session_id_); + std::swap(data_format_, graph.data_format_); + std::swap(is_unknown_shape_graph_, graph.is_unknown_shape_graph_); + + // Update Node owner. + SetNodesOwner(); + graph.SetNodesOwner(); +} + +void ComputeGraph::SetNodesOwner() { + for (const auto &node : nodes_) { + if (node == nullptr) { + continue; + } + node->SetOwnerComputeGraph(shared_from_this()); + } +} + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ComputeGraph::IsolateNode(const NodePtr &node) { GE_CHECK_NOTNULL(node); auto next_nodes = node->GetOutAllNodes(); @@ -1104,9 +1186,11 @@ graphStatus ComputeGraph::RemoveExtraOutEdge(const NodePtr &node) { } graphStatus ComputeGraph::Verify() { + bool is_unknown_graph = GetGraphUnknownFlag(); for (const auto &node_ptr : GetAllNodes()) { GE_CHECK_NOTNULL(node_ptr); GE_CHECK_NOTNULL(node_ptr->GetOpDesc()); + GE_IF_BOOL_EXEC(is_unknown_graph, continue); GE_CHK_BOOL_EXEC(node_ptr->GetOpDesc()->CommonVerify() == GRAPH_SUCCESS, return GRAPH_FAILED, "Verifying %s failed.", node_ptr->GetName().c_str()); } diff --git a/src/common/graph/debug/ge_op_types.h b/src/common/graph/debug/ge_op_types.h index da36f72c..f11ef31e 100644 --- a/src/common/graph/debug/ge_op_types.h +++ b/src/common/graph/debug/ge_op_types.h @@ -34,12 +34,16 @@ GE_REGISTER_OPTYPE(EXPANDDIMS, "ExpandDims"); GE_REGISTER_OPTYPE(SWITCH, "Switch"); GE_REGISTER_OPTYPE(MERGE, "Merge"); GE_REGISTER_OPTYPE(STREAMMERGE, "StreamMerge"); +GE_REGISTER_OPTYPE(ENTER, "Enter"); +GE_REGISTER_OPTYPE(REFENTER, "RefEnter"); GE_REGISTER_OPTYPE(NEXTITERATION, "NextIteration"); GE_REGISTER_OPTYPE(REFNEXTITERATION, "RefNextIteration"); GE_REGISTER_OPTYPE(CONSTANT, "Const"); +GE_REGISTER_OPTYPE(PLACEHOLDER, "PlaceHolder"); GE_REGISTER_OPTYPE(FRAMEWORKOP, "FrameworkOp"); GE_REGISTER_OPTYPE(GETNEXT, "GetNext"); GE_REGISTER_OPTYPE(INITDATA, "InitData"); +GE_REGISTER_OPTYPE(REFIDENTITY, "RefIdentity"); GE_REGISTER_OPTYPE(ANN_DATA, "AnnData"); GE_REGISTER_OPTYPE(CONSTANTOP, "Constant"); diff --git a/src/common/graph/format_refiner.cc b/src/common/graph/format_refiner.cc index 11a610ce..9cb76539 100644 --- a/src/common/graph/format_refiner.cc +++ b/src/common/graph/format_refiner.cc @@ -41,11 +41,9 @@ using namespace ge; using namespace std; namespace ge { namespace { -static const std::unordered_set kChangeDimNodes = {PERMUTE, EXPANDDIMS, SQUEEZE}; -static bool net_format_is_nd = true; -static Format g_user_set_format = FORMAT_ND; -static bool is_first_infer = true; -static RefRelations reflection_builder; +const std::unordered_set kChangeDimNodes = {PERMUTE, EXPANDDIMS, SQUEEZE}; +const string kIsGraphInferred = "_is_graph_inferred"; +RefRelations reflection_builder; } // namespace graphStatus ReflectionProcess(const std::unordered_set &reflection, @@ -72,9 +70,49 @@ graphStatus ReflectionProcess(const std::unordered_set &re return GRAPH_SUCCESS; } -graphStatus FormatRefiner::RefreshConstantOutProcess(const OpDescPtr &op_desc) { +graphStatus BiasAddFormatFixProcess(ge::NodePtr &node_ptr) { + // 5 meas dim num + if (node_ptr->GetType() != "BiasAdd") { + return GRAPH_SUCCESS; + } + std::unordered_map kTfFormatFix = {{"NHWC", FORMAT_NDHWC}, {"NCHW", FORMAT_NCDHW}}; + for (size_t i = 0; i < node_ptr->GetOpDesc()->GetInputsSize(); i++) { + auto in_desc = node_ptr->GetOpDesc()->MutableInputDesc(i); + GE_CHECK_NOTNULL(in_desc); + if (in_desc->MutableShape().GetDimNum() != 5) { // 5 means dim num + continue; + } + auto format = in_desc->GetOriginFormat(); + auto key = TypeUtils::FormatToSerialString(format); + auto fixed_format = (kTfFormatFix.count(key) == 0) ? format : kTfFormatFix[key]; + in_desc->SetOriginFormat(fixed_format); + in_desc->SetFormat(fixed_format); + GELOGD("fix the %zu'th input of node[%s]. Origin format is %s , after fixed it is %s", i, + node_ptr->GetName().c_str(), TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::FormatToSerialString(fixed_format).c_str()); + } + for (size_t i = 0; i < node_ptr->GetOpDesc()->GetOutputsSize(); i++) { + auto out_desc = node_ptr->GetOpDesc()->MutableOutputDesc(i); + GE_CHECK_NOTNULL(out_desc); + if (out_desc->MutableShape().GetDimNum() != 5) { // 5 means dim num + continue; + } + auto format = out_desc->GetOriginFormat(); + auto key = TypeUtils::FormatToSerialString(format); + auto fixed_format = (kTfFormatFix.count(key) == 0) ? format : kTfFormatFix[key]; + out_desc->SetOriginFormat(fixed_format); + out_desc->SetFormat(fixed_format); + GELOGD("fix the %zu'th output of node[%s]. Origin format is %s , after fixed it is %s", i, + node_ptr->GetName().c_str(), TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::FormatToSerialString(fixed_format).c_str()); + } + return GRAPH_SUCCESS; +} + +graphStatus FormatRefiner::RefreshConstantOutProcess(const ComputeGraphPtr &graph, const OpDescPtr &op_desc) { + GE_CHECK_NOTNULL(graph); GE_CHECK_NOTNULL(op_desc); - if (op_desc->GetType() == CONSTANTOP && is_first_infer == true) { + if (op_desc->GetType() == CONSTANTOP && !IsGraphInferred(graph)) { ConstGeTensorPtr tensor_value; if (!AttrUtils::GetTensor(op_desc, "value", tensor_value)) { GELOGE(GRAPH_FAILED, "Get value failed, node name:%s.", op_desc->GetName().c_str()); @@ -95,7 +133,7 @@ graphStatus FormatRefiner::GetAnchorPoints(const ge::ComputeGraphPtr &graph, std } anchor_points.clear(); // Get all anchor point nodes and switch nodes - for (const auto &node_ptr : graph->GetAllNodes()) { + for (auto &node_ptr : graph->GetAllNodes()) { if (node_ptr == nullptr) { return GRAPH_FAILED; } @@ -103,7 +141,7 @@ graphStatus FormatRefiner::GetAnchorPoints(const ge::ComputeGraphPtr &graph, std if (op_desc == nullptr) { return GRAPH_FAILED; } - graphStatus status = RefreshConstantOutProcess(op_desc); + graphStatus status = RefreshConstantOutProcess(graph, op_desc); if (status != GRAPH_SUCCESS) { GELOGE(GRAPH_FAILED, "refresh constant out process failed!"); return GRAPH_FAILED; @@ -135,6 +173,16 @@ graphStatus FormatRefiner::GetAnchorPoints(const ge::ComputeGraphPtr &graph, std if (!node_is_all_nd) { continue; } + // special process for biasAdd op + // In tensorflow, biasAdd's format is alwayse NHWC even though set the arg + // "data_format" to NDHWC or NCDHW.It will destroy our format-infer mechanism + // so here do special process + status = BiasAddFormatFixProcess(node_ptr); + if (status != GRAPH_SUCCESS) { + GELOGE(GRAPH_FAILED, "fix biasAdd process failed!"); + return GRAPH_FAILED; + } + GELOGD("Node[%s] is anchor point!", node_ptr->GetName().c_str()); anchor_points.push_back(node_ptr); } @@ -344,14 +392,11 @@ void FormatRefiner::RefreshOriginFormatOfAnchor(std::vector &anchor } } -void FormatRefiner::SetInferOrigineFormatFlag(bool is_first) { is_first_infer = is_first; } - -graphStatus FormatRefiner::DataNodeFormatProcess(std::vector &data_nodes, ge::Format data_format, +graphStatus FormatRefiner::DataNodeFormatProcess(const ComputeGraphPtr &graph, std::vector &data_nodes, + ge::Format data_format, std::unordered_map &node_status) { - bool is_internal_format = TypeUtils::IsInternalFormat(data_format); - bool need_process = (!is_first_infer) && (!is_internal_format) && (data_format != FORMAT_ND); - if (!need_process) { - GELOGI("no necessary to do DataNodeFormatProcess.is_first_infer:%d, data_format:%s", is_first_infer, + if (!(IsGraphInferred(graph) && (!TypeUtils::IsInternalFormat(data_format)) && (data_format != FORMAT_ND))) { + GELOGI("no necessary to do DataNodeFormatProcess. is_graph_inferred:%d, data_format:%s", IsGraphInferred(graph), TypeUtils::FormatToSerialString(data_format).c_str()); return GRAPH_SUCCESS; } @@ -410,8 +455,6 @@ graphStatus FormatRefiner::InferOrigineFormat(const ge::ComputeGraphPtr &graph) std::vector anchor_points; std::vector data_nodes; // global net format - net_format_is_nd = true; - g_user_set_format = FORMAT_ND; if (graph == nullptr) { GELOGE(GRAPH_FAILED, "input graph is null"); @@ -448,10 +491,15 @@ graphStatus FormatRefiner::InferOrigineFormat(const ge::ComputeGraphPtr &graph) /// format for these data nodes. /// Notice: ignore 5D formats auto data_format = graph->GetDataFormat(); - status = DataNodeFormatProcess(data_nodes, data_format, node_status); - // Set infer flag to false - SetInferOrigineFormatFlag(false); + status = DataNodeFormatProcess(graph, data_nodes, data_format, node_status); + + (void)AttrUtils::SetBool(graph, kIsGraphInferred, true); return status; } + +bool FormatRefiner::IsGraphInferred(const ComputeGraphPtr &graph) { + bool is_graph_inferred = false; + return (AttrUtils::GetBool(graph, kIsGraphInferred, is_graph_inferred) && is_graph_inferred); +} } // namespace ge diff --git a/src/common/graph/format_refiner.h b/src/common/graph/format_refiner.h index fa40a034..eca93bae 100644 --- a/src/common/graph/format_refiner.h +++ b/src/common/graph/format_refiner.h @@ -30,10 +30,9 @@ namespace ge { class FormatRefiner { public: static graphStatus InferOrigineFormat(const ge::ComputeGraphPtr &graph); - static void SetInferOrigineFormatFlag(bool is_first = true); private: - static graphStatus RefreshConstantOutProcess(const OpDescPtr &op_desc); + static graphStatus RefreshConstantOutProcess(const ComputeGraphPtr &graph, const OpDescPtr &op_desc); static graphStatus GetAnchorPoints(const ge::ComputeGraphPtr &graph, std::vector &anchor_points, std::vector &data_nodes, std::unordered_map &node_status); @@ -43,8 +42,9 @@ class FormatRefiner { std::unordered_map &node_status); static graphStatus ForwardInferProcess(std::deque &nodes, ge::NodePtr &node, std::unordered_map &node_status); - static graphStatus DataNodeFormatProcess(std::vector &data_nodes, ge::Format data_format, - std::unordered_map &node_status); + static graphStatus DataNodeFormatProcess(const ComputeGraphPtr &graph, std::vector &data_nodes, + ge::Format data_format, std::unordered_map &node_status); + static bool IsGraphInferred(const ComputeGraphPtr &graph); }; } // namespace ge #endif // COMMON_GRAPH_FORMAT_REFINER_H_ diff --git a/src/common/graph/ge_attr_define.cc b/src/common/graph/ge_attr_define.cc index 96638249..f78ca7aa 100644 --- a/src/common/graph/ge_attr_define.cc +++ b/src/common/graph/ge_attr_define.cc @@ -158,6 +158,10 @@ const std::string ATTR_NAME_AUTOMIC_ADD_MEM_SIZE = "automic_add_mem_size"; const std::string ATTR_NAME_DYNAMIC_OUTPUT_DIMS = "_dynamic_output_dims"; const std::string ATTR_NAME_INPUT_ORIGIN_SIZE = "input_origin_size"; +// Identify node connecting to input and output +const std::string ATTR_NAME_NODE_CONNECT_INPUT = "_is_connected_to_data"; +const std::string ATTR_NAME_NODE_CONNECT_OUTPUT = "_is_connected_to_netoutput"; + // To be deleted const std::string ATTR_TO_BE_DELETED = "to_be_deleted"; const std::string PERMUTE_RESHAPE_FUSION = "permute_reshape_fusion"; @@ -725,6 +729,10 @@ const std::string ATTR_MODEL_TASK_INDEX_OP_NAME = "task_index_op_name"; const std::string ATTR_MODEL_CORE_TYPE = "core_type"; +const std::string ATTR_MODEL_ATC_VERSION = "atc_version"; + +const std::string ATTR_MODEL_OPP_VERSION = "opp_version"; + // Public attribute const std::string ATTR_NAME_IMPLY_TYPE = "imply_type"; @@ -901,6 +909,7 @@ const std::string ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE = "is_end_of_inputmem_l const std::string ATTR_NAME_PRED_VALUE = "_pred_value"; const std::string ATTR_NAME_BATCH_NUM = "_batch_num"; const std::string ATTR_NAME_BATCH_LABEL = "_batch_label"; +const std::string ATTR_NAME_COMBINED_BATCH = "_combined_batch"; // Control flow const std::string ATTR_NAME_STREAM_SWITCH_COND = "switch_condition"; @@ -910,6 +919,7 @@ const std::string ATTR_NAME_SWITCHN_PRED_VALUE = "switch_pred_value"; const std::string ATTR_NAME_ITERATORS_PER_LOOP = "iterations_per_loop"; const std::string ATTR_NAME_FLOW_CTRL_NODE_FLAG = "is_flow_ctrl_node"; const std::string ATTR_NAME_SUBGRAPH_FIRST_ACTIVE = "subgraph_first_active"; +const std::string ATTR_NAME_COMBINED_DYNAMIC_DIMS = "combined_dynamic_dims"; const std::string ATTR_NAME_SWITCH_BRANCH_NODE_LABEL = "_switch_branch_node_label"; const std::string ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG = "_switch_true_branch_flag"; @@ -934,7 +944,7 @@ const std::string ATTR_NAME_MEMORY_TYPE_WORKSPACE = "memory_type_workspace"; const std::string MODEL_ATTR_SESSION_ID = "session_id"; -// l1 fusion and other fusion in future +// lx fusion const std::string ATTR_NAME_L1_FUSION_GROUP_ID = "_l1_fusion_group_id"; const std::string ATTR_NAME_FUSION_GROUP_KEY = "_fusion_group_key"; const std::string ATTR_NAME_L1_FUSION_GROUP_KEY = "_l1_fusion_group_key"; @@ -948,9 +958,17 @@ const std::string ATTR_NAME_OUTPUT_OFFSET_FOR_L1_FUSION = "_output_offset_for_l1 const std::string ATTR_NAME_SWITCH_FOR_L1_FUSION = "_enable_l1_fusion"; const std::string ATTR_N_BATCH_SPILT = "_is_n_batch_split"; const std::string ATTR_NO_TASK_AND_DUMP_NEEDED = "_no_task_and_dump_needed"; +const std::string ATTR_DATA_DUMP_REF = "_datadump_ref"; const std::string ATTR_NAME_OUTPUT_OFFSET_FOR_BUFFER_FUSION = "_output_offset_for_buffer_fusion"; const std::string ATTR_NAME_L2_FUSION_GROUP_ID = "_l2_fusion_group_id"; const std::string ATTR_NAME_SWITCH_FOR_L2_FUSION = "_enable_l2_fusion"; +const std::string ATTR_NAME_OP_INPUT_L1_FLAG = "_op_input_l1_flag"; +const std::string ATTR_NAME_OP_INPUT_L1_ADDR = "_op_input_l1_addr"; +const std::string ATTR_NAME_OP_INPUT_L1_VALID_SIZE = "_op_input_l1_valid_size"; + +// Op debug attrs +const std::string ATTR_OP_DEBUG_FLAG = "_op_debug_flag"; +const std::string ATTR_OP_DEBUG_MODE = "_op_debug_mode"; // Atomic addr clean attrs const std::string ATOMIC_ATTR_INPUT_INDEX = "atomic_input_index"; @@ -971,6 +989,8 @@ const std::string ATTR_INSERT_BY_MBATCH = "mbatch-inserted-node"; const std::string ATTR_MBATCH_ORIGIN_INPUT_DIMS = "_mbatch_origin_input_dims"; +const std::string ATTR_DYNAMIC_TYPE = "mbatch_dynamic_type"; + // For inserted op const std::string ATTR_INSERTED_BY_GE = "_inserted_by_ge"; @@ -1009,10 +1029,38 @@ const std::string ATTR_NAME_VALID_OUTPUT_SHAPE_LIST_LIST = "_valid_output_shape_ const std::string ATTR_NAME_SLICE_INPUT_OFFSET_LIST_LIST = "_input_offset_list_list"; const std::string ATTR_NAME_SLICE_OUTPUT_OFFSET_LIST_LIST = "_output_offset_list_list"; +// for unregistered op +const std::string ATTR_NAME_UNREGST_OPPATH = "_unregst_oppath"; +const std::string ATTR_NAME_UNREGST_ATTRLIST = "_unregst_attrlist"; + // used for Horovod const std::string ATTR_INTER_EVENT_IDENTIFY = "event_id"; const std::string ATTR_HOROVOD_ATTR_REDUCE_TYPE = "reduce_op"; // used for allreduce tailing optimization const std::string ATTR_NAME_HCCL_FUSED_GROUP = "_hccl_fused_group"; const std::string ATTR_NAME_HCCL_FUSED_FLAG = "_hccl_fused_node"; + +// dynamic shape attr +const std::string ATTR_DYNAMIC_SHAPE_FIXED_ADDR = "_alloc_fixed_addr"; +const std::string ATTR_DYNAMIC_SHAPE_FIXED_ADDR_INDEX = "_alloc_fixed_addr_index"; + +// atc user def dtype&format +const std::string ATTR_ATC_USER_DEFINE_DATATYPE = "_user_defined_data_type"; +const std::string ATTR_ATC_USER_DEFINE_FORMAT = "_user_defined_format"; + +// for fusion op plugin +const std::string ATTR_NAME_FUSIONOP_ORIGINAL_TYPE = "_fusionop_original_type"; + +// graph partition for aicpu +const std::string ATTR_NAME_PLD_FRONT_NODE_ENGINE_NAME = "pld_front_node_engine_name"; +const std::string ATTR_NAME_END_REAR_NODE_ENGINE_NAME = "end_rear_node_engine_name"; + +// input and output memory type +const std::string ATTR_VARIABLE_PLACEMENT = "_variable_placement"; +const std::string ATTR_INPUT_MEMORY_TYPE = "_input_memory_type"; +const std::string ATTR_OUTPUT_MEMORY_TYPE = "_output_memory_type"; + +// input_output_offset +const std::string ATTR_ZERO_COPY_BASIC_OFFSET = "_zero_copy_basic_offset"; +const std::string ATTR_ZERO_COPY_RELATIVE_OFFSET = "_zero_copy_relative_offset"; } // namespace ge diff --git a/src/common/graph/ge_attr_value.cc b/src/common/graph/ge_attr_value.cc index 3a1dec6d..a8490470 100644 --- a/src/common/graph/ge_attr_value.cc +++ b/src/common/graph/ge_attr_value.cc @@ -33,7 +33,8 @@ using std::vector; namespace ge { NamedAttrs::NamedAttrs() { named_attrs_.InitDefault(); } -NamedAttrs::NamedAttrs(const ProtoMsgOwner &owner, proto::NamedAttrs *proto_msg) : named_attrs_(owner, proto_msg) {} +NamedAttrs::NamedAttrs(const ProtoMsgOwner &owner, proto::NamedAttrs *proto_msg) + : named_attrs_(owner, proto_msg) {} // lint !e1744 void NamedAttrs::SetName(const std::string &name) { auto proto_msg = named_attrs_.GetProtoMsg(); @@ -238,7 +239,7 @@ ATTR_VALUE_SET_GET_IMP(GeAttrValue::STR) ATTR_VALUE_SET_GET_IMP(vector) ATTR_VALUE_SET_GET_IMP(GeAttrValue::INT) ATTR_VALUE_SET_GET_IMP(vector) -ATTR_VALUE_SET_GET_IMP(GeAttrValue::FLOAT) +ATTR_VALUE_SET_GET_IMP(GeAttrValue::FLOAT) // lint !e524 ATTR_VALUE_SET_GET_IMP(vector) ATTR_VALUE_SET_GET_IMP(GeAttrValue::BOOL) ATTR_VALUE_SET_GET_IMP(vector) @@ -252,9 +253,11 @@ ATTR_VALUE_SET_GET_IMP(GeAttrValue::BYTES) ATTR_VALUE_SET_GET_IMP(vector) ATTR_VALUE_SET_GET_IMP(GeAttrValue::NAMED_ATTRS) ATTR_VALUE_SET_GET_IMP(vector) +/*lint -e665*/ ATTR_VALUE_SET_GET_IMP(vector>) -ATTR_VALUE_SET_GET_IMP(vector) -ATTR_VALUE_SET_GET_IMP(GeAttrValue::DATA_TYPE) +/*lint +e665*/ +ATTR_VALUE_SET_GET_IMP(vector) // lint !e665 +ATTR_VALUE_SET_GET_IMP(GeAttrValue::DATA_TYPE) // lint !e665 #undef ATTR_VALUE_SET_GET_IMP @@ -782,14 +785,14 @@ bool GeAttrValueImp::GetValue(const proto::AttrDef &proto_attr_val, const ProtoM if (graph_def == nullptr) { GELOGE(GRAPH_FAILED, "proto::GraphDef make shared failed"); graph_def = nullptr; - return false; + return false; // lint !e665 } else { ModelSerializeImp imp; imp.SetProtobufOwner(graph_def); if (!imp.UnserializeGraph(graph, *graph_def)) { GELOGE(GRAPH_FAILED, "UnserializeGraph Failed"); return false; - } + } // lint !e514 value = graph; } return true; @@ -809,7 +812,7 @@ bool GeAttrValueImp::GetValue(const proto::AttrDef &proto_attr_val, const ProtoM if (graph_def == nullptr) { GELOGE(GRAPH_FAILED, "proto::GraphDef make shared failed"); graph_def = nullptr; - return false; + return false; // lint !e665 } else { ComputeGraphPtr graph = nullptr; ModelSerializeImp imp; @@ -817,7 +820,7 @@ bool GeAttrValueImp::GetValue(const proto::AttrDef &proto_attr_val, const ProtoM if (!imp.UnserializeGraph(graph, *graph_def)) { GELOGE(GRAPH_FAILED, "UnserializeGraph Failed"); return false; - } + } // lint !e514 value.push_back(graph); } } @@ -969,7 +972,9 @@ ATTR_UTILS_SET_IMP(Tensor, GeTensor) ATTR_UTILS_SET_GET_IMP(NamedAttrs, GeAttrValue::NAMED_ATTRS) ATTR_UTILS_SET_GET_IMP(Bytes, Buffer) ATTR_UTILS_SET_GET_IMP(Graph, ComputeGraphPtr) +/*lint -e665*/ ATTR_UTILS_SET_GET_IMP(ListListInt, vector>) +/*lint +e665*/ ATTR_UTILS_SET_GET_IMP(ListInt, vector) ATTR_UTILS_SET_IMP(ListInt, vector) @@ -984,8 +989,8 @@ ATTR_UTILS_SET_IMP(ListTensor, vector) ATTR_UTILS_SET_GET_IMP(ListNamedAttrs, vector) ATTR_UTILS_SET_GET_IMP(ListBytes, vector) ATTR_UTILS_SET_GET_IMP(ListGraph, vector) -ATTR_UTILS_SET_GET_IMP(ListDataType, vector) -ATTR_UTILS_SET_GET_IMP(DataType, ge::DataType) +ATTR_UTILS_SET_GET_IMP(ListDataType, vector) // lint !e665 +ATTR_UTILS_SET_GET_IMP(DataType, ge::DataType) // lint !e665 bool AttrUtils::SetListTensor(AttrHolderAdapter &&obj, const string &name, std::initializer_list &&value) { @@ -1154,7 +1159,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool AttrUtils::GetListOpDesc(Con } for (const auto &item : bytes_vals) { ModelSerialize serialize; - auto op_desc = serialize.UnserializeOpDesc(item.GetData(), item.GetSize()); + auto op_desc = serialize.UnserializeOpDesc(item.GetData(), item.GetSize()); // lint !e732 value.push_back(op_desc); } return true; @@ -1206,7 +1211,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OpDescPtr AttrUtils::CloneOpDesc( op_def = ComGraphMakeShared(); if (op_def == nullptr) { GELOGE(GRAPH_FAILED, "proto::OpDef make shared failed"); - return nullptr; + return nullptr; // lint !e665 } ModelSerializeImp imp; (void)imp.SerializeOpDesc(org_op_desc, op_def.get()); @@ -1216,27 +1221,16 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OpDescPtr AttrUtils::CloneOpDesc( GE_CHK_BOOL_EXEC(imp.UnserializeOpDesc(op_desc, *op_def), return op_desc, "op_desc unserialize failed"); op_desc->extAttrs_ = org_op_desc->extAttrs_; - if (op_desc->HasAttr("_input_name_idx_key")) { - if (op_desc->DelAttr("_input_name_idx_key") != SUCCESS) { - GELOGE(GRAPH_FAILED, "DelAttr _input_name_idx_key failed."); - } - } - - if (op_desc->HasAttr("_input_name_idx_value")) { - if (op_desc->DelAttr("_input_name_idx_value") != SUCCESS) { - GELOGE(GRAPH_FAILED, "DelAttr _input_name_idx_value failed."); - } + // This function may be called by some passes of fusion engine, in this condition, do not need these attribute + if (!op_desc->input_name_idx_.empty()) { + op_desc->input_name_idx_.clear(); } - - if (op_desc->HasAttr("_opt_input")) { - if (op_desc->DelAttr("_opt_input") != SUCCESS) { - GELOGE(GRAPH_FAILED, "DelAttr _opt_input failed."); - } - } - if (!op_desc->output_name_idx_.empty()) { op_desc->output_name_idx_.clear(); } + if (!op_desc->optional_input_names_.empty()) { + op_desc->optional_input_names_.clear(); + } return op_desc; } @@ -1260,6 +1254,9 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OpDescPtr AttrUtils::CopyOpDesc(c op_desc->extAttrs_ = org_op_desc->extAttrs_; + op_desc->input_name_idx_.insert(org_op_desc->input_name_idx_.begin(), org_op_desc->input_name_idx_.end()); + op_desc->optional_input_names_.insert(org_op_desc->optional_input_names_.begin(), + org_op_desc->optional_input_names_.end()); op_desc->output_name_idx_.insert(org_op_desc->output_name_idx_.begin(), org_op_desc->output_name_idx_.end()); op_desc->infer_func_ = org_op_desc->infer_func_; diff --git a/src/common/graph/ge_tensor.cc b/src/common/graph/ge_tensor.cc index 8ffbba91..196b8569 100644 --- a/src/common/graph/ge_tensor.cc +++ b/src/common/graph/ge_tensor.cc @@ -220,6 +220,7 @@ const string TENSOR_UTILS_ORIGIN_SHAPE = "origin_shape"; const string TENSOR_UTILS_ORIGIN_FORMAT = "origin_format"; const string TENSOR_UTILS_ORIGIN_DATA_TYPE = "origin_data_type"; const string TENSOR_UTILS_SHAPE_RANGE = "shape_range"; +const string TENSOR_UTILS_REF_PORT_INDEX = "ref_port_index"; GeShape::GeShape(const ProtoMsgOwner &proto_owner, proto::ShapeDef *proto_msg) : shape_def_(proto_owner, proto_msg) {} @@ -567,6 +568,16 @@ DataType GeTensorDesc::GetOriginDataType() const { return TypeUtils::SerialStringToDataType(origin_data_type_str); } +std::vector GeTensorDesc::GetRefPortIndex() const { + vector ref_port_index; + (void)AttrUtils::GetListInt(this, TENSOR_UTILS_REF_PORT_INDEX, ref_port_index); + return ref_port_index; +} + +void GeTensorDesc::SetRefPortByIndex(const std::vector &index) { + (void)AttrUtils::SetListInt(this, TENSOR_UTILS_REF_PORT_INDEX, index); +} + graphStatus GeTensorDesc::IsValid() const { auto dtype = this->GetDataType(); auto format = this->GetFormat(); diff --git a/src/common/graph/graph.cc b/src/common/graph/graph.cc index 09d4fd56..fc30e9d6 100644 --- a/src/common/graph/graph.cc +++ b/src/common/graph/graph.cc @@ -210,7 +210,7 @@ class GraphImpl { graphStatus FindOpByName(const string &name, ge::Operator &op) const { auto it = op_list_.find(name); - GE_CHK_BOOL_EXEC(it != op_list_.end(), return GRAPH_FAILED, "Error: there is no op: %s.", name.c_str()); + GE_CHK_BOOL_EXEC(it != op_list_.end(), return GRAPH_FAILED, "there is no op: %s.", name.c_str()); op = it->second; return GRAPH_SUCCESS; } diff --git a/src/common/graph/graph.mk b/src/common/graph/graph.mk index 5eaf7d86..b007dac8 100644 --- a/src/common/graph/graph.mk +++ b/src/common/graph/graph.mk @@ -77,6 +77,7 @@ LOCAL_SHARED_LIBRARIES := \ libc_sec \ libprotobuf \ libslog \ + liberror_manager \ LOCAL_LDFLAGS := -lrt -ldl @@ -94,10 +95,36 @@ LOCAL_CPPFLAGS += -fexceptions LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) LOCAL_SRC_FILES := \ - ../../out/atc/lib64/stub/graph.cc \ - ../../out/atc/lib64/stub/operator.cc \ - ../../out/atc/lib64/stub/tensor.cc \ - ../../out/atc/lib64/stub/operator_factory.cc \ + ../../out/graph/lib64/stub/graph.cc \ + ../../out/graph/lib64/stub/operator.cc \ + ../../out/graph/lib64/stub/tensor.cc \ + ../../out/graph/lib64/stub/operator_factory.cc \ + + +LOCAL_SHARED_LIBRARIES := + +LOCAL_LDFLAGS := -lrt -ldl + +LOCAL_MULTILIB := 64 +LOCAL_PROPRIETARY_MODULE := true + +include $(BUILD_HOST_SHARED_LIBRARY) + +#compiler for host +include $(CLEAR_VARS) +LOCAL_MODULE := fwk_stub/libgraph + +LOCAL_CFLAGS += -DFMK_SUPPORT_DUMP -O2 +LOCAL_CPPFLAGS += -fexceptions + +LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) +LOCAL_SRC_FILES := \ + ../../out/graph/lib64/stub/attr_value.cc \ + ../../out/graph/lib64/stub/graph.cc \ + ../../out/graph/lib64/stub/operator.cc \ + ../../out/graph/lib64/stub/operator_factory.cc \ + ../../out/graph/lib64/stub/tensor.cc \ + ../../out/graph/lib64/stub/inference_context.cc \ LOCAL_SHARED_LIBRARIES := @@ -122,6 +149,7 @@ LOCAL_SHARED_LIBRARIES := \ libc_sec \ libprotobuf \ libslog \ + liberror_manager \ LOCAL_LDFLAGS := -lrt -ldl @@ -142,10 +170,39 @@ LOCAL_CFLAGS += -O2 LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) LOCAL_SRC_FILES := \ - ../../out/atc/lib64/stub/graph.cc \ - ../../out/atc/lib64/stub/operator.cc \ - ../../out/atc/lib64/stub/tensor.cc \ - ../../out/atc/lib64/stub/operator_factory.cc \ + ../../out/graph/lib64/stub/graph.cc \ + ../../out/graph/lib64/stub/operator.cc \ + ../../out/graph/lib64/stub/tensor.cc \ + ../../out/graph/lib64/stub/operator_factory.cc \ + + +LOCAL_SHARED_LIBRARIES := + +LOCAL_LDFLAGS := -lrt -ldl + +ifeq ($(device_os),android) +LOCAL_LDFLAGS := -ldl +endif + +LOCAL_MULTILIB := 64 +LOCAL_PROPRIETARY_MODULE := true + +include $(BUILD_SHARED_LIBRARY) + +#compiler for device +include $(CLEAR_VARS) +LOCAL_MODULE := fwk_stub/libgraph + +LOCAL_CFLAGS += -O2 + +LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) +LOCAL_SRC_FILES := \ + ../../out/graph/lib64/stub/attr_value.cc \ + ../../out/graph/lib64/stub/graph.cc \ + ../../out/graph/lib64/stub/operator.cc \ + ../../out/graph/lib64/stub/operator_factory.cc \ + ../../out/graph/lib64/stub/tensor.cc \ + ../../out/graph/lib64/stub/inference_context.cc \ LOCAL_SHARED_LIBRARIES := @@ -174,6 +231,7 @@ LOCAL_SHARED_LIBRARIES := \ libc_sec \ libprotobuf \ libslog \ + liberror_manager \ LOCAL_LDFLAGS := -lrt -ldl @@ -199,6 +257,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \ libc_sec \ libslog \ + liberror_manager \ LOCAL_LDFLAGS := -lrt -ldl @@ -222,6 +281,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \ libc_sec \ libslog \ + liberror_manager \ LOCAL_LDFLAGS := -lrt -ldl diff --git a/src/common/graph/model_serialize.cc b/src/common/graph/model_serialize.cc index 19cb4538..673bb31b 100644 --- a/src/common/graph/model_serialize.cc +++ b/src/common/graph/model_serialize.cc @@ -88,10 +88,8 @@ bool ModelSerializeImp::SerializeEdge(const NodePtr &node, proto::OpDef *op_def_ } bool ModelSerializeImp::SerializeOpDesc(const ConstOpDescPtr &op_desc, proto::OpDef *op_def_proto, bool is_dump) { - if (op_desc == nullptr || op_def_proto == nullptr) { - GELOGE(GRAPH_FAILED, "Input Para Invalid"); - return false; - } + GE_CHK_BOOL_EXEC(op_desc != nullptr, return false, "op_desc is null."); + GE_CHK_BOOL_EXEC(op_def_proto != nullptr, return false, "op_def_proto is null."); if (op_desc->op_def_.GetProtoMsg() != nullptr) { *op_def_proto = *op_desc->op_def_.GetProtoMsg(); // Delete unnecessary attr @@ -130,18 +128,40 @@ bool ModelSerializeImp::SerializeOpDesc(const ConstOpDescPtr &op_desc, proto::Op for (const std::string &name : op_desc->GetSubgraphInstanceNames()) { op_def_proto->add_subgraph_name(name); } + OpDescToAttrDef(op_desc, op_def_proto); + } + return true; +} - proto::AttrDef key; - proto::AttrDef value; +void ModelSerializeImp::OpDescToAttrDef(const ConstOpDescPtr &op_desc, proto::OpDef *op_def_proto) { + proto::AttrDef key_in; + proto::AttrDef value_in; + auto op_desc_attr = op_def_proto->mutable_attr(); + if (!op_desc->input_name_idx_.empty()) { + for (auto &item : op_desc->input_name_idx_) { + key_in.mutable_list()->add_s(item.first); + value_in.mutable_list()->add_i(item.second); + } + op_desc_attr->insert({"_input_name_key", key_in}); + op_desc_attr->insert({"_input_name_value", value_in}); + } + proto::AttrDef key_out; + proto::AttrDef value_out; + if (!op_desc->output_name_idx_.empty()) { for (auto &item : op_desc->output_name_idx_) { - key.mutable_list()->add_s(item.first); - value.mutable_list()->add_i(item.second); + key_out.mutable_list()->add_s(item.first); + value_out.mutable_list()->add_i(item.second); } - auto op_desc_attr = op_def_proto->mutable_attr(); - op_desc_attr->insert({"_output_name_key", key}); - op_desc_attr->insert({"_output_name_value", value}); + op_desc_attr->insert({"_output_name_key", key_out}); + op_desc_attr->insert({"_output_name_value", value_out}); + } + proto::AttrDef opt_input; + if (!op_desc->optional_input_names_.empty()) { + for (auto &item : op_desc->optional_input_names_) { + opt_input.mutable_list()->add_s(item); + } + op_desc_attr->insert({"_opt_input", opt_input}); } - return true; } bool ModelSerializeImp::SerializeNode(const NodePtr &node, proto::OpDef *op_def_proto, bool is_dump) { @@ -237,13 +257,70 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool ModelSerializeImp::Unseriali } } +void ModelSerializeImp::AttrDefToOpDesc(OpDescPtr &op_desc, std::vector &key_in, std::vector &key_out, + std::vector &value_in, std::vector &value_out, + std::vector &opt_input) { + if (!key_in.empty()) { + if (key_in.size() != value_in.size()) { + GELOGW("Key and value vector size is different. key_size: %zu, value_size: %zu.", key_out.size(), + value_in.size()); + } else { + for (uint32_t i = 0; i < key_in.size(); ++i) { + op_desc->input_name_idx_.insert(std::pair(key_in.at(i), value_in.at(i))); + } + } + } + if (!key_out.empty()) { + if (key_out.size() != value_out.size()) { + GELOGW("Key and value vector size is different. key_size: %zu, value_size: %zu.", key_out.size(), + value_out.size()); + } else { + for (uint32_t i = 0; i < key_out.size(); ++i) { + op_desc->output_name_idx_.insert(std::pair(key_out.at(i), value_out.at(i))); + } + } + } + if (!opt_input.empty()) { + for (const auto &i : opt_input) { + op_desc->optional_input_names_.insert(i); + } + } +} + bool ModelSerializeImp::UnserializeOpDesc(OpDescPtr &op_desc, proto::OpDef &op_def_proto) { - std::vector key; - std::vector value; + std::vector opt_input; + std::vector key_in; + std::vector value_in; + if (op_def_proto.attr().count("_opt_input") > 0) { + auto &name_list = op_def_proto.attr().at("_opt_input").list(); + for (const auto &item_s : name_list.s()) { + opt_input.push_back(item_s); + } + auto op_desc_attr = op_def_proto.mutable_attr(); + op_desc_attr->erase("_opt_input"); + } + if (op_def_proto.attr().count("_input_name_key") > 0) { + auto &output_name_key_list = op_def_proto.attr().at("_input_name_key").list(); + for (const auto &item_s : output_name_key_list.s()) { + key_in.push_back(item_s); + } + auto op_desc_attr = op_def_proto.mutable_attr(); + op_desc_attr->erase("_input_name_key"); + } + if (op_def_proto.attr().count("_input_name_value") > 0) { + auto &input_name_value_list = op_def_proto.attr().at("_input_name_value").list(); + for (const auto &item_i : input_name_value_list.i()) { + value_in.push_back(static_cast(item_i)); + } + auto op_desc_attr = op_def_proto.mutable_attr(); + op_desc_attr->erase("_input_name_value"); + } + std::vector key_out; + std::vector value_out; if (op_def_proto.attr().count("_output_name_key") > 0) { auto &output_name_key_list = op_def_proto.attr().at("_output_name_key").list(); for (const auto &item_s : output_name_key_list.s()) { - key.push_back(item_s); + key_out.push_back(item_s); } auto op_desc_attr = op_def_proto.mutable_attr(); op_desc_attr->erase("_output_name_key"); @@ -251,7 +328,7 @@ bool ModelSerializeImp::UnserializeOpDesc(OpDescPtr &op_desc, proto::OpDef &op_d if (op_def_proto.attr().count("_output_name_value") > 0) { auto &output_name_value_list = op_def_proto.attr().at("_output_name_value").list(); for (const auto &item_i : output_name_value_list.i()) { - value.push_back(static_cast(item_i)); + value_out.push_back(static_cast(item_i)); } auto op_desc_attr = op_def_proto.mutable_attr(); op_desc_attr->erase("_output_name_value"); @@ -282,15 +359,8 @@ bool ModelSerializeImp::UnserializeOpDesc(OpDescPtr &op_desc, proto::OpDef &op_d op_desc->SetSubgraphInstanceName(graph_index++, name); } - if (key.size() != 0) { - if (key.size() != value.size()) { - GELOGE(GRAPH_FAILED, "twe vector size is different. key_size: %zu, value_size: %zu.", key.size(), value.size()); - } else { - for (uint32_t i = 0; i < key.size(); ++i) { - op_desc->output_name_idx_.insert(std::pair(key.at(i), value.at(i))); - } - } - } + // insert name index by key and value + AttrDefToOpDesc(op_desc, key_in, key_out, value_in, value_out, opt_input); return true; } @@ -338,13 +408,13 @@ bool ModelSerializeImp::HandleNodeNameRef() { item.dst_node_name.c_str(), item.dst_in_index); return false; } - GE_CHK_BOOL_ONLY_LOG((src_anchor->LinkTo(dst_anchor) == GRAPH_SUCCESS), " linkTo failed."); + GE_CHK_BOOL_ONLY_LOG((src_anchor->LinkTo(dst_anchor) == GRAPH_SUCCESS), " linkTo failed."); // lint !e737 } else { // Control edge auto src_anchor = src_node_it->second->GetOutControlAnchor(); auto dst_anchor = item.dst_node->GetInControlAnchor(); if (src_anchor != nullptr && dst_anchor != nullptr) { - GE_CHK_BOOL_ONLY_LOG((src_anchor->LinkTo(dst_anchor) == GRAPH_SUCCESS), " linkTo failed."); + GE_CHK_BOOL_ONLY_LOG((src_anchor->LinkTo(dst_anchor) == GRAPH_SUCCESS), " linkTo failed."); // lint !e737 } } } diff --git a/src/common/graph/node.cc b/src/common/graph/node.cc index e0939e7e..b210957d 100644 --- a/src/common/graph/node.cc +++ b/src/common/graph/node.cc @@ -26,6 +26,7 @@ #include "utils/ge_ir_utils.h" #include "utils/node_utils.h" #include "utils/op_desc_utils.h" +#include "common/util/error_manager/error_manager.h" using std::string; using std::vector; @@ -154,7 +155,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool Node::NodeAnchorIsEqual(cons const auto &peer_node = left_anchor->GetPeerAnchors().at(j)->GetOwnerNode(); const auto &r_peer_node = right_anchor->GetPeerAnchors().at(j)->GetOwnerNode(); if (peer_node == nullptr || r_peer_node == nullptr) { - GELOGE(GRAPH_FAILED, "Error: anchor's peer node is null, node name: %s index[%zu] peer node index[%zu]. ", + GELOGE(GRAPH_FAILED, "anchor's peer node is null, node name: %s index[%zu] peer node index[%zu]. ", this->GetName().c_str(), i, j); return false; } @@ -434,8 +435,11 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY Node::Vistor Node::Get GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY InDataAnchorPtr Node::GetInDataAnchor(int idx) const { if (idx < 0 || idx >= static_cast(in_data_anchors_.size())) { - GELOGE(GRAPH_FAILED, "the node doesn't have %d th in_data_anchor, node %s:%s", idx, GetType().c_str(), - GetName().c_str()); + ErrorManager::GetInstance().ATCReportErrMessage( + "E19019", {"opname", "index", "anchorname", "optype"}, + {GetName().c_str(), std::to_string(idx), "in_data_anchor", GetType().c_str()}); + GELOGE(GRAPH_FAILED, "Op[%s] doesn't have index[%d]'s in_data_anchor which optype is %s.", GetName().c_str(), idx, + GetType().c_str()); return nullptr; } else { return in_data_anchors_[idx]; @@ -445,7 +449,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY InDataAnchorPtr Node::GetInDataAn GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AnchorPtr Node::GetInAnchor(int idx) const { // Idx can't be less than -1 or >= in_data_anchors_.size(), -1 means index of control anchor_ if (idx < -1 || idx >= static_cast(in_data_anchors_.size())) { - GELOGW("the node doesn't have %d th in_anchor, node %s:%s", idx, GetType().c_str(), GetName().c_str()); + GELOGW("Op[%s] doesn't have index[%d]'s in_anchor which optype is %s.", GetName().c_str(), idx, GetType().c_str()); return nullptr; } else { // Return control anchor @@ -461,8 +465,15 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AnchorPtr Node::GetInAnchor(int i GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AnchorPtr Node::GetOutAnchor(int idx) const { // Idx can't be less than -1 or >= out_data_anchors_.size(), -1 means index of control anchor_ if (idx < -1 || idx >= static_cast(out_data_anchors_.size())) { - GELOGE(GRAPH_FAILED, "the node doesn't have %d th out_anchor, node %s:%s", idx, GetType().c_str(), - GetName().c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E19019", {"opname", "index", "anchorname", "optype"}, + { + GetName().c_str(), + std::to_string(idx), + "out_anchor", + GetType().c_str(), + }); + GELOGE(GRAPH_FAILED, "Op[%s] doesn't have index[%d]'s out_anchor which optype is %s.", GetName().c_str(), idx, + GetType().c_str()); return nullptr; } else { // Return control anchor @@ -477,8 +488,11 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY AnchorPtr Node::GetOutAnchor(int GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OutDataAnchorPtr Node::GetOutDataAnchor(int idx) const { if (idx < 0 || idx >= static_cast(out_data_anchors_.size())) { - GELOGE(GRAPH_FAILED, "the node doesn't have %d th out_data_anchor, node %s:%s", idx, GetType().c_str(), - GetName().c_str()); + ErrorManager::GetInstance().ATCReportErrMessage( + "E19019", {"opname", "index", "anchorname", "optype"}, + {GetName().c_str(), std::to_string(idx), "out_data_anchor", GetType().c_str()}); + GELOGE(GRAPH_FAILED, "Op[%s] doesn't have index[%d]'s out_data_anchor which optype is %s.", GetName().c_str(), idx, + GetType().c_str()); return nullptr; } else { return out_data_anchors_[idx]; @@ -726,22 +740,27 @@ graphStatus Node::Verify() const { const string aipp_data_type = "AippData"; const string const_type = "Const"; const string variable_type = "Variable"; + bool is_unknown_graph = GetOwnerComputeGraph()->GetGraphUnknownFlag(); GE_CHK_BOOL_EXEC(op_ != nullptr, return GRAPH_FAILED, "original OpDesc is nullptr"); - for (const auto &in_anchor_ptr : GetAllInDataAnchors()) { - if (in_anchor_ptr == nullptr) { - GELOGW("in anchor ptr is null"); - continue; + if (!is_unknown_graph) { + for (const auto &in_anchor_ptr : GetAllInDataAnchors()) { + GE_IF_BOOL_EXEC(in_anchor_ptr == nullptr, GELOGW("in anchor ptr is null"); continue); + bool valid_anchor = op_->GetType() == data_type || op_->GetType() == aipp_data_type || + op_->GetType() == const_type || op_->GetType() == variable_type || + op_->IsOptionalInput(in_anchor_ptr->GetIdx()) || in_anchor_ptr->GetPeerAnchors().size() > 0; + if (!valid_anchor) { + ErrorManager::GetInstance().ATCReportErrMessage("E11019", {"opname", "index"}, + {GetName(), std::to_string(in_anchor_ptr->GetIdx())}); + GELOGE(GRAPH_FAILED, "operator %s's input %d is not linked.", GetName().c_str(), in_anchor_ptr->GetIdx()); + return GRAPH_FAILED; + } } - GE_CHK_BOOL_RET_STATUS( - op_->GetType() == data_type || op_->GetType() == aipp_data_type || op_->GetType() == const_type || - op_->GetType() == variable_type || op_->IsOptionalInput(in_anchor_ptr->GetIdx()) || - in_anchor_ptr->GetPeerAnchors().size() > 0, - GRAPH_FAILED, "operator %s's input %d is not linked.", GetName().c_str(), in_anchor_ptr->GetIdx()); } string frameworkop_type = "FrameworkOp"; - if (op_->GetType() != frameworkop_type) { + bool need_update_name = op_->GetType() != frameworkop_type && !is_unknown_graph; + if (need_update_name) { auto node_op = ge::OperatorFactoryImpl::CreateOperator("node_op", op_->GetType()); if (node_op.IsEmpty()) { GELOGW("get op from OperatorFactory fail. opType: %s", op_->GetType().c_str()); @@ -761,7 +780,7 @@ graphStatus Node::Verify() const { } node_op.BreakConnect(); } - + GE_IF_BOOL_EXEC(is_unknown_graph, return GRAPH_SUCCESS;); if (op_->CommonVerify() == GRAPH_SUCCESS) { Operator op_proxy = ge::OpDescUtils::CreateOperatorFromNode(shared_from_this()); auto verify_func = op_->GetVerifyFunc(); diff --git a/src/common/graph/op_desc.cc b/src/common/graph/op_desc.cc index adb52162..a7451641 100644 --- a/src/common/graph/op_desc.cc +++ b/src/common/graph/op_desc.cc @@ -19,6 +19,7 @@ #include "debug/ge_util.h" #include "external/graph/operator.h" #include "framework/common/debug/ge_log.h" +#include "common/util/error_manager/error_manager.h" #include "graph/ge_attr_value.h" #include "graph/ge_tensor.h" #include "graph/operator_factory_impl.h" @@ -32,6 +33,7 @@ using std::shared_ptr; using std::string; using std::vector; +/*lint -save -e521 -e681 -e732 -e737*/ namespace ge { const std::string ATTR_NAME_ID = "id"; @@ -63,12 +65,6 @@ const std::string ATTR_NAME_IS_INPUT_CONST = "is_input_const"; const std::string ATTR_NAME_OP_INFER_DEPENDS = "_op_infer_depends"; -const std::string ATTR_NAME_OPT_INPUT = "_opt_input"; - -const std::string ATTR_NAME_INPUT_NAME_IDX_KEY = "_input_name_idx_key"; - -const std::string ATTR_NAME_INPUT_NAME_IDX_VALUE = "_input_name_idx_value"; - GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OpDesc::OpDesc() { op_def_.InitDefault(); if (op_def_.GetProtoMsg() != nullptr) { @@ -210,8 +206,7 @@ graphStatus OpDesc::AddInputDesc(uint32_t index, const ge::GeTensorDesc &input_d } graphStatus OpDesc::AddInputDesc(const string &name, const ge::GeTensorDesc &input_desc) { - auto input_name_idx = GetAllInputName(); - if (input_name_idx.find(name) != input_name_idx.end()) { + if (input_name_idx_.find(name) != input_name_idx_.end()) { GELOGI("input %s is exist, update it", name.c_str()); graphStatus ret = UpdateInputDesc(name, input_desc); return ret; @@ -223,17 +218,15 @@ graphStatus OpDesc::AddInputDesc(const string &name, const ge::GeTensorDesc &inp return GRAPH_FAILED; } inputs_desc_.push_back(in_desc); - (void)input_name_idx.insert(make_pair(name, index)); - SetAllInputName(input_name_idx); + (void)input_name_idx_.insert(make_pair(name, index)); return GRAPH_SUCCESS; } } graphStatus OpDesc::AddInputDescMiddle(const string &name, const unsigned int num, size_t index) { - auto input_name_idx = GetAllInputName(); for (unsigned int i = 0; i < num; i++) { string input_name = name + std::to_string(i); - GE_CHK_BOOL_RET_STATUS((input_name_idx.find(input_name) == input_name_idx.end()), GRAPH_FAILED, + GE_CHK_BOOL_RET_STATUS((input_name_idx_.find(input_name) == input_name_idx_.end()), GRAPH_FAILED, "Add input tensor_desc is existed. name[%s]", input_name.c_str()); std::shared_ptr in_desc = ComGraphMakeShared(GeTensorDesc()); @@ -250,24 +243,22 @@ graphStatus OpDesc::AddInputDescMiddle(const string &name, const unsigned int nu (void)inputs_desc_.insert(inputs_desc_.begin() + index + i, in_desc); // Update index in input_name_idx - for (auto it = input_name_idx.begin(); it != input_name_idx.end(); ++it) { + for (auto it = input_name_idx_.begin(); it != input_name_idx_.end(); ++it) { if (it->second >= (index + i)) { it->second += 1; } } - (void)input_name_idx.insert(make_pair(input_name, i + index)); + (void)input_name_idx_.insert(make_pair(input_name, i + index)); } - SetAllInputName(input_name_idx); return GRAPH_SUCCESS; } graphStatus OpDesc::AddInputDescForward(const string &name, const unsigned int num) { - auto input_name_idx = GetAllInputName(); for (unsigned int i = 0; i < num; i++) { string input_name = name + std::to_string(i); - GE_CHK_BOOL_RET_STATUS((input_name_idx.find(input_name) == input_name_idx.end()), GRAPH_FAILED, + GE_CHK_BOOL_RET_STATUS((input_name_idx_.find(input_name) == input_name_idx_.end()), GRAPH_FAILED, "Add input tensor_desc is existed. name[%s]", input_name.c_str()); std::shared_ptr in_desc = ComGraphMakeShared(GeTensorDesc()); @@ -278,13 +269,12 @@ graphStatus OpDesc::AddInputDescForward(const string &name, const unsigned int n (void)inputs_desc_.insert(inputs_desc_.begin(), in_desc); // Update index in input_name_idx - for (auto it = input_name_idx.begin(); it != input_name_idx.end(); ++it) { + for (auto it = input_name_idx_.begin(); it != input_name_idx_.end(); ++it) { it->second += 1; } - (void)input_name_idx.insert(make_pair(input_name, 0)); + (void)input_name_idx_.insert(make_pair(input_name, 0)); } - SetAllInputName(input_name_idx); return GRAPH_SUCCESS; } @@ -315,19 +305,10 @@ graphStatus OpDesc::AddOutputDescForward(const string &name, const unsigned int graphStatus OpDesc::AddOptionalInputDesc(const string &name, const ge::GeTensorDesc &input_desc) { if (OpDesc::AddInputDesc(name, input_desc) == GRAPH_FAILED) return GRAPH_FAILED; - vector optional_input_names; - (void)AttrUtils::GetListStr(this, ATTR_NAME_OPT_INPUT, optional_input_names); - optional_input_names.push_back(name); - (void)AttrUtils::SetListStr(this, ATTR_NAME_OPT_INPUT, optional_input_names); + (void)optional_input_names_.insert(name); return GRAPH_SUCCESS; } -std::vector OpDesc::GetAllOptionalInputName() const { - vector optional_input_names; - (void)AttrUtils::GetListStr(this, ATTR_NAME_OPT_INPUT, optional_input_names); - return optional_input_names; -} - GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus OpDesc::UpdateInputDesc(uint32_t index, const ge::GeTensorDesc &tensor_Desc) { GE_CHK_BOOL_RET_STATUS((index < inputs_desc_.size()), GRAPH_FAILED, "The index is invalid. index[%u]", index); @@ -342,12 +323,11 @@ OpDesc::UpdateInputDesc(uint32_t index, const ge::GeTensorDesc &tensor_Desc) { } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool OpDesc::OpDescMembersAreEqual(const OpDesc &r_op_desc) const { - return ( - IsEqual(this->GetAllInputName(), r_op_desc.GetAllInputName(), "OpDesc.GetAllInputName()") && - IsEqual(this->output_name_idx_, r_op_desc.output_name_idx_, "OpDesc.output_name_idx_") && - IsEqual(this->GetAllOptionalInputName(), r_op_desc.GetAllOptionalInputName(), "OpDesc.GetAllOptionalInputName()") && - IsEqual(this->engine_name_, r_op_desc.engine_name_, "OpDesc.engine_name_") && - IsEqual(this->op_kernel_lib_name_, r_op_desc.op_kernel_lib_name_, "OpDesc.op_kernel_lib_name_")); + return (IsEqual(this->input_name_idx_, r_op_desc.input_name_idx_, "OpDesc.input_name_idx_") && + IsEqual(this->output_name_idx_, r_op_desc.output_name_idx_, "OpDesc.output_name_idx_") && + IsEqual(this->optional_input_names_, r_op_desc.optional_input_names_, "OpDesc.optional_input_names_") && + IsEqual(this->engine_name_, r_op_desc.engine_name_, "OpDesc.engine_name_") && + IsEqual(this->op_kernel_lib_name_, r_op_desc.op_kernel_lib_name_, "OpDesc.op_kernel_lib_name_")); } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool OpDesc::OpDescAttrsAreEqual(const OpDesc &r_op_desc) const { @@ -421,9 +401,8 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY bool OpDesc::operator==(const OpD } graphStatus OpDesc::UpdateInputDesc(const string &name, const ge::GeTensorDesc &tensor_Desc) { - auto input_name_idx = GetAllInputName(); - auto it = input_name_idx.find(name); - if (it == input_name_idx.end()) { + auto it = input_name_idx_.find(name); + if (it == input_name_idx_.end()) { GELOGW("Cann't find the input desc. name[%s]", name.c_str()); return GRAPH_FAILED; } @@ -443,9 +422,8 @@ graphStatus OpDesc::UpdateInputDesc(const string &name, const ge::GeTensorDesc & } bool OpDesc::InputIsSet(const string &name) const { - auto input_name_idx = GetAllInputName(); - auto it = input_name_idx.find(name); - if (it != input_name_idx.end()) { + auto it = input_name_idx_.find(name); + if (it != input_name_idx_.end()) { GE_IF_BOOL_EXEC(it->second >= inputs_desc_.size(), GELOGE(GRAPH_FAILED, "it->second is invalid."); return false); auto tensor_desc = inputs_desc_[it->second]; GE_IF_BOOL_EXEC(tensor_desc == nullptr, GELOGE(GRAPH_FAILED, "tensor_desc is null."); return false); @@ -463,20 +441,40 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDesc OpDesc::GetInputDesc } GeTensorDesc OpDesc::GetInputDesc(const string &name) const { - auto input_name_idx = GetAllInputName(); - auto it = input_name_idx.find(name); - GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx.end(), GeTensorDesc()); + auto it = input_name_idx_.find(name); + GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx_.end(), GeTensorDesc()); GE_CHK_BOOL_RET_STATUS_NOLOG(it->second < inputs_desc_.size(), GeTensorDesc()); return *(inputs_desc_[it->second].get()); } -GE_FUNC_HOST_VISIBILITY OpDesc::Vistor OpDesc::GetAllInputNames() const { +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDescPtr OpDesc::MutableInputDesc(uint32_t index) const { + GE_CHK_BOOL_RET_STATUS(index < inputs_desc_.size(), nullptr, "Can't find the input desc %u", index); + if (inputs_desc_[index] == nullptr) { + return nullptr; + } + if (inputs_desc_[index]->IsValid() != GRAPH_SUCCESS) { + GELOGW("input desc is invalid"); + return nullptr; + } + return inputs_desc_[index]; +} + +GeTensorDescPtr OpDesc::MutableInputDesc(const string &name) const { auto input_name_idx = GetAllInputName(); + auto it = input_name_idx.find(name); + if (it == input_name_idx.end()) { + GELOGW("Failed to get [%s] input desc", name.c_str()); + return nullptr; + } + return MutableInputDesc(it->second); +} + +GE_FUNC_HOST_VISIBILITY OpDesc::Vistor OpDesc::GetAllInputNames() const { vector names; - if (input_name_idx.empty()) { + if (input_name_idx_.empty()) { return OpDesc::Vistor(shared_from_this(), names); } - for (std::pair input : input_name_idx) { + for (std::pair input : input_name_idx_) { names.push_back(input.first); } return OpDesc::Vistor(shared_from_this(), names); @@ -496,15 +494,6 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void OpDesc::SetOpEngineName(cons GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY std::string OpDesc::GetOpEngineName() const { return engine_name_; } -GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDescPtr OpDesc::MutableInputDesc(uint32_t index) const { - GE_CHK_BOOL_RET_STATUS(index < inputs_desc_.size(), nullptr, "Can't find the input desc %u", index); - if (inputs_desc_[index] == nullptr) { - return nullptr; - } - GE_CHK_BOOL_RET_STATUS(inputs_desc_[index]->IsValid() == GRAPH_SUCCESS, nullptr, "input desc is invalid"); - return inputs_desc_[index]; -} - GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY OpDesc::Vistor OpDesc::GetAllInputsDesc() const { vector temp{}; for (const auto &it : inputs_desc_) { @@ -609,6 +598,15 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDescPtr OpDesc::MutableOu return outputs_desc_[index]; } +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeTensorDescPtr OpDesc::MutableOutputDesc(const string &name) const { + auto it = output_name_idx_.find(name); + if (it == output_name_idx_.end()) { + GELOGW("Failed to get [%s] output desc", name.c_str()); + return nullptr; + } + return MutableOutputDesc(it->second); +} + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY uint32_t OpDesc::GetAllOutputsDescSize() const { return static_cast(outputs_desc_.size()); } @@ -652,9 +650,8 @@ OpDesc::GetInputDescPtrDfault(uint32_t index) const { } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ConstGeTensorDescPtr OpDesc::GetInputDescPtr(const string &name) const { - auto input_name_idx = GetAllInputName(); - auto it = input_name_idx.find(name); - GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx.end(), shared_ptr()); + auto it = input_name_idx_.find(name); + GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx_.end(), shared_ptr()); return inputs_desc_[it->second]; } @@ -687,47 +684,26 @@ graphStatus OpDesc::AddDynamicOutputDesc(const string &name, const unsigned int return GRAPH_SUCCESS; } -bool OpDesc::IsOptionalInput(const string &name) const { - vector optional_input_names; - (void)AttrUtils::GetListStr(this, ATTR_NAME_OPT_INPUT, optional_input_names); - for (auto &item : optional_input_names) { - if (item == name) { - return true; - } +void OpDesc::RemoveInputDesc(uint32_t index) { + while (inputs_desc_.size() > index) { + inputs_desc_.pop_back(); } - return false; } -bool OpDesc::IsOptionalInput(uint32_t index) const { return IsOptionalInput(GetInputNameByIndex(index)); } - -std::map OpDesc::GetAllInputName() const { - std::map input_name_idx; - std::vector key; - std::vector value; - (void)AttrUtils::GetListStr(this, ATTR_NAME_INPUT_NAME_IDX_KEY, key); - (void)AttrUtils::GetListInt(this, ATTR_NAME_INPUT_NAME_IDX_VALUE, value); - - if (key.size() != value.size()) { - GE_LOGE("twe vector size is different. key_size: %zu, value_size: %zu.", key.size(), value.size()); - } else { - for (uint32_t i = 0; i < key.size(); ++i) { - input_name_idx.insert(std::pair(key.at(i), value.at(i))); - } +void OpDesc::RemoveOutputDesc(uint32_t index) { + while (outputs_desc_.size() > index) { + outputs_desc_.pop_back(); } - return input_name_idx; } -void OpDesc::SetAllInputName(const std::map &input_name_idx) { - std::vector key; - std::vector value; - for (auto &item : input_name_idx) { - key.emplace_back(item.first); - value.emplace_back(item.second); - } - (void)AttrUtils::SetListStr(this, ATTR_NAME_INPUT_NAME_IDX_KEY, key); - (void)AttrUtils::SetListInt(this, ATTR_NAME_INPUT_NAME_IDX_VALUE, value); +bool OpDesc::IsOptionalInput(const string &name) const { + return optional_input_names_.find(name) != optional_input_names_.end(); } +bool OpDesc::IsOptionalInput(uint32_t index) const { return IsOptionalInput(GetInputNameByIndex(index)); } + +std::map OpDesc::GetAllInputName() const { return input_name_idx_; } + std::map OpDesc::GetAllOutputName() { return output_name_idx_; } bool OpDesc::UpdateInputName(std::map input_name_idx) { @@ -737,7 +713,6 @@ bool OpDesc::UpdateInputName(std::map input_name_idx) { auto factory_map_size = input_name_idx.size(); // It indicates that some inputs have no optionalname. // The redundant optionalname of factory needs to be deleted and then assigned - auto all_input_name_idx = GetAllInputName(); if (input_map_size < factory_map_size) { GELOGI("UpdateInputName org inputname map size: %zu, factory inputname map size: %zu", input_map_size, factory_map_size); @@ -750,18 +725,17 @@ bool OpDesc::UpdateInputName(std::map input_name_idx) { } if (input_name_idx.size() == input_map_size) { GELOGI("UpdateInputName"); - all_input_name_idx = input_name_idx; + input_name_idx_ = input_name_idx; } else { ret = false; GELOGW("after UpdateInputName factoryName map size : %zu", input_name_idx.size()); } } else if (input_map_size == factory_map_size) { - all_input_name_idx = input_name_idx; + input_name_idx_ = input_name_idx; } else { ret = false; GELOGW("org inputname map size: %zu, factory inputname map size: %zu", input_map_size, factory_map_size); } - SetAllInputName(all_input_name_idx); return ret; } @@ -882,36 +856,41 @@ graphStatus OpDesc::CommonVerify() const { // Checking shape of all inputs vector ishape = GetInputDescPtr(iname)->GetShape().GetDims(); for (int64_t dim : ishape) { - GE_CHK_BOOL_RET_STATUS(dim >= -2, GRAPH_FAILED, "operator input %s shape contains negative or zero dimension.", - iname.c_str()); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + dim < -2, ErrorManager::GetInstance().ATCReportErrMessage( + "E19014", {"opname", "value", "reason"}, + {GetName(), "input " + iname + " shape", "contains negative or zero dimension"}); + return GRAPH_FAILED, "Op[%s]'s input %s shape contains negative or zero dimension.", GetName().c_str(), + iname.c_str()); } } // Check all attributes defined const auto &all_attributes = GetAllAttrs(); for (const auto &name : GetAllAttrNames()) { - GE_CHK_BOOL_RET_STATUS(all_attributes.find(name) != all_attributes.end(), GRAPH_FAILED, - "operator attribute %s is empty.", name.c_str()); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + all_attributes.find(name) == all_attributes.end(), + ErrorManager::GetInstance().ATCReportErrMessage("E19014", {"opname", "value", "reason"}, + {GetName(), "attribute " + name, "is empty"}); + return GRAPH_FAILED, "operator attribute %s is empty.", name.c_str()); } return GRAPH_SUCCESS; } GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY string OpDesc::GetInputNameByIndex(uint32_t index) const { - auto input_name_idx = GetAllInputName(); - auto it = input_name_idx.begin(); - for (; it != input_name_idx.end(); ++it) { + auto it = input_name_idx_.begin(); + for (; it != input_name_idx_.end(); ++it) { if (it->second == index) { break; } } - GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx.end(), ""); + GE_CHK_BOOL_RET_STATUS_NOLOG(it != input_name_idx_.end(), ""); return it->first; } int OpDesc::GetInputIndexByName(const string &name) const { - auto input_name_idx = GetAllInputName(); - auto it_find = input_name_idx.find(name); - GE_CHK_BOOL_RET_STATUS_NOLOG(it_find != input_name_idx.end(), -1); + auto it_find = input_name_idx_.find(name); + GE_CHK_BOOL_RET_STATUS_NOLOG(it_find != input_name_idx_.end(), -1); return static_cast(it_find->second); } @@ -1204,12 +1183,10 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY vector OpDesc::GetIsInputCo GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus OpDesc::RestoreInputNameIdx(const string &name, const int &index) { - auto input_name_idx = GetAllInputName(); - if (input_name_idx.find(name) != input_name_idx.end()) { + if (input_name_idx_.find(name) != input_name_idx_.end()) { GELOGI("Restore input name index is existed. name[%s]", name.c_str()); } - (void)input_name_idx.insert(make_pair(name, index)); - SetAllInputName(input_name_idx); + (void)input_name_idx_.insert(make_pair(name, index)); return GRAPH_SUCCESS; } diff --git a/src/common/graph/operator.cc b/src/common/graph/operator.cc index 1ac8d41d..03d4221e 100644 --- a/src/common/graph/operator.cc +++ b/src/common/graph/operator.cc @@ -21,7 +21,7 @@ #include #include #include -#include "array_ops.h" +#include "./array_ops.h" #include "debug/ge_log.h" #include "debug/ge_op_types.h" #include "debug/ge_util.h" @@ -36,6 +36,8 @@ #include "graph/op_desc.h" #include "graph/runtime_inference_context.h" #include "graph/usr_types.h" +#include "graph/utils/node_utils.h" +#include "graph/debug/ge_attr_define.h" #include "utils/graph_utils.h" #include "utils/op_desc_utils.h" #include "utils/tensor_adapter.h" @@ -54,11 +56,13 @@ using std::string; using std::to_string; using std::vector; +/*lint -save -e529 -e728*/ +/*lint -e446 -e732*/ +/*lint -e665*/ namespace ge { class OpIO { public: - explicit OpIO(const string &name, int index, const OperatorImplPtr &owner) - : name_(name), index_(index), owner_(owner) {} + OpIO(const string &name, int index, const OperatorImplPtr &owner) : name_(name), index_(index), owner_(owner) {} ~OpIO() = default; @@ -546,56 +550,46 @@ Operator &Operator::AddControlInput(const Operator &src_oprt) { } graphStatus Operator::GetInputConstData(const string &dst_name, Tensor &data) const { - if (operator_impl_ == nullptr) { - GELOGE(GRAPH_FAILED, "operator impl is nullptr."); - return GRAPH_FAILED; - } - ge::ConstNodePtr node_ptr = operator_impl_->GetNode(); - if (node_ptr) { + GE_CHECK_NOTNULL(operator_impl_); + auto node_ptr = operator_impl_->GetNode(); + if (node_ptr != nullptr) { // For inner compute graph auto op_desc = node_ptr->GetOpDesc(); - if (op_desc == nullptr) { - GELOGE(GRAPH_FAILED, "op_desc is nullptr."); - return GRAPH_FAILED; - } + GE_CHECK_NOTNULL(op_desc); auto index = op_desc->GetInputIndexByName(dst_name); auto in_data_anchor = node_ptr->GetInDataAnchor(index); - if (in_data_anchor == nullptr) { - GELOGE(GRAPH_FAILED, "in_data_anchor is nullptr."); - return GRAPH_FAILED; - } + GE_CHECK_NOTNULL(in_data_anchor); auto out_data_anchor = in_data_anchor->GetPeerOutAnchor(); - if (out_data_anchor == nullptr) { - GELOGE(GRAPH_FAILED, "out_data_anchor is nullptr."); - return GRAPH_FAILED; - } - std::shared_ptr peer_node_ptr = out_data_anchor->GetOwnerNode(); - if (peer_node_ptr == nullptr) { - GELOGE(GRAPH_FAILED, "peer_node_ptr is nullptr."); - return GRAPH_FAILED; - } - ge::OperatorImplPtr operator_impl_ptr = nullptr; - operator_impl_ptr = ComGraphMakeShared(peer_node_ptr); - if (operator_impl_ptr == nullptr) { - GELOGE(GRAPH_FAILED, "OperatorImpl make shared failed"); - return GRAPH_FAILED; - } - Operator const_op(std::move(operator_impl_ptr)); - if (peer_node_ptr->GetOpDesc() != nullptr) { - const auto &op_descType = peer_node_ptr->GetOpDesc()->GetType(); - if (op_descType == CONSTANTOP) { - return const_op.GetAttr(op::Constant::name_attr_value(), data); - } else if (op_descType == CONSTANT) { - return const_op.GetAttr(op::Const::name_attr_value(), data); + GE_CHECK_NOTNULL(out_data_anchor); + auto peer_node = out_data_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_node); + auto peer_op_desc = peer_node->GetOpDesc(); + GE_CHECK_NOTNULL(peer_op_desc); + auto peer_op_type = peer_op_desc->GetType(); + if (peer_op_type == CONSTANTOP || peer_op_type == CONSTANT) { + auto const_op_impl = ComGraphMakeShared(peer_node); + GE_CHECK_NOTNULL(const_op_impl); + Operator const_op(std::move(const_op_impl)); + return const_op.GetAttr(ATTR_NAME_WEIGHTS, data); + } else if (peer_op_type == DATA) { + auto parent_node = NodeUtils::GetParentInput(peer_node); + while ((parent_node != nullptr) && (parent_node->GetType() == DATA)) { + parent_node = NodeUtils::GetParentInput(parent_node); + } + if ((parent_node != nullptr) && + ((parent_node->GetType() == CONSTANT) || (parent_node->GetType() == CONSTANTOP))) { + auto const_op_impl = ComGraphMakeShared(parent_node); + GE_CHECK_NOTNULL(const_op_impl); + Operator const_op(std::move(const_op_impl)); + return const_op.GetAttr(ATTR_NAME_WEIGHTS, data); } } - // Try get from runtime inference context auto session_id = std::to_string(GetContext().SessionId()); RuntimeInferenceContext *runtime_infer_ctx = nullptr; if (RuntimeInferenceContext::GetContext(session_id, &runtime_infer_ctx) == GRAPH_SUCCESS) { GELOGD("To get constant from runtime inference context. session_id = %s", session_id.c_str()); - auto ret = runtime_infer_ctx->GetTensor(peer_node_ptr->GetOpDesc()->GetId(), out_data_anchor->GetIdx(), data); + auto ret = runtime_infer_ctx->GetTensor(peer_node->GetOpDesc()->GetId(), out_data_anchor->GetIdx(), data); if (ret == GRAPH_SUCCESS) { return GRAPH_SUCCESS; } @@ -604,6 +598,8 @@ graphStatus Operator::GetInputConstData(const string &dst_name, Tensor &data) co // For outer graph return GetInputConstDataOut(dst_name, data); } + auto op_name = operator_impl_->GetName(); + GELOGW("node[%s]'s input[%s]'s peer node is not const", op_name.c_str(), dst_name.c_str()); return GRAPH_FAILED; } graphStatus Operator::GetInputConstDataOut(const string &dst_name, Tensor &data) const { @@ -914,7 +910,7 @@ OperatorImplPtr Operator::GetOperatorImplPtr() const { return operator_impl_; } GELOGW("set attr name %s failed.", name.c_str()); \ } \ return *this; \ - } + } // lint !e665 #define OP_ATTR_GET_IMP(ArgType, AttrUtilsFun) \ graphStatus Operator::GetAttr(const string &name, ArgType attr_value) const { \ @@ -927,7 +923,7 @@ OperatorImplPtr Operator::GetOperatorImplPtr() const { return operator_impl_; } return GRAPH_FAILED; \ } \ return GRAPH_SUCCESS; \ - } + } // lint !e665 void Operator::BreakConnect() const { if (operator_impl_ == nullptr) { @@ -948,7 +944,7 @@ void Operator::BreakConnect() const { if (!AttrUtils::Set##AttrUtilsFun(operator_impl_->GetOpDescImpl(), name, attr_value)) { \ GELOGW("reg attr name %s failed.", name.c_str()); \ } \ - } + } // lint !e665 OP_ATTR_SET_IMP(int64_t, Int) OP_ATTR_SET_IMP(int32_t, Int) @@ -969,22 +965,22 @@ OP_ATTR_SET_IMP(const vector> &, ListListInt) OP_ATTR_SET_IMP(float, Float) OP_ATTR_GET_IMP(float &, Float) OP_ATTR_SET_IMP(const vector &, ListFloat) -OP_ATTR_GET_IMP(vector &, ListFloat) +OP_ATTR_GET_IMP(vector &, ListFloat) // lint !e665 OP_ATTR_SET_IMP(bool, Bool) OP_ATTR_GET_IMP(bool &, Bool) OP_ATTR_SET_IMP(const vector &, ListBool) -OP_ATTR_GET_IMP(vector &, ListBool) +OP_ATTR_GET_IMP(vector &, ListBool) // lint !e665 OP_ATTR_SET_IMP(const string &, Str) OP_ATTR_GET_IMP(string &, Str) OP_ATTR_SET_IMP(const vector &, ListStr) -OP_ATTR_GET_IMP(vector &, ListStr) +OP_ATTR_GET_IMP(vector &, ListStr) // lint !e665 OP_ATTR_SET_IMP(const GeAttrValue::NAMED_ATTRS &, NamedAttrs) OP_ATTR_GET_IMP(GeAttrValue::NAMED_ATTRS &, NamedAttrs) OP_ATTR_SET_IMP(const vector &, ListNamedAttrs) -OP_ATTR_GET_IMP(vector &, ListNamedAttrs) +OP_ATTR_GET_IMP(vector &, ListNamedAttrs) // lint !e665 OP_ATTR_REG_IMP(int64_t, Int) OP_ATTR_REG_IMP(const vector &, ListInt) @@ -1547,3 +1543,5 @@ void GraphUtils::BreakConnect(const std::map &all_node } } } // namespace ge +/*lint +e446 +e732*/ +/*lint +e665*/ diff --git a/src/common/graph/opsproto/opsproto_manager.cc b/src/common/graph/opsproto/opsproto_manager.cc index c2afc191..4c8c1be5 100644 --- a/src/common/graph/opsproto/opsproto_manager.cc +++ b/src/common/graph/opsproto/opsproto_manager.cc @@ -31,7 +31,9 @@ OpsProtoManager *OpsProtoManager::Instance() { } bool OpsProtoManager::Initialize(const std::map &options) { + /*lint -e1561*/ auto proto_iter = options.find("ge.opsProtoLibPath"); + /*lint +e1561*/ if (proto_iter == options.end()) { GELOGW("ge.opsProtoLibPath option not set, return."); return false; diff --git a/src/common/graph/option/ge_context.cc b/src/common/graph/option/ge_context.cc index f5ebdeee..f5f5e4c9 100644 --- a/src/common/graph/option/ge_context.cc +++ b/src/common/graph/option/ge_context.cc @@ -85,6 +85,8 @@ uint32_t GEContext::DeviceId() { return device_id_; } uint64_t GEContext::TraceId() { return trace_id_; } +void GEContext::SetSessionId(uint64_t session_id) { session_id_ = session_id; } + void GEContext::SetCtxDeviceId(uint32_t device_id) { device_id_ = device_id; } } // namespace ge diff --git a/src/common/graph/ref_relation.cc b/src/common/graph/ref_relation.cc index b3cf37af..7785bc43 100644 --- a/src/common/graph/ref_relation.cc +++ b/src/common/graph/ref_relation.cc @@ -37,7 +37,7 @@ const string kWhile = "While"; const string kIf = "If"; const string kCase = "Case"; -const int kMaxElementNum = 100; +const uint16_t kMaxElementNum = 100; std::unordered_set function_op = {kWhile, kIf, kCase}; } // namespace @@ -170,6 +170,7 @@ graphStatus RefRelations::Impl::BuildRefRelationsForWhile( // data_nodes has been sorted // for while, input num must be same as output num auto input_num = root_node->GetAllInDataAnchorsSize(); + NodePtr netoutput = nullptr; size_t ref_i = 0; while (ref_i < input_num) { @@ -212,10 +213,44 @@ graphStatus RefRelations::Impl::BuildRefRelationsForWhile( cell_netoutput_in.in_out = NODE_IN; cell_netoutput_in.in_out_idx = ele.second; ref_i_all_refs.emplace_back(cell_netoutput_in); + netoutput = ele.first; } node_refs.emplace_back(ref_i_all_refs); ref_i++; } + /* There exist scene like the follows, it means data0 data1 netoutput 0'th + * and 1'th tensor should be the same addr. + * Data0 Data1 + * \/ + * /\ + * netoutput + */ + if (netoutput == nullptr) { + return GRAPH_SUCCESS; + } + for (const auto &in_anchor : netoutput->GetAllInDataAnchors()) { + auto peer_out_data_anchor = in_anchor->GetPeerOutAnchor(); + if (peer_out_data_anchor == nullptr) { + continue; + } + auto peer_out_data_node = peer_out_data_anchor->GetOwnerNode(); + if (peer_out_data_node == nullptr || peer_out_data_node->GetOpDesc() == nullptr) { + GELOGW("Node[%s]\'s peer_out_data_node or peer_out_data_node desc is null", (netoutput->GetName()).c_str()); + continue; + } + if (peer_out_data_node->GetType() != DATA) { + continue; + } + auto in_data_anchor_idx = in_anchor->GetIdx(); + auto net_in_desc = netoutput->GetOpDesc()->MutableInputDesc(static_cast(in_data_anchor_idx)); + int ref_d; + int ref_n; + (void)AttrUtils::GetInt(peer_out_data_node->GetOpDesc(), kRefIndex, ref_d); + (void)AttrUtils::GetInt(net_in_desc, kRefIndex, ref_n); + + node_refs[ref_d].insert(node_refs[ref_d].end(), node_refs[ref_n].begin(), node_refs[ref_n].end()); + node_refs[ref_n].insert(node_refs[ref_n].end(), node_refs[ref_d].begin(), node_refs[ref_d].end()); + } return GRAPH_SUCCESS; } @@ -242,6 +277,10 @@ void RefRelations::Impl::GetDataAndNetoutputOfSubGraph(const ge::ComputeGraph &r int sub_graph_idx = 0; for (const auto &name : sub_graph_names) { auto sub_graph = root_graph.GetSubgraph(name); + if (sub_graph == nullptr) { + GELOGW("Can not find the sub graph %s for root graph %s.", name.c_str(), root_graph.GetName().c_str()); + continue; + } for (const auto &sub_graph_node : sub_graph->GetDirectNode()) { auto sub_graph_node_type = sub_graph_node->GetType(); @@ -296,6 +335,9 @@ graphStatus RefRelations::Impl::ProcessSubgraphDataNodes(vector &data_n data_nodes.pop_back(); int ref_idx = 0; (void)AttrUtils::GetInt(data->GetOpDesc(), kRefIndex, ref_idx); + if (ref_idx >= static_cast(classed_data_nodes.size())) { + return GRAPH_FAILED; + } classed_data_nodes[ref_idx].emplace_back(data); } return GRAPH_SUCCESS; @@ -317,7 +359,7 @@ graphStatus RefRelations::Impl::ProcessSubgraphNetoutput( } int ref_o; if (AttrUtils::GetInt(in_desc, kRefIndex, ref_o)) { - if (ref_o >= kMaxElementNum) { + if (ref_o >= static_cast(classed_netoutput_nodes.size())) { return GRAPH_FAILED; } classed_netoutput_nodes[ref_o].emplace_back( @@ -349,8 +391,9 @@ graphStatus RefRelations::Impl::BuildRefRelations(ge::ComputeGraph &graph) { vector netoutput_nodes; // Get data and netoutput of sub_graph GetDataAndNetoutputOfSubGraph(root_graph, data_nodes, netoutput_nodes, sub_graph_names, node_type); - vector> classed_data_nodes(kMaxElementNum); // according to ref_idx - vector>> classed_netoutput_nodes(kMaxElementNum); // according to ref_idx + size_t max_elem_num = (data_nodes.size() > kMaxElementNum) ? data_nodes.size() : kMaxElementNum; + vector> classed_data_nodes(max_elem_num); // according to ref_idx + vector>> classed_netoutput_nodes(max_elem_num); // according to ref_idx status = ProcessSubgraphDataNodes(data_nodes, classed_data_nodes); if (status != GRAPH_SUCCESS) { GELOGE(GRAPH_FAILED, "classfy data nodes failed!"); diff --git a/src/common/graph/runtime_inference_context.cc b/src/common/graph/runtime_inference_context.cc index 916da564..95068481 100644 --- a/src/common/graph/runtime_inference_context.cc +++ b/src/common/graph/runtime_inference_context.cc @@ -30,6 +30,7 @@ graphStatus RuntimeInferenceContext::CreateContext(const std::string &context_id return GRAPH_FAILED; } + std::lock_guard lk(ctx_mu_); auto emplace_ret = contexts_.emplace(context_id, std::move(ctx)); if (!emplace_ret.second) { GELOGE(GRAPH_FAILED, "Old context not destroyed"); diff --git a/src/common/graph/shape_refiner.cc b/src/common/graph/shape_refiner.cc index edf426a5..479ec1cb 100644 --- a/src/common/graph/shape_refiner.cc +++ b/src/common/graph/shape_refiner.cc @@ -37,6 +37,162 @@ namespace ge { namespace { +const uint32_t kWhileBodySubGraphIdx = 1; + +graphStatus ReverseBrushWhileBodySubGraph(const ConstNodePtr &node) { + GELOGD("Enter reverse brush while body subgraph process!"); + + auto sub_graph_body = NodeUtils::GetSubgraph(*node, kWhileBodySubGraphIdx); + if (sub_graph_body == nullptr) { + GELOGE(GRAPH_FAILED, "Get while body graph failed!"); + return GRAPH_FAILED; + } + + for (const auto &node_sub : sub_graph_body->GetAllNodes()) { + for (size_t i = 0; i < node_sub->GetAllInDataAnchorsSize(); i++) { + auto input_desc = node_sub->GetOpDesc()->MutableInputDesc(i); + (void)input_desc->SetUnknownDimNumShape(); + } + for (size_t i = 0; i < node_sub->GetAllOutDataAnchorsSize(); i++) { + auto output_desc = node_sub->GetOpDesc()->MutableOutputDesc(i); + (void)output_desc->SetUnknownDimNumShape(); + } + } + + return GRAPH_SUCCESS; +} + +graphStatus UpdataOutputForMultiBatcch(const ConstNodePtr &node, + std::vector> &ref_out_tensors) { + // check sub_graph shape. Get max for update. + for (size_t i = 0; i < ref_out_tensors.size(); ++i) { + if (ref_out_tensors[i].empty()) { + continue; + } + + int64_t max_size = 0; + size_t max_shape_index = 0; + auto &ref_out_tensor = ref_out_tensors[i].at(0); + const auto &ref_out_tensor_shape = ref_out_tensor.MutableShape(); + for (size_t j = 0; j < ref_out_tensors[i].size(); ++j) { + auto &tensor = ref_out_tensors[i].at(j); + if (ref_out_tensor.GetDataType() != tensor.GetDataType()) { + GELOGE(GRAPH_FAILED, "node[%s] does not support diff dtype output", node->GetName().c_str()); + return GRAPH_FAILED; + } + + auto shape = tensor.MutableShape(); + if (shape.GetDims().size() != ref_out_tensor_shape.GetDims().size()) { + GELOGE(GRAPH_FAILED, "node is %s, i : %d, shape size: %lu, ref_out_tensor_shape size: %lu", + node->GetName().c_str(), i, shape.GetShapeSize(), ref_out_tensor_shape.GetShapeSize()); + return GRAPH_FAILED; + } + + int64_t size = 1; + for (auto dim : shape.GetDims()) { + if (INT64_MAX / dim < size) { + GELOGE(PARAM_INVALID, "The shape size overflow"); + return PARAM_INVALID; + } + size *= dim; + } + + if (size > max_size) { + max_size = size; + max_shape_index = j; + } + } + + (void)node->GetOpDesc()->UpdateOutputDesc(i, ref_out_tensors[i].at(max_shape_index)); + } + + return GRAPH_SUCCESS; +} + +graphStatus UpdateParentNodeForBranch(const ConstNodePtr &node, + std::vector> &ref_out_tensors) { + GELOGD("Enter update parent node shape for class branch op process"); + if (node->GetOpDesc()->HasAttr(ATTR_NAME_BATCH_NUM)) { + return UpdataOutputForMultiBatcch(node, ref_out_tensors); + } + + // check sub_graph shape.If not same ,do unknown shape process + for (size_t i = 0; i < ref_out_tensors.size(); i++) { + if (ref_out_tensors[i].empty()) { + continue; + } + auto ref_out_tensor = ref_out_tensors[i].at(0); + ge::GeShape &ref_out_tensor_shape = ref_out_tensor.MutableShape(); + for (auto &tensor : ref_out_tensors[i]) { + if (ref_out_tensor.GetDataType() != tensor.GetDataType()) { + GELOGE(GRAPH_FAILED, "node[%s] does not support diff dtype output", node->GetName().c_str()); + return GRAPH_FAILED; + } + auto shape = tensor.MutableShape(); + if (shape.GetDims().size() != ref_out_tensor_shape.GetDims().size()) { + GELOGD("node is %s, i : %d, shape size: %lu, ref_out_tensor_shape size: %lu", node->GetName().c_str(), i, + shape.GetShapeSize(), ref_out_tensor_shape.GetShapeSize()); + ref_out_tensor_shape = GeShape(UNKNOWN_RANK); + break; + } + for (size_t j = 0; j < ref_out_tensor_shape.GetDims().size(); j++) { + if (ref_out_tensor_shape.GetDim(j) == shape.GetDim(j)) { + continue; + } + GELOGD("node is %s, i : %d, j: %d ,shape size: %lu, ref_out_tensor_shape size: %lu", node->GetName().c_str(), i, + j, shape.GetShapeSize(), ref_out_tensor_shape.GetShapeSize()); + (void)ref_out_tensor_shape.SetDim(j, UNKNOWN_DIM); + } + } + (void)node->GetOpDesc()->UpdateOutputDesc(i, ref_out_tensor); + } + return GRAPH_SUCCESS; +} + +graphStatus UpdateParentNodeForWhile(const ConstNodePtr &node, std::vector> &ref_data_tensors, + std::vector> &ref_out_tensors) { + GELOGD("Enter update parent node shape for class while op process"); + if (ref_data_tensors.size() != ref_out_tensors.size()) { + GELOGE(GRAPH_FAILED, "while op [%s] input number[%zu] and output number[%zu] is not same!", node->GetName().c_str(), + ref_data_tensors.size(), ref_out_tensors.size()); + return GRAPH_FAILED; + } + for (size_t i = 0; i < ref_data_tensors.size(); i++) { + if (ref_out_tensors[i].size() != 1) { + GELOGE(GRAPH_FAILED, "while op, every output should only find one output tensor in all graph!"); + return GRAPH_FAILED; + } + } + bool is_need_reverse_brush = false; + // check input and output + for (size_t i = 0; i < ref_out_tensors.size(); i++) { + if (ref_out_tensors[i].empty()) { + continue; + } + auto ref_out_tensor = ref_out_tensors[i].at(0); + auto tmp_shape = ref_out_tensor.MutableShape(); + // ref_i's data and output tensor shape should be same + for (auto &tensor : ref_data_tensors[i]) { + if (ref_out_tensor.GetDataType() != tensor.GetDataType()) { + GELOGE(GRAPH_FAILED, "node[%s] does not support diff dtype or format output.", node->GetName().c_str()); + return GRAPH_FAILED; + } + auto shape = tensor.MutableShape(); + if (shape.GetDims() != tmp_shape.GetDims()) { + ref_out_tensor.SetUnknownDimNumShape(); + is_need_reverse_brush = true; + break; + } + } + (void)node->GetOpDesc()->UpdateOutputDesc(i, ref_out_tensor); + } + // reverse refresh while body shape + if (is_need_reverse_brush) { + return ReverseBrushWhileBodySubGraph(node); + } + return GRAPH_SUCCESS; +} + graphStatus UpdateSubGraphDataNodes(const ConstNodePtr &node) { auto op_desc = node->GetOpDesc(); auto sub_graph_names = op_desc->GetSubgraphInstanceNames(); @@ -66,11 +222,14 @@ graphStatus UpdateSubGraphDataNodes(const ConstNodePtr &node) { node->GetName().c_str()); return GRAPH_FAILED; } - if (!AttrUtils::GetInt(node_sub->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, ref_i)) { + if (!AttrUtils::GetInt(data_opdesc, ATTR_NAME_PARENT_NODE_INDEX, ref_i)) { GE_LOGE("Invalid data node on the sub graph %s parent node %s, no ref-index attribute", name.c_str(), node->GetName().c_str()); return GRAPH_FAILED; } + if (data_opdesc->HasAttr(ATTR_MBATCH_ORIGIN_INPUT_DIMS)) { + continue; + } auto input_desc = op_desc->MutableInputDesc(ref_i); if (input_desc == nullptr) { GE_LOGE( @@ -98,6 +257,37 @@ graphStatus UpdateSubGraphDataNodes(const ConstNodePtr &node) { } return GRAPH_SUCCESS; } + +graphStatus FindSubgraphDataAndNetoutput(std::shared_ptr &sub_graph, NodePtr &netoutput, + const ConstNodePtr &node, + std::vector> &ref_data_tensors) { + auto sub_nodes = sub_graph->GetDirectNode(); + for (size_t i = sub_nodes.size(); i > 0; --i) { + auto sub_node = sub_nodes.at(i - 1); + if (sub_node->GetType() == NETOUTPUT) { + netoutput = sub_node; + } + if (sub_node->GetType() == DATA) { + if (sub_node->GetOpDesc() == nullptr) { + return GRAPH_FAILED; + } + + int ref_i; + if (!AttrUtils::GetInt(sub_node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, ref_i)) { + GELOGE(GRAPH_FAILED, "subgraph data node[%s] has no parent node!", sub_node->GetName().c_str()); + return GRAPH_FAILED; + } + if (ref_i < 0 || static_cast(ref_i) >= node->GetAllInDataAnchorsSize()) { + GELOGE(GRAPH_FAILED, "data node[%s]'s ref index[%d] is not in range [0, %zu)!", sub_node->GetName().c_str(), + ref_i, node->GetAllInDataAnchorsSize()); + return GRAPH_FAILED; + } + ref_data_tensors[ref_i].emplace_back(sub_node->GetOpDesc()->GetOutputDesc(0)); + } + } + return GRAPH_SUCCESS; +} + graphStatus UpdateParentNodeOutTensor(const ConstNodePtr &node) { auto op_desc = node->GetOpDesc(); auto sub_graph_names = op_desc->GetSubgraphInstanceNames(); @@ -105,7 +295,10 @@ graphStatus UpdateParentNodeOutTensor(const ConstNodePtr &node) { return GRAPH_SUCCESS; } + std::vector> ref_data_tensors(node->GetAllInDataAnchorsSize()); + std::vector> ref_out_tensors(node->GetAllOutDataAnchorsSize()); auto root_graph = GraphUtils::FindRootGraph(node->GetOwnerComputeGraph()); + for (const auto &name : sub_graph_names) { if (name.empty()) { GELOGW("The node %s contains empty subgraph instance name", node->GetName().c_str()); @@ -117,13 +310,9 @@ graphStatus UpdateParentNodeOutTensor(const ConstNodePtr &node) { return GRAPH_FAILED; } NodePtr netoutput = nullptr; - auto sub_nodes = sub_graph->GetDirectNode(); - for (size_t i = sub_nodes.size(); i > 0; --i) { - auto sub_node = sub_nodes.at(i - 1); - if (sub_node->GetType() == NETOUTPUT) { - netoutput = sub_node; - break; - } + auto ret = FindSubgraphDataAndNetoutput(sub_graph, netoutput, node, ref_data_tensors); + if (ret != GRAPH_SUCCESS) { + return ret; } if (netoutput == nullptr) { GE_LOGE("No NetOutput node on sub graph %s, parent node %s", name.c_str(), node->GetName().c_str()); @@ -150,22 +339,23 @@ graphStatus UpdateParentNodeOutTensor(const ConstNodePtr &node) { continue; } GELOGI("Parent node index of edge desc is %d", ref_i); - auto output_desc = op_desc->MutableOutputDesc(static_cast(ref_i)); - if (output_desc == nullptr) { - GE_LOGE( - "The ref index(%d) on the input %d of netoutput %s on the sub graph %s " - "parent node %s are incompatible, outputs num %u", - ref_i, edge_anchor->GetIdx(), netoutput->GetName().c_str(), name.c_str(), node->GetName().c_str(), - node->GetAllOutDataAnchorsSize()); + if (ref_i < 0 || static_cast(ref_i) >= node->GetAllOutDataAnchorsSize()) { return GRAPH_FAILED; } - op_desc->UpdateOutputDesc(edge_anchor->GetIdx(), *edge_desc); + ref_out_tensors[ref_i].emplace_back(*edge_desc); } } - return GRAPH_SUCCESS; + + if (node->GetType() == WHILE) { + return UpdateParentNodeForWhile(node, ref_data_tensors, ref_out_tensors); + } + return UpdateParentNodeForBranch(node, ref_out_tensors); } } // namespace void ShapeRefiner::PrintInOutTensorShape(const ge::NodePtr &node, const std::string &phase) { + if (!IsLogEnable(GE, DLOG_DEBUG)) { + return; + } if (node == nullptr) { GELOGE(GRAPH_FAILED, "node is null"); return; @@ -185,6 +375,18 @@ void ShapeRefiner::PrintInOutTensorShape(const ge::NodePtr &node, const std::str TypeUtils::FormatToSerialString(input_desc->GetFormat()) + " "; } str += input_desc_str; + + input_desc_str = "input origin shape: "; + for (const auto &input_desc : op_desc->GetAllInputsDescPtr()) { + input_desc_str += "["; + for (int64_t dim : input_desc->GetOriginShape().GetDims()) { + input_desc_str += std::to_string(dim) + " "; + } + input_desc_str += "]"; + input_desc_str += ":" + TypeUtils::DataTypeToSerialString(input_desc->GetOriginDataType()) + ":" + + TypeUtils::FormatToSerialString(input_desc->GetOriginFormat()) + " "; + } + str += input_desc_str; } if (op_desc->GetAllOutputsDescSize() != 0) { @@ -202,6 +404,21 @@ void ShapeRefiner::PrintInOutTensorShape(const ge::NodePtr &node, const std::str TypeUtils::FormatToSerialString(output_desc->GetFormat()) + " "; } str += output_desc_str; + + output_desc_str = "output origin shape: "; + for (const auto &output_desc : op_desc->GetAllOutputsDescPtr()) { + if (output_desc == nullptr) { + continue; + } + output_desc_str += "["; + for (int64_t dim : output_desc->GetOriginShape().GetDims()) { + output_desc_str += std::to_string(dim) + " "; + } + output_desc_str += "]"; + output_desc_str += ":" + TypeUtils::DataTypeToSerialString(output_desc->GetOriginDataType()) + ":" + + TypeUtils::FormatToSerialString(output_desc->GetOriginFormat()) + " "; + } + str += output_desc_str; } GELOGD("Shape dump [%s], Node name: [%s]. %s", phase.c_str(), node->GetName().c_str(), str.c_str()); } @@ -222,7 +439,6 @@ graphStatus ShapeRefiner::InferShapeAndType(const ConstNodePtr &node, Operator & return ret; } } - // Get infer func and execute ret = op_desc->CallInferFunc(op); if (ret == GRAPH_PARAM_INVALID) { @@ -329,6 +545,9 @@ InferenceContextPtr CreateInferenceContext(const std::unordered_map context_map; } + +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void ShapeRefiner::ClearContextMap() { context_map.clear(); } + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ShapeRefiner::InferShapeAndType(const NodePtr &node) { return InferShapeAndType(node, true); } @@ -339,19 +558,20 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ShapeRefiner::InferSh GELOGE(GRAPH_FAILED, "Verifying %s failed.", node->GetName().c_str()); return GRAPH_FAILED; } + PrintInOutTensorShape(node, "before_infershape"); + Operator op = OpDescUtils::CreateOperatorFromNode(node); - auto inference_context = CreateInferenceContext(context_map, node); - if (inference_context == nullptr) { - GELOGE(GRAPH_FAILED, "inference context is null"); - return GRAPH_FAILED; + bool is_unknown_graph = node->GetOwnerComputeGraph()->GetGraphUnknownFlag(); + if (!is_unknown_graph) { + auto inference_context = CreateInferenceContext(context_map, node); + if (inference_context == nullptr) { + GELOGE(GRAPH_FAILED, "inference context is null"); + return GRAPH_FAILED; + } + GELOGD("create context for node:%s, marks %zu", node->GetName().c_str(), inference_context->GetMarks().size()); + op.SetInferenceContext(inference_context); } - GELOGD("create context for node:%s, marks %zu", node->GetName().c_str(), inference_context->GetMarks().size()); - - PrintInOutTensorShape(node, "before_infershape"); - - Operator op = OpDescUtils::CreateOperatorFromNode(node); - op.SetInferenceContext(inference_context); graphStatus status = InferShapeAndType(node, op, before_subgraph); if (status == GRAPH_PARAM_INVALID || status == GRAPH_SUCCESS) { (void)ge::NodeUtils::UpdatePeerNodeInputDesc(node); @@ -359,16 +579,17 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus ShapeRefiner::InferSh GELOGE(GRAPH_FAILED, "%s call infer function failed.", node->GetName().c_str()); return GRAPH_FAILED; } - - auto ctx_after_infer = op.GetInferenceContext(); - if (ctx_after_infer != nullptr) { - GELOGD("[%s] after infershape. mark:%zu", node->GetName().c_str(), ctx_after_infer->GetMarks().size()); - if (!ctx_after_infer->GetOutputHandleShapesAndTypes().empty() || !ctx_after_infer->GetMarks().empty()) { - GELOGD("[%s] set inference context after. mark:%zu", node->GetName().c_str(), ctx_after_infer->GetMarks().size()); - (void)context_map.emplace(node, ctx_after_infer); + if (!is_unknown_graph) { + auto ctx_after_infer = op.GetInferenceContext(); + if (ctx_after_infer != nullptr) { + GELOGD("[%s] after infershape. mark:%zu", node->GetName().c_str(), ctx_after_infer->GetMarks().size()); + if (!ctx_after_infer->GetOutputHandleShapesAndTypes().empty() || !ctx_after_infer->GetMarks().empty()) { + GELOGD("[%s] set inference context after. mark:%zu", node->GetName().c_str(), + ctx_after_infer->GetMarks().size()); + (void)context_map.emplace(node, ctx_after_infer); + } } } - PrintInOutTensorShape(node, "after_infershape"); return GRAPH_SUCCESS; diff --git a/src/common/graph/stub/Makefile b/src/common/graph/stub/Makefile deleted file mode 100644 index 832adcd5..00000000 --- a/src/common/graph/stub/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -inc_path := $(shell pwd)/inc/external/ -out_path := $(shell pwd)/out/atc/lib64/stub/ -stub_path := $(shell pwd)/common/graph/stub/ - -mkdir_stub := $(shell mkdir -p $(out_path)) -graph_local_stub := $(shell $(HI_PYTHON) $(stub_path)/gen_stubapi.py $(inc_path) $(out_path)) diff --git a/src/common/graph/stub/gen_stubapi.py b/src/common/graph/stub/gen_stubapi.py deleted file mode 100644 index 6185c479..00000000 --- a/src/common/graph/stub/gen_stubapi.py +++ /dev/null @@ -1,573 +0,0 @@ -import os -import re -import sys -import logging - -logging.basicConfig(stream=sys.stdout, format='[%(asctime)s] [%(lineno)s] %(levelname)s: %(message)s', - level=logging.INFO) - -""" - this attr is used for symbol table visible -""" -GE_ATTR = 'GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY' - -""" - generate stub func body by return type -""" -RETURN_STATEMENTS = { - 'graphStatus': ' return GRAPH_SUCCESS;', - 'Status': ' return SUCCESS;', - 'Graph': ' return Graph();', - 'Graph&': ' return *this;', - 'Format': ' return Format();', - 'Format&': ' return *this;', - 'Shape': ' return Shape();', - 'Shape&': ' return *this;', - 'TensorDesc': ' return TensorDesc();', - 'TensorDesc&': ' return *this;', - 'Tensor': ' return Tensor();', - 'Tensor&': ' return *this;', - 'Operator': ' return Operator();', - 'Operator&': ' return *this;', - 'Ptr': ' return nullptr;', - 'std::string': ' return "";', - 'std::string&': ' return "";', - 'string': ' return "";', - 'int': ' return 0;', - 'DataType': ' return DT_FLOAT;', - 'InferenceContextPtr': ' return nullptr;', - 'SubgraphBuilder': ' return nullptr;', - 'OperatorImplPtr': ' return nullptr;', - 'OutHandler': ' return nullptr;', - 'std::vector': ' return {};', - 'std::vector': ' return {};', - 'std::map': ' return {};', - 'uint32_t': ' return 0;', - 'int64_t': ' return 0;', - 'uint64_t': ' return 0;', - 'size_t': ' return 0;', - 'float': ' return 0.0f;', - 'bool': ' return false;', -} - -""" - max code len per line in hua_wei software programming specifications -""" -max_code_len_per_line = 100 - -""" - white_list_for_debug, include_dir_key_words is to - determines which header files to generate cc files from - when DEBUG on -""" -white_list_for_debug = ["operator.h", "tensor.h", - "graph.h", "operator_factory.h", - "ge_ir_build.h"] -include_dir_key_words = ["ge", "graph"] -DEBUG = True - - -def need_generate_func(func_line): - """ - :param func_line: - :return: - """ - if func_line.strip().endswith("default") or func_line.strip().endswith("delete") \ - or func_line.strip().startswith("typedef") or func_line.strip().startswith("using"): - return False - return True - - -def file_endswith_white_list_suffix(file): - """ - :param file: - :return: - """ - if DEBUG: - for suffix in white_list_for_debug: - if file.endswith(suffix): - return True - return False - else: - return True - - -""" - belows are patterns used for analyse .h file -""" -# pattern function -pattern_func = re.compile(r"""(^[\s]*) #leading with space,we will find and delete after -([a-zA-Z~_] # void int likely -.* -[)] #we find ) -(?!.*{) # we do not want the case int abc() const { return 1;} -.*) -(;.*) #we want to find ; and after for we will replace these later -\n$ -""", re.VERBOSE | re.MULTILINE | re.DOTALL) - -# pattern comment -pattern_comment = re.compile(r'^\s*//') -pattern_comment_2_start = re.compile(r'^\s*/[*]') -pattern_comment_2_end = re.compile(r'[*]/\s*$') -# pattern define -pattern_define = re.compile(r'^\s*#define') -pattern_define_return = re.compile(r'\\\s*$') -# blank line -pattern_blank_line = re.compile(r'^\s*$') -# virtual,explicit,friend,static -pattern_keyword = re.compile(r'(virtual\s+|explicit\s+|friend\s+|static\s+)') -# lead space -pattern_leading_space = re.compile(r'(^[\s]*)[a-zA-Z~_]') -# functions will have patterns such as func ( or func( -# but operator is an exception; the class name is preceded by an operator, and the above mode does not exist -# format like :"operator = ()" -pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*|operator?.*)[(]') -# template -pattern_template = re.compile(r'^\s*template') -pattern_template_end = re.compile(r'>\s*$') -# namespace -pattern_namespace = re.compile(r'namespace.*{') -# class : which can handle classA a and {not on the same line, but if found ';' after class,then don't deal with -pattern_class = re.compile(r'^[\s]*(class|struct)\s+(%s\s+)?([a-zA-Z0-9_\-]+ 0 and not friend_match: - line, func_name = self.handle_class_member_func(line, template_string) - # Normal functions - else: - line, func_name = self.handle_normal_func(line, template_string) - - need_generate = need_generate_func(line) - # func body - line += self.implement_function(line) - # comment - line = self.gen_comment(start_i) + line - # write to out file - self.write_func_content(line, func_name, need_generate) - # next loop - self.line_index += 1 - - logging.info('Added %s functions', len(self.func_list_exist)) - logging.info('Successfully converted,please see ' + self.output_file) - - def handle_func1(self, line): - """ - :param line: - :return: - """ - find1 = re.search('[(]', line) - if not find1: - self.line_index += 1 - return "continue", line, None - find2 = re.search('[)]', line) - start_i = self.line_index - space_match = pattern_leading_space.search(line) - # deal with - # int abc(int a, - # int b) - if find1 and (not find2): - self.line_index += 1 - line2 = self.input_content[self.line_index] - if space_match: - line2 = re.sub('^' + space_match.group(1), '', line2) - line += line2 - while self.line_index < len(self.input_content) and (not re.search('[)]', line2)): - self.line_index += 1 - line2 = self.input_content[self.line_index] - line2 = re.sub('^' + space_match.group(1), '', line2) - line += line2 - - match_start = pattern_start.search(self.input_content[self.line_index]) - match_end = pattern_end.search(self.input_content[self.line_index]) - if match_start: # like ) { or ) {} int the last line - if not match_end: - self.stack.append('normal_now') - ii = start_i - while ii <= self.line_index: - ii += 1 - self.line_index += 1 - return "continue", line, start_i - logging.info("line[%s]", line) - # ' int abc();'->'int abc()' - (line, match) = pattern_func.subn(r'\2\n', line) - logging.info("line[%s]", line) - # deal with case: - # 'int \n abc(int a, int b)' - if re.search(r'^\s*(inline)?\s*[a-zA-Z0-9_]+\s*$', self.input_content[start_i - 1]): - line = self.input_content[start_i - 1] + line - line = line.lstrip() - if not match: - self.line_index += 1 - return "continue", line, start_i - return "pass", line, start_i - - def handle_stack(self, match_start): - """ - :param match_start: - :return: - """ - line = self.input_content[self.line_index] - match_end = pattern_end.search(line) - if match_start: - self.stack.append('normal_now') - if match_end: - top_status = self.stack.pop() - if top_status == 'namespace_now': - self.output_fd.write(line + '\n') - elif top_status == 'class_now': - self.stack_class.pop() - self.stack_template.pop() - if match_start or match_end: - self.line_index += 1 - return "continue" - - if len(self.stack) > 0 and self.stack[-1] == 'normal_now': - self.line_index += 1 - return "continue" - return "pass" - - def handle_class(self, template_string, line, match_start, match_class): - """ - :param template_string: - :param line: - :param match_start: - :param match_class: - :return: - """ - if match_class: # we face a class - self.stack_template.append(template_string) - self.stack.append('class_now') - class_name = match_class.group(3) - - # class template specializations: class A > - if '<' in class_name: - k = line.index('<') - fit = 1 - for ii in range(k + 1, len(line)): - if line[ii] == '<': - fit += 1 - if line[ii] == '>': - fit -= 1 - if fit == 0: - break - class_name += line[k + 1:ii + 1] - logging.info('class_name[%s]', class_name) - self.stack_class.append(class_name) - while not match_start: - self.line_index += 1 - line = self.input_content[self.line_index] - match_start = pattern_start.search(line) - self.line_index += 1 - return "continue" - return "pass" - - def handle_template(self): - line = self.input_content[self.line_index] - match_template = pattern_template.search(line) - template_string = '' - if match_template: - match_template_end = pattern_template_end.search(line) - template_string = line - while not match_template_end: - self.line_index += 1 - line = self.input_content[self.line_index] - template_string += line - match_template_end = pattern_template_end.search(line) - self.line_index += 1 - return template_string - - def handle_namespace(self): - line = self.input_content[self.line_index] - match_namespace = pattern_namespace.search(line) - if match_namespace: # we face namespace - self.output_fd.write(line + '\n') - self.stack.append('namespace_now') - self.line_index += 1 - - def handle_normal_func(self, line, template_string): - template_line = '' - self.stack_template.append(template_string) - if self.stack_template[-1] != '': - template_line = re.sub(r'\s*template', 'template', self.stack_template[-1]) - # change '< class T = a, class U = A(3)>' to '' - template_line = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_line) - template_line = re.sub(r'\s*=.*,', ',', template_line) - template_line = re.sub(r'\s*=.*', '', template_line) - line = re.sub(r'\s*=.*,', ',', line) - line = re.sub(r'\s*=.*\)', ')', line) - line = template_line + line - self.stack_template.pop() - func_name = re.search(r'^.*\)', line, re.MULTILINE | re.DOTALL).group() - logging.info("line[%s]", line) - logging.info("func_name[%s]", func_name) - return line, func_name - - def handle_class_member_func(self, line, template_string): - template_line = '' - x = '' - if template_string != '': - template_string = re.sub(r'\s*template', 'template', template_string) - template_string = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_string) - template_string = re.sub(r'\s*=.*,', ',', template_string) - template_string = re.sub(r'\s*=.*', '', template_string) - if self.stack_template[-1] != '': - if not (re.search(r'<\s*>', stack_template[-1])): - template_line = re.sub(r'^\s*template', 'template', stack_template[-1]) - if not (re.search(r'<.*>', self.stack_class[-1])): - # for x we get like template -> - x = re.sub(r'template\s*<', '<', template_line) # remove template -> - x = re.sub(r'\n', '', x) - x = re.sub(r'\s*=.*,', ',', x) - x = re.sub(r'\s*=.*\>', '>', x) - x = x.rstrip() # remove \n - x = re.sub(r'(class|typename)\s+|(|\s*class)', '', - x) # remove class,typename -> - x = re.sub(r'<\s+', '<', x) - x = re.sub(r'\s+>', '>', x) - x = re.sub(r'\s+,', ',', x) - x = re.sub(r',\s+', ', ', x) - line = re.sub(r'\s*=\s+0', '', line) - line = re.sub(r'\s*=\s+.*,', ',', line) - line = re.sub(r'\s*=\s+.*\)', ')', line) - logging.info("x[%s]\nline[%s]", x, line) - # if the function is long, void ABC::foo() - # breaks into two lines void ABC::\n foo() - temp_line = pattern_func_name.sub(self.stack_class[-1] + x + '::' + r'\1(', line, count=1) - if len(temp_line) > max_code_len_per_line: - line = pattern_func_name.sub(self.stack_class[-1] + x + '::\n' + r'\1(', line, count=1) - else: - line = temp_line - logging.info("line[%s]", line) - # add template as the above if there is one - template_line = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_line) - template_line = re.sub(r'\s*=.*,', ',', template_line) - template_line = re.sub(r'\s*=.*', '', template_line) - line = template_line + template_string + line - func_name = re.search(r'^.*\)', line, re.MULTILINE | re.DOTALL).group() - logging.info("line[%s]", line) - logging.info("func_name[%s]", func_name) - return line, func_name - - def write_func_content(self, content, func_name, need_generate): - if not (func_name in self.func_list_exist) and need_generate: - self.output_fd.write(content) - self.func_list_exist.append(func_name) - logging.info('add func:[%s]', func_name) - - def gen_comment(self, start_i): - comment_line = '' - # Function comments are on top of function declarations, copy them over - k = start_i - 1 # one line before this func start - if pattern_template.search(self.input_content[k]): - k -= 1 - if pattern_comment_2_end.search(self.input_content[k]): - comment_line = self.input_content[k].lstrip() - while not pattern_comment_2_start.search(self.input_content[k]): - k -= 1 - comment_line = self.input_content[k].lstrip() + comment_line - else: - for j in range(k, 0, -1): - c_line = self.input_content[j] - if pattern_comment.search(c_line): - c_line = re.sub(r'\s*//', '//', c_line) - comment_line = c_line + comment_line - else: - break - return comment_line - - @staticmethod - def implement_function(func): - function_def = '' - function_def += '{\n' - - all_items = func.split() - start = 0 - return_type = all_items[start] - if return_type == "const": - start += 1 - return_type = all_items[start] - if return_type.startswith(('std::map', 'std::set', 'std::vector')): - return_type = "std::map" - if return_type.endswith('*') or (len(all_items) > start + 1 and all_items[start + 1].startswith('*')): - return_type = "Ptr" - if len(all_items) > start + 1 and all_items[start + 1].startswith('&'): - return_type += "&" - if RETURN_STATEMENTS.__contains__(return_type): - function_def += RETURN_STATEMENTS[return_type] - else: - logging.warning("Unhandled return type[%s]", return_type) - - function_def += '\n' - function_def += '}\n' - function_def += '\n' - return function_def - - -def collect_header_files(path): - """ - :param path: - :return: - """ - header_files = [] - shared_includes_content = [] - for root, dirs, files in os.walk(path): - files.sort() - for file in files: - if file.find("git") >= 0: - continue - if not file.endswith('.h'): - continue - file_path = os.path.join(root, file) - file_path = file_path.replace('\\', '/') - header_files.append(file_path) - include_str = '#include "{}"\n'.format(file_path[path.rindex('/') + 1:]) - shared_includes_content.append(include_str) - return header_files, shared_includes_content - - -def generate_stub_file(inc_dir, out_cc_dir): - """ - :param inc_dir: - :param out_cc_dir: - :return: - """ - target_header_files, shared_includes_content = collect_header_files(inc_dir) - for header_file in target_header_files: - if not file_endswith_white_list_suffix(header_file): - continue - cc_file = re.sub('.h*$', '.cc', header_file) - h_2_cc = H2CC(header_file, out_cc_dir + cc_file[cc_file.rindex('/') + 1:], shared_includes_content) - h_2_cc.h2cc() - - -def gen_code(inc_dir, out_cc_dir): - """ - :param inc_dir: - :param out_cc_dir: - :return: - """ - if not inc_dir.endswith('/'): - inc_dir += '/' - if not out_cc_dir.endswith('/'): - out_cc_dir += '/' - for include_dir_key_word in include_dir_key_words: - generate_stub_file(inc_dir + include_dir_key_word, out_cc_dir) - - -if __name__ == '__main__': - inc_dir = sys.argv[1] - out_cc_dir = sys.argv[2] - gen_code(inc_dir, out_cc_dir) diff --git a/src/common/graph/tensor.cc b/src/common/graph/tensor.cc index 0d511645..1f30c876 100644 --- a/src/common/graph/tensor.cc +++ b/src/common/graph/tensor.cc @@ -178,16 +178,18 @@ int64_t Shape::GetShapeSize() const { return 0; } -TensorDesc::TensorDesc() { impl = ComGraphMakeShared(); } +TensorDesc::TensorDesc() { + impl = ComGraphMakeShared(); // lint !e665 +} TensorDesc::TensorDesc(Shape shape, Format format, DataType dt) { - impl = ComGraphMakeShared(shape, format, dt); + impl = ComGraphMakeShared(shape, format, dt); // lint !e665 SetRealDimCnt(shape.GetDimNum()); } TensorDesc::TensorDesc(const TensorDesc &desc) { // Copy - impl = ComGraphMakeShared(); + impl = ComGraphMakeShared(); // lint !e665 if (desc.impl != nullptr && impl != nullptr) { *impl = *desc.impl; } @@ -358,7 +360,9 @@ void TensorDesc::SetName(const std::string &name) { Tensor::Tensor() { impl = ComGraphMakeShared(); } -Tensor::Tensor(const TensorDesc &tensor_desc) { impl = ComGraphMakeShared(tensor_desc); } +Tensor::Tensor(const TensorDesc &tensor_desc) { + impl = ComGraphMakeShared(tensor_desc); // lint !e665 +} Tensor::Tensor(const TensorDesc &tensor_desc, const std::vector &data) { uint64_t shape_size = tensor_desc.GetShape().GetShapeSize(); @@ -380,7 +384,7 @@ Tensor::Tensor(const TensorDesc &tensor_desc, const std::vector &data) } } } - impl = ComGraphMakeShared(tensor_desc, data); + impl = ComGraphMakeShared(tensor_desc, data); // lint !e665 } Tensor::Tensor(const TensorDesc &tensor_desc, const uint8_t *data, size_t size) { @@ -402,7 +406,7 @@ Tensor::Tensor(const TensorDesc &tensor_desc, const uint8_t *data, size_t size) } } - impl = ComGraphMakeShared(tensor_desc, data, size); + impl = ComGraphMakeShared(tensor_desc, data, size); // lint !e665 } Tensor::Tensor(TensorDesc &&tensor_desc, std::vector &&data) { @@ -425,7 +429,7 @@ Tensor::Tensor(TensorDesc &&tensor_desc, std::vector &&data) { } } } - impl = ComGraphMakeShared(std::move(tensor_desc), std::move(data)); + impl = ComGraphMakeShared(std::move(tensor_desc), std::move(data)); // lint !e665 } TensorDesc Tensor::GetTensorDesc() const { @@ -639,7 +643,7 @@ TensorDesc TensorAdapter::GeTensorDesc2TensorDesc(const GeTensorDesc &ge_tensor_ GeTensorPtr TensorAdapter::Tensor2GeTensor(const Tensor &tensor) { GeTensorPtr ge_tensor; if (tensor.impl != nullptr) { - ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor.Clone()); + ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor.Clone()); // lint !e665 } return ge_tensor; } @@ -655,7 +659,7 @@ Tensor TensorAdapter::GeTensor2Tensor(const ConstGeTensorPtr &ge_tensor) { ConstGeTensorPtr TensorAdapter::AsGeTensorPtr(const Tensor &tensor) { GeTensorPtr ge_tensor; if (tensor.impl != nullptr) { - ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor); + ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor); // lint !e665 } return ge_tensor; } @@ -663,7 +667,7 @@ ConstGeTensorPtr TensorAdapter::AsGeTensorPtr(const Tensor &tensor) { GeTensorPtr TensorAdapter::AsGeTensorPtr(Tensor &tensor) { GeTensorPtr ge_tensor; if (tensor.impl != nullptr) { - ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor); + ge_tensor = ComGraphMakeShared(tensor.impl->ge_tensor); // lint !e665 } return ge_tensor; } diff --git a/src/common/graph/utils/graph_utils.cc b/src/common/graph/utils/graph_utils.cc index ca2ebcdc..19c28c63 100644 --- a/src/common/graph/utils/graph_utils.cc +++ b/src/common/graph/utils/graph_utils.cc @@ -38,6 +38,7 @@ #include "utils/ge_ir_utils.h" #include "utils/node_utils.h" #include "debug/ge_op_types.h" +#include "external/ge/ge_api_types.h" #include "graph/debug/ge_attr_define.h" #include "graph/utils/op_desc_utils.h" #include "graph/utils/tensor_utils.h" @@ -410,8 +411,8 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus GraphUtils::InsertTra /// @return graphStatus /// GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus -GraphUtils::InsertNodeBefore(const OutDataAnchorPtr &src, const std::vector &dsts, - const NodePtr &insert_node, uint32_t input_index, uint32_t output_index) { +GraphUtils::InsertNodeAfter(const OutDataAnchorPtr &src, const std::vector &dsts, + const NodePtr &insert_node, uint32_t input_index, uint32_t output_index) { GE_CHECK_NOTNULL(src); GE_CHECK_NOTNULL(insert_node); @@ -570,7 +571,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void GraphUtils::DumpGEGraph(cons static int max_dumpfile_num = 0; if (max_dumpfile_num == 0) { string opt = "0"; - (void)GetContext().GetOption("ge.maxDumpFileNum", opt); + (void)GetContext().GetOption(OPTION_GE_MAX_DUMP_FILE_NUM, opt); max_dumpfile_num = std::strtol(opt.c_str(), nullptr, kBaseOfIntegerValue); } if (max_dumpfile_num != 0 && file_idx > max_dumpfile_num) { @@ -670,7 +671,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void GraphUtils::WriteProtoToText if (maxDumpFileSize == 0) { string opt = "0"; // Can not check return value - (void)GetContext().GetOption("ge.maxDumpFileSize", opt); + (void)GetContext().GetOption(OPTION_GE_MAX_DUMP_FILE_SIZE, opt); maxDumpFileSize = atol(opt.c_str()); } if (maxDumpFileSize != 0 && fileSize != -1 && fileSize > maxDumpFileSize) { @@ -740,7 +741,7 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY void GraphUtils::DumpGEGraphToOnn static int max_dumpfile_num = 0; if (max_dumpfile_num == 0) { string opt = "0"; - (void)GetContext().GetOption("ge.maxDumpFileNum", opt); + (void)GetContext().GetOption(OPTION_GE_MAX_DUMP_FILE_NUM, opt); max_dumpfile_num = std::strtol(opt.c_str(), nullptr, kBaseOfIntegerValue); } if (max_dumpfile_num != 0 && file_index > max_dumpfile_num) { @@ -920,7 +921,7 @@ graphStatus RelinkDataIO(const NodePtr &node, const std::vector &io_map, In InNodesToOut GetFullConnectIONodes(const NodePtr &node) { InNodesToOut in_nodes_to_out; if (node == nullptr) { - GELOGE(GRAPH_FAILED, "Node is nullptr,node is %s", node->GetName().c_str()); + GELOGE(GRAPH_FAILED, "Node is nullptr"); return in_nodes_to_out; } auto in_nodes_list = node->GetInNodes(); @@ -1308,6 +1309,36 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus GraphUtils::MoveOutCt return GRAPH_SUCCESS; } +/// +/// Copy all in-data edges from `src_node` to `dst_node`. +/// @param src_node +/// @param dst_node +/// @return +/// +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus GraphUtils::CopyInDataEdges(const NodePtr &src_node, + NodePtr &dst_node) { + if ((src_node == nullptr) || (dst_node == nullptr)) { + GELOGE(GRAPH_FAILED, "Parameter is nullptr"); + return GRAPH_PARAM_INVALID; + } + auto src_data_in_nodes = src_node->GetInDataNodes(); + if (src_data_in_nodes.empty()) { + return GRAPH_SUCCESS; + } + for (const auto &in_data_anchor : src_node->GetAllInDataAnchors()) { + auto input_desc = src_node->GetOpDesc()->GetInputDesc(in_data_anchor->GetIdx()); + auto ret = + GraphUtils::AddEdge(in_data_anchor->GetPeerOutAnchor(), dst_node->GetInDataAnchor(in_data_anchor->GetIdx())); + if (ret != GRAPH_SUCCESS) { + GELOGE(GRAPH_FAILED, "Failed to add data edge from %s to %s when copy in data edge from %s to %s", + in_data_anchor->GetPeerOutAnchor()->GetOwnerNode()->GetName().c_str(), dst_node->GetName().c_str(), + src_node->GetName().c_str(), dst_node->GetName().c_str()); + return ret; + } + } + return GRAPH_SUCCESS; +} + GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus GraphUtils::AppendInputNode(const ComputeGraphPtr &graph, const NodePtr &node) { if (graph->AddInputNode(node) == nullptr) { @@ -1329,6 +1360,153 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ComputeGraphPtr GraphUtils::FindR } /// +/// Make a copy of ComputeGraph. +/// @param graph: original graph. +/// @param prefix: node name prefix of new graph. +/// @return ComputeGraphPtr +/// +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY ComputeGraphPtr +GraphUtils::CloneGraph(const ComputeGraphPtr &graph, const std::string &prefix, std::vector &input_nodes, + std::vector &output_nodes) { + GE_CHK_BOOL_EXEC(graph != nullptr, return nullptr, "Original graph is null"); + ComputeGraphPtr new_graph = ComGraphMakeShared(graph->GetName()); + GE_CHK_BOOL_EXEC(new_graph != nullptr, return nullptr, "Create new graph failed"); + + std::unordered_map all_new_nodes; + for (const auto &n : graph->GetDirectNode()) { + OpDescPtr op_desc = AttrUtils::CopyOpDesc(n->GetOpDesc()); + GE_CHK_BOOL_EXEC(op_desc != nullptr, return nullptr, "Create new node failed"); + + if (CopyTensorAttrs(op_desc, n) != GRAPH_SUCCESS) { + return nullptr; + } + + op_desc->SetName(prefix + n->GetName()); + NodePtr node = new_graph->AddNode(op_desc); + GE_CHK_BOOL_EXEC(node != nullptr, return nullptr, "Add node[%s] to graph failed", op_desc->GetName().c_str()); + all_new_nodes[node->GetName()] = node; + + if (node->GetType() == DATA) { + input_nodes.emplace_back(node); + } else if (node->GetType() == NETOUTPUT) { + output_nodes.emplace_back(node); + } + } + + for (const auto &n : graph->GetDirectNode()) { + if (RelinkGraphEdges(n, prefix, all_new_nodes) != GRAPH_SUCCESS) { + return nullptr; + } + } + + return new_graph; +} + +/// +/// Copy tensor attribute to new node. +/// @param [in] dst_node: cloned node. +/// @param [in] src_node: original node. +/// @return success: GRAPH_SUCESS +/// +graphStatus GraphUtils::CopyTensorAttrs(const OpDescPtr &dst_desc, const NodePtr &src_node) { + if (dst_desc == nullptr) { + GELOGE(GRAPH_FAILED, "Input param dst node not valid"); + return GRAPH_FAILED; + } + if (src_node == nullptr || src_node->GetOpDesc() == nullptr) { + GELOGE(GRAPH_FAILED, "Input param src node not valid"); + return GRAPH_FAILED; + } + + const auto &src_desc = src_node->GetOpDesc(); + dst_desc->CopyAttrsFrom(*src_desc); + + for (uint32_t i = 0; i < src_node->GetAllInDataAnchorsSize(); ++i) { + auto input_desc = dst_desc->MutableInputDesc(i); + if (input_desc == nullptr) { + GELOGE(GRAPH_FAILED, "Param dst node not valid"); + return GRAPH_FAILED; + } + input_desc->CopyAttrsFrom(src_desc->GetInputDesc(i)); + } + + for (uint32_t i = 0; i < src_node->GetAllOutDataAnchorsSize(); ++i) { + auto output_desc = dst_desc->MutableOutputDesc(i); + if (output_desc == nullptr) { + GELOGE(GRAPH_FAILED, "Param dst node not valid"); + return GRAPH_FAILED; + } + output_desc->CopyAttrsFrom(src_desc->GetOutputDesc(i)); + } + + return GRAPH_SUCCESS; +} + +/// +/// Relink all edges for cloned ComputeGraph. +/// @param [in] node: original node. +/// @param [in] prefix: node name prefix of new node. +/// @param [in] all_nodes: all nodes in new graph. +/// @return success: GRAPH_SUCESS +/// +graphStatus GraphUtils::RelinkGraphEdges(const NodePtr &node, const string &prefix, + const std::unordered_map &all_nodes) { + if (node == nullptr || node->GetOpDesc() == nullptr) { + GELOGE(GRAPH_FAILED, "Input node not valid"); + return GRAPH_FAILED; + } + + auto it = all_nodes.find(prefix + node->GetName()); + if (it == all_nodes.end()) { + GELOGE(GRAPH_FAILED, "node[%s] not found", node->GetName().c_str()); + return GRAPH_FAILED; + } + const auto &new_node = it->second; + + for (const auto &in_anchor : node->GetAllInDataAnchors()) { + GE_CHK_BOOL_EXEC(in_anchor != nullptr, return GRAPH_FAILED, "In data anchor is null"); + const auto &out_anchor = in_anchor->GetPeerOutAnchor(); + if (out_anchor == nullptr) { + GELOGW("Peer out anchor is null: %s", node->GetName().c_str()); + continue; + } + GE_CHK_BOOL_EXEC(out_anchor->GetOwnerNode() != nullptr, return GRAPH_FAILED, "Peer out node is null"); + + it = all_nodes.find(prefix + out_anchor->GetOwnerNode()->GetName()); + if (it == all_nodes.end()) { + GELOGE(GRAPH_FAILED, "node[%s] not found", out_anchor->GetOwnerNode()->GetName().c_str()); + return GRAPH_FAILED; + } + const auto &new_out_node = it->second; + + auto rslt = + GraphUtils::AddEdge(new_out_node->GetOutAnchor(out_anchor->GetIdx()), new_node->GetInAnchor(in_anchor->GetIdx())); + GE_CHK_BOOL_EXEC(rslt == GRAPH_SUCCESS, return GRAPH_FAILED, "link failed[%s to %s]", + new_out_node->GetName().c_str(), new_node->GetName().c_str()); + } + + if (node->GetInControlAnchor() != nullptr) { + for (const auto &out_anchor : node->GetInControlAnchor()->GetPeerAnchors()) { + GE_CHK_BOOL_EXEC(out_anchor != nullptr, continue, "Peer out anchor is null: %s", node->GetName().c_str()); + GE_CHK_BOOL_EXEC(out_anchor->GetOwnerNode() != nullptr, return GRAPH_FAILED, "Peer out node is null"); + + it = all_nodes.find(prefix + out_anchor->GetOwnerNode()->GetName()); + if (it == all_nodes.end()) { + GELOGE(GRAPH_FAILED, "node[%s] not found", out_anchor->GetOwnerNode()->GetName().c_str()); + return GRAPH_FAILED; + } + const auto &new_out_node = it->second; + + auto rslt = GraphUtils::AddEdge(new_out_node->GetOutAnchor(out_anchor->GetIdx()), new_node->GetInControlAnchor()); + GE_CHK_BOOL_EXEC(rslt == GRAPH_SUCCESS, return GRAPH_FAILED, "link failed[%s to %s]", + new_out_node->GetName().c_str(), new_node->GetName().c_str()); + } + } + + return GRAPH_SUCCESS; +} + +/// /// Get reference-mapping of all data_anchors in graph /// @param [in] graph /// @param [out] symbol_to_anchors @@ -1339,7 +1517,7 @@ graphStatus GraphUtils::GetRefMapping(const ComputeGraphPtr &graph, std::map> &symbol_to_anchors, std::map &anchor_to_symbol) { GE_CHECK_NOTNULL(graph); - for (auto &node : graph->GetAllNodes()) { + for (const auto &node : graph->GetAllNodes()) { // in_data_anchor if (HandleInAnchorMapping(node, symbol_to_anchors, anchor_to_symbol) != GRAPH_SUCCESS) { GE_LOGE("Find ref_mapping for in_data_anchors of node %s failed.", node->GetName().c_str()); @@ -1396,16 +1574,16 @@ graphStatus GraphUtils::HandleInAnchorMapping(const NodePtr &node, return HandleSubgraphInput(node, symbol_to_anchors, anchor_to_symbol); } - std::string type = node->GetType(); + const std::string &type = node->GetType(); if ((type == MERGE) || (type == STREAMMERGE)) { return HandleMergeInput(node, symbol_to_anchors, anchor_to_symbol); } - for (auto &in_data_anchor : node->GetAllInDataAnchors()) { + for (const auto &in_data_anchor : node->GetAllInDataAnchors()) { NodeIndexIO cur_node_info(node, in_data_anchor->GetIdx(), kIn); OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); if (peer_out_anchor == nullptr) { - std::string symbol = cur_node_info.ToString(); + const std::string &symbol = cur_node_info.ToString(); GELOGD("Add anchor %s, symbol %s.", cur_node_info.ToString().c_str(), symbol.c_str()); symbol_to_anchors[symbol] = {cur_node_info}; anchor_to_symbol[symbol] = symbol; @@ -1432,7 +1610,7 @@ graphStatus GraphUtils::HandleOutAnchorMapping(const NodePtr &node, std::map> &symbol_to_anchors, std::map &anchor_to_symbol) { GE_CHECK_NOTNULL(node); - for (auto &out_data_anchor : node->GetAllOutDataAnchors()) { + for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) { NodeIndexIO cur_node_info(node, out_data_anchor->GetIdx(), kOut); if (anchor_to_symbol.find(cur_node_info.ToString()) != anchor_to_symbol.end()) { continue; @@ -1446,7 +1624,7 @@ graphStatus GraphUtils::HandleOutAnchorMapping(const NodePtr &node, return GRAPH_FAILED; } } else { - std::string symbol = cur_node_info.ToString(); + const std::string &symbol = cur_node_info.ToString(); GELOGD("Add anchor %s, symbol %s.", cur_node_info.ToString().c_str(), symbol.c_str()); symbol_to_anchors.emplace(std::make_pair(symbol, std::list{cur_node_info})); anchor_to_symbol.emplace(std::make_pair(symbol, symbol)); @@ -1506,7 +1684,7 @@ graphStatus GraphUtils::HandleMergeInput(const NodePtr &node, GE_CHECK_NOTNULL(node); std::vector exist_node_infos; std::vector cur_node_infos; - for (auto &in_data_anchor : node->GetAllInDataAnchors()) { + for (const auto &in_data_anchor : node->GetAllInDataAnchors()) { auto peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); if (peer_out_anchor == nullptr) { std::string next_name; @@ -1529,10 +1707,10 @@ graphStatus GraphUtils::HandleMergeInput(const NodePtr &node, size_t anchor_nums = 0; NodeIndexIO max_node_index_io(nullptr, 0, kOut); - for (auto &temp_node_info : exist_node_infos) { + for (const auto &temp_node_info : exist_node_infos) { auto iter1 = anchor_to_symbol.find(temp_node_info.ToString()); if (iter1 != anchor_to_symbol.end()) { - std::string temp_symbol = iter1->second; + const std::string &temp_symbol = iter1->second; auto iter2 = symbol_to_anchors.find(temp_symbol); if (iter2 != symbol_to_anchors.end()) { if (iter2->second.size() > anchor_nums) { @@ -1544,7 +1722,7 @@ graphStatus GraphUtils::HandleMergeInput(const NodePtr &node, } std::string symbol; - for (auto &temp_node_info : exist_node_infos) { + for (const auto &temp_node_info : exist_node_infos) { if ((UnionSymbolMapping(max_node_index_io, temp_node_info, symbol_to_anchors, anchor_to_symbol, symbol) != GRAPH_SUCCESS) || symbol.empty()) { @@ -1556,7 +1734,7 @@ graphStatus GraphUtils::HandleMergeInput(const NodePtr &node, auto iter = symbol_to_anchors.find(symbol); if (iter != symbol_to_anchors.end()) { - for (auto &temp_node_info : cur_node_infos) { + for (const auto &temp_node_info : cur_node_infos) { GELOGD("Add anchor %s, symbol %s.", temp_node_info.ToString().c_str(), symbol.c_str()); iter->second.emplace_back(temp_node_info); anchor_to_symbol.emplace(std::make_pair(temp_node_info.ToString(), symbol)); @@ -1584,7 +1762,7 @@ graphStatus GraphUtils::HandleSubgraphOutput(const NodePtr &node, OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); - for (auto &in_data_anchor : node->GetAllInDataAnchors()) { + for (const auto &in_data_anchor : node->GetAllInDataAnchors()) { OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); GE_CHECK_NOTNULL(peer_out_anchor); @@ -1627,8 +1805,8 @@ graphStatus GraphUtils::HandleSubgraphOutput(const NodePtr &node, graphStatus GraphUtils::UnionSymbolMapping(const NodeIndexIO &exist_node_info1, const NodeIndexIO &exist_node_info2, std::map> &symbol_to_anchors, std::map &anchor_to_symbol, std::string &symbol) { - std::string symbol1 = anchor_to_symbol[exist_node_info1.ToString()]; - std::string symbol2 = anchor_to_symbol[exist_node_info2.ToString()]; + const std::string &symbol1 = anchor_to_symbol[exist_node_info1.ToString()]; + const std::string &symbol2 = anchor_to_symbol[exist_node_info2.ToString()]; if (symbol1 == symbol2) { symbol = symbol1; GELOGI("no need to union."); @@ -1684,7 +1862,7 @@ graphStatus GraphUtils::UpdateRefMapping(const NodeIndexIO &cur_node_info, const return GRAPH_FAILED; } - std::string symbol = iter1->second; + const std::string &symbol = iter1->second; auto iter2 = symbol_to_anchors.find(symbol); if (iter2 == symbol_to_anchors.end()) { GE_LOGE("symbol %s not found.", symbol.c_str()); @@ -1712,7 +1890,7 @@ bool GraphUtils::IsRefFromInput(const OutDataAnchorPtr &out_data_anchor, int32_t // pass-through op NodePtr node = out_data_anchor->GetOwnerNode(); - std::string type = node->GetType(); + const std::string &type = node->GetType(); const std::set pass_through_set = {NETOUTPUT, WHILE, _WHILE, STATELESSWHILE}; if ((pass_through_set.count(type) > 0) || (NodeUtils::IsSubgraphInput(node))) { reuse_in_index = output_index; @@ -1755,7 +1933,7 @@ bool GraphUtils::IsRefFromInput(const OutDataAnchorPtr &out_data_anchor, int32_t uint32_t reuse_input_index = 0; if (TensorUtils::GetReuseInputIndex(*output_op_desc, reuse_input_index) == GRAPH_SUCCESS) { reuse_in_index = static_cast(reuse_input_index); - GELOGI("ReuseInput name[%s] output[%u] reuse input[%d].", op_desc->GetName().c_str(), output_index, + GELOGI("ReuseInput name[%s] output[%d] reuse input[%d].", op_desc->GetName().c_str(), output_index, reuse_in_index); return true; } @@ -2297,7 +2475,7 @@ void CompleteGraphBuilder::AddRetValNodes(graphStatus &error_code, std::string & return; } - std::string name = node->GetName() + "_RetVal"; + std::string name = node->GetName() + "_RetVal_" + std::to_string(index); OpDescPtr ret_val_desc = shared_ptr(new (std::nothrow) OpDesc(name, FRAMEWORKOP)); if (ret_val_desc == nullptr) { error_code = GRAPH_FAILED; diff --git a/src/common/graph/utils/node_utils.cc b/src/common/graph/utils/node_utils.cc index e4fb8b82..35a842e5 100644 --- a/src/common/graph/utils/node_utils.cc +++ b/src/common/graph/utils/node_utils.cc @@ -295,16 +295,21 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus NodeUtils::UpdatePeer if (op_desc == nullptr) { return GRAPH_FAILED; } + bool is_unknown_graph = node_ptr->GetOwnerComputeGraph()->GetGraphUnknownFlag(); + if (is_unknown_graph) { + return GRAPH_SUCCESS; + } for (const auto &out_anchor : node_ptr->GetAllOutDataAnchors()) { - GeTensorDesc output_tensor = op_desc->GetOutputDesc(out_anchor->GetIdx()); - ge::TensorUtils::SetRealDimCnt(output_tensor, static_cast(output_tensor.GetShape().GetDims().size())); - output_tensor.SetOriginShape(output_tensor.GetShape()); - output_tensor.SetOriginDataType(output_tensor.GetDataType()); + auto output_tensor = op_desc->MutableOutputDesc(out_anchor->GetIdx()); + ge::TensorUtils::SetRealDimCnt(*output_tensor, static_cast(output_tensor->GetShape().GetDims().size())); + output_tensor->SetOriginShape(output_tensor->GetShape()); + output_tensor->SetOriginDataType(output_tensor->GetDataType()); + GELOGD("node name is %s, origin shape is %ld, origin format is %s, origin data type is %s", - node_ptr->GetName().c_str(), output_tensor.GetOriginShape().GetShapeSize(), - TypeUtils::FormatToSerialString(output_tensor.GetOriginFormat()).c_str(), - TypeUtils::DataTypeToSerialString(output_tensor.GetOriginDataType()).c_str()); - (void)op_desc->UpdateOutputDesc(out_anchor->GetIdx(), output_tensor); + node_ptr->GetName().c_str(), output_tensor->GetOriginShape().GetShapeSize(), + TypeUtils::FormatToSerialString(output_tensor->GetOriginFormat()).c_str(), + TypeUtils::DataTypeToSerialString(output_tensor->GetOriginDataType()).c_str()); + for (const auto &peer_anchor : out_anchor->GetPeerInDataAnchors()) { if (peer_anchor->GetOwnerNode()->GetOpDesc() == nullptr) { GELOGE(GRAPH_FAILED, "peer_anchor opdesc is null"); @@ -316,17 +321,17 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus NodeUtils::UpdatePeer continue; } GELOGI("Peer input opdesc name is %s, need to flush: shape size is %zu, datatype is %d, original datatype is %d", - peer_anchor->GetOwnerNode()->GetOpDesc()->GetName().c_str(), output_tensor.GetShape().GetDimNum(), - output_tensor.GetDataType(), output_tensor.GetOriginDataType()); - peer_input_desc->SetShape(output_tensor.GetShape()); - peer_input_desc->SetOriginShape(output_tensor.GetOriginShape()); - peer_input_desc->SetDataType(output_tensor.GetDataType()); - peer_input_desc->SetOriginDataType(output_tensor.GetOriginDataType()); + peer_anchor->GetOwnerNode()->GetOpDesc()->GetName().c_str(), output_tensor->GetShape().GetDimNum(), + output_tensor->GetDataType(), output_tensor->GetOriginDataType()); + peer_input_desc->SetOriginShape(output_tensor->GetOriginShape()); + peer_input_desc->SetShape(output_tensor->GetShape()); + peer_input_desc->SetDataType(output_tensor->GetDataType()); + peer_input_desc->SetOriginDataType(output_tensor->GetOriginDataType()); std::vector> shape_range; - (void)output_tensor.GetShapeRange(shape_range); + (void)output_tensor->GetShapeRange(shape_range); peer_input_desc->SetShapeRange(shape_range); ge::TensorUtils::SetRealDimCnt(*peer_input_desc, - static_cast(output_tensor.GetShape().GetDims().size())); + static_cast(output_tensor->GetShape().GetDims().size())); GELOGI("Peer input opdesc name is %s, shape size is %zu, datatype is %d, original datatype is %d", peer_anchor->GetOwnerNode()->GetOpDesc()->GetName().c_str(), peer_input_desc->GetShape().GetDimNum(), peer_input_desc->GetDataType(), peer_input_desc->GetOriginDataType()); @@ -334,6 +339,50 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus NodeUtils::UpdatePeer } return GRAPH_SUCCESS; } + +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus NodeUtils::AppendInputAnchor(const NodePtr &node, + uint32_t index) { + if (node == nullptr) { + GELOGE(GRAPH_FAILED, "Nodeptr is nullptr"); + return GRAPH_FAILED; + } + + GeTensorDesc data_desc(GeShape(), FORMAT_ND, DT_FLOAT); + OpDescPtr op_desc = node->op_; + for (size_t i = op_desc->GetInputsSize(); i < index; ++i) { + if (op_desc->AddInputDesc(data_desc) != GRAPH_SUCCESS) { + GELOGE(GRAPH_FAILED, "Add input desc failed"); + return GRAPH_FAILED; + } + + auto anchor = ComGraphMakeShared(node, i); + if (anchor == nullptr) { + GELOGE(GRAPH_FAILED, "Current in_data_anchor is null, malloc shared_ptr failed."); + return GRAPH_FAILED; + } + node->in_data_anchors_.push_back(anchor); + } + + return GRAPH_SUCCESS; +} + +GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus NodeUtils::RemoveInputAnchor(const NodePtr &node, + uint32_t index) { + if (node == nullptr) { + GELOGE(GRAPH_FAILED, "Nodeptr is nullptr"); + return GRAPH_FAILED; + } + + OpDescPtr op_desc = node->op_; + op_desc->RemoveInputDesc(index); + + while (node->in_data_anchors_.size() > index) { + node->in_data_anchors_.pop_back(); + } + + return GRAPH_SUCCESS; +} + bool NodeUtils::IsInNodesEmpty(const Node &node) { for (const auto &in_anchor : node.in_data_anchors_) { if (in_anchor != nullptr) { @@ -401,10 +450,13 @@ graphStatus NodeUtils::UpdateInputShape(const Node &node, uint32_t index, const graphStatus NodeUtils::GetNodeUnknownShapeStatus(const Node &node, bool &is_unknow) { auto desc = node.GetOpDesc(); GE_CHECK_NOTNULL(desc); - + // check self + is_unknow = OpShapeIsUnknown(desc); + if (is_unknow) { + return GRAPH_SUCCESS; + } auto sub_graph_names = desc->GetSubgraphInstanceNames(); if (sub_graph_names.empty()) { - is_unknow = OpShapeIsUnknown(desc); return GRAPH_SUCCESS; } else { auto owner_graph = node.GetOwnerComputeGraph(); @@ -440,6 +492,7 @@ std::string NodeUtils::GetNodeType(const Node &node) { (void)AttrUtils::GetStr(node.GetOpDesc(), ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type); return type; } + ComputeGraphPtr NodeUtils::GetSubgraph(const Node &node, uint32_t index) { auto op_desc = node.GetOpDesc(); if (op_desc == nullptr) { @@ -492,6 +545,14 @@ bool NodeUtils::IsSubgraphInput(const NodePtr &node) { return false; } if (AttrUtils::HasAttr(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE)) { + bool is_unknown_shape = false; + (void)AttrUtils::GetBool(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape); + if (is_unknown_shape) return false; + } + + if (AttrUtils::HasAttr(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE) && + kCaseOpTypes.count(parent_op_desc->GetType()) == 0 && kWhileOpTypes.count(parent_op_desc->GetType()) == 0 && + kForOpTypes.count(parent_op_desc->GetType()) == 0 && kIfOpTypes.count(parent_op_desc->GetType()) == 0) { return false; } @@ -513,7 +574,16 @@ bool NodeUtils::IsSubgraphOutput(const NodePtr &node) { if (parent_op_desc == nullptr) { return false; } + if (AttrUtils::HasAttr(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE)) { + bool is_unknown_shape = false; + (void)AttrUtils::GetBool(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape); + if (is_unknown_shape) return false; + } + + if (AttrUtils::HasAttr(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE) && + kCaseOpTypes.count(parent_op_desc->GetType()) == 0 && kWhileOpTypes.count(parent_op_desc->GetType()) == 0 && + kForOpTypes.count(parent_op_desc->GetType()) == 0 && kIfOpTypes.count(parent_op_desc->GetType()) == 0) { return false; } @@ -556,6 +626,53 @@ NodePtr NodeUtils::GetParentInput(const NodePtr &node) { } /// +/// @brief Check is varying_input for while node +/// @param [in] node: Data node for subgraph +/// @return bool +/// +bool NodeUtils::IsWhileVaryingInput(const ge::NodePtr &node) { + if (node == nullptr) { + return false; + } + if (node->GetType() != DATA) { + return false; // not input_node for subgraph + } + + const NodePtr &parent_node = node->GetOwnerComputeGraph()->GetParentNode(); + if (parent_node == nullptr) { + return false; // root graph + } + + if (kWhileOpTypes.count(parent_node->GetType()) == 0) { + return false; // not input_node for while subgraph + } + + uint32_t index_i = 0; + if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, index_i)) { + GELOGW("Node %s has no attr PARENT_NODE_INDEX.", node->GetName().c_str()); + return false; + } + bool varying_flag = true; + for (const auto &item : node->GetOutDataNodesAndAnchors()) { + if (item.first->GetType() != NETOUTPUT) { + continue; + } + OpDescPtr op_desc = item.first->GetOpDesc(); + uint32_t index_o = 0; + if ((op_desc == nullptr) || + !AttrUtils::GetInt(op_desc->GetInputDesc(item.second->GetIdx()), ATTR_NAME_PARENT_NODE_INDEX, index_o)) { + continue; // input for while-cond subgraph + } + if (index_i != index_o) { + continue; // varying input for while-body subgraph + } + varying_flag = false; + break; + } + return varying_flag; +} + +/// /// @brief Get subgraph input is constant. /// @param [in] node /// @param [out] string @@ -637,4 +754,86 @@ Status NodeUtils::RemoveSubgraphsOnNode(const NodePtr &node) { return GRAPH_SUCCESS; } +/// +/// @brief Get subgraph input data node by index. +/// @param [in] node +/// @return Node +/// +vector NodeUtils::GetSubgraphDataNodesByIndex(const Node &node, int index) { + vector in_data_node_vec; + auto op_desc = node.GetOpDesc(); + GE_CHECK_NOTNULL_EXEC(op_desc, return in_data_node_vec); + auto subgraph_names = op_desc->GetSubgraphInstanceNames(); + if (subgraph_names.empty()) { + GELOGW("Node %s is single node without sub graph.", node.GetName().c_str()); + return in_data_node_vec; + } + auto compute_graph = node.GetOwnerComputeGraph(); + for (const std::string &instance_name : subgraph_names) { + auto subgraph = compute_graph->GetSubgraph(instance_name); + for (const auto &node_in_subgraph : subgraph->GetDirectNode()) { + int parent_index = -1; + if (NodeUtils::IsSubgraphInput(node_in_subgraph)) { + (void)AttrUtils::GetInt(node_in_subgraph->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, parent_index); + if (parent_index == index) { + in_data_node_vec.emplace_back(node_in_subgraph); + } + } + } + } + return in_data_node_vec; +} +/// +/// @brief Get subgraph input data node by index. +/// @param [in] node +/// @return Node +/// +vector NodeUtils::GetSubgraphOutputNodes(const Node &node) { + vector out_data_node_vec; + auto op_desc = node.GetOpDesc(); + GE_CHECK_NOTNULL_EXEC(op_desc, return out_data_node_vec); + auto subgraph_names = op_desc->GetSubgraphInstanceNames(); + if (subgraph_names.empty()) { + GELOGI("Node %s is single node without sub graph.", node.GetName().c_str()); + return out_data_node_vec; + } + auto compute_graph = node.GetOwnerComputeGraph(); + for (const std::string &instance_name : subgraph_names) { + auto subgraph = compute_graph->GetSubgraph(instance_name); + for (const auto &node_in_subgraph : subgraph->GetDirectNode()) { + if (NodeUtils::IsSubgraphOutput(node_in_subgraph)) { + out_data_node_vec.emplace_back(node_in_subgraph); + } + } + } + return out_data_node_vec; +} + +NodePtr NodeUtils::GetInDataNodeByIndex(const Node &node, int index) { + if (node.GetInDataAnchor(index) == nullptr) { + return nullptr; + } + if (node.GetInDataAnchor(index)->GetPeerOutAnchor() == nullptr) { + return nullptr; + } + return node.GetInDataAnchor(index)->GetPeerOutAnchor()->GetOwnerNode(); +} + +vector NodeUtils::GetOutDataNodesByIndex(const Node &node, int index) { + vector out_data_nodes; + auto out_data_anchor = node.GetOutDataAnchor(index); + if (out_data_anchor == nullptr) { + return out_data_nodes; + } + for (const auto peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { + if (peer_in_anchor == nullptr) { + continue; + } + if (peer_in_anchor->GetOwnerNode() == nullptr) { + continue; + } + out_data_nodes.emplace_back(peer_in_anchor->GetOwnerNode()); + } + return out_data_nodes; +} } // namespace ge diff --git a/src/common/graph/utils/op_desc_utils.cc b/src/common/graph/utils/op_desc_utils.cc index 6264ddb9..7a52a7f8 100644 --- a/src/common/graph/utils/op_desc_utils.cc +++ b/src/common/graph/utils/op_desc_utils.cc @@ -28,6 +28,7 @@ using std::vector; +/*lint -e512 -e737 -e752*/ namespace ge { const char OP_DESC_QUANT_PARAMS[] = "quantize_factor"; static const int CONST_OP_NORMAL_WEIGHT_SIZE = 1; @@ -132,11 +133,11 @@ graphStatus OpDescUtils::GetQuantizeFactorParams(const OpDesc &op_desc, Quantize GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus OpDescUtils::SetQuantizeFactorParams(const OpDescPtr &op_desc, const QuantizeFactorParams &quant) { GE_CHK_BOOL_EXEC_INFO(op_desc != nullptr, return GRAPH_FAILED, "op_desc is nullptr"); - return op_desc->SetAttr(OP_DESC_QUANT_PARAMS, GeAttrValue::CreateFrom(quant)); + return op_desc->SetAttr(OP_DESC_QUANT_PARAMS, GeAttrValue::CreateFrom(quant)); // lint !e732 } graphStatus OpDescUtils::SetQuantizeFactorParams(OpDesc &op_desc, const QuantizeFactorParams &quant) { - return op_desc.SetAttr(OP_DESC_QUANT_PARAMS, GeAttrValue::CreateFrom(quant)); + return op_desc.SetAttr(OP_DESC_QUANT_PARAMS, GeAttrValue::CreateFrom(quant)); // lint !e732 } GeTensorPtr OpDescUtils::MutableWeights(OpDesc &op_desc) { @@ -197,24 +198,33 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY vector OpDescUtils:: continue; } auto in_node = out_anchor->GetOwnerNode(); - if ((in_node->GetType() == CONSTANT) || (in_node->GetType() == CONSTANTOP)) { - ret.push_back(in_node); - } else if (in_node->GetType() == DATA) { - const ComputeGraphPtr &graph = node.GetOwnerComputeGraph(); - GE_CHK_BOOL_EXEC(graph != nullptr, continue, "Owner graph is null"); - - const NodePtr &parent_node = graph->GetParentNode(); - if (parent_node == nullptr) { - continue; // Root graph. - } - - if (kWhileOpTypes.count(parent_node->GetType()) > 0) { - continue; // Subgraph of While cond or body. + while (true) { + if (in_node == nullptr) { + break; } - - NodePtr input_node = NodeUtils::GetParentInput(in_node); - if ((input_node != nullptr) && ((input_node->GetType() == CONSTANT) || (input_node->GetType() == CONSTANTOP))) { - ret.push_back(input_node); + if ((in_node->GetType() == CONSTANT) || (in_node->GetType() == CONSTANTOP)) { + ret.push_back(in_node); + break; + } else if (in_node->GetType() == DATA) { + if (NodeUtils::IsWhileVaryingInput(in_node)) { + break; + } + in_node = NodeUtils::GetParentInput(in_node); + } else if ((in_node->GetType() == ENTER) || (in_node->GetType() == REFENTER)) { + bool is_constant = false; + (void)AttrUtils::GetBool(in_node->GetOpDesc(), ENTER_ATTR_CONSTANT_FLAG, is_constant); + if (!is_constant) { + break; + } + // Enter node has and only has one input + if (in_node->GetInDataNodes().size() != 1) { + GELOGW("Check number of input_nodes for Enter node %s failed, size=%zu.", node.GetName().c_str(), + in_node->GetInDataNodes().size()); + break; + } + in_node = in_node->GetInDataNodes().at(0); + } else { + break; } } } @@ -245,7 +255,7 @@ size_t OpDescUtils::GetNonConstInputsSize(const ge::Node &node) { continue; } } - return input_num; + return input_num; // lint !e712 } else { GE_IF_BOOL_EXEC( node.GetInDataNodes().size() < GetConstInputs(node).size(), @@ -350,7 +360,7 @@ bool OpDescUtils::IsNonConstInput(const ge::Node &node, const size_t index) { bool ret = false; if (index < node.GetAllInDataAnchors().size()) { if (NodeUtils::IsAnchorStatusSet(node)) { - ret = (ge::AnchorUtils::GetStatus(node.GetInDataAnchor(static_cast(index))) == ANCHOR_DATA); + ret = (ge::AnchorUtils::GetStatus(node.GetInDataAnchor(static_cast(index))) == ANCHOR_DATA); // lint !e712 } else { for (const auto &anchor : node.GetAllInDataAnchors()) { if (anchor->GetIdx() != static_cast(index)) { @@ -435,10 +445,27 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY vector OpDescUtils:: GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY vector OpDescUtils::MutableWeights(const ge::Node &node) { vector ret; - GE_CHK_BOOL_EXEC(node.GetOpDesc() != nullptr, return ret, "node.GetOpDesc is nullptr!"); + auto op_desc = node.GetOpDesc(); + GE_CHK_BOOL_EXEC(op_desc != nullptr, return ret, "op_desc is nullptr!"); + // Place holder operator, try to get the weight from parent node + // when parent node is const operator + if (node.GetType() == PLACEHOLDER) { + std::string parent_op; + (void)AttrUtils::GetStr(op_desc, "parentOpType", parent_op); + // This if judgment is necessary because the current subgraph optimization is multithreaded + // and the parent node of the PLD operation should be a stable type, such as const + if (parent_op == CONSTANT || parent_op == CONSTANTOP) { + NodePtr parent_node = nullptr; + parent_node = op_desc->TryGetExtAttr("parentNode", parent_node); + if (parent_node != nullptr) { + op_desc = parent_node->GetOpDesc(); + GELOGD("pld[%s] get weight from const[%s]", node.GetName().c_str(), op_desc->GetName().c_str()); + } + } + } // Const operator, take the weight directly - if (node.GetOpDesc()->GetType() == CONSTANT || (node.GetOpDesc()->GetType() == CONSTANTOP)) { - auto weight = MutableWeights(node.GetOpDesc()); + if (op_desc->GetType() == CONSTANT || (op_desc->GetType() == CONSTANTOP)) { + auto weight = MutableWeights(op_desc); if (weight == nullptr) { GELOGI("const op has no weight, op name:%s", node.GetName().c_str()); return ret; @@ -733,3 +760,4 @@ GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY graphStatus OpDescUtils::SetSubgr return op_desc->SetSubgraphInstanceName(iter->second, subgraph_instance_name); } } // namespace ge +/*lint +e512 +e737 +e752*/ diff --git a/src/common/graph/utils/tensor_utils.cc b/src/common/graph/utils/tensor_utils.cc index 674cab55..26ac8cc8 100644 --- a/src/common/graph/utils/tensor_utils.cc +++ b/src/common/graph/utils/tensor_utils.cc @@ -19,6 +19,7 @@ #include "debug/ge_log.h" #include "framework/common/debug/ge_log.h" +#include "common/util/error_manager/error_manager.h" #include "graph/ge_tensor.h" #include "graph/types.h" #include "graph/utils/type_utils.h" @@ -105,7 +106,10 @@ static graphStatus CalcElementCntByDims(const std::vector &dims, int64_ element_cnt = 1; for (int64_t dim : dims) { if (CheckMultiplyOverflowInt64(element_cnt, dim)) { - GELOGE(GRAPH_FAILED, "CalcElementCntByDims failed, as when multiplying %ld and %ld.", element_cnt, dim); + ErrorManager::GetInstance().ATCReportErrMessage( + "E19013", {"function", "var1", "var2"}, + {"CheckMultiplyOverflowInt64", std::to_string(element_cnt), std::to_string(dim)}); + GELOGE(GRAPH_FAILED, "CalcElementCntByDims failed, when multiplying %ld and %ld.", element_cnt, dim); return GRAPH_FAILED; } element_cnt *= dim; @@ -273,7 +277,6 @@ static graphStatus CalcTensorElementCnt(const std::vector &dims, Format case FORMAT_FRACTAL_Z: graph_status = CalcElementCntOfFractalZ(dims, data_type, element_cnt); break; - case FORMAT_NC1HWC0_C04: case FORMAT_FRACTAL_NZ: case FORMAT_FRACTAL_ZZ: case FORMAT_NDHWC: @@ -285,6 +288,7 @@ static graphStatus CalcTensorElementCnt(const std::vector &dims, Format case FORMAT_NDC1HWC0: case FORMAT_FRACTAL_Z_C04: case FORMAT_FRACTAL_ZN_LSTM: + case FORMAT_NC1HWC0_C04: graph_status = CalcElementCntByDims(dims, element_cnt); break; default: diff --git a/src/common/graph/utils/type_utils.cc b/src/common/graph/utils/type_utils.cc index e4986931..5215b141 100644 --- a/src/common/graph/utils/type_utils.cc +++ b/src/common/graph/utils/type_utils.cc @@ -147,7 +147,8 @@ static const std::map kStringToFormatMap = { {"FRACTAL_ZN_LSTM", FORMAT_FRACTAL_ZN_LSTM}, {"FRACTAL_Z_G", FORMAT_FRACTAL_Z_G}, {"FORMAT_RESERVED", FORMAT_RESERVED}, - {"ALL", FORMAT_ALL}}; + {"ALL", FORMAT_ALL}, + {"NULL", FORMAT_NULL}}; static const std::map kDataTypeToStringMap = { {DT_UNDEFINED, "DT_UNDEFINED"}, // Used to indicate a DataType field has not been set. diff --git a/src/ge/CMakeLists.txt b/src/ge/CMakeLists.txt index 894eaf1e..a527bc1f 100755 --- a/src/ge/CMakeLists.txt +++ b/src/ge/CMakeLists.txt @@ -60,6 +60,7 @@ file(GLOB TRAIN_SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "common/formats/formats.cc" "common/formats/utils/formats_trans_utils.cc" "common/fp16_t.cc" + "common/ge/op_tiling_manager.cc" "common/ge/plugin_manager.cc" "common/helper/model_cache_helper.cc" "common/profiling/profiling_manager.cc" @@ -94,14 +95,25 @@ file(GLOB TRAIN_SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc" "graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc" "graph/load/new_model_manager/task_info/task_info.cc" - "graph/load/output/output.cc" - "graph/manager/*.cc" + "graph/manager/graph_context.cc" + "graph/manager/graph_manager.cc" + "graph/manager/graph_manager_utils.cc" + "graph/manager/graph_mem_allocator.cc" + "graph/manager/graph_caching_allocator.cc" + "graph/manager/graph_var_manager.cc" + "graph/manager/model_manager/event_manager.cc" + "graph/manager/trans_var_data_utils.cc" + "graph/manager/util/debug.cc" + "graph/manager/util/hcom_util.cc" + "graph/manager/util/rt_context_util.cc" + "graph/manager/util/variable_accelerate_ctrl.cc" "graph/manager/model_manager/event_manager.cc" "graph/manager/util/debug.cc" "graph/manager/util/hcom_util.cc" "graph/manager/util/rt_context_util.cc" "graph/manager/util/variable_accelerate_ctrl.cc" "graph/optimize/graph_optimize.cc" + "graph/optimize/mem_rw_conflict_optimize.cc" "graph/optimize/optimizer/allreduce_fusion_pass.cc" "graph/optimize/summary_optimize.cc" "graph/partition/dynamic_shape_partition.cc" @@ -159,8 +171,11 @@ file(GLOB TRAIN_SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "hybrid/node_executor/aicpu/aicpu_ext_info.cc" "hybrid/node_executor/aicpu/aicpu_node_executor.cc" "hybrid/node_executor/compiledsubgraph/known_node_executor.cc" + "hybrid/node_executor/controlop/control_op_executor.cc" + "hybrid/node_executor/hccl/hccl_node_executor.cc" "hybrid/node_executor/hostcpu/ge_local_node_executor.cc" "hybrid/node_executor/node_executor.cc" + "hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc" "hybrid/node_executor/task_context.cc" "init/gelib.cc" "model/ge_model.cc" @@ -204,6 +219,7 @@ file(GLOB INFER_SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "common/formats/formats.cc" "common/formats/utils/formats_trans_utils.cc" "common/fp16_t.cc" + "common/ge/op_tiling_manager.cc" "common/ge/plugin_manager.cc" "common/helper/model_cache_helper.cc" "common/profiling/profiling_manager.cc" @@ -236,13 +252,19 @@ file(GLOB INFER_SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc" "graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc" "graph/load/new_model_manager/task_info/task_info.cc" - "graph/load/output/output.cc" - "graph/manager/*.cc" + "graph/manager/graph_caching_allocator.cc" + "graph/manager/graph_context.cc" + "graph/manager/graph_manager.cc" + "graph/manager/graph_manager_utils.cc" + "graph/manager/graph_mem_allocator.cc" + "graph/manager/trans_var_data_utils.cc" + "graph/manager/graph_var_manager.cc" "graph/manager/model_manager/event_manager.cc" "graph/manager/util/debug.cc" "graph/manager/util/rt_context_util.cc" "graph/manager/util/variable_accelerate_ctrl.cc" "graph/optimize/graph_optimize.cc" + "graph/optimize/mem_rw_conflict_optimize.cc" "graph/optimize/summary_optimize.cc" "graph/partition/dynamic_shape_partition.cc" "graph/partition/engine_place.cc" diff --git a/src/ge/client/ge_api.cc b/src/ge/client/ge_api.cc index ae6a9892..120c144a 100644 --- a/src/ge/client/ge_api.cc +++ b/src/ge/client/ge_api.cc @@ -28,6 +28,7 @@ #include "graph/opsproto_manager.h" #include "graph/utils/type_utils.h" #include "graph/manager/util/rt_context_util.h" +#include "graph/common/ge_call_wrapper.h" #include "register/op_registry.h" #include "common/ge/tbe_plugin_manager.h" @@ -41,8 +42,8 @@ namespace { const int32_t kMaxStrLen = 128; } -static bool kGeInitialized = false; -static std::mutex kGeReleaseMutex; // GEFinalize and ~Session use +static bool g_ge_initialized = false; +static std::mutex g_ge_release_mutex; // GEFinalize and ~Session use namespace ge { void GetOpsProtoPath(std::string &opsproto_path) { @@ -61,31 +62,6 @@ void GetOpsProtoPath(std::string &opsproto_path) { opsproto_path = (path_base + "ops/op_proto/custom/" + ":") + (path_base + "ops/op_proto/built-in/"); } -Status CheckDumpAndReuseMemory(const std::map &options) { - const int kDecimal = 10; - auto dump_op_env = std::getenv("DUMP_OP"); - int dump_op_flag = (dump_op_env != nullptr) ? std::strtol(dump_op_env, nullptr, kDecimal) : 0; - auto disableReuseMemoryIter = options.find("ge.exec.disableReuseMemory"); - if (disableReuseMemoryIter != options.end()) { - if (disableReuseMemoryIter->second == "0") { - GELOGD("ge.exec.disableReuseMemory=0, reuse memory is open"); - if (dump_op_flag) { - GELOGW("Will dump incorrect op data with GE Option ge.exec.disableReuseMemory=0"); - } - } else if (disableReuseMemoryIter->second == "1") { - GELOGD("ge.exec.disableReuseMemory=1, reuse memory is close"); - } else { - GELOGE(PARAM_INVALID, "CheckDumpAndReuseMemory ge.exec.disableReuseMemory is valid"); - return FAILED; - } - } else { - if (dump_op_flag) { - GELOGW("Will dump incorrect op data with default reuse memory"); - } - } - return SUCCESS; -} - Status CheckOptionsValid(const std::map &options) { // check job_id is valid auto job_id_iter = options.find(OPTION_EXEC_JOB_ID); @@ -96,11 +72,6 @@ Status CheckOptionsValid(const std::map &options) { } } - // Check ge.exec.disableReuseMemory and env DUMP_OP - if (CheckDumpAndReuseMemory(options) != SUCCESS) { - return FAILED; - } - return SUCCESS; } @@ -108,7 +79,7 @@ Status CheckOptionsValid(const std::map &options) { Status GEInitialize(const std::map &options) { GELOGT(TRACE_INIT, "GEInitialize start"); // 0.check init status - if (kGeInitialized) { + if (g_ge_initialized) { GELOGW("GEInitialize is called more than once"); return SUCCESS; } @@ -147,9 +118,9 @@ Status GEInitialize(const std::map &options) { } // 7.check return status, return - if (!kGeInitialized) { + if (!g_ge_initialized) { // Initialize success, first time calling initialize - kGeInitialized = true; + g_ge_initialized = true; } GELOGT(TRACE_STOP, "GEInitialize finished"); @@ -160,12 +131,12 @@ Status GEInitialize(const std::map &options) { Status GEFinalize() { GELOGT(TRACE_INIT, "GEFinalize start"); // check init status - if (!kGeInitialized) { + if (!g_ge_initialized) { GELOGW("GEFinalize is called before GEInitialize"); return SUCCESS; } - std::lock_guard lock(kGeReleaseMutex); + std::lock_guard lock(g_ge_release_mutex); // call Finalize Status ret = SUCCESS; Status middle_ret; @@ -187,10 +158,10 @@ Status GEFinalize() { ret = middle_ret; } - if (kGeInitialized && ret == SUCCESS) { + if (g_ge_initialized && ret == SUCCESS) { // Unified destruct rt_context - RtContextUtil::GetInstance().DestroyrtContexts(); - kGeInitialized = false; + RtContextUtil::GetInstance().DestroyAllRtContexts(); + g_ge_initialized = false; } GELOGT(TRACE_STOP, "GEFinalize finished"); @@ -202,7 +173,7 @@ Session::Session(const std::map &options) { GELOGT(TRACE_INIT, "Session Constructor start"); // check init status sessionId_ = 0; - if (!kGeInitialized) { + if (!g_ge_initialized) { GELOGE(GE_CLI_GE_NOT_INITIALIZED); return; } @@ -232,13 +203,13 @@ Session::Session(const std::map &options) { Session::~Session() { GELOGT(TRACE_INIT, "Session Destructor start"); // 0.check init status - if (!kGeInitialized) { + if (!g_ge_initialized) { GELOGW("GE is not yet initialized or is finalized."); return; } Status ret = FAILED; - std::lock_guard lock(kGeReleaseMutex); + std::lock_guard lock(g_ge_release_mutex); try { uint64_t session_id = sessionId_; // call DestroySession diff --git a/src/ge/common/convert/pb2json.cc b/src/ge/common/convert/pb2json.cc index 832a8278..0a5d24ee 100644 --- a/src/ge/common/convert/pb2json.cc +++ b/src/ge/common/convert/pb2json.cc @@ -72,9 +72,6 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void Pb2Json::Message2Json(cons void Pb2Json::OneField2Json(const ProtobufMsg &message, const ProtobufFieldDescriptor *field, const ProtobufReflection *reflection, const set &black_fields, Json &json, bool enum2str) { - if (field == nullptr || reflection == nullptr) { - return; - } switch (field->type()) { case ProtobufFieldDescriptor::TYPE_MESSAGE: { const ProtobufMsg &tmp_message = reflection->GetMessage(message, field); @@ -118,8 +115,12 @@ void Pb2Json::OneField2Json(const ProtobufMsg &message, const ProtobufFieldDescr case ProtobufFieldDescriptor::TYPE_FLOAT: char str[kSignificantDigits]; - sprintf_s(str, kSignificantDigits, "%g", reflection->GetFloat(message, field)); - json[field->name()] = str; + if (sprintf_s(str, kSignificantDigits, "%g", reflection->GetFloat(message, field)) != -1) { + json[field->name()] = str; + } else { + json[field->name()] = reflection->GetFloat(message, field); + } + break; case ProtobufFieldDescriptor::TYPE_STRING: diff --git a/src/ge/common/formats/format_transfers/datatype_transfer.cc b/src/ge/common/formats/format_transfers/datatype_transfer.cc index 0bd4b8e5..08c6889f 100644 --- a/src/ge/common/formats/format_transfers/datatype_transfer.cc +++ b/src/ge/common/formats/format_transfers/datatype_transfer.cc @@ -29,7 +29,6 @@ namespace ge { namespace formats { - namespace { enum DataTypeTransMode { kTransferWithDatatypeFloatToFloat16, diff --git a/src/ge/common/formats/format_transfers/datatype_transfer.h b/src/ge/common/formats/format_transfers/datatype_transfer.h index 0702592f..4d93fd6c 100644 --- a/src/ge/common/formats/format_transfers/datatype_transfer.h +++ b/src/ge/common/formats/format_transfers/datatype_transfer.h @@ -27,7 +27,6 @@ namespace ge { namespace formats { - struct CastArgs { const uint8_t *data; size_t src_data_size; diff --git a/src/ge/common/formats/format_transfers/format_transfer_dhwcn_fracz3D.cc b/src/ge/common/formats/format_transfers/format_transfer_dhwcn_fracz3D.cc index dc8e1033..76d8696a 100644 --- a/src/ge/common/formats/format_transfers/format_transfer_dhwcn_fracz3D.cc +++ b/src/ge/common/formats/format_transfers/format_transfer_dhwcn_fracz3D.cc @@ -179,6 +179,5 @@ Status FormatTransferDhwcnFractalZ3D::TransShape(Format src_format, const std::v } REGISTER_FORMAT_TRANSFER(FormatTransferDhwcnFractalZ3D, FORMAT_DHWCN, FORMAT_FRACTAL_Z_3D) - } // namespace formats } // namespace ge diff --git a/src/ge/common/formats/format_transfers/format_transfer_dhwnc_fracz3D_transpose.cc b/src/ge/common/formats/format_transfers/format_transfer_dhwnc_fracz3D_transpose.cc index 11e3d270..9de2e3a0 100644 --- a/src/ge/common/formats/format_transfers/format_transfer_dhwnc_fracz3D_transpose.cc +++ b/src/ge/common/formats/format_transfers/format_transfer_dhwnc_fracz3D_transpose.cc @@ -180,6 +180,5 @@ Status FormatTransferDhwncFractalZ3DTranspose::TransShape(Format src_format, con } REGISTER_FORMAT_TRANSFER(FormatTransferDhwncFractalZ3DTranspose, FORMAT_DHWNC, FORMAT_FRACTAL_Z_3D_TRANSPOSE) - } // namespace formats } // namespace ge diff --git a/src/ge/common/formats/format_transfers/format_transfer_fractal_nz.cc b/src/ge/common/formats/format_transfers/format_transfer_fractal_nz.cc index ff7b84a4..65798f29 100644 --- a/src/ge/common/formats/format_transfers/format_transfer_fractal_nz.cc +++ b/src/ge/common/formats/format_transfers/format_transfer_fractal_nz.cc @@ -56,7 +56,7 @@ Status TransShapeToFracNz(const ShapeVector &src_shape, DataType data_type, Shap dst_shape.clear(); hw_shape.clear(); auto w0 = GetCubeSizeByDataType(data_type); - auto h0 = GetCubeSizeByDataType(data_type); + int64_t h0 = kCubeSize; switch (src_shape.size()) { case 1: dst_shape.push_back(Ceil(src_shape[0], w0)); diff --git a/src/ge/common/formats/format_transfers/format_transfer_fractal_z.cc b/src/ge/common/formats/format_transfers/format_transfer_fractal_z.cc index f3d06496..f2ec29da 100644 --- a/src/ge/common/formats/format_transfers/format_transfer_fractal_z.cc +++ b/src/ge/common/formats/format_transfers/format_transfer_fractal_z.cc @@ -19,6 +19,7 @@ #include #include +#include "common/debug/log.h" #include "common/formats/utils/formats_definitions.h" #include "common/formats/utils/formats_trans_utils.h" #include "framework/common/debug/ge_log.h" @@ -107,8 +108,8 @@ Status TransFormatFromNchwToFz(const TransArgs &args, TransResult &result) { int64_t hw = h * w; int64_t chw = c * hw; - int64_t hwc0 = hw * c0; int64_t nchw = n * chw; + int64_t hwc0 = hw * c0; // horizontal fractal matrix count (N) int64_t hf_cnt = Ceil(n, static_cast(kNiSize)); @@ -119,18 +120,15 @@ Status TransFormatFromNchwToFz(const TransArgs &args, TransResult &result) { int64_t total_ele_cnt = hf_cnt * vf_cnt * fractal_ele_cnt; int size = GetSizeByDataType(args.src_data_type); int64_t dst_size = total_ele_cnt * size; - if (dst_size == 0) { - result.length = static_cast(dst_size); - return SUCCESS; - } + GE_CHK_BOOL_EXEC_NOLOG(dst_size != 0, result.length = static_cast(dst_size); return SUCCESS;); std::shared_ptr dst(new (std::nothrow) uint8_t[dst_size], std::default_delete()); - if (dst == nullptr) { + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + dst == nullptr, GELOGE(OUT_OF_MEMORY, "Failed to trans format from %s to %s, can not alloc the memory for dst buf %ld", TypeUtils::FormatToSerialString(args.src_format).c_str(), TypeUtils::FormatToSerialString(args.dst_format).c_str(), dst_size); - return OUT_OF_MEMORY; - } + return OUT_OF_MEMORY;); for (int64_t vfi = 0; vfi < vf_cnt; vfi++) { // vertical fractal matrix base index @@ -156,12 +154,20 @@ Status TransFormatFromNchwToFz(const TransArgs &args, TransResult &result) { auto protected_size = dst_size - offset < static_cast(SECUREC_MEM_MAX_LEN) ? dst_size - offset : static_cast(SECUREC_MEM_MAX_LEN); - errno_t ret; + errno_t ret = EOK; if (need_pad_zero) { ret = memset_s(dst.get() + offset, static_cast(protected_size), 0, static_cast(size)); } else { - ret = memcpy_s(dst.get() + offset, static_cast(protected_size), args.data + src_offset * size, - static_cast(size)); + if (protected_size < size) { + GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory, protected_size is %ld and size is %ld", + protected_size, size); + return INTERNAL_ERROR; + } + char *dst_data = reinterpret_cast(dst.get() + offset); + const char *src_data = reinterpret_cast(args.data + src_offset * size); + for (int64_t index = 0; index < size; index++) { + *dst_data++ = *src_data++; + } } if (ret != EOK) { GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory at offset %ld, error-code %d pad mode %d", offset, @@ -199,18 +205,15 @@ Status TransFormatHwcnToFz(const TransArgs &args, TransResult &result) { dst_size *= dim; } dst_size *= data_size; - if (dst_size == 0) { - result.length = static_cast(dst_size); - return SUCCESS; - } + GE_CHK_BOOL_EXEC_NOLOG(dst_size != 0, result.length = static_cast(dst_size); return SUCCESS;); std::shared_ptr dst(new (std::nothrow) uint8_t[dst_size], std::default_delete()); - if (dst == nullptr) { + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + dst == nullptr, GELOGE(OUT_OF_MEMORY, "Failed to trans format from %s to %s, can not alloc the memory for dst buf %ld", TypeUtils::FormatToSerialString(args.src_format).c_str(), TypeUtils::FormatToSerialString(args.dst_format).c_str(), dst_size); - return OUT_OF_MEMORY; - } + return OUT_OF_MEMORY;); for (int64_t c1i = 0; c1i < c1; c1i++) { for (int64_t hi = 0; hi < h; hi++) { @@ -223,14 +226,22 @@ Status TransFormatHwcnToFz(const TransArgs &args, TransResult &result) { ? dst_size - dst_offset : static_cast(SECUREC_MEM_MAX_LEN); auto pad_zero = ((c1i * c0 + c0i) >= c) || (n1n0i >= n); - errno_t ret; + errno_t ret = EOK; if (pad_zero) { ret = memset_s(dst.get() + dst_offset, static_cast(protected_size), 0, static_cast(data_size)); } else { + if (protected_size < data_size) { + GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory, protected_size is %ld and size is %ld", + protected_size, data_size); + return INTERNAL_ERROR; + } int64_t src_idx = hi * wcn + wi * cn + (c1i * c0 + c0i) * n + n1n0i; - ret = memcpy_s(dst.get() + dst_offset, static_cast(protected_size), - args.data + src_idx * data_size, static_cast(data_size)); + char *dst_data = reinterpret_cast(dst.get() + dst_offset); + const char *src_data = reinterpret_cast(args.data + src_idx * data_size); + for (int64_t index = 0; index < data_size; index++) { + *dst_data++ = *src_data++; + } } if (ret != EOK) { GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory at offset %ld, error-code %d, pad mode %d", @@ -269,18 +280,15 @@ Status TransFormatNhwcToFz(const TransArgs &args, TransResult &result) { dst_size *= dim; } dst_size *= data_size; - if (dst_size == 0) { - result.length = static_cast(dst_size); - return SUCCESS; - } + GE_CHK_BOOL_EXEC_NOLOG(dst_size != 0, result.length = static_cast(dst_size); return SUCCESS;); std::shared_ptr dst(new (std::nothrow) uint8_t[dst_size], std::default_delete()); - if (dst == nullptr) { + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + dst == nullptr, GELOGE(OUT_OF_MEMORY, "Failed to trans format from %s to %s, can not alloc the memory for dst buf %ld", TypeUtils::FormatToSerialString(args.src_format).c_str(), TypeUtils::FormatToSerialString(args.dst_format).c_str(), dst_size); - return OUT_OF_MEMORY; - } + return OUT_OF_MEMORY;); for (int64_t c1i = 0; c1i < c1; c1i++) { for (int64_t hi = 0; hi < h; hi++) { @@ -293,14 +301,22 @@ Status TransFormatNhwcToFz(const TransArgs &args, TransResult &result) { ? dst_size - dst_offset : static_cast(SECUREC_MEM_MAX_LEN); auto pad_zero = ((c1i * c0 + c0i) >= c) || (n1n0i >= n); - errno_t ret; + errno_t ret = EOK; if (pad_zero) { ret = memset_s(dst.get() + dst_offset, static_cast(protected_size), 0, static_cast(data_size)); } else { + if (protected_size < data_size) { + GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory, protected_size is %ld and size is %ld", + protected_size, data_size); + return INTERNAL_ERROR; + } int64_t src_idx = n1n0i * hwc + hi * wc + wi * c + (c1i * c0 + c0i); - ret = memcpy_s(dst.get() + dst_offset, static_cast(protected_size), - args.data + src_idx * data_size, static_cast(data_size)); + char *dst_data = reinterpret_cast(dst.get() + dst_offset); + const char *src_data = reinterpret_cast(args.data + src_idx * data_size); + for (int64_t index = 0; index < data_size; index++) { + *dst_data++ = *src_data++; + } } if (ret != EOK) { GELOGE(INTERNAL_ERROR, "Failed to operate the dst memory at offset %ld, error-code %d, pad mode %d", @@ -337,16 +353,16 @@ Status FormatTransferFractalZ::TransFormat(const TransArgs &args, TransResult &r return PARAM_INVALID; } - if (args.src_format == FORMAT_NCHW && args.dst_format == FORMAT_FRACTAL_Z) { - return TransFormatFromNchwToFz(args, result); + if (args.src_format == FORMAT_NHWC && args.dst_format == FORMAT_FRACTAL_Z) { + return TransFormatNhwcToFz(args, result); } if (args.src_format == FORMAT_HWCN && args.dst_format == FORMAT_FRACTAL_Z) { return TransFormatHwcnToFz(args, result); } - if (args.src_format == FORMAT_NHWC && args.dst_format == FORMAT_FRACTAL_Z) { - return TransFormatNhwcToFz(args, result); + if (args.src_format == FORMAT_NCHW && args.dst_format == FORMAT_FRACTAL_Z) { + return TransFormatFromNchwToFz(args, result); } return UNSUPPORTED; @@ -358,14 +374,14 @@ Status FormatTransferFractalZ::TransShape(Format src_format, const std::vector 0 ? SUCCESS : UNSUPPORTED; } @@ -109,7 +108,7 @@ Status TransFormatFromNchwToFzC04(const TransArgs &args, TransResult &result) { return NOT_CHANGED; } - /* prepare for padding in chw*/ + // prepare for padding in chw int64_t tmp = h * w * c; int64_t n_o = Ceil(n, static_cast(c0)); int64_t c_o = c0; @@ -309,6 +308,5 @@ Status FormatTransferNchwToFZC04::TransShape(Format src_format, const std::vecto } REGISTER_FORMAT_TRANSFER(FormatTransferNchwToFZC04, FORMAT_NCHW, FORMAT_FRACTAL_Z_C04) - } // namespace formats } // namespace ge diff --git a/src/ge/common/formats/utils/formats_definitions.h b/src/ge/common/formats/utils/formats_definitions.h index d889c33c..2faa60e1 100644 --- a/src/ge/common/formats/utils/formats_definitions.h +++ b/src/ge/common/formats/utils/formats_definitions.h @@ -19,7 +19,6 @@ namespace ge { namespace formats { - static const int kCubeSize = 16; static const int kNiSize = 16; static const int64_t kShapeItemNumMAX = 1024UL * 1024UL * 1024UL * 1024UL; @@ -47,7 +46,6 @@ enum FracZDimIndex { kFracZHWC1, kFracZN0, kFracZNi, kFracZC0, kFracZDimsNum }; enum DhwcnDimIndex { kDhwcnD, kDhwcnH, kDhwcnW, kDhwcnC, kDhwcnN, kDhwcnDimsNum }; enum DhwncDimIndex { kDhwncD, kDhwncH, kDhwncW, kDhwncN, kDhwncC, kDhwncDimsNum }; - } // namespace formats } // namespace ge #endif // GE_COMMON_FORMATS_UTILS_FORMATS_DEFINITIONS_H_ diff --git a/src/ge/common/formats/utils/formats_trans_utils.h b/src/ge/common/formats/utils/formats_trans_utils.h index a8fbd09b..8b6f0604 100644 --- a/src/ge/common/formats/utils/formats_trans_utils.h +++ b/src/ge/common/formats/utils/formats_trans_utils.h @@ -21,7 +21,6 @@ #include #include #include - #include "external/graph/types.h" #include "graph/ge_tensor.h" @@ -69,7 +68,6 @@ T Ceil(T n1, T n2) { } return (n2 != 0) ? (n1 - 1) / n2 + 1 : 0; } - } // namespace formats } // namespace ge #endif // GE_COMMON_FORMATS_UTILS_FORMATS_TRANS_UTILS_H_ diff --git a/src/ge/common/fp16_t.h b/src/ge/common/fp16_t.h index 34908b95..0fda2cd2 100644 --- a/src/ge/common/fp16_t.h +++ b/src/ge/common/fp16_t.h @@ -600,5 +600,5 @@ int16_t GetManBitLength(T man) { } return len; } -}; // namespace ge +} // namespace ge #endif // GE_COMMON_FP16_T_H_ diff --git a/src/ge/common/ge/op_tiling_manager.cc b/src/ge/common/ge/op_tiling_manager.cc new file mode 100644 index 00000000..7fb7a8fc --- /dev/null +++ b/src/ge/common/ge/op_tiling_manager.cc @@ -0,0 +1,81 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "common/ge/op_tiling_manager.h" +#include "framework/common/debug/log.h" +#include + +namespace { +const char *const kEnvName = "ASCEND_OPP_PATH"; +const std::string kDefaultPath = "/usr/local/Ascend/opp"; +const std::string kDefaultBuiltInTilingPath = "/op_impl/built-in/liboptiling.so"; +const std::string kDefaultCustomTilingPath = "/op_impl/custom/liboptiling.so"; +const uint8_t kPrefixIndex = 9; +} // namespace + +namespace ge { +void OpTilingManager::ClearHandles() noexcept { + for (const auto &handle : handles_) { + if (dlclose(handle.second) != 0) { + GELOGE(FAILED, "Failed to close handle of %s: %s", handle.first.c_str(), dlerror()); + } + } + handles_.clear(); +} + +OpTilingManager::~OpTilingManager() { ClearHandles(); } + +std::string OpTilingManager::GetPath() { + const char *opp_path_env = std::getenv(kEnvName); + std::string opp_path = kDefaultPath; + if (opp_path_env != nullptr) { + char resolved_path[PATH_MAX]; + if (realpath(opp_path_env, resolved_path) == NULL) { + GELOGE(PARAM_INVALID, "Failed load tiling lib as env 'ASCEND_OPP_PATH'(%s) is invalid path.", opp_path_env); + return std::string(); + } + opp_path = resolved_path; + } + return opp_path; +} + +void OpTilingManager::LoadSo() { + std::string opp_path = GetPath(); + if (opp_path.empty()) { + GELOGW("Skip load tiling lib."); + return; + } + std::string built_in_tiling_lib = opp_path + kDefaultBuiltInTilingPath; + std::string custom_tiling_lib = opp_path + kDefaultCustomTilingPath; + std::string built_in_name = kDefaultBuiltInTilingPath.substr(kPrefixIndex); + std::string custom_name = kDefaultCustomTilingPath.substr(kPrefixIndex); + + void *handle_bi = dlopen(built_in_tiling_lib.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (handle_bi == nullptr) { + GELOGW("Failed to dlopen %s!", dlerror()); + } else { + handles_[built_in_name] = handle_bi; + } + + void *handle_ct = dlopen(custom_tiling_lib.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (handle_ct == nullptr) { + GELOGW("Failed to dlopen %s!", dlerror()); + } else { + handles_[custom_name] = handle_ct; + } +} + +} // namespace ge diff --git a/src/ge/common/ge/op_tiling_manager.h b/src/ge/common/ge/op_tiling_manager.h new file mode 100644 index 00000000..320e1411 --- /dev/null +++ b/src/ge/common/ge/op_tiling_manager.h @@ -0,0 +1,38 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_COMMON_GE_OP_TILING_MANAGER_H_ +#define GE_COMMON_GE_OP_TILING_MANAGER_H_ + +#include + +namespace ge { +using SoToHandleMap = std::map; + +class OpTilingManager { + public: + OpTilingManager() = default; + ~OpTilingManager(); + void LoadSo(); + + private: + static std::string GetPath(); + void ClearHandles() noexcept; + SoToHandleMap handles_; +}; +} // namespace ge + +#endif // GE_COMMON_GE_OP_TILING_MANAGER_H_ diff --git a/src/ge/common/ge/tbe_plugin_manager.cc b/src/ge/common/ge/tbe_plugin_manager.cc index e02b9422..d651ced1 100644 --- a/src/ge/common/ge/tbe_plugin_manager.cc +++ b/src/ge/common/ge/tbe_plugin_manager.cc @@ -182,7 +182,7 @@ void TBEPluginManager::GetCustomOpPath(std::string &customop_path) { } void TBEPluginManager::LoadCustomOpLib() { - LoadPluginSo(); + LoadPluginSo(options_); std::vector registration_datas = domi::OpRegistry::Instance()->registrationDatas; GELOGI("The size of registration_datas is: %zu", registration_datas.size()); @@ -193,10 +193,13 @@ void TBEPluginManager::LoadCustomOpLib() { } } -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void TBEPluginManager::LoadPluginSo() { +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void TBEPluginManager::LoadPluginSo( + const std::map &options) { vector file_list; string caffe_parser_path; std::string plugin_path; + + options_ = options; GetCustomOpPath(plugin_path); // Whether there are files in the plugin so path diff --git a/src/ge/common/ge/tbe_plugin_manager.h b/src/ge/common/ge/tbe_plugin_manager.h index 82264ae8..2a55e450 100644 --- a/src/ge/common/ge/tbe_plugin_manager.h +++ b/src/ge/common/ge/tbe_plugin_manager.h @@ -48,7 +48,7 @@ class TBEPluginManager { static void InitPreparation(const std::map &options); - void LoadPluginSo(); + void LoadPluginSo(const std::map &options); private: TBEPluginManager() = default; diff --git a/src/ge/common/ge_common.mk b/src/ge/common/ge_common.mk index e913c8f5..e99ff654 100644 --- a/src/ge/common/ge_common.mk +++ b/src/ge/common/ge_common.mk @@ -36,6 +36,7 @@ GE_COMMON_LOCAL_SRC_FILES := \ properties_manager.cc \ types.cc\ model_parser/base.cc \ + model_parser/graph_parser_util.cc \ tbe_kernel_store.cc \ op/attr_value_util.cc \ op/ge_op_utils.cc \ diff --git a/src/ge/common/helper/model_helper.cc b/src/ge/common/helper/model_helper.cc index 2f95cbb1..19614566 100644 --- a/src/ge/common/helper/model_helper.cc +++ b/src/ge/common/helper/model_helper.cc @@ -17,6 +17,7 @@ #include "framework/common/helper/model_helper.h" #include "common/ge/ge_util.h" +#include "common/util/error_manager/error_manager.h" #include "framework/common/debug/log.h" #include "framework/common/util.h" #include "framework/common/debug/ge_log.h" @@ -89,10 +90,12 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelHelper::SaveToOmMod } } auto ge_model_weight = ge_model->GetWeight(); - GELOGI("WEIGHTS_DATA size is %zu , %p", ge_model_weight.GetSize(), ge_model_weight.GetData()); - if (SaveModelPartition(om_file_save_helper, ModelPartitionType::WEIGHTS_DATA, ge_model_weight.GetData(), - ge_model_weight.GetSize()) != SUCCESS) { - GELOGW("Add weight partition failed"); // weight is not necessary + GELOGI("WEIGHTS_DATA size is %zu, %p", ge_model_weight.GetSize(), ge_model_weight.GetData()); + // weight is not necessary + if (ge_model_weight.GetSize() > 0) { + GE_CHK_STATUS_RET(SaveModelPartition(om_file_save_helper, ModelPartitionType::WEIGHTS_DATA, + ge_model_weight.GetData(), ge_model_weight.GetSize()), + "Add weight partition failed"); } TBEKernelStore tbe_kernel_store = ge_model->GetTBEKernelStore(); @@ -238,44 +241,48 @@ ModelHelper::SaveOriginalGraphToOmModel(const ge::Graph &graph, const std::strin FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelHelper::LoadModel(const ge::ModelData &model_data) { if (model_data.model_data == nullptr || model_data.model_len == 0) { - GELOGE(FAILED, "Model_data is nullptr, or model_data_size is 0"); - return FAILED; + GELOGE(GE_EXEC_MODEL_DATA_SIZE_INVALID, "Model_data is nullptr, or model_data_size is 0"); + return GE_EXEC_MODEL_DATA_SIZE_INVALID; } if (is_assign_model_) { - GELOGE(FAILED, "Model helper has already loaded!"); - return FAILED; + GELOGE(GE_EXEC_LOAD_MODEL_REPEATED, "Model helper has already loaded!"); + return GE_EXEC_LOAD_MODEL_REPEATED; } if (ReleaseLocalModelData() != SUCCESS) { - GELOGE(FAILED, "ReleaseLocalModelData failed."); - return FAILED; + GELOGE(INTERNAL_ERROR, "ReleaseLocalModelData failed."); + return INTERNAL_ERROR; } + Status status = ge::DavinciModelParser::ParseModelContent(model_data, model_addr_tmp_, model_len_tmp_); if (ge::DavinciModelParser::ParseModelContent(model_data, model_addr_tmp_, model_len_tmp_) != SUCCESS) { - GELOGE(FAILED, "Parse model content failed!"); - return FAILED; + GELOGE(status, "Parse model content failed!"); + return status; } file_header_ = reinterpret_cast(model_data.model_data); OmFileLoadHelper om_load_helper; - if (om_load_helper.Init(model_addr_tmp_, model_len_tmp_) != SUCCESS) { - GELOGE(FAILED, "Om_load_helper init failed"); + status = om_load_helper.Init(model_addr_tmp_, model_len_tmp_); + if (status != SUCCESS) { + GELOGE(status, "Om_load_helper init failed"); model_addr_tmp_ = nullptr; - return FAILED; + return status; } auto partition_table = reinterpret_cast(model_addr_tmp_); if (partition_table->num == kOriginalOmPartitionNum) { - GELOGE(FAILED, "om model is error,please use executable om model"); - return FAILED; + model_addr_tmp_ = nullptr; + GELOGE(GE_EXEC_MODEL_PARTITION_NUM_INVALID, "om model is error,please use executable om model"); + return GE_EXEC_MODEL_PARTITION_NUM_INVALID; } // Encrypt model need to del temp model/no encrypt model don't need to del model model_addr_tmp_ = nullptr; - if (GenerateGeModel(om_load_helper) != SUCCESS) { - GELOGE(FAILED, "GenerateGeModel failed"); - return FAILED; + status = GenerateGeModel(om_load_helper); + if (status != SUCCESS) { + GELOGE(status, "GenerateGeModel failed"); + return status; } is_assign_model_ = true; @@ -287,19 +294,19 @@ Status ModelHelper::GenerateGeModel(OmFileLoadHelper &om_load_helper) { GE_CHECK_NOTNULL(model_); Status ret = LoadModelData(om_load_helper); if (ret != SUCCESS) { - return ret; + return GE_EXEC_LOAD_MODEL_PARTITION_FAILED; } ret = LoadWeights(om_load_helper); if (ret != SUCCESS) { - return ret; + return GE_EXEC_LOAD_WEIGHT_PARTITION_FAILED; } ret = LoadTask(om_load_helper); if (ret != SUCCESS) { - return ret; + return GE_EXEC_LOAD_TASK_PARTITION_FAILED; } ret = LoadTBEKernelStore(om_load_helper); if (ret != SUCCESS) { - return ret; + return GE_EXEC_LOAD_KERNEL_PARTITION_FAILED; } return SUCCESS; } @@ -390,107 +397,6 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY GeModelPtr ModelHelper::GetGeMo return out_model; } -// Transit func for model to ge_model. It will be removed when load and build support ge_model in future -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelHelper::TransModelToGeModel(const ModelPtr &model, - GeModelPtr &ge_model) { - if (model == nullptr) { - GELOGE(FAILED, "Model is null"); - return FAILED; - } - ge_model = ge::MakeShared(); - GE_CHECK_NOTNULL(ge_model); - ge_model->SetGraph(model->GetGraph()); - ge_model->SetName(model->GetName()); - ge_model->SetVersion(model->GetVersion()); - ge_model->SetPlatformVersion(model->GetPlatformVersion()); - ge_model->SetAttr(model->MutableAttrMap()); - - // Copy weight info - auto compute_graph = ge::GraphUtils::GetComputeGraph(model->GetGraph()); - // ge::Buffer weight; - ge::Buffer weight; - (void)ge::AttrUtils::GetZeroCopyBytes(compute_graph, ge::ATTR_NAME_WEIGHTS_DATA, weight); - ge_model->SetWeight(weight); - // Copy task info - if (model->HasAttr(MODEL_ATTR_TASKS)) { - ge::Buffer task_buffer; - GE_CHK_BOOL_RET_STATUS(ge::AttrUtils::GetZeroCopyBytes(model, MODEL_ATTR_TASKS, task_buffer), FAILED, - "Get bytes failed."); - - std::shared_ptr task = ge::MakeShared(); - GE_CHECK_NOTNULL(task); - GE_IF_BOOL_EXEC(task_buffer.GetData() == nullptr, GELOGE(FAILED, "Get data fail"); return FAILED); - GE_IF_BOOL_EXEC(task_buffer.GetSize() == 0, GELOGE(FAILED, "Get size fail"); return FAILED); - - GE_CHK_BOOL_EXEC(ReadProtoFromArray(task_buffer.GetData(), static_cast(task_buffer.GetSize()), task.get()), - return INTERNAL_ERROR, "ReadProtoFromArray failed."); - - ge_model->SetModelTaskDef(task); - } - // Copy tbe kernel info - // TBEKernelStore kernel_store; - TBEKernelStore kernel_store; - if (compute_graph != nullptr && compute_graph->GetDirectNodesSize() != 0) { - for (const ge::NodePtr &n : compute_graph->GetDirectNode()) { - auto node_op_desc = n->GetOpDesc(); - GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue); - TBEKernelPtr tbe_kernel = node_op_desc->TryGetExtAttr(ge::OP_EXTATTR_NAME_TBE_KERNEL, TBEKernelPtr()); - GE_IF_BOOL_EXEC(tbe_kernel == nullptr, continue); - kernel_store.AddTBEKernel(tbe_kernel); - GELOGI("Add tbe kernel bin %s", tbe_kernel->GetName().c_str()); - } - } - if (!kernel_store.Build()) { - GELOGE(FAILED, "TBE Kernels store build failed!"); - return FAILED; - } - ge_model->SetTBEKernelStore(kernel_store); - - return SUCCESS; -} - -// trasit func for ge_model to Model. will be removed when load and build support ge_model in future -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelHelper::TransGeModelToModel(const GeModelPtr &ge_model, - ModelPtr &model) { - if (ge_model == nullptr) { - GELOGE(FAILED, "Ge_model is null"); - return FAILED; - } - model = ge::MakeShared(); - GE_CHECK_NOTNULL(model); - model->SetGraph(ge_model->GetGraph()); - model->SetName(ge_model->GetName()); - model->SetVersion(ge_model->GetVersion()); - model->SetPlatformVersion(ge_model->GetPlatformVersion()); - model->SetAttr(ge_model->MutableAttrMap()); - // Copy weight info - auto compute_graph = ge::GraphUtils::GetComputeGraph(model->GetGraph()); - bool ret = ge::AttrUtils::SetZeroCopyBytes(compute_graph, ge::ATTR_NAME_WEIGHTS_DATA, ge_model->GetWeight()); - if (!ret) { - GELOGE(FAILED, "Copy weight buffer failed!"); - return FAILED; - } - // Copy task info - std::shared_ptr model_task = ge_model->GetModelTaskDefPtr(); - - if (model_task != nullptr) { - int size = model_task->ByteSize(); - ge::Buffer buffer(static_cast(size)); - if (buffer.GetSize() == 0) { - GELOGE(MEMALLOC_FAILED, "alloc model attr task buffer failed!"); - return MEMALLOC_FAILED; - } - // no need to check value - (void)model_task->SerializePartialToArray(buffer.GetData(), size); - ret = ge::AttrUtils::SetZeroCopyBytes(model, MODEL_ATTR_TASKS, std::move(buffer)); - if (!ret) { - GELOGE(FAILED, "Copy task buffer failed!"); - return FAILED; - } - } - return SUCCESS; -} - Status ModelHelper::ReleaseLocalModelData() noexcept { Status result = SUCCESS; if (model_addr_tmp_ != nullptr) { diff --git a/src/ge/common/helper/om_file_helper.cc b/src/ge/common/helper/om_file_helper.cc index 0d58fe71..f25e2af3 100644 --- a/src/ge/common/helper/om_file_helper.cc +++ b/src/ge/common/helper/om_file_helper.cc @@ -41,8 +41,9 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status OmFileLoadHelper::Init(c FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status OmFileLoadHelper::Init(uint8_t *model_data, const uint32_t model_data_size) { - if (LoadModelPartitionTable(model_data, model_data_size) != SUCCESS) { - return FAILED; + Status status = LoadModelPartitionTable(model_data, model_data_size); + if (status != SUCCESS) { + return status; } is_inited_ = true; return SUCCESS; @@ -66,7 +67,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status OmFileLoadHelper::GetMod } if (!found) { - if (type != ModelPartitionType::TBE_KERNELS) { + if (type != ModelPartitionType::TBE_KERNELS && type != ModelPartitionType::WEIGHTS_DATA) { GELOGE(FAILED, "GetModelPartition:type:%d is not in partition_datas!", static_cast(type)); return FAILED; } @@ -83,7 +84,9 @@ Status OmFileLoadHelper::CheckModelValid(const ge::ModelData &model) const { // Model length too small if (model.model_len < (sizeof(ModelFileHeader) + sizeof(ModelPartitionTable))) { - GELOGE(PARAM_INVALID, "Invalid model. length < sizeof(ModelFileHeader) + sizeof(ModelPartitionTable)."); + GELOGE(PARAM_INVALID, + "Invalid model. length[%u] < sizeof(ModelFileHeader)[%zu] + sizeof(ModelPartitionTable)[%zu].", + model.model_len, sizeof(ModelFileHeader), sizeof(ModelPartitionTable)); return PARAM_INVALID; } @@ -93,9 +96,9 @@ Status OmFileLoadHelper::CheckModelValid(const ge::ModelData &model) const { if ((model_header->length != model.model_len - sizeof(ModelFileHeader)) || (MODEL_FILE_MAGIC_NUM != model_header->magic)) { GELOGE(PARAM_INVALID, - "Invalid model. file_header->length(%u) + sizeof(ModelFileHeader)(%zu) != model->model_len(%u) || " - "MODEL_FILE_MAGIC_NUM != file_header->magic", - model_header->length, sizeof(ModelFileHeader), model.model_len); + "Invalid model. file_header->length[%u] + sizeof(ModelFileHeader)[%zu] != model->model_len[%u] || " + "MODEL_FILE_MAGIC_NUM[%u] != file_header->magic[%u]", + model_header->length, sizeof(ModelFileHeader), model.model_len, MODEL_FILE_MAGIC_NUM, model_header->magic); return PARAM_INVALID; } return SUCCESS; @@ -112,16 +115,16 @@ Status OmFileLoadHelper::LoadModelPartitionTable(uint8_t *model_data, const uint // Original model partition include graph-info if ((partition_table->num != PARTITION_SIZE) && (partition_table->num != (PARTITION_SIZE - 1)) && (partition_table->num != 1)) { - GELOGE(PARAM_INVALID, "Invalid partition_table->num:%u", partition_table->num); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_PARTITION_NUM_INVALID, "Invalid partition_table->num:%u", partition_table->num); + return GE_EXEC_MODEL_PARTITION_NUM_INVALID; } size_t mem_offset = SIZE_OF_MODEL_PARTITION_TABLE(*partition_table); GELOGI("ModelPartitionTable num :%u, ModelFileHeader length :%zu, ModelPartitionTable length :%zu", partition_table->num, sizeof(ModelFileHeader), mem_offset); if (model_data_size <= mem_offset) { - GELOGE(PARAM_INVALID, "invalid model data, partition_table->num:%u, model data size %u", partition_table->num, - model_data_size); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_DATA_SIZE_INVALID, "invalid model data, partition_table->num:%u, model data size %u", + partition_table->num, model_data_size); + return GE_EXEC_MODEL_DATA_SIZE_INVALID; } for (uint32_t i = 0; i < partition_table->num; i++) { ModelPartition partition; @@ -131,9 +134,9 @@ Status OmFileLoadHelper::LoadModelPartitionTable(uint8_t *model_data, const uint context_.partition_datas_.push_back(partition); if (partition.size > model_data_size || mem_offset > model_data_size - partition.size) { - GELOGE(PARAM_INVALID, "The partition size %zu is greater than the model data size %u.", + GELOGE(GE_EXEC_MODEL_DATA_SIZE_INVALID, "The partition size %zu is greater than the model data size %u.", partition.size + mem_offset, model_data_size); - return PARAM_INVALID; + return GE_EXEC_MODEL_DATA_SIZE_INVALID; } mem_offset += partition.size; GELOGI("Partition, type:%d, size:%u", static_cast(partition.type), partition.size); diff --git a/src/ge/common/math/fp16_math.h b/src/ge/common/math/fp16_math.h index 5bc9ac6d..c3a4eb28 100644 --- a/src/ge/common/math/fp16_math.h +++ b/src/ge/common/math/fp16_math.h @@ -92,5 +92,5 @@ fp16_t max(fp16_t fp1, fp16_t fp2); /// @brief Calculate the minimum fp16_t of fp1 and fp2 /// @return Returns minimum fp16_t of fp1 and fp2 fp16_t min(fp16_t fp1, fp16_t fp2); -}; // namespace ge +} // namespace ge #endif // GE_COMMON_MATH_FP16_MATH_H_ \ No newline at end of file diff --git a/src/ge/common/math_util.h b/src/ge/common/math_util.h index 5e783e81..a12be9e0 100644 --- a/src/ge/common/math_util.h +++ b/src/ge/common/math_util.h @@ -27,7 +27,6 @@ #include "mmpa/mmpa_api.h" namespace ge { - /** * @ingroup domi_calibration * @brief Initializes an input array to a specified value @@ -67,7 +66,6 @@ Status NnSet(const int32_t n, const Dtype alpha, Dtype *output) { } return SUCCESS; } - } // end namespace ge #endif // GE_COMMON_MATH_UTIL_H_ diff --git a/src/ge/common/model_parser/base.cc b/src/ge/common/model_parser/base.cc index fb6a647f..3b6b9407 100644 --- a/src/ge/common/model_parser/base.cc +++ b/src/ge/common/model_parser/base.cc @@ -35,15 +35,16 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelParserBase::LoadFro ge::ModelData &model_data) { std::string real_path = RealPath(model_path); if (real_path.empty()) { - GELOGE(PARAM_INVALID, "Model file path '%s' is invalid", model_path); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_PATH_INVALID, "Model file path '%s' is invalid", model_path); + return GE_EXEC_MODEL_PATH_INVALID; } - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(GetFileLength(model_path) == -1, return FAILED, "File size not valid."); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(GetFileLength(model_path) == -1, return GE_EXEC_READ_MODEL_FILE_FAILED, + "File size not valid."); std::ifstream fs(real_path.c_str(), std::ifstream::binary); - GE_CHK_BOOL_RET_STATUS(fs.is_open(), FAILED, "Open file failed! path:%s", model_path); + GE_CHK_BOOL_RET_STATUS(fs.is_open(), GE_EXEC_READ_MODEL_FILE_FAILED, "Open file failed! path:%s", model_path); // get length of file: (void)fs.seekg(0, std::ifstream::end); @@ -55,7 +56,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelParserBase::LoadFro char *data = new (std::nothrow) char[len]; if (data == nullptr) { - GELOGE(MEMALLOC_FAILED, "Load model From file failed, bad memory allocation occur. (need:%ld)", len); + GELOGE(MEMALLOC_FAILED, "Load model From file failed, bad memory allocation occur. (need:%u)", len); return MEMALLOC_FAILED; } @@ -79,31 +80,33 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelParserBase::ParseMo GE_CHECK_NOTNULL(model.model_data); // Model length too small - GE_CHK_BOOL_RET_STATUS(model.model_len >= sizeof(ModelFileHeader), PARAM_INVALID, - "Invalid model. length < sizeof(ModelFileHeader)."); + GE_CHK_BOOL_RET_STATUS(model.model_len >= sizeof(ModelFileHeader), GE_EXEC_MODEL_DATA_SIZE_INVALID, + "Invalid model. Model data size %u must be greater than or equal to %zu.", model.model_len, + sizeof(ModelFileHeader)); // Get file header auto file_header = reinterpret_cast(model.model_data); // Determine whether the file length and magic number match GE_CHK_BOOL_RET_STATUS( file_header->length == model.model_len - sizeof(ModelFileHeader) && file_header->magic == MODEL_FILE_MAGIC_NUM, - PARAM_INVALID, - "Invalid model. file_header->length + sizeof(ModelFileHeader) != model->model_len || MODEL_FILE_MAGIC_NUM != " - "file_header->magic"); + GE_EXEC_MODEL_DATA_SIZE_INVALID, + "Invalid model. file_header->length[%u] + sizeof(ModelFileHeader)[%zu] != model->model_len[%u] || " + "MODEL_FILE_MAGIC_NUM[%u] != file_header->magic[%u]", + file_header->length, sizeof(ModelFileHeader), model.model_len, MODEL_FILE_MAGIC_NUM, file_header->magic); Status res = SUCCESS; // Get data address uint8_t *data = reinterpret_cast(model.model_data) + sizeof(ModelFileHeader); if (file_header->is_encrypt == ModelEncryptType::UNENCRYPTED) { // Unencrypted model - GE_CHK_BOOL_RET_STATUS(model.key.empty(), PARAM_INVALID, + GE_CHK_BOOL_RET_STATUS(model.key.empty(), GE_EXEC_MODEL_NOT_SUPPORT_ENCRYPTION, "Invalid param. model is unencrypted, but key is not empty."); model_data = data; model_len = file_header->length; GELOGI("Model_len is %u, model_file_head_len is %zu.", model_len, sizeof(ModelFileHeader)); } else { - GELOGE(PARAM_INVALID, "Invalid model. ModelEncryptType not supported."); - res = PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_NOT_SUPPORT_ENCRYPTION, "Invalid model. ModelEncryptType not supported."); + res = GE_EXEC_MODEL_NOT_SUPPORT_ENCRYPTION; } return res; diff --git a/src/ge/common/model_parser/graph_parser_util.cc b/src/ge/common/model_parser/graph_parser_util.cc new file mode 100644 index 00000000..19f505c1 --- /dev/null +++ b/src/ge/common/model_parser/graph_parser_util.cc @@ -0,0 +1,501 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph_parser_util.h" +#include +#include "common/auth/file_saver.h" +#include "common/convert/pb2json.h" +#include "common/debug/log.h" +#include "common/debug/memory_dumper.h" +#include "common/model_parser/base.h" +#include "common/model_saver.h" +#include "common/properties_manager.h" +#include "common/string_util.h" +#include "common/types.h" +#include "common/util.h" +#include "common/util/error_manager/error_manager.h" +#include "external/register/register_types.h" +#include "framework/common/debug/ge_log.h" +#include "framework/omg/parser/parser_inner_ctx.h" +#include "graph/compute_graph.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/optimize/common/params.h" +#include "graph/utils/type_utils.h" +#include "omg/omg_inner_types.h" +#include "omg/parser/model_parser.h" +#include "omg/parser/parser_factory.h" +#include "omg/parser/weights_parser.h" +#include "parser/common/pre_checker.h" +#include "proto/ge_ir.pb.h" +#include "register/op_registry.h" + +namespace ge { +namespace { +// The function is incomplete. Currently, only l2_optimize, off_optimize is supported. +const char *const kInputShapeSample1 = "\"input_name1:n1,c1,h1,w1\""; +const char *const kInputShapeSample2 = "\"input_name1:1,3,224,224\""; +const char *const kSplitError1 = "size not equal to 2 split by \":\""; +const char *const kEmptyError = "can not be empty"; +const char *const kFloatNumError = "exist float number"; +const char *const kDigitError = "is not digit"; +const char *const kOutputTypeSample = "correct sample is \"opname:index:dtype\""; +const char *const kOutputTypeSupport = "only support FP32, FP16, UINT8"; +const char *const kOutputTypeError = "The multiple out nodes set in output_type must be found in out_nodes."; + +vector SplitInputShape(const std::string &input_shape) { + vector shape_pair_vec; + size_t pos = input_shape.rfind(":"); + if (pos != std::string::npos) { + shape_pair_vec.emplace_back(input_shape.substr(0, pos)); + shape_pair_vec.emplace_back(input_shape.substr(pos + 1, input_shape.size() - pos)); + } + return shape_pair_vec; +} + +static std::map output_type_str_to_datatype = { + {"FP32", ge::DT_FLOAT}, {"FP16", ge::DT_FLOAT16}, {"UINT8", ge::DT_UINT8}}; + +static bool CheckInputTrueOrFalse(const std::string &s, const std::string &atc_param) { + if ((s == "true") || (s == "false")) { + return true; + } else { + ErrorManager::GetInstance().ATCReportErrMessage("E10033", {"parameter", "value"}, {atc_param, s}); + GELOGE(PARAM_INVALID, "Input parameter[--%s]'s value[%s] must be true or false.", atc_param.c_str(), s.c_str()); + return false; + } +} + +bool CheckDigitStr(std::string &str) { + for (char c : str) { + if (!isdigit(c)) { + GELOGE(domi::FAILED, "value[%s] is not positive integer", str.c_str()); + return false; + } + } + return true; +} + +Status StringToInt(std::string &str, int32_t &value) { + try { + if (!CheckDigitStr(str)) { + GELOGE(PARAM_INVALID, "Invalid of digit string: %s ", str.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", str, "is not positive integer"}); + return PARAM_INVALID; + } + value = stoi(str); + } catch (std::invalid_argument &) { + GELOGE(PARAM_INVALID, "Invalid of digit string: %s, catch invalid_argument.", str.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10014", {"parameter", "value"}, {"output_type", str}); + return PARAM_INVALID; + } catch (std::out_of_range &) { + GELOGE(PARAM_INVALID, "Invalid of digit string: %s, catch out_of_range.", str.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10013", {"parameter", "value"}, {"output_type", str}); + return PARAM_INVALID; + } + return SUCCESS; +} + +Status VerifyOutputTypeAndOutNodes(std::vector &out_type_vec) { + std::vector> user_out_nodes = domi::GetContext().user_out_nodes; + std::set out_nodes_info; + for (uint32_t i = 0; i < user_out_nodes.size(); ++i) { + // out_nodes set should include output_type and output_format + std::string tmp = user_out_nodes[i].first + ":" + to_string(user_out_nodes[i].second); + out_nodes_info.emplace(tmp); + } + for (uint32_t i = 0; i < out_type_vec.size(); ++i) { + if (out_nodes_info.find(out_type_vec[i]) == out_nodes_info.end()) { + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", out_type_vec[i], kOutputTypeError}); + GELOGE(domi::FAILED, "Invalid value for --output_type[%s], %s.", out_type_vec[i].c_str(), kOutputTypeError); + return domi::FAILED; + } + } + return domi::SUCCESS; +} + +Status ParseOutputType(const std::string &output_type, std::map> &out_type_index_map, + std::map> &out_type_dt_map) { + if (output_type.find(':') == std::string::npos) { + GELOGI("output_type is not multiple nodes, means all out nodes"); + auto it = output_type_str_to_datatype.find(output_type); + if (it == output_type_str_to_datatype.end()) { + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", output_type, kOutputTypeSupport}); + GELOGE(PARAM_INVALID, "Invalid value for --output_type[%s], %s.", output_type.c_str(), kOutputTypeSupport); + return domi::FAILED; + } + return domi::SUCCESS; + } + std::vector out_type_vec; + vector nodes_v = StringUtils::Split(output_type, ';'); + for (const string &node : nodes_v) { + vector node_index_type_v = StringUtils::Split(node, ':'); + if (node_index_type_v.size() != 3) { // The size must be 3. + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", node, kOutputTypeSample}); + GELOGE(PARAM_INVALID, "Invalid value for --output_type[%s], %s.", node.c_str(), kOutputTypeSample); + return domi::FAILED; + } + ge::DataType tmp_dt; + std::string node_name = StringUtils::Trim(node_index_type_v[0]); + std::string index_str = StringUtils::Trim(node_index_type_v[1]); + int32_t index; + if (StringToInt(index_str, index) != SUCCESS) { + GELOGE(PARAM_INVALID, "This str must be digit string, while the actual input is %s.", index_str.c_str()); + return domi::FAILED; + } + std::string dt_value = StringUtils::Trim(node_index_type_v[2]); + auto it = output_type_str_to_datatype.find(dt_value); + if (it == output_type_str_to_datatype.end()) { + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", dt_value, kOutputTypeSupport}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --output_type[%s], %s.", dt_value.c_str(), kOutputTypeSupport); + return domi::FAILED; + } else { + tmp_dt = it->second; + } + out_type_vec.push_back(node_name + ":" + index_str); + auto it_index = out_type_index_map.find(node_name); + if (it_index == out_type_index_map.end()) { + vector tmp_vec; + tmp_vec.push_back(index); + out_type_index_map.emplace(node_name, tmp_vec); + } else { + it_index->second.push_back(index); + } + + auto it_dt = out_type_dt_map.find(node_name); + if (it_dt == out_type_dt_map.end()) { + vector tmp_vec; + tmp_vec.push_back(tmp_dt); + out_type_dt_map.emplace(node_name, tmp_vec); + } else { + it_dt->second.push_back(tmp_dt); + } + } + return VerifyOutputTypeAndOutNodes(out_type_vec); +} + +Status CheckOutNode(ge::OpDescPtr op_desc, int32_t index) { + int32_t out_size = op_desc->GetOutputsSize(); + if (index < 0 || index >= out_size) { + GELOGE(domi::FAILED, + "out_node [%s] output index:%d must be smaller " + "than node output size:%d and can not be negative!", + op_desc->GetName().c_str(), index, out_size); + std::string fail_reason = "output index:" + to_string(index) + + " must be smaller than output size:" + to_string(out_size) + " and can not be negative!"; + ErrorManager::GetInstance().ATCReportErrMessage("E10003", {"parameter", "value", "reason"}, + {"out_nodes", op_desc->GetName(), fail_reason}); + return domi::FAILED; + } + return domi::SUCCESS; +} + +Status GetOutputLeaf(NodePtr node, std::vector> &output_nodes_info) { + ge::OpDescPtr tmpDescPtr = node->GetOpDesc(); + if (tmpDescPtr == nullptr) { + GELOGE(domi::FAILED, "Get outnode op desc fail."); + return domi::FAILED; + } + size_t size = tmpDescPtr->GetOutputsSize(); + if (node->GetType() != NETOUTPUT) { + for (size_t index = 0; index < size; ++index) { + output_nodes_info.push_back(std::make_pair(node, index)); + } + } else { + const auto in_anchors = node->GetAllInDataAnchors(); + for (auto in_anchor : in_anchors) { + auto out_anchor = in_anchor->GetPeerOutAnchor(); + if (out_anchor == nullptr) { + GELOGE(domi::FAILED, "Get leaf node op desc fail."); + return domi::FAILED; + } + auto out_node = out_anchor->GetOwnerNode(); + output_nodes_info.push_back(std::make_pair(out_node, out_anchor->GetIdx())); + } + } + return SUCCESS; +} + +void GetOutputNodesNameAndIndex(std::vector> &output_nodes_info, + std::vector &output_nodes_name) { + output_nodes_name.clear(); + if (domi::GetContext().out_top_names.empty()) { + // tf process, no top name. + for (const auto output_node_info : output_nodes_info) { + std::string node_name = output_node_info.first->GetName(); + int32_t index = output_node_info.second; + output_nodes_name.push_back(node_name + ":" + std::to_string(index)); + } + return; + } + // caffe process, need add top name after node_name:index + for (size_t i = 0; i < output_nodes_info.size(); ++i) { + std::string node_name = output_nodes_info[i].first->GetName(); + int32_t index = output_nodes_info[i].second; + if (i < domi::GetContext().out_top_names.size()) { + output_nodes_name.push_back(node_name + ":" + std::to_string(index) + ":" + domi::GetContext().out_top_names[i]); + } else { + GELOGW("Get top name of node [%s] fail.", node_name.c_str()); + output_nodes_name.push_back(node_name + ":" + std::to_string(index)); + } + } +} +} // namespace + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ParseOutputFp16NodesFormat(const string &is_output_fp16) { + if (is_output_fp16.empty()) { + return SUCCESS; + } + + vector &output_formats = domi::GetContext().output_formats; + output_formats.clear(); + vector node_format_vec = StringUtils::Split(is_output_fp16, ','); + for (auto &is_fp16 : node_format_vec) { + StringUtils::Trim(is_fp16); + if (!CheckInputTrueOrFalse(is_fp16, "is_output_adjust_hw_layout")) { + GELOGE(PARAM_INVALID, "Invalid Param, is_output_adjust_hw_layout only support true/false: but is [%s]", + is_output_fp16.c_str()); + return PARAM_INVALID; + } + if (is_fp16 == "false") { + output_formats.push_back(DOMI_TENSOR_ND); + } else if (is_fp16 == "true") { + output_formats.push_back(domi::DOMI_TENSOR_NC1HWC0); + } + } + return SUCCESS; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status SetOutputNodeInfo(ge::Graph &graph, + const std::string &output_type, + const std::string &output) { + ge::ComputeGraphPtr compute_graph = ge::GraphUtils::GetComputeGraph(graph); + GE_CHECK_NOTNULL(compute_graph); + + std::vector> user_out_nodes = domi::GetContext().user_out_nodes; + std::vector output_formats = domi::GetContext().output_formats; + std::vector> output_nodes_info; + std::vector output_nodes_name; + std::map> out_type_index_map; + std::map> out_type_dt_map; + if (!output_type.empty()) { + if (ParseOutputType(output_type, out_type_index_map, out_type_dt_map) != SUCCESS) { + GELOGE(domi::FAILED, "Parse output_type failed."); + return domi::FAILED; + } + } + + // User declared outputs + for (uint32_t i = 0; i < user_out_nodes.size(); ++i) { + ge::NodePtr out_node = compute_graph->FindNode(user_out_nodes[i].first); + if (out_node == nullptr) { + GELOGE(domi::FAILED, "Can not find src node (%s) in graph.", user_out_nodes[i].first.c_str()); + return domi::FAILED; + } + auto op_desc = out_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (CheckOutNode(op_desc, user_out_nodes[i].second) != SUCCESS) { + GELOGE(domi::FAILED, "Check out node (%s) fail.", user_out_nodes[i].first.c_str()); + return domi::FAILED; + } + if (i < output_formats.size()) { + if (output_formats[i] == domi::DOMI_TENSOR_NC1HWC0) { + GELOGI("The output node [%s] should be set NC1HWC0", user_out_nodes[i].first.c_str()); + if (!ge::AttrUtils::SetBool(op_desc, "output_set_fp16_nc1hwc0", true)) { + GELOGW("The output node [%s] set NC1HWC0 failed", user_out_nodes[i].first.c_str()); + } + } + } + auto it_index = out_type_index_map.find(user_out_nodes[i].first); + auto it_dt = out_type_dt_map.find(user_out_nodes[i].first); + if ((it_index != out_type_index_map.end()) && (it_dt != out_type_dt_map.end())) { + GELOGI("The output node [%s] need to be set output_type", user_out_nodes[i].first.c_str()); + (void)ge::AttrUtils::SetListDataType(op_desc, "_output_dt_list", it_dt->second); + (void)ge::AttrUtils::SetListInt(op_desc, "_output_dt_index", it_index->second); + } + output_nodes_info.push_back(std::make_pair(out_node, user_out_nodes[i].second)); + } + // default output node (leaf) + if (user_out_nodes.empty()) { + for (ge::NodePtr node : compute_graph->GetDirectNode()) { + if (!node->GetInDataNodes().empty() && node->GetOutDataNodes().empty()) { + Status ret = GetOutputLeaf(node, output_nodes_info); + GE_CHK_BOOL_RET_STATUS(ret == SUCCESS, ret, "find leaf fail."); + } + } + } + GetOutputNodesNameAndIndex(output_nodes_info, output_nodes_name); + compute_graph->SetGraphOutNodesInfo(output_nodes_info); + domi::GetContext().net_out_nodes = output_nodes_name; + return domi::SUCCESS; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool ParseInputShape( + const string &input_shape, unordered_map> &shape_map, + vector>> &user_shape_map, bool is_dynamic_input) { + vector shape_vec = StringUtils::Split(input_shape, ';'); + const int DEFAULT_SHAPE_PAIR_SIZE = 2; + for (const auto &shape : shape_vec) { + vector shape_pair_vec = SplitInputShape(shape); + if (shape_pair_vec.size() != DEFAULT_SHAPE_PAIR_SIZE) { + ErrorManager::GetInstance().ATCReportErrMessage("E10002", {"shape", "reason", "sample"}, + {shape, kSplitError1, kInputShapeSample1}); + GELOGW("Parse input parameter [--input_shape]'s shape[%s] failed, reason: %s, correct sample is %s.", + shape.c_str(), kSplitError1, kInputShapeSample1); + return false; + } + if (shape_pair_vec[1].empty()) { + ErrorManager::GetInstance().ATCReportErrMessage("E10002", {"shape", "reason", "sample"}, + {shape, kEmptyError, kInputShapeSample1}); + GELOGW("Parse input parameter [--input_shape]'s shape[%s] failed, reason: %s, correct sample is %s.", + shape.c_str(), kEmptyError, kInputShapeSample1); + return false; + } + + vector shape_value_strs = StringUtils::Split(shape_pair_vec[1], ','); + vector shape_values; + for (auto &shape_value_str : shape_value_strs) { + // stoul: The method may throw an exception: invalid_argument/out_of_range + if (std::string::npos != shape_value_str.find('.')) { + ErrorManager::GetInstance().ATCReportErrMessage("E10002", {"shape", "reason", "sample"}, + {shape, kFloatNumError, kInputShapeSample2}); + GELOGW("Parse input parameter [--input_shape]'s shape[%s] failed, reason: %s, correct sample is %s.", + shape.c_str(), kFloatNumError, kInputShapeSample2); + return false; + } + + long left_result = 0; + try { + left_result = stol(StringUtils::Trim(shape_value_str)); + if (!shape_value_str.empty() && (shape_value_str.front() == '-')) { + // The value maybe dynamic shape [-1], need substr it and verify isdigit. + shape_value_str = shape_value_str.substr(1); + } + for (char c : shape_value_str) { + if (!isdigit(c)) { + ErrorManager::GetInstance().ATCReportErrMessage("E10002", {"shape", "reason", "sample"}, + {shape, kDigitError, kInputShapeSample2}); + GELOGE(PARAM_INVALID, "--input_shape's shape value[%s] is not digit", shape_value_str.c_str()); + return false; + } + } + } catch (const std::out_of_range &) { + ErrorManager::GetInstance().ATCReportErrMessage("E10013", {"parameter", "value"}, + {"input_shape", shape_value_str}); + GELOGW("Input parameter[--input_shape]’s value[%s] cause out of range execption!", shape_value_str.c_str()); + return false; + } catch (const std::invalid_argument &) { + ErrorManager::GetInstance().ATCReportErrMessage("E10014", {"parameter", "value"}, + {"input_shape", shape_value_str}); + GELOGW("Input parameter[--input_shape]’s value[%s] cause invalid argument!", shape_value_str.c_str()); + return false; + } catch (...) { + ErrorManager::GetInstance().ATCReportErrMessage("E10015", {"parameter", "value"}, + {"input_shape", shape_value_str}); + GELOGW("Input parameter[--input_shape]’s value[%s] cause unkown execption!", shape_value_str.c_str()); + return false; + } + int64_t result = left_result; + // - 1 is not currently supported + if (!is_dynamic_input && result <= 0) { + ErrorManager::GetInstance().ATCReportErrMessage("E10011", {"shape", "result"}, {shape, std::to_string(result)}); + GELOGW( + "Input parameter[--input_shape]’s shape value[%s] is invalid, " + "expect positive integer, but value is %ld.", + shape.c_str(), result); + return false; + } + shape_values.push_back(result); + } + + shape_map.emplace(make_pair(StringUtils::Trim(shape_pair_vec[0]), shape_values)); + user_shape_map.push_back(make_pair(StringUtils::Trim(shape_pair_vec[0]), shape_values)); + } + + return true; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ParseOutputNodes(const string &out_nodes) { + try { + // parse output node + if (!out_nodes.empty()) { + domi::GetContext().out_nodes_map.clear(); + domi::GetContext().user_out_nodes.clear(); + + vector nodes_v = StringUtils::Split(out_nodes, ';'); + for (const string &node : nodes_v) { + vector key_value_v = StringUtils::Split(node, ':'); + if (key_value_v.size() != 2) { // The size must be 2. + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--out_nodes", node, "the correct format is \"node_name1:0;node_name1:1;node_name2:0\""}); + GELOGE(PARAM_INVALID, + "The input format of --out_nodes is invalid, the correct format is " + "\"node_name1:0;node_name1:1;node_name2:0\", while the actual input is %s.", + node.c_str()); + return PARAM_INVALID; + } + auto iter = domi::GetContext().out_nodes_map.find(key_value_v[0]); + // stoi: The method may throw an exception: invalid_argument/out_of_range + if (!CheckDigitStr(key_value_v[1])) { + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--out_nodes", out_nodes, "is not positive integer"}); + GELOGE(PARAM_INVALID, "This str must be digit string, while the actual input is %s", out_nodes.c_str()); + return PARAM_INVALID; + } + int32_t index = stoi(StringUtils::Trim(key_value_v[1])); + if (iter != domi::GetContext().out_nodes_map.end()) { + iter->second.emplace_back(index); + } else { + std::vector index_v; + index_v.emplace_back(index); + domi::GetContext().out_nodes_map.emplace(key_value_v[0], index_v); + } + domi::GetContext().user_out_nodes.push_back(std::make_pair(key_value_v[0], index)); + } + } + } catch (std::invalid_argument &) { + GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", out_nodes.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10014", {"parameter", "value"}, {"out_nodes", out_nodes}); + return PARAM_INVALID; + } catch (std::out_of_range &) { + GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", out_nodes.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10013", {"parameter", "value"}, {"out_nodes", out_nodes}); + return PARAM_INVALID; + } + return SUCCESS; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ParseOpConf(const char *op_conf) { + if (op_conf != nullptr && *op_conf != '\0') { + // divided by ":" + PropertiesManager::Instance().SetPropertyDelimiter(OP_CONF_DELIMITER); + // Parsing the op_conf configuration item file + if (!PropertiesManager::Instance().Init(op_conf)) { + GELOGE(FAILED, "op_name_map init failed!"); + return FAILED; + } + // Return map and put it into ATC global variable + domi::GetContext().op_conf_map = PropertiesManager::Instance().GetPropertyMap(); + } + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/common/model_parser/graph_parser_util.h b/src/ge/common/model_parser/graph_parser_util.h new file mode 100644 index 00000000..b38642c2 --- /dev/null +++ b/src/ge/common/model_parser/graph_parser_util.h @@ -0,0 +1,62 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_COMMON_GRAPH_PARSER_UTIL_H_ +#define GE_COMMON_GRAPH_PARSER_UTIL_H_ + +#include +#include +#include +#include +#include "framework/common/types.h" +#include "framework/omg/omg_inner_types.h" +#include "proto/ge_ir.pb.h" +#include "proto/om.pb.h" + +#include "graph/compute_graph.h" +#include "graph/graph.h" +#include "graph/model.h" +#include "runtime/kernel.h" + +using domi::Status; +using std::pair; +using std::string; +using std::unordered_map; +using std::vector; + +namespace ge { +Status SetOutputNodeInfo(ge::Graph &graph, const std::string &output_type, const std::string &output_format); + +Status ParseOutputFp16NodesFormat(const string &is_output_fp16); + +Status ParseOutputNodes(const string &out_nodes); + +bool ParseInputShape(const string &input_shape, unordered_map> &shape_map, + vector>> &user_shape_map, bool is_dynamic_input); + +Status ParseOpConf(const char *op_conf); +} // namespace ge + +namespace domi { +/** + * @ingroup domi_omg + * @brief get omg context + * @return reference of OmgContext + */ +ge::OmgContext &GetContext(); +} // namespace domi + +#endif // GE_COMMON_GRAPH_PARSER_UTIL_H_ diff --git a/src/ge/common/model_saver.cc b/src/ge/common/model_saver.cc index 11d9e804..821fde60 100644 --- a/src/ge/common/model_saver.cc +++ b/src/ge/common/model_saver.cc @@ -60,8 +60,8 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelSaver::SaveJsonToFi mode_t mode = S_IRUSR | S_IWUSR; int32_t fd = mmOpen2(real_path, O_RDWR | O_CREAT | O_TRUNC, mode); if (fd == EN_ERROR || fd == EN_INVALID_PARAM) { - ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"filepath", "errMsg"}, {file_path, strerror(errno)}); - GELOGE(FAILED, "Open file failed. file path : %s, %s", file_path, strerror(errno)); + ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"file", "errmsg"}, {file_path, strerror(errno)}); + GELOGE(FAILED, "Open file[%s] failed. %s", file_path, strerror(errno)); return FAILED; } const char *model_char = model_str.c_str(); @@ -69,8 +69,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status ModelSaver::SaveJsonToFi // Write data to file mmSsize_t mmpa_ret = mmWrite(fd, const_cast((const void *)model_char), len); if (mmpa_ret == EN_ERROR || mmpa_ret == EN_INVALID_PARAM) { - ErrorManager::GetInstance().ATCReportErrMessage("E19003", {"mmpa_ret", "errMsg"}, - {std::to_string(mmpa_ret), strerror(errno)}); + ErrorManager::GetInstance().ATCReportErrMessage("E19004", {"file", "errmsg"}, {file_path, strerror(errno)}); // Need to both print the error info of mmWrite and mmClose, so return ret after mmClose GELOGE(FAILED, "Write to file failed. errno = %d, %s", mmpa_ret, strerror(errno)); ret = FAILED; diff --git a/src/ge/common/profiling/profiling_manager.cc b/src/ge/common/profiling/profiling_manager.cc index ecbbf5f2..364f8298 100644 --- a/src/ge/common/profiling/profiling_manager.cc +++ b/src/ge/common/profiling/profiling_manager.cc @@ -363,16 +363,17 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void ProfilingManager::Profilin std::string data; for (const auto &task : task_desc_info) { + std::string model_name = task.model_name; std::string op_name = task.op_name; uint32_t block_dim = task.block_dim; uint32_t task_id = task.task_id; uint32_t stream_id = task.stream_id; - data = op_name.append(" ").append(std::to_string(block_dim) - .append(" ") - .append(std::to_string(task_id)) - .append(" ") - .append(std::to_string(stream_id)) - .append("\n")); + data = model_name.append(" ").append(op_name).append(" ").append(std::to_string(block_dim) + .append(" ") + .append(std::to_string(task_id)) + .append(" ") + .append(std::to_string(stream_id)) + .append("\n")); Msprof::Engine::ReporterData reporter_data{}; reporter_data.deviceId = device_id; @@ -403,7 +404,12 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void ProfilingManager::Profilin std::string data; for (const auto &graph : compute_graph_desc_info) { - data.append("op_name:").append(graph.op_name).append(" op_type:").append(graph.op_type); + data.append("model_name:") + .append(graph.model_name) + .append(" op_name:") + .append(graph.op_name) + .append(" op_type:") + .append(graph.op_type); for (size_t i = 0; i < graph.input_format.size(); ++i) { data.append(" input_id:") .append(std::to_string(i)) diff --git a/src/ge/common/properties_manager.cc b/src/ge/common/properties_manager.cc index cf1ada05..0c2b1db6 100644 --- a/src/ge/common/properties_manager.cc +++ b/src/ge/common/properties_manager.cc @@ -20,15 +20,204 @@ #include #include +#include "common/ge/ge_util.h" #include "common/util.h" #include "framework/common/debug/ge_log.h" #include "framework/common/debug/log.h" #include "framework/common/ge_types.h" #include "framework/common/types.h" #include "graph/debug/ge_attr_define.h" +#include "graph/ge_context.h" #include "graph/utils/attr_utils.h" namespace ge { +namespace { +const string kEnableFlag = "1"; + +const uint32_t kAicoreOverflow = (0x1 << 0); +const uint32_t kAtomicOverflow = (0x1 << 1); +const uint32_t kAllOverflow = (kAicoreOverflow | kAtomicOverflow); +} // namespace + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY DumpProperties::DumpProperties(const DumpProperties &other) { + CopyFrom(other); +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY DumpProperties &DumpProperties::operator=( + const DumpProperties &other) { + CopyFrom(other); + return *this; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::InitByOptions() { + enable_dump_.clear(); + enable_dump_debug_.clear(); + dump_path_.clear(); + dump_step_.clear(); + dump_mode_.clear(); + is_op_debug_ = false; + op_debug_mode_ = 0; + + string enable_dump; + (void)GetContext().GetOption(OPTION_EXEC_ENABLE_DUMP, enable_dump); + enable_dump_ = enable_dump; + + string enable_dump_debug; + (void)GetContext().GetOption(OPTION_EXEC_ENABLE_DUMP_DEBUG, enable_dump_debug); + enable_dump_debug_ = enable_dump_debug; + + if ((enable_dump_ == kEnableFlag) || (enable_dump_debug_ == kEnableFlag)) { + string dump_path; + if (GetContext().GetOption(OPTION_EXEC_DUMP_PATH, dump_path) == GRAPH_SUCCESS) { + if (!dump_path.empty() && dump_path[dump_path.size() - 1] != '/') { + dump_path = dump_path + "/"; + } + dump_path = dump_path + CurrentTimeInStr() + "/"; + GELOGI("Get dump path %s successfully", dump_path.c_str()); + SetDumpPath(dump_path); + } else { + GELOGW("DUMP_PATH is not set"); + } + } + + if (enable_dump_ == kEnableFlag) { + string dump_step; + if (GetContext().GetOption(OPTION_EXEC_DUMP_STEP, dump_step) == GRAPH_SUCCESS) { + GELOGD("Get dump step %s successfully", dump_step.c_str()); + SetDumpStep(dump_step); + } + string dump_mode; + if (GetContext().GetOption(OPTION_EXEC_DUMP_MODE, dump_mode) == GRAPH_SUCCESS) { + GELOGD("Get dump mode %s successfully", dump_mode.c_str()); + SetDumpMode(dump_mode); + } + AddPropertyValue(DUMP_ALL_MODEL, {}); + } + + SetDumpDebugOptions(); +} + +// The following is the new dump scenario of the fusion operator +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::AddPropertyValue( + const std::string &model, const std::set &layers) { + for (const std::string &layer : layers) { + GELOGI("This model %s config to dump layer %s", model.c_str(), layer.c_str()); + } + + model_dump_properties_map_[model] = layers; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::DeletePropertyValue(const std::string &model) { + auto iter = model_dump_properties_map_.find(model); + if (iter != model_dump_properties_map_.end()) { + model_dump_properties_map_.erase(iter); + } +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::set DumpProperties::GetAllDumpModel() const { + std::set model_list; + for (auto &iter : model_dump_properties_map_) { + model_list.insert(iter.first); + } + + return model_list; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::set DumpProperties::GetPropertyValue( + const std::string &model) const { + auto iter = model_dump_properties_map_.find(model); + if (iter != model_dump_properties_map_.end()) { + return iter->second; + } + return {}; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool DumpProperties::IsLayerNeedDump( + const std::string &model, const std::string &om_name, const std::string &op_name) const { + // if dump all + if (model_dump_properties_map_.find(DUMP_ALL_MODEL) != model_dump_properties_map_.end()) { + return true; + } + + // if this model need dump + auto om_name_iter = model_dump_properties_map_.find(om_name); + auto model_name_iter = model_dump_properties_map_.find(model); + if (om_name_iter != model_dump_properties_map_.end() || model_name_iter != model_dump_properties_map_.end()) { + // if no dump layer info, dump all layer in this model + auto model_iter = om_name_iter != model_dump_properties_map_.end() ? om_name_iter : model_name_iter; + if (model_iter->second.empty()) { + return true; + } + + return model_iter->second.find(op_name) != model_iter->second.end(); + } + + GELOGD("Model %s is not seated to be dump.", model.c_str()); + return false; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::SetDumpPath(const std::string &path) { + dump_path_ = path; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string DumpProperties::GetDumpPath() const { return dump_path_; } + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::SetDumpStep(const std::string &step) { + dump_step_ = step; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string DumpProperties::GetDumpStep() const { return dump_step_; } + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void DumpProperties::SetDumpMode(const std::string &mode) { + dump_mode_ = mode; +} + +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string DumpProperties::GetDumpMode() const { return dump_mode_; } + +void DumpProperties::CopyFrom(const DumpProperties &other) { + if (&other != this) { + enable_dump_ = other.enable_dump_; + enable_dump_debug_ = other.enable_dump_debug_; + dump_path_ = other.dump_path_; + dump_step_ = other.dump_step_; + dump_mode_ = other.dump_mode_; + + model_dump_properties_map_ = other.model_dump_properties_map_; + is_op_debug_ = other.is_op_debug_; + op_debug_mode_ = other.op_debug_mode_; + } +} + +void DumpProperties::SetDumpDebugOptions() { + if (enable_dump_debug_ == kEnableFlag) { + string dump_debug_mode; + if (GetContext().GetOption(OPTION_EXEC_DUMP_DEBUG_MODE, dump_debug_mode) == GRAPH_SUCCESS) { + GELOGD("Get dump debug mode %s successfully", dump_debug_mode.c_str()); + } else { + GELOGW("Dump debug mode is not set."); + return; + } + + if (dump_debug_mode == OP_DEBUG_AICORE) { + GELOGD("ge.exec.dumpDebugMode=aicore_overflow, op debug is open."); + is_op_debug_ = true; + op_debug_mode_ = kAicoreOverflow; + } else if (dump_debug_mode == OP_DEBUG_ATOMIC) { + GELOGD("ge.exec.dumpDebugMode=atomic_overflow, op debug is open."); + is_op_debug_ = true; + op_debug_mode_ = kAtomicOverflow; + } else if (dump_debug_mode == OP_DEBUG_ALL) { + GELOGD("ge.exec.dumpDebugMode=all, op debug is open."); + is_op_debug_ = true; + op_debug_mode_ = kAllOverflow; + } else { + GELOGW("ge.exec.dumpDebugMode is invalid."); + } + } else { + GELOGI("ge.exec.enableDumpDebug is false or is not set."); + } +} + PropertiesManager::PropertiesManager() : is_inited_(false), delimiter("=") {} PropertiesManager::~PropertiesManager() {} @@ -159,131 +348,22 @@ PropertiesManager::GetPropertyMap() { // Set separator FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::SetPropertyDelimiter(const std::string &de) { + std::lock_guard lock(mutex_); delimiter = de; } -// The following is the new dump scenario of the fusion operator -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::AddDumpPropertyValue( - const std::string &model, const std::set &layers) { - for (const std::string &layer : layers) { - GELOGI("This model %s config to dump layer %s", model.c_str(), layer.c_str()); - } - - std::lock_guard lock(dump_mutex_); - model_dump_properties_map_[model] = layers; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::DeleteDumpPropertyValue( - const std::string &model) { - std::lock_guard lock(dump_mutex_); - auto iter = model_dump_properties_map_.find(model); - if (iter != model_dump_properties_map_.end()) { - model_dump_properties_map_.erase(iter); - } -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::ClearDumpPropertyValue() { - std::lock_guard lock(dump_mutex_); - model_dump_properties_map_.clear(); -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::set PropertiesManager::GetAllDumpModel() { - std::set model_list; - std::lock_guard lock(dump_mutex_); - for (auto &iter : model_dump_properties_map_) { - model_list.insert(iter.first); - } - - return model_list; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::set PropertiesManager::GetDumpPropertyValue( - const std::string &model) { - std::lock_guard lock(dump_mutex_); - auto iter = model_dump_properties_map_.find(model); - if (iter != model_dump_properties_map_.end()) { - return iter->second; - } - return {}; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool PropertiesManager::IsLayerNeedDump(const std::string &model, - const std::string &om_name, - const std::string &op_name) { - std::lock_guard lock(dump_mutex_); - // if dump all - if (model_dump_properties_map_.find(ge::DUMP_ALL_MODEL) != model_dump_properties_map_.end()) { - return true; - } - - // if this model need dump - auto om_name_iter = model_dump_properties_map_.find(om_name); - auto model_name_iter = model_dump_properties_map_.find(model); - if (om_name_iter != model_dump_properties_map_.end() || model_name_iter != model_dump_properties_map_.end()) { - // if no dump layer info, dump all layer in this model - auto model_iter = om_name_iter != model_dump_properties_map_.end() ? om_name_iter : model_name_iter; - if (model_iter->second.empty()) { - return true; - } - - return model_iter->second.find(op_name) != model_iter->second.end(); - } - - GELOGD("Model %s is not seated to be dump.", model.c_str()); - return false; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY DumpProperties &PropertiesManager::GetDumpProperties( + uint64_t session_id) { + std::lock_guard lock(mutex_); + // If session_id is not found in dump_properties_map_, operator[] will insert one. + return dump_properties_map_[session_id]; } -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool PropertiesManager::QueryModelDumpStatus( - const std::string &model) { - std::lock_guard lock(dump_mutex_); - auto iter = model_dump_properties_map_.find(model); - if (iter != model_dump_properties_map_.end()) { - return true; - } else if (model_dump_properties_map_.find(ge::DUMP_ALL_MODEL) != model_dump_properties_map_.end()) { - return true; +FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::RemoveDumpProperties(uint64_t session_id) { + std::lock_guard lock(mutex_); + auto iter = dump_properties_map_.find(session_id); + if (iter != dump_properties_map_.end()) { + dump_properties_map_.erase(iter); } - return false; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::SetDumpOutputModel( - const std::string &output_mode) { - std::lock_guard lock(dump_mutex_); - this->output_mode_ = output_mode; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string PropertiesManager::GetDumpOutputModel() { - std::lock_guard lock(dump_mutex_); - return this->output_mode_; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::SetDumpOutputPath( - const std::string &output_path) { - std::lock_guard lock(dump_mutex_); - this->output_path_ = output_path; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string PropertiesManager::GetDumpOutputPath() { - std::lock_guard lock(dump_mutex_); - return this->output_path_; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::SetDumpStep(const std::string &dump_step) { - std::lock_guard lock(dump_mutex_); - this->dump_step_ = dump_step; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string PropertiesManager::GetDumpStep() { - std::lock_guard lock(dump_mutex_); - return this->dump_step_; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY void PropertiesManager::SetDumpMode(const std::string &dump_mode) { - std::lock_guard lock(dump_mutex_); - this->dump_mode_ = dump_mode; -} - -FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string PropertiesManager::GetDumpMode() { - std::lock_guard lock(dump_mutex_); - return this->dump_mode_; } } // namespace ge diff --git a/src/ge/common/properties_manager.h b/src/ge/common/properties_manager.h index 7cbb5949..3b1547f5 100644 --- a/src/ge/common/properties_manager.h +++ b/src/ge/common/properties_manager.h @@ -32,6 +32,50 @@ static const char *USE_FUSION __attribute__((unused)) = "FMK_USE_FUSION"; static const char *TIMESTAT_ENABLE __attribute__((unused)) = "DAVINCI_TIMESTAT_ENABLE"; static const char *ANNDROID_DEBUG __attribute__((unused)) = "ANNDROID_DEBUG"; +class DumpProperties { + public: + DumpProperties() = default; + ~DumpProperties() = default; + DumpProperties(const DumpProperties &dump); + DumpProperties &operator=(const DumpProperties &dump); + + void InitByOptions(); + + void AddPropertyValue(const std::string &model, const std::set &layers); + void DeletePropertyValue(const std::string &model); + + std::set GetAllDumpModel() const; + std::set GetPropertyValue(const std::string &model) const; + bool IsLayerNeedDump(const std::string &model, const std::string &om_name, const std::string &op_name) const; + + void SetDumpPath(const std::string &path); + std::string GetDumpPath() const; + + void SetDumpStep(const std::string &step); + std::string GetDumpStep() const; + + void SetDumpMode(const std::string &mode); + std::string GetDumpMode() const; + + bool IsOpDebugOpen() const { return is_op_debug_; } + uint32_t GetOpDebugMode() const { return op_debug_mode_; } + + private: + void CopyFrom(const DumpProperties &other); + void SetDumpDebugOptions(); + + string enable_dump_; + string enable_dump_debug_; + + std::string dump_path_; + std::string dump_step_; + std::string dump_mode_; + std::map> model_dump_properties_map_; + + bool is_op_debug_ = false; + uint32_t op_debug_mode_ = 0; +}; + class PropertiesManager { public: // Singleton @@ -81,21 +125,8 @@ class PropertiesManager { */ void SetPropertyDelimiter(const std::string &de); - void AddDumpPropertyValue(const std::string &model, const std::set &layers); - std::set GetAllDumpModel(); - std::set GetDumpPropertyValue(const std::string &model); - bool IsLayerNeedDump(const std::string &model, const std::string &om_name, const std::string &op_name); - void DeleteDumpPropertyValue(const std::string &model); - void ClearDumpPropertyValue(); - bool QueryModelDumpStatus(const std::string &model); - void SetDumpOutputModel(const std::string &output_model); - std::string GetDumpOutputModel(); - void SetDumpOutputPath(const std::string &output_path); - std::string GetDumpOutputPath(); - void SetDumpStep(const std::string &dump_step); - std::string GetDumpStep(); - void SetDumpMode(const std::string &dump_mode); - std::string GetDumpMode(); + DumpProperties &GetDumpProperties(uint64_t session_id); + void RemoveDumpProperties(uint64_t session_id); private: // Private construct, destructor @@ -119,12 +150,7 @@ class PropertiesManager { std::map properties_map_; std::mutex mutex_; - std::string output_mode_; - std::string output_path_; - std::string dump_step_; - std::string dump_mode_; - std::map> model_dump_properties_map_; // model_dump_layers_map_ - std::mutex dump_mutex_; + std::map dump_properties_map_; }; } // namespace ge diff --git a/src/ge/common/tbe_kernel_store.h b/src/ge/common/tbe_kernel_store.h index da231358..51d69af2 100644 --- a/src/ge/common/tbe_kernel_store.h +++ b/src/ge/common/tbe_kernel_store.h @@ -28,7 +28,6 @@ #include "graph/op_kernel_bin.h" namespace ge { - using TBEKernel = ge::OpKernelBin; using TBEKernelPtr = std::shared_ptr; diff --git a/src/ge/common/types.cc b/src/ge/common/types.cc index 97761dea..2de75ff6 100644 --- a/src/ge/common/types.cc +++ b/src/ge/common/types.cc @@ -26,6 +26,11 @@ const std::string DUMP_LAYER = "layer"; const std::string DUMP_FILE_PATH = "path"; const std::string DUMP_MODE = "dump_mode"; +// op debug mode +const std::string OP_DEBUG_AICORE = "aicore_overflow"; +const std::string OP_DEBUG_ATOMIC = "atomic_overflow"; +const std::string OP_DEBUG_ALL = "all"; + const int DEFAULT_FORMAT = static_cast(ge::FORMAT_NCHW); // Supported public property names const std::string PROP_OME_START_TIME = "ome_start_time"; // start time @@ -277,8 +282,8 @@ REGISTER_OPTYPE_DEFINE(GETSPAN, "GetSpan"); REGISTER_OPTYPE_DEFINE(STOPGRADIENT, "StopGradient"); REGISTER_OPTYPE_DEFINE(PREVENTGRADIENT, "PreventGradient"); REGISTER_OPTYPE_DEFINE(GUARANTEECONST, "GuaranteeConst"); -REGISTER_OPTYPE_DEFINE(BROADCASTGRADIENTARGS, "BroadcastGradientArgs") -REGISTER_OPTYPE_DEFINE(BROADCASTARGS, "BroadcastArgs") +REGISTER_OPTYPE_DEFINE(BROADCASTGRADIENTARGS, "BroadcastGradientArgs"); +REGISTER_OPTYPE_DEFINE(BROADCASTARGS, "BroadcastArgs"); REGISTER_OPTYPE_DEFINE(CONFUSIONMATRIX, "ConfusionMatrix"); REGISTER_OPTYPE_DEFINE(RANK, "Rank"); REGISTER_OPTYPE_DEFINE(PLACEHOLDER, "PlaceHolder"); @@ -286,6 +291,8 @@ REGISTER_OPTYPE_DEFINE(END, "End"); REGISTER_OPTYPE_DEFINE(BASICLSTMCELL, "BasicLSTMCell"); REGISTER_OPTYPE_DEFINE(GETNEXT, "GetNext"); REGISTER_OPTYPE_DEFINE(INITDATA, "InitData"); +REGISTER_OPTYPE_DEFINE(REFIDENTITY, "RefIdentity"); +REGISTER_OPTYPE_DEFINE(BITCAST, "Bitcast"); /***************Ann special operator*************************/ REGISTER_OPTYPE_DEFINE(ANN_MEAN, "AnnMean"); @@ -376,6 +383,8 @@ REGISTER_OPTYPE_DEFINE(HCOMALLREDUCE, "HcomAllReduce"); REGISTER_OPTYPE_DEFINE(HCOMREDUCESCATTER, "HcomReduceScatter"); REGISTER_OPTYPE_DEFINE(HCOMSEND, "HcomSend"); REGISTER_OPTYPE_DEFINE(HCOMRECEIVE, "HcomReceive"); +REGISTER_OPTYPE_DEFINE(HCOMREMOTEREAD, "HcomRemoteRead"); +REGISTER_OPTYPE_DEFINE(HCOMREMOTEWRITE, "HcomRemoteWrite"); REGISTER_OPTYPE_DEFINE(VARASSIGN, "VarAssign"); REGISTER_OPTYPE_DEFINE(VARISINITIALIZEDOP, "VarIsInitializedOp"); @@ -479,72 +488,72 @@ const uint64_t ALLOC_MEMORY_MAX_SIZE = 536870912; // Max size of 512M. #endif /// -///@brief Magic number of model file +/// @brief Magic number of model file /// const uint32_t MODEL_FILE_MAGIC_NUM = 0x444F4D49; // magic number /// -///@brief Model head length +/// @brief Model head length /// const uint32_t MODEL_FILE_HEAD_LEN = 256; /// -///@ingroup domi_omg -///@brief Input node type +/// @ingroup domi_omg +/// @brief Input node type /// const std::string INPUT_TYPE = "Input"; /// -///@ingroup domi_omg -///@brief AIPP label, label AIPP conv operator +/// @ingroup domi_omg +/// @brief AIPP label, label AIPP conv operator /// const std::string AIPP_CONV_FLAG = "Aipp_Conv_Flag"; /// -///@ingroup domi_omg -///@brief AIPP label, label aipp data operator +/// @ingroup domi_omg +/// @brief AIPP label, label aipp data operator /// const std::string AIPP_DATA_FLAG = "Aipp_Data_Flag"; /// -///@ingroup domi_omg -///@brief Record the w dimension of model input corresponding to dynamic AIPP +/// @ingroup domi_omg +/// @brief Record the w dimension of model input corresponding to dynamic AIPP /// const std::string AIPP_RELATED_DATA_DIM_W = "aipp_related_data_dim_w"; /// -///@ingroup domi_omg -///@brief Record the H dimension of model input corresponding to dynamic AIPP +/// @ingroup domi_omg +/// @brief Record the H dimension of model input corresponding to dynamic AIPP /// const std::string AIPP_RELATED_DATA_DIM_H = "aipp_related_data_dim_h"; /// -///@ingroup domi_omg -///@brief The tag of the data operator. Mark this input to the dynamic AIPP operator +/// @ingroup domi_omg +/// @brief The tag of the data operator. Mark this input to the dynamic AIPP operator /// const std::string INPUT_TO_DYNAMIC_AIPP = "input_to_dynamic_aipp"; /// -///@ingroup domi_omg -///@brief DATA node type +/// @ingroup domi_omg +/// @brief DATA node type /// const std::string DATA_TYPE = "Data"; /// -///@ingroup domi_omg -///@brief DATA node type +/// @ingroup domi_omg +/// @brief DATA node type /// const std::string AIPP_DATA_TYPE = "AippData"; /// -///@ingroup domi_omg -///@brief Frame operator type +/// @ingroup domi_omg +/// @brief Frame operator type /// const std::string FRAMEWORK_OP_TYPE = "FrameworkOp"; /// -///@ingroup domi_omg -///@brief Data node type +/// @ingroup domi_omg +/// @brief Data node type /// const std::string ANN_DATA_TYPE = "AnnData"; const std::string ANN_NETOUTPUT_TYPE = "AnnNetOutput"; @@ -552,136 +561,139 @@ const std::string ANN_DEPTHCONV_TYPE = "AnnDepthConv"; const std::string ANN_CONV_TYPE = "AnnConvolution"; const std::string ANN_FC_TYPE = "AnnFullConnection"; /// -///@ingroup domi_omg -///@brief Convolution node type +/// @ingroup domi_omg +/// @brief Convolution node type /// const std::string NODE_NAME_NET_OUTPUT = "Node_Output"; const std::string NODE_NAME_END_GRAPH = "Node_EndGraph"; +const std::string NODE_NAME_OP_DEBUG = "Node_OpDebug"; +const std::string OP_TYPE_OP_DEBUG = "Opdebug"; + /// -///@ingroup domi_omg -///@brief Convolution node type +/// @ingroup domi_omg +/// @brief Convolution node type /// const std::string OP_TYPE_CONVOLUTION = "Convolution"; /// -///@ingroup domi_omg -///@brief Add convolution node name to AIPP +/// @ingroup domi_omg +/// @brief Add convolution node name to AIPP /// const std::string AIPP_CONV_OP_NAME = "aipp_conv_op"; /// -///@ingroup domi_omg -///@brief Operator configuration item separator +/// @ingroup domi_omg +/// @brief Operator configuration item separator /// const std::string OP_CONF_DELIMITER = ":"; /// -///@ingroup domi_omg -///@brief attr value name +/// @ingroup domi_omg +/// @brief attr value name /// const std::string ATTR_NAME_VALUE1 = "value1"; /// -///@ingroup domi_omg -///@brief attr value name, 6d_2_4d C +/// @ingroup domi_omg +/// @brief attr value name, 6d_2_4d C /// const std::string ATTR_NAME_INPUT_CVALUE = "input_cvalue"; /// -///@ingroup domi_omg -///@brief alpha default value +/// @ingroup domi_omg +/// @brief alpha default value /// const float ALPHA_DEFAULT_VALUE = 1.0; /// -///@ingroup domi_omg -///@brief beta default value +/// @ingroup domi_omg +/// @brief beta default value /// const float BETA_DEFAULT_VALUE = 0.0; /// -///@ingroup domi_omg -///@brief coef default value +/// @ingroup domi_omg +/// @brief coef default value /// const float COEF_DEFAULT_VALUE = 0.0; /// -///@ingroup domi_omg -///@brief Relu6 coef value +/// @ingroup domi_omg +/// @brief Relu6 coef value /// const float RELU6_COEF = 6.0; /// -///@ingroup domi_omg -///@brief stride default value +/// @ingroup domi_omg +/// @brief stride default value /// const uint32_t STRIDE_DEFAULT_VALUE = 1; /// -///@ingroup domi_omg -///@brief pad default value +/// @ingroup domi_omg +/// @brief pad default value /// const uint32_t PAD_DEFAULT_VALUE = 0; /// -///@ingroup domi_omg -///@brief dilation default value +/// @ingroup domi_omg +/// @brief dilation default value /// const int DILATION_DEFAULT_VALUE = 1; /// -///@ingroup domi_omg -///@brief kernel default value +/// @ingroup domi_omg +/// @brief kernel default value /// const uint32_t KERNEL_DEFAULT_VALUE = 0; /// -///@ingroup domi_omg -///@brief defaule convolution group size +/// @ingroup domi_omg +/// @brief defaule convolution group size /// const uint32_t DEFAULT_CONV_GROUP = 1; /// -///@ingroup domi_omg -///@brief Default deconvolution adj +/// @ingroup domi_omg +/// @brief Default deconvolution adj /// const uint32_t DEFAULT_DECONV_ADJ = 0; /// -///@ingroup domi_omg -///@brief Represents value 1 +/// @ingroup domi_omg +/// @brief Represents value 1 /// const uint32_t NUM_ONE = 1; /// -///@ingroup domi_omg -///@brief spatial dim size default value +/// @ingroup domi_omg +/// @brief spatial dim size default value /// const int32_t SPATIAL_DIM_DEFAULT_SIZE = 2; /// -///@ingroup domi_omg -///@brief dim extended default value +/// @ingroup domi_omg +/// @brief dim extended default value /// const int32_t DIM_DEFAULT_VALUE = 1; /// -///@ingroup domi_omg -///@brief The first weight list in opdef is filter +/// @ingroup domi_omg +/// @brief The first weight list in opdef is filter /// const int32_t WEIGHT_FILTER_INDEX = 0; /// -///@ingroup domi_omg -///@brief The second weight list in opdef is bias +/// @ingroup domi_omg +/// @brief The second weight list in opdef is bias /// const int32_t WEIGHT_BIAS_INDEX = 1; const int32_t TENSOR_ND_SUPPORT_SIZE = 8; /// -///@ingroup domi_omg -///@brief NCHW index default value +/// @ingroup domi_omg +/// @brief NCHW index default value /// const uint32_t NCHW_DIM_N = 0; const uint32_t NCHW_DIM_C = 1; @@ -689,8 +701,8 @@ const uint32_t NCHW_DIM_H = 2; const uint32_t NCHW_DIM_W = 3; /// -///@ingroup domi_omg -///@brief KCHW index default value +/// @ingroup domi_omg +/// @brief KCHW index default value /// const uint32_t KCHW_DIM_K = 0; const uint32_t KCHW_DIM_C = 1; @@ -698,8 +710,8 @@ const uint32_t KCHW_DIM_H = 2; const uint32_t KCHW_DIM_W = 3; /// -///@ingroup domi_omg -///@brief HWCK index default value +/// @ingroup domi_omg +/// @brief HWCK index default value /// const uint32_t HWCK_DIM_H = 0; const uint32_t HWCK_DIM_W = 1; @@ -707,8 +719,8 @@ const uint32_t HWCK_DIM_C = 2; const uint32_t HWCK_DIM_K = 3; /// -///@ingroup domi_omg -///@brief NHWC index default value +/// @ingroup domi_omg +/// @brief NHWC index default value /// const uint32_t NHWC_DIM_N = 0; const uint32_t NHWC_DIM_H = 1; @@ -716,8 +728,8 @@ const uint32_t NHWC_DIM_W = 2; const uint32_t NHWC_DIM_C = 3; /// -///@ingroup domi_omg -///@brief CHWN index default value +/// @ingroup domi_omg +/// @brief CHWN index default value /// const uint32_t CHWN_DIM_N = 3; const uint32_t CHWN_DIM_C = 0; @@ -725,23 +737,23 @@ const uint32_t CHWN_DIM_H = 1; const uint32_t CHWN_DIM_W = 2; /// -///@ingroup domi_omg -///@brief CHW index default value +/// @ingroup domi_omg +/// @brief CHW index default value /// const uint32_t CHW_DIM_C = 0; const uint32_t CHW_DIM_H = 1; const uint32_t CHW_DIM_W = 2; /// -///@ingroup domi_omg -///@brief HWC index default value +/// @ingroup domi_omg +/// @brief HWC index default value /// const uint32_t HWC_DIM_H = 0; const uint32_t HWC_DIM_W = 1; const uint32_t HWC_DIM_C = 2; /// -///@ingroup domi_omg -///@brief Pad index default value +/// @ingroup domi_omg +/// @brief Pad index default value /// const uint32_t PAD_H_HEAD = 0; const uint32_t PAD_H_TAIL = 1; @@ -749,35 +761,35 @@ const uint32_t PAD_W_HEAD = 2; const uint32_t PAD_W_TAIL = 3; /// -///@ingroup domi_omg -///@brief window index default value +/// @ingroup domi_omg +/// @brief window index default value /// const uint32_t WINDOW_H = 0; const uint32_t WINDOW_W = 1; /// -///@ingroup domi_omg -///@brief stride index default value +/// @ingroup domi_omg +/// @brief stride index default value /// const uint32_t STRIDE_H = 0; const uint32_t STRIDE_W = 1; /// -///@ingroup domi_omg -///@brief dilation index default value +/// @ingroup domi_omg +/// @brief dilation index default value /// const uint32_t DILATION_H = 0; const uint32_t DILATION_W = 1; /// -///@ingroup domi_omg -///@brief the num of XRBG channel +/// @ingroup domi_omg +/// @brief the num of XRBG channel /// const uint32_t XRGB_CHN_NUM = 4; /// -///@ingroup domi_omg -///@brief global pooling default value +/// @ingroup domi_omg +/// @brief global pooling default value /// const bool DEFAULT_GLOBAL_POOLING = false; @@ -801,4 +813,4 @@ const uint32_t STREAM_SWITCH_INPUT_NUM = 2; const std::string NODE_NAME_GLOBAL_STEP = "ge_global_step"; const std::string NODE_NAME_GLOBAL_STEP_ASSIGNADD = "global_step_assignadd"; -}; // namespace ge +} // namespace ge diff --git a/src/ge/common/util.cc b/src/ge/common/util.cc index 50ed2f33..a52978af 100644 --- a/src/ge/common/util.cc +++ b/src/ge/common/util.cc @@ -20,12 +20,12 @@ #include #include +#include #include #include #include #include #include -#include #include "external/ge/ge_api_error_codes.h" #include "common/util/error_manager/error_manager.h" @@ -56,6 +56,8 @@ const int kWarningThreshold = 536870912 * 2; // 536870912 represent 512M /// The maximum length of the file. /// Based on the security coding specification and the current actual (protobuf) model size, it is determined as 2G-1 const int kMaxFileSizeLimit = INT_MAX; +const int kMaxBuffSize = 256; +const char *const kPathValidReason = "The path can only contains 'a-z' 'A-Z' '0-9' '-' '.' '_' and chinese character"; } // namespace namespace ge { @@ -77,7 +79,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool ReadProtoFromBinaryFile(co std::ifstream fs(real_path, std::ifstream::in | std::ifstream::binary); if (!fs.is_open()) { - ErrorManager::GetInstance().ATCReportErrMessage("E19004", {"realpath"}, {file}); + ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"file", "errmsg"}, {file, "ifstream is_open failed"}); GELOGE(ge::FAILED, "Open real path[%s] failed.", file); return false; } @@ -90,7 +92,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool ReadProtoFromBinaryFile(co fs.close(); if (!ret) { - ErrorManager::GetInstance().ATCReportErrMessage("E19005", {"filepath"}, {file}); + ErrorManager::GetInstance().ATCReportErrMessage("E19005", {"file"}, {file}); GELOGE(ge::FAILED, "Parse file[%s] failed.", file); return ret; } @@ -114,17 +116,18 @@ long GetFileLength(const std::string &input_file) { GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(real_path.empty(), return -1, "input_file path '%s' not valid", input_file.c_str()); unsigned long long file_length = 0; - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(mmGetFileSize(input_file.c_str(), &file_length) != EN_OK, - ErrorManager::GetInstance().ATCReportErrMessage("E10037", {"filepath"}, {input_file}); - return -1, "Open file[%s] failed", input_file.c_str()); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + mmGetFileSize(input_file.c_str(), &file_length) != EN_OK, + ErrorManager::GetInstance().ATCReportErrMessage("E19001", {"file", "errmsg"}, {input_file, strerror(errno)}); + return -1, "Open file[%s] failed. %s", input_file.c_str(), strerror(errno)); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG((file_length == 0), - ErrorManager::GetInstance().ATCReportErrMessage("E10038", {"filepath"}, {input_file}); + ErrorManager::GetInstance().ATCReportErrMessage("E19015", {"filepath"}, {input_file}); return -1, "File[%s] size is 0, not valid.", input_file.c_str()); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( file_length > kMaxFileSizeLimit, ErrorManager::GetInstance().ATCReportErrMessage( - "E10039", {"filepath", "filesize", "maxlen"}, + "E19016", {"filepath", "filesize", "maxlen"}, {input_file, std::to_string(file_length), std::to_string(kMaxFileSizeLimit)}); return -1, "File[%s] size %lld is out of limit: %d.", input_file.c_str(), file_length, kMaxFileSizeLimit); return static_cast(file_length); @@ -219,7 +222,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY int CreateDirectory(const std:: if (ret != 0) { if (errno != EEXIST) { ErrorManager::GetInstance().ATCReportErrMessage("E19006", {"path"}, {directory_path}); - GELOGW("Cannot create directory %s. Make sure the directory exists and writable.", directory_path.c_str()); + GELOGW("Can not create directory %s. Make sure the directory exists and writable.", directory_path.c_str()); return ret; } } @@ -230,7 +233,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY int CreateDirectory(const std:: if (ret != 0) { if (errno != EEXIST) { ErrorManager::GetInstance().ATCReportErrMessage("E19006", {"path"}, {directory_path}); - GELOGW("Cannot create directory %s. Make sure the directory exists and writable.", directory_path.c_str()); + GELOGW("Can not create directory %s. Make sure the directory exists and writable.", directory_path.c_str()); return ret; } } @@ -258,16 +261,16 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool ReadProtoFromText(const ch "incorrect parameter. nullptr == file || nullptr == message"); std::string real_path = RealPath(file); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(real_path.empty(), - ErrorManager::GetInstance().ATCReportErrMessage("E10036", {"filepath"}, {file}); - return false, "Get path[%s]'s real path failed", file); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(real_path.empty(), ErrorManager::GetInstance().ATCReportErrMessage( + "E19000", {"path", "errmsg"}, {file, strerror(errno)}); + return false, "Path[%s]'s realpath is empty, errmsg[%s]", file, strerror(errno)); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(GetFileLength(real_path) == -1, return false, "file size not valid."); std::ifstream fs(real_path.c_str(), std::ifstream::in); if (!fs.is_open()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10040", {"realpth", "protofile"}, {real_path, file}); + ErrorManager::GetInstance().ATCReportErrMessage("E19017", {"realpth", "protofile"}, {real_path, file}); GELOGE(ge::FAILED, "Fail to open proto file real path is '%s' when orginal file path is '%s'.", real_path.c_str(), file); return false; @@ -275,7 +278,7 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool ReadProtoFromText(const ch google::protobuf::io::IstreamInputStream input(&fs); bool ret = google::protobuf::TextFormat::Parse(&input, message); - GE_IF_BOOL_EXEC(!ret, ErrorManager::GetInstance().ATCReportErrMessage("E10041", {"protofile"}, {file}); + GE_IF_BOOL_EXEC(!ret, ErrorManager::GetInstance().ATCReportErrMessage("E19018", {"protofile"}, {file}); GELOGE(ret, "Parse file[%s] through [google::protobuf::TextFormat::Parse] failed, " "please check whether the file is a valid protobuf format file.", @@ -339,17 +342,13 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY std::string RealPath(const char strlen(path) >= PATH_MAX, ErrorManager::GetInstance().ATCReportErrMessage("E19002", {"filepath", "size"}, {path, std::to_string(PATH_MAX)}); return "", "Path[%s] len is too long, it must be less than %d", path, PATH_MAX); - // PATH_MAX is the system's own macro, indicating the maximum file path length supported - std::shared_ptr resolved_path(new (std::nothrow) char[PATH_MAX](), std::default_delete()); - - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(resolved_path == nullptr, return "", "Path[%s] new string object len[%d] failed.", - path, PATH_MAX); // Nullptr is returned when the path does not exist or there is no permission // Return absolute path when path is accessible std::string res; - if (realpath(path, resolved_path.get()) != nullptr) { - res = resolved_path.get(); + char resolved_path[PATH_MAX] = {0}; + if (realpath(path, resolved_path) != nullptr) { + res = resolved_path; } return res; @@ -360,36 +359,34 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool CheckInputPathValid(const // The specified path is empty std::map args_map; if (file_path.empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {atc_param}); - GELOGW("Input parameter's value is empty."); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {atc_param}); + GELOGW("Input parameter %s is empty.", file_path.c_str()); return false; } std::string real_path = RealPath(file_path.c_str()); // Unable to get absolute path (does not exist or does not have permission to access) if (real_path.empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10002", {"path", "errmsg"}, {file_path.c_str(), strerror(errno)}); + ErrorManager::GetInstance().ATCReportErrMessage("E19000", {"path", "errmsg"}, {file_path, strerror(errno)}); GELOGW("Path[%s]'s realpath is empty, errmsg[%s]", file_path.c_str(), strerror(errno)); return false; } // A regular matching expression to verify the validity of the input file path // ^(/|./|(../)+|)([.]?[\u4e00-\u9fa5A-Za-z0-9_.-]+/)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$ - // Path section:Support upper and lower case letters, numbers dots(.) chinese and underscores - // File name section:Support upper and lower case letters, numbers, underscores chinese and dots(.) + // Path section: Support upper and lower case letters, numbers dots(.) chinese and underscores + // File name section: Support upper and lower case letters, numbers, underscores chinese and dots(.) std::string mode = "^(/+|./+|(../+)+|)(../|([.]?[\u4e00-\u9fa5A-Za-z0-9_.-]+)/+)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$"; GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( !ValidateStr(real_path, mode), - ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "path"}, {atc_param, real_path}); - return false, - "Input parameter[--%s]'s value[%s] is illegal. The path can only contains 'a-z' 'A-Z' '0-9' '-' '.' '_' " - "and chinese character.", - atc_param.c_str(), real_path.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {atc_param, real_path, kPathValidReason}); + return false, "Invalid value for %s[%s], %s.", atc_param.c_str(), real_path.c_str(), kPathValidReason); // The absolute path points to a file that is not readable if (access(real_path.c_str(), R_OK) != 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10003", {"path", "errmsg"}, {file_path.c_str(), strerror(errno)}); - GELOGW("Read path[%s] failed, errmsg[%s]", file_path.c_str(), strerror(errno)); + ErrorManager::GetInstance().ATCReportErrMessage("E19003", {"file", "errmsg"}, {file_path.c_str(), strerror(errno)}); + GELOGW("Read file[%s] failed, errmsg[%s]", file_path.c_str(), strerror(errno)); return false; } @@ -400,34 +397,35 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool CheckOutputPathValid(const const std::string &atc_param) { // The specified path is empty if (file_path.empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {atc_param}); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {atc_param}); GELOGW("Input parameter's value is empty."); return false; } + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + strlen(file_path.c_str()) >= PATH_MAX, ErrorManager::GetInstance().ATCReportErrMessage( + "E19002", {"filepath", "size"}, {file_path, std::to_string(PATH_MAX)}); + return "", "Path[%s] len is too long, it must be less than %d", file_path.c_str(), PATH_MAX); + + // A regular matching expression to verify the validity of the input file path + // ^(/|./|(../)+|)([.]?[\u4e00-\u9fa5A-Za-z0-9_-]+/)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$ + // Path section: Support upper and lower case letters, numbers dots(.) chinese and underscores + // File name section: Support upper and lower case letters, numbers, underscores chinese and dots(.) + std::string mode = "^(/+|./+|(../+)+|)(../|([.]?[\u4e00-\u9fa5A-Za-z0-9_.-]+)/+)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$"; + + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + !ValidateStr(file_path, mode), + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {atc_param, file_path, kPathValidReason}); + return false, "Invalid value for %s[%s], %s.", atc_param.c_str(), file_path.c_str(), kPathValidReason); + std::string real_path = RealPath(file_path.c_str()); // Can get absolute path (file exists) if (!real_path.empty()) { - // A regular matching expression to verify the validity of the input file path - // ^(/|./|(../)+|)([.]?[\u4e00-\u9fa5A-Za-z0-9_-]+/)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$ - // Path section:Support upper and lower case letters, numbers dots(.) chinese and underscores - // File name section:Support upper and lower case letters, numbers, underscores chinese and dots(.) - std::string mode = "^(/+|./+|(../+)+|)(../|([.]?[\u4e00-\u9fa5A-Za-z0-9_.-]+)/+)*[\u4e00-\u9fa5A-Za-z0-9_+.-]+$"; - - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( - !ValidateStr(real_path, mode), - ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "path"}, {atc_param, real_path}); - return false, - "Input parameter[--%s]'s value[%s] is illegal. The path can only contains 'a-z' 'A-Z' '0-9' '-' '.' '_' " - "and chinese character.", - atc_param.c_str(), real_path.c_str()); - // File is not readable or writable if (access(real_path.c_str(), W_OK | F_OK) != 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"realpath", "path", "errmsg"}, - {real_path, file_path, strerror(errno)}); - GELOGW("Write file[%s] failed, input path is %s, errmsg[%s]", real_path.c_str(), file_path.c_str(), - strerror(errno)); + ErrorManager::GetInstance().ATCReportErrMessage("E19004", {"file", "errmsg"}, {real_path, strerror(errno)}); + GELOGW("Write file[%s] failed, errmsg[%s]", real_path.c_str(), strerror(errno)); return false; } } else { @@ -445,8 +443,8 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool CheckOutputPathValid(const std::string prefix_path = std::string(file_path).substr(0, static_cast(path_split_pos)); // Determine whether the specified path is valid by creating the path if (CreateDirectory(prefix_path) != 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10005", {"path"}, {file_path}); - GELOGW("Can not create prefix path for path[%s].", file_path.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E19006", {"path"}, {file_path}); + GELOGW("Can not create directory[%s].", file_path.c_str()); return false; } } @@ -456,17 +454,26 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY bool CheckOutputPathValid(const } FMK_FUNC_HOST_VISIBILITY bool ValidateStr(const std::string &str, const std::string &mode) { -#ifndef OS_CENTOS - std::regex reg(mode); + char ebuff[kMaxBuffSize]; + regex_t reg; + int cflags = REG_EXTENDED | REG_NOSUB; + int ret = regcomp(®, mode.c_str(), cflags); + if (ret) { + regerror(ret, ®, ebuff, kMaxBuffSize); + GELOGE(ge::PARAM_INVALID, "regcomp failed, reason: %s", ebuff); + regfree(®); + return false; + } - // Matching string part - std::smatch match; + ret = regexec(®, str.c_str(), 0, nullptr, 0); + if (ret) { + regerror(ret, ®, ebuff, kMaxBuffSize); + GELOGE(ge::PARAM_INVALID, "regexec failed, reason: %s", ebuff); + regfree(®); + return false; + } - bool res = regex_match(str, match, reg); - res = regex_search(str, std::regex("[`!@#$%^&*()|{}':;',\\[\\]<>?]")); - return !(res) && (str.size() == match.str().size()); -#else + regfree(®); return true; -#endif } } // namespace ge diff --git a/src/ge/engine_manager/dnnengine_manager.cc b/src/ge/engine_manager/dnnengine_manager.cc index c8843c09..ad36ebb5 100644 --- a/src/ge/engine_manager/dnnengine_manager.cc +++ b/src/ge/engine_manager/dnnengine_manager.cc @@ -24,6 +24,7 @@ #include "common/debug/log.h" #include "common/ge/ge_util.h" +#include "common/util/error_manager/error_manager.h" #include "framework/common/debug/ge_log.h" #include "graph/ge_context.h" #include "init/gelib.h" @@ -161,6 +162,10 @@ bool DNNEngineManager::IsEngineRegistered(const std::string &name) { return false; } +void DNNEngineManager::InitPerformanceStaistic() { checksupport_cost_.clear(); } + +const map &DNNEngineManager::GetCheckSupportCost() const { return checksupport_cost_; } + std::string DNNEngineManager::GetDNNEngineName(const OpDescPtr &op_desc) { GE_IF_BOOL_EXEC(op_desc == nullptr, GELOGE(GE_CLI_GE_NOT_INITIALIZED, "DNNEngineManager: op_desc is nullptr"); return ""); @@ -176,13 +181,12 @@ std::string DNNEngineManager::GetDNNEngineName(const OpDescPtr &op_desc) { GELOGI("DNNEngineManager: Can not get op info by op type %s", op_desc->GetType().c_str()); return ""; } - string ge_core_type; + std::string ge_core_type; Status ret = ge::GetContext().GetOption(ge::CORE_TYPE, ge_core_type); - if (ret != SUCCESS) { - GELOGD("get the option CORE_TYPE fail, set it to default value VECTOR_ENGINE"); - } - string exclude_core_Type = (ge_core_type == kVectorCore) ? kAIcoreEngine : kVectorEngine; + GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGD("get the option CORE_TYPE fail, set it to default value VECTOR_ENGINE")); + std::string exclude_core_Type = (ge_core_type == kVectorCore) ? kAIcoreEngine : kVectorEngine; GELOGD("engine type will exclude: %s", exclude_core_Type.c_str()); + std::map unsupported_reasons; for (const auto &it : op_infos) { if (it.engine == exclude_core_Type) { @@ -194,15 +198,20 @@ std::string DNNEngineManager::GetDNNEngineName(const OpDescPtr &op_desc) { if (kernel_info_store != kernel_map.end()) { std::string unsupported_reason; // It will be replaced by engine' checksupport + uint64_t start_time = GetCurrentTimestap(); if (kernel_info_store->second->CheckSupported(op_desc, unsupported_reason)) { + checksupport_cost_[kernel_name] += GetCurrentTimestap() - start_time; op_desc->SetOpEngineName(it.engine); op_desc->SetOpKernelLibName(kernel_name); - GELOGD("DNNEngineManager:Set OpKernelLibName %s and engine name %s into op_desc %s", kernel_name.c_str(), + GELOGD("DNNEngineManager:Set OpKernelLibName %s and engine name %s to op_desc %s", kernel_name.c_str(), it.engine.c_str(), op_desc->GetName().c_str()); return it.engine; } else { + checksupport_cost_[kernel_name] += GetCurrentTimestap() - start_time; bool is_custom_op = false; if ((ge::AttrUtils::GetBool(op_desc, kCustomOpFlag, is_custom_op)) && is_custom_op) { + ErrorManager::GetInstance().ATCReportErrMessage("E13001", {"kernelname", "optype", "opname"}, + {kernel_name, op_desc->GetType(), op_desc->GetName()}); GELOGE(FAILED, "The custom operator registered by the user does not support the logic function delivered by this " "network. Check support failed, kernel_name is %s, op type is %s, op name is %s", @@ -212,6 +221,9 @@ std::string DNNEngineManager::GetDNNEngineName(const OpDescPtr &op_desc) { unsupported_reasons.emplace(kernel_name, unsupported_reason); GELOGI("DNNEngineManager:Check support failed, kernel_name is %s, op type is %s, op name is %s", kernel_name.c_str(), op_desc->GetType().c_str(), op_desc->GetName().c_str()); + if (!op_desc->HasAttr("_is_ge_op")) { + ErrorManager::GetInstance().ATCReportErrMessage("W11001", {"opname"}, {op_desc->GetName()}); + } } } else { GELOGW( @@ -221,9 +233,13 @@ std::string DNNEngineManager::GetDNNEngineName(const OpDescPtr &op_desc) { } } for (const auto &it : unsupported_reasons) { + ErrorManager::GetInstance().ATCReportErrMessage("E13002", {"optype", "opskernel", "reason"}, + {op_desc->GetType(), it.first, it.second}); GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED, "GetDNNEngineName:Op type %s of ops kernel %s is unsupported, reason:%s", op_desc->GetType().c_str(), it.first.c_str(), it.second.c_str()); } + ErrorManager::GetInstance().ATCReportErrMessage("E13003", {"opname", "optype"}, + {op_desc->GetName(), op_desc->GetType()}); GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED, "Can't find any supported ops kernel and engine of %s, type is %s", op_desc->GetName().c_str(), op_desc->GetType().c_str()); return ""; @@ -357,7 +373,7 @@ Status DNNEngineManager::ParserEngineMessage(const json engines_json, const std: } Status DNNEngineManager::ReadJsonFile(const std::string &file_path, JsonHandle handle) { - GELOGI("Begin to read json file"); + GELOGD("Begin to read json file"); if (file_path.empty()) { GELOGE(FAILED, "Json path %s is not valid", file_path.c_str()); return FAILED; @@ -384,14 +400,20 @@ Status DNNEngineManager::ReadJsonFile(const std::string &file_path, JsonHandle h return FAILED; } - ifs >> *json_file; + try { + ifs >> *json_file; + } catch (const json::exception &e) { + GELOGE(FAILED, "Read json file failed"); + ifs.close(); + return FAILED; + } ifs.close(); - GELOGI("Read json file success"); + GELOGD("Read json file success"); return SUCCESS; } Status DNNEngineManager::CheckJsonFile() { - GELOGI("Begin to check json file"); + GELOGD("Begin to check json file"); for (auto &it : engines_map_) { std::string engine_name = it.first; int count = 0; @@ -411,7 +433,7 @@ Status DNNEngineManager::CheckJsonFile() { return FAILED; } } - GELOGI("Check json file success"); + GELOGD("Check json file success"); return SUCCESS; } } // namespace ge diff --git a/src/ge/engine_manager/dnnengine_manager.h b/src/ge/engine_manager/dnnengine_manager.h index ab813398..15628ecf 100644 --- a/src/ge/engine_manager/dnnengine_manager.h +++ b/src/ge/engine_manager/dnnengine_manager.h @@ -63,6 +63,8 @@ class DNNEngineManager { // If can't find appropriate engine name, return "", report error string GetDNNEngineName(const OpDescPtr &op_desc); const map &GetSchedulers() const; + const map &GetCheckSupportCost() const; + void InitPerformanceStaistic(); private: DNNEngineManager(); @@ -78,6 +80,7 @@ class DNNEngineManager { std::map engines_map_; std::map engines_attrs_map_; std::map schedulers_; + std::map checksupport_cost_; bool init_flag_; }; } // namespace ge diff --git a/src/ge/executor/CMakeLists.txt b/src/ge/executor/CMakeLists.txt index cddf25b7..1b0b8131 100755 --- a/src/ge/executor/CMakeLists.txt +++ b/src/ge/executor/CMakeLists.txt @@ -26,6 +26,7 @@ file(GLOB PROTO_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} file(GLOB SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "ge_executor.cc" + "../common/ge/op_tiling_manager.cc" "../common/ge/plugin_manager.cc" "../common/profiling/profiling_manager.cc" "../graph/execute/graph_execute.cc" @@ -58,8 +59,8 @@ file(GLOB SRC_LIST RELATIVE ${CMAKE_CURRENT_LIST_DIR} "../graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc" "../graph/load/new_model_manager/task_info/task_info.cc" "../graph/load/new_model_manager/tbe_handle_store.cc" + "../graph/load/new_model_manager/zero_copy_offset.cc" "../graph/load/new_model_manager/zero_copy_task.cc" - "../graph/load/output/output.cc" "../graph/manager/graph_caching_allocator.cc" "../graph/manager/graph_manager_utils.cc" "../graph/manager/graph_mem_allocator.cc" diff --git a/src/ge/executor/ge_executor.cc b/src/ge/executor/ge_executor.cc index b5a3b3cf..ee65faec 100644 --- a/src/ge/executor/ge_executor.cc +++ b/src/ge/executor/ge_executor.cc @@ -36,6 +36,9 @@ #include "mmpa/mmpa_api.h" #include "single_op/single_op_manager.h" +using std::string; +using std::vector; + namespace { const size_t kDynamicBatchSizeVecSize = 1; const size_t kStaticBatchInfoSize = 1; @@ -102,20 +105,36 @@ void SetDynamicInputDataFlag(const ge::RunModelData &input_data, const std::vect ge::InputData &inputs) { inputs.is_dynamic_batch = true; std::string batch_label; + size_t match_idx = 0; for (size_t i = 0; i < batch_info.size(); ++i) { - if (batch_info[i].size() == kDynamicBatchSizeVecSize && - batch_info[i][0] == static_cast(input_data.dynamic_batch_size)) { - batch_label = kBatchLabel + std::to_string(i); - inputs.batch_label = batch_label; + // dynamic_dims + if (input_data.dynamic_dims.size() != 0) { + bool is_match = true; + for (size_t j = 0; j < static_cast(input_data.dynamic_dims.size()); ++j) { + if (static_cast(batch_info[i][j]) != input_data.dynamic_dims[j]) { + is_match = false; + break; + } + } + if (is_match) { + match_idx = i; + break; + } + // dynamic_batch_size + } else if (batch_info[i].size() == kDynamicBatchSizeVecSize && + batch_info[i][0] == static_cast(input_data.dynamic_batch_size)) { + match_idx = i; break; + // dynamic_image_size } else if (batch_info[i].size() == kDynamicImageSizeVecSize && batch_info[i][0] == static_cast(input_data.dynamic_image_height) && batch_info[i][1] == static_cast(input_data.dynamic_image_width)) { - batch_label = kBatchLabel + std::to_string(i); - inputs.batch_label = batch_label; + match_idx = i; break; } } + batch_label = kBatchLabel + std::to_string(match_idx); + inputs.batch_label = batch_label; GELOGI("current batch label:%s", batch_label.c_str()); } @@ -225,39 +244,41 @@ Status GeExecutor::Finalize() { Status GeExecutor::SetDynamicBatchSize(uint32_t model_id, void *dynamic_input_addr, uint64_t length, uint64_t batch_size) { if (dynamic_input_addr == nullptr) { - GELOGE(FAILED, "Dynamic input addr is nullptr!"); - return FAILED; + GELOGE(PARAM_INVALID, "Dynamic input addr is nullptr!"); + return PARAM_INVALID; } uint64_t size = sizeof(uint64_t); if (length < size) { - GELOGE(FAILED, "Dynamic input size [%lu] is less than [%lu]!", length, size); - return FAILED; + GELOGE(PARAM_INVALID, "Dynamic input size [%lu] is less than [%lu]!", length, size); + return PARAM_INVALID; } // Verify whether the input dynamic batch matches the model gear std::vector> batch_info; std::vector batch_num{batch_size}; - Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info); + int32_t dynamic_type = static_cast(FIXED); + Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { - GELOGE(FAILED, "Get dynamic input info failed."); - return FAILED; + GELOGE(ret, "Get dynamic input info failed."); + return ret; } if (!IsDynamicBatchSizeMatchModel(batch_size, batch_info)) { - GELOGE(FAILED, "The current dynamic input does not match the gear of the model."); - return FAILED; + GELOGE(PARAM_INVALID, "The current dynamic input does not match the gear of the model."); + return PARAM_INVALID; } - ret = GraphExecutor::SetDynamicSize(model_id, batch_num); + ret = GraphExecutor::SetDynamicSize(model_id, batch_num, static_cast(DYNAMIC_BATCH)); if (ret != SUCCESS) { - GELOGE(FAILED, "Set dynamic size failed"); - return FAILED; + GELOGE(ret, "Set dynamic size failed"); + return ret; } // memcpy dynamic_batch_size from host to device - if (rtMemcpy(dynamic_input_addr, length, &batch_size, size, RT_MEMCPY_HOST_TO_DEVICE) != RT_ERROR_NONE) { - GELOGE(FAILED, "memcpy dynamic batch input data failed!"); - return FAILED; + rtError_t rt_ret = rtMemcpy(dynamic_input_addr, length, &batch_size, size, RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "memcpy dynamic batch input data failed! ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; } @@ -265,40 +286,42 @@ Status GeExecutor::SetDynamicBatchSize(uint32_t model_id, void *dynamic_input_ad Status GeExecutor::SetDynamicImageSize(uint32_t model_id, void *dynamic_input_addr, uint64_t length, uint64_t image_height, uint64_t image_width) { if (dynamic_input_addr == nullptr) { - GELOGE(FAILED, "Dynamic input addr is nullptr!"); - return FAILED; + GELOGE(PARAM_INVALID, "Dynamic input addr is nullptr!"); + return PARAM_INVALID; } uint64_t dynamic_input_size = kDynamicImageSizeInputSize * sizeof(uint64_t); if (length < dynamic_input_size) { - GELOGE(FAILED, "Dynamic input size [%lu] is less than [%lu]!", length, dynamic_input_size); - return FAILED; + GELOGE(PARAM_INVALID, "Dynamic input size [%lu] is less than [%lu]!", length, dynamic_input_size); + return PARAM_INVALID; } // Verify whether the input dynamic resolution matches the model gear std::vector> batch_info; std::vector batch_num{image_height, image_width}; - Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info); + int32_t dynamic_type = static_cast(FIXED); + Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { - GELOGE(FAILED, "Get dynamic input info failed."); - return FAILED; + GELOGE(ret, "Get dynamic input info failed."); + return ret; } if (!IsDynamicImageSizeMatchModel(image_height, image_width, batch_info)) { - GELOGE(FAILED, "The current dynamic input does not match the gear of the model."); - return FAILED; + GELOGE(PARAM_INVALID, "The current dynamic input does not match the gear of the model."); + return PARAM_INVALID; } - ret = GraphExecutor::SetDynamicSize(model_id, batch_num); + ret = GraphExecutor::SetDynamicSize(model_id, batch_num, static_cast(DYNAMIC_IMAGE)); if (ret != SUCCESS) { - GELOGE(FAILED, "Set dynamic size failed"); - return FAILED; + GELOGE(ret, "Set dynamic size failed"); + return ret; } // Memcpy dynamic resolution height from host to device - if (rtMemcpy(dynamic_input_addr, sizeof(uint64_t), &image_height, sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE) != - RT_ERROR_NONE) { - GELOGE(FAILED, "memcpy dynamic resolution input data failed!"); - return FAILED; + rtError_t rt_ret = + rtMemcpy(dynamic_input_addr, sizeof(uint64_t), &image_height, sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "memcpy dynamic resolution input data failed! ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } uint64_t remain_size = length - sizeof(uint64_t); @@ -311,16 +334,109 @@ Status GeExecutor::SetDynamicImageSize(uint32_t model_id, void *dynamic_input_ad return SUCCESS; } -Status GeExecutor::GetCurShape(const uint32_t model_id, std::vector &batch_info) { +Status GeExecutor::SetDynamicDims(uint32_t model_id, void *dynamic_input_addr, uint64_t length, + const vector &dynamic_dims) { + if (dynamic_input_addr == nullptr) { + GELOGE(FAILED, "Dynamic input addr is nullptr!"); + return FAILED; + } + + Status ret = GraphExecutor::SetDynamicSize(model_id, dynamic_dims, static_cast(DYNAMIC_DIMS)); + if (ret != SUCCESS) { + GELOGE(FAILED, "Set dynamic size failed"); + return FAILED; + } + + vector cur_dynamic_dims; + if (GetCurDynamicDims(model_id, dynamic_dims, cur_dynamic_dims) != SUCCESS) { + GELOGE(FAILED, "GetCurDynamicDims failed."); + return FAILED; + } + + size_t dynamic_dim_num = cur_dynamic_dims.size(); + uint64_t dynamic_input_size = static_cast(dynamic_dim_num * sizeof(uint64_t)); + if (length < dynamic_input_size) { + GELOGE(FAILED, "Dynamic input size [%lu] is less than [%lu]!", length, dynamic_input_size); + return FAILED; + } + + for (uint32_t i = 0; i < dynamic_dim_num; ++i) { + // Memcpy dynamic dim[i] from host to device + if (rtMemcpy(reinterpret_cast(reinterpret_cast(dynamic_input_addr) + sizeof(uint64_t) * i), + length - sizeof(uint64_t) * i, &cur_dynamic_dims[i], sizeof(uint64_t), + RT_MEMCPY_HOST_TO_DEVICE) != RT_ERROR_NONE) { + GELOGE(FAILED, "memcpy dynamic resolution input data failed!"); + return FAILED; + } + } + return SUCCESS; +} + +Status GeExecutor::GetCurDynamicDims(uint32_t model_id, const vector &combined_dims, + vector &cur_dynamic_dims) { + vector> combined_batch; + if (GraphExecutor::GetCombinedDynamicDims(model_id, combined_batch) != SUCCESS) { + GELOGE(FAILED, "Get combined dynamic dims info failed."); + return FAILED; + } + if (combined_batch.empty()) { + GELOGE(FAILED, "Combined dynamic dims is empty."); + return FAILED; + } + + if (combined_dims.size() != combined_batch[0].size()) { + GELOGE(FAILED, "Input dynamic dims's dimension size[%zu] is different from model[%zu].", combined_dims.size(), + combined_batch[0].size()); + return FAILED; + } + bool matched = false; + size_t idx = 0; + for (size_t i = 0; i < combined_batch.size(); i++) { + bool is_match = true; + for (size_t j = 0; j < combined_dims.size(); j++) { + if (combined_dims[j] != static_cast(combined_batch[i][j])) { + is_match = false; + break; + } + } + if (is_match) { + idx = i; + matched = true; + break; + } + } + + if (!matched) { + GELOGE(FAILED, "Input dynamic dims can not match model."); + return FAILED; + } + + // batch_info save the dynamic info of combined_dims + vector> batch_info; + int32_t dynamic_type = static_cast(FIXED); + if (GraphExecutor::GetDynamicBatchInfo(model_id, batch_info, dynamic_type) != SUCCESS) { + GELOGE(FAILED, "Get dynamic input info failed."); + return FAILED; + } + + cur_dynamic_dims.clear(); + for (size_t i = 0; i < batch_info[idx].size(); i++) { + cur_dynamic_dims.emplace_back(static_cast(batch_info[idx][i])); + } + + return SUCCESS; +} + +Status GeExecutor::GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type) { GELOGI("Begin to get current shape"); if (!isInit_) { GELOGE(GE_EXEC_NOT_INIT, "GeExecutor has not been initialized!"); return GE_EXEC_NOT_INIT; } - Status ret = GraphExecutor::GetCurShape(model_id, batch_info); + Status ret = GraphExecutor::GetCurShape(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { - GELOGE(FAILED, "Get current shape failed"); - return FAILED; + GELOGE(ret, "Get current shape failed"); + return ret; } return SUCCESS; } @@ -330,12 +446,12 @@ Status GeExecutor::SetDynamicAippData(uint32_t model_id, void *dynamic_input_add const kAippDynamicPara &aippParms) { GELOGI("Enter to SetDynamicAippData."); if (dynamic_input_addr == nullptr) { - GELOGE(FAILED, "Dynamic aipp input addr is nullptr!"); - return FAILED; + GELOGE(PARAM_INVALID, "Dynamic aipp input addr is nullptr!"); + return PARAM_INVALID; } if (aippBatchPara.empty()) { - GELOGE(FAILED, "aippBatchPara is empty."); - return FAILED; + GELOGE(PARAM_INVALID, "aippBatchPara is empty."); + return PARAM_INVALID; } uint64_t batch_num = aippBatchPara.size(); uint64_t real_aippParms_size = sizeof(kAippDynamicPara) - sizeof(kAippDynamicBatchPara); @@ -345,24 +461,25 @@ Status GeExecutor::SetDynamicAippData(uint32_t model_id, void *dynamic_input_add "batch num is %lu, struct_len is %lu", model_id, length, batch_num, struct_len); if (struct_len > length) { - GELOGE(FAILED, "input dynamic aipp param len [%lu] is larger than aipp_data size [%lu]", struct_len, length); - return FAILED; + GELOGE(PARAM_INVALID, "input dynamic aipp param len [%lu] is larger than aipp_data size [%lu]", struct_len, length); + return PARAM_INVALID; } // Memcpy real kAippDynamicBatchPara from host to device - if (rtMemcpy(dynamic_input_addr, length, &aippParms, real_aippParms_size, RT_MEMCPY_HOST_TO_DEVICE) != - RT_ERROR_NONE) { - GELOGE(FAILED, "memcpy real_aippParms_size failed!"); - return FAILED; + rtError_t rt_ret = rtMemcpy(dynamic_input_addr, length, &aippParms, real_aippParms_size, RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "memcpy real_aippParms_size failed! ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } uint64_t remain_len = length - real_aippParms_size; uint8_t *aipp_batch_para_dev = reinterpret_cast(dynamic_input_addr) + real_aippParms_size; for (uint64_t i = 0; i < batch_num; ++i) { - if (rtMemcpy(reinterpret_cast(aipp_batch_para_dev + i * sizeof(kAippDynamicBatchPara)), - (remain_len - i * sizeof(kAippDynamicBatchPara)), &(aippBatchPara[i]), sizeof(kAippDynamicBatchPara), - RT_MEMCPY_HOST_TO_DEVICE) != RT_ERROR_NONE) { - GELOGE(FAILED, "memcpy kAippDynamicBatchPara input data failed!"); - return FAILED; + rt_ret = rtMemcpy(reinterpret_cast(aipp_batch_para_dev + i * sizeof(kAippDynamicBatchPara)), + (remain_len - i * sizeof(kAippDynamicBatchPara)), &(aippBatchPara[i]), + sizeof(kAippDynamicBatchPara), RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "memcpy kAippDynamicBatchPara input data failed! ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } } return SUCCESS; @@ -429,7 +546,7 @@ Status GeExecutor::UnloadModel(uint32_t model_id) { } Status ret = GraphLoader::DestroyAicpuSessionForInfer(model_id); if (ret != SUCCESS) { - GELOGE(ret, "[GraphLoader] DestroyAicpuSessionForInfer failed."); + GELOGE(ret, "[GraphLoader] DestroyAicpuSessionForInfer failed. model id: %u", model_id); return FAILED; } return GraphLoader::UnloadModel(model_id); @@ -468,17 +585,19 @@ Status GeExecutor::GetModelDescInfo(uint32_t model_id, std::vector> &batch_info) { +Status GeExecutor::GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type) { GELOGI("Begin to get dynamic batch info."); if (!isInit_) { GELOGE(GE_EXEC_NOT_INIT, "GeExecutor has not been initialized!"); return GE_EXEC_NOT_INIT; } - Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info); + Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { GELOGE(ret, "GetDynamicBatchInfo failed."); return ret; @@ -515,6 +636,30 @@ Status GeExecutor::GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info) { + GELOGI("Begin to get combined dynamic dims info."); + if (!isInit_) { + GELOGE(GE_EXEC_NOT_INIT, "GeExecutor has not been initialized!"); + return GE_EXEC_NOT_INIT; + } + + Status ret = GraphExecutor::GetCombinedDynamicDims(model_id, batch_info); + if (ret != SUCCESS) { + GELOGE(ret, "GetCombinedDynamicDims failed."); + return ret; + } + + GELOGI("Get combined dynamic dims succ."); + return SUCCESS; +} + +/// +/// @ingroup ge /// @brief Get AIPP input format /// @param [in] model_id /// @param [in] index @@ -628,8 +773,8 @@ Status GeExecutor::LoadDataFromFile(const std::string &path, ModelData &model_da string filePath = RealPath(path.c_str()); if (filePath.empty()) { - GELOGE(ge::FAILED, "File path is invalid. please check your text file '%s'.", path.c_str()); - return ge::FAILED; + GELOGE(GE_EXEC_MODEL_PATH_INVALID, "File path is invalid. please check your text file '%s'.", path.c_str()); + return GE_EXEC_MODEL_PATH_INVALID; } GELOGI("load modelData from file: %s.", path.c_str()); std::string key_path; @@ -710,12 +855,20 @@ Status GeExecutor::ExecModel(uint32_t model_id, void *stream, const ge::RunModel GetDomiOutputData(run_output_data, output_data); if ((run_input_data.dynamic_batch_size != 0) || (run_input_data.dynamic_image_width != 0) || - (run_input_data.dynamic_image_height != 0)) { + (run_input_data.dynamic_image_height != 0) || (run_input_data.dynamic_dims.size() != 0)) { std::vector> batch_info; - Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info); + int32_t dynamic_type = static_cast(FIXED); + Status ret = GraphExecutor::GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { - GELOGE(FAILED, "Get dynamic input info failed."); - return FAILED; + GELOGE(ret, "Get dynamic input info failed."); + return ret; + } + if (dynamic_type == static_cast(DYNAMIC_DIMS)) { + ret = GraphExecutor::GetCombinedDynamicDims(model_id, batch_info); + if (ret != SUCCESS) { + GELOGE(FAILED, "Get dynamic input info failed."); + return FAILED; + } } if (!batch_info.empty()) { SetDynamicInputDataFlag(run_input_data, batch_info, input_data); @@ -790,6 +943,11 @@ Status GeExecutor::LoadSingleOp(const std::string &model_name, const ge::ModelDa return SingleOpManager::GetInstance().GetOpFromModel(model_name, modelData, stream, single_op); } +Status GeExecutor::LoadDynamicSingleOp(const std::string &model_name, const ge::ModelData &modelData, void *stream, + DynamicSingleOp **single_op) { + return SingleOpManager::GetInstance().GetDynamicOpFromModel(model_name, modelData, stream, single_op); +} + Status GeExecutor::ExecuteAsync(SingleOp *executor, const std::vector &inputs, std::vector &outputs) { if (executor == nullptr) { @@ -800,13 +958,21 @@ Status GeExecutor::ExecuteAsync(SingleOp *executor, const std::vectorExecuteAsync(inputs, outputs); } +ge::Status GeExecutor::ExecuteAsync(DynamicSingleOp *executor, const vector &input_desc, + const vector &inputs, vector &output_desc, + vector &outputs) { + GE_CHECK_NOTNULL(executor); + return executor->ExecuteAsync(input_desc, inputs, output_desc, outputs); +} + Status GeExecutor::ReleaseSingleOpResource(void *stream) { return SingleOpManager::GetInstance().ReleaseResource(stream); } Status GeExecutor::GetBatchInfoSize(uint32_t model_id, size_t &shape_count) { std::vector> batch_info; - Status ret = GetDynamicBatchInfo(model_id, batch_info); + int32_t dynamic_type = static_cast(FIXED); + Status ret = GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { GELOGE(ret, "Calc batch info size failed. ret = %d", ret); return ret; @@ -854,5 +1020,4 @@ Status GeExecutor::GetAllAippInputOutputDims(uint32_t model_id, uint32_t index, GELOGI("GetAllAippInputOutputDims succ."); return SUCCESS; } - } // namespace ge diff --git a/src/ge/executor/module.mk b/src/ge/executor/module.mk index efed8854..b19f3c24 100644 --- a/src/ge/executor/module.mk +++ b/src/ge/executor/module.mk @@ -4,6 +4,7 @@ local_ge_executor_src_files := \ ge_executor.cc \ ../common/profiling/profiling_manager.cc \ ../common/ge/plugin_manager.cc \ + ../common/ge/op_tiling_manager.cc \ ../graph/load/graph_loader.cc \ ../graph/execute/graph_execute.cc \ ../omm/csa_interact.cc \ @@ -25,6 +26,7 @@ local_ge_executor_src_files := \ ../graph/load/new_model_manager/data_inputer.cc \ ../graph/load/new_model_manager/data_dumper.cc \ ../graph/load/new_model_manager/zero_copy_task.cc \ + ../graph/load/new_model_manager/zero_copy_offset.cc \ ../graph/load/new_model_manager/task_info/task_info.cc \ ../graph/load/new_model_manager/task_info/event_record_task_info.cc \ ../graph/load/new_model_manager/task_info/event_wait_task_info.cc \ @@ -44,7 +46,6 @@ local_ge_executor_src_files := \ ../graph/load/new_model_manager/task_info/end_graph_task_info.cc \ ../graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc \ ../graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc \ - ../graph/load/output/output.cc \ ../single_op/single_op_manager.cc \ ../single_op/single_op_model.cc \ ../single_op/single_op.cc \ @@ -53,6 +54,7 @@ local_ge_executor_src_files := \ ../single_op/task/build_task_utils.cc \ ../single_op/task/tbe_task_builder.cc \ ../single_op/task/aicpu_task_builder.cc \ + ../single_op/task/aicpu_kernel_task_builder.cc \ ../hybrid/hybrid_davinci_model_stub.cc\ local_ge_executor_c_include := \ @@ -78,6 +80,7 @@ local_ge_executor_shared_library := \ libslog \ libmmpa \ libgraph \ + libregister \ libmsprof \ local_ge_executor_ldflags := -lrt -ldl \ @@ -127,6 +130,7 @@ LOCAL_SHARED_LIBRARIES := \ libslog \ libmmpa \ libgraph \ + libregister \ libmsprof \ LOCAL_LDFLAGS += $(local_ge_executor_ldflags) @@ -152,6 +156,7 @@ LOCAL_C_INCLUDES := $(local_ge_executor_c_include) LOCAL_STATIC_LIBRARIES := \ libge_common \ libgraph \ + libregister \ libprotobuf \ LOCAL_SHARED_LIBRARIES := \ @@ -183,6 +188,7 @@ LOCAL_C_INCLUDES := $(local_ge_executor_c_include) LOCAL_STATIC_LIBRARIES := \ libge_common \ libgraph \ + libregister \ libprotobuf \ LOCAL_SHARED_LIBRARIES := \ diff --git a/src/ge/ge_inference.mk b/src/ge/ge_inference.mk index 2b26b214..e3e1e10c 100644 --- a/src/ge/ge_inference.mk +++ b/src/ge/ge_inference.mk @@ -32,6 +32,7 @@ COMMON_LOCAL_SRC_FILES := \ GRAPH_MANAGER_LOCAL_SRC_FILES := \ common/ge/plugin_manager.cc\ + common/ge/op_tiling_manager.cc\ init/gelib.cc \ session/inner_session.cc \ session/session_manager.cc \ @@ -45,6 +46,7 @@ GRAPH_MANAGER_LOCAL_SRC_FILES := \ graph/execute/graph_execute.cc \ graph/load/graph_loader.cc \ graph/optimize/graph_optimize.cc \ + graph/optimize/mem_rw_conflict_optimize.cc \ graph/optimize/summary_optimize.cc \ graph/build/graph_builder.cc \ graph/partition/engine_place.cc \ @@ -69,6 +71,7 @@ OMG_HOST_SRC_FILES := \ graph/passes/resource_pair_remove_control_pass.cc \ graph/passes/pass_utils.cc \ graph/passes/base_pass.cc \ + graph/passes/bitcast_pass.cc \ graph/passes/constant_folding_pass.cc \ graph/passes/aicpu_constant_folding_pass.cc \ graph/passes/reshape_remove_pass.cc \ @@ -90,7 +93,10 @@ OMG_HOST_SRC_FILES := \ graph/passes/print_op_pass.cc \ graph/passes/no_use_reshape_remove_pass.cc \ graph/passes/iterator_op_pass.cc \ + graph/passes/input_output_connection_identify_pass.cc \ graph/passes/atomic_addr_clean_pass.cc \ + graph/passes/mark_same_addr_pass.cc \ + graph/passes/mark_graph_unknown_status_pass.cc \ graph/common/omg_util.cc \ graph/common/bcast.cc \ graph/passes/dimension_compute_pass.cc \ @@ -105,6 +111,7 @@ OMG_HOST_SRC_FILES := \ graph/passes/isolated_op_remove_pass.cc \ graph/passes/permute_pass.cc \ graph/passes/ctrl_edge_transfer_pass.cc \ + graph/passes/end_of_sequence_add_control_pass.cc \ host_kernels/broadcast_gradient_args_kernel.cc \ host_kernels/greater_kernel.cc \ host_kernels/gather_v2_kernel.cc \ @@ -145,6 +152,7 @@ OMG_HOST_SRC_FILES := \ graph/passes/stop_gradient_pass.cc \ graph/passes/prevent_gradient_pass.cc \ graph/passes/identity_pass.cc \ + graph/passes/ref_identity_delete_op_pass.cc \ graph/passes/placeholder_with_default_pass.cc \ graph/passes/snapshot_pass.cc \ graph/passes/guarantee_const_pass.cc \ @@ -153,7 +161,9 @@ OMG_HOST_SRC_FILES := \ graph/passes/folding_pass.cc \ graph/passes/cast_translate_pass.cc \ graph/passes/prune_pass.cc \ - graph/passes/switch_op_pass.cc \ + graph/passes/merge_to_stream_merge_pass.cc \ + graph/passes/switch_to_stream_switch_pass.cc \ + graph/passes/attach_stream_label_pass.cc \ graph/passes/multi_batch_pass.cc \ graph/passes/next_iteration_pass.cc \ graph/passes/control_trigger_pass.cc \ @@ -173,7 +183,6 @@ OMG_HOST_SRC_FILES := \ graph/passes/variable_op_pass.cc \ graph/passes/cast_remove_pass.cc \ graph/passes/transpose_transdata_pass.cc \ - graph/passes/identify_reference_pass.cc \ graph/passes/hccl_memcpy_pass.cc \ graph/passes/flow_ctrl_pass.cc \ graph/passes/link_gen_mask_nodes_pass.cc \ @@ -181,6 +190,8 @@ OMG_HOST_SRC_FILES := \ graph/passes/hccl_group_pass.cc \ graph/passes/switch_fusion_pass.cc \ graph/passes/switch_split_pass.cc \ + graph/passes/memcpy_addr_async_pass.cc \ + graph/passes/set_input_output_offset_pass.cc \ OMG_DEVICE_SRC_FILES := $(OMG_HOST_SRC_FILES) @@ -199,7 +210,7 @@ OME_HOST_SRC_FILES := \ graph/load/new_model_manager/tbe_handle_store.cc \ graph/load/new_model_manager/cpu_queue_schedule.cc \ graph/load/new_model_manager/zero_copy_task.cc \ - graph/load/output/output.cc \ + graph/load/new_model_manager/zero_copy_offset.cc \ graph/load/new_model_manager/data_dumper.cc \ graph/load/new_model_manager/task_info/task_info.cc \ graph/load/new_model_manager/task_info/event_record_task_info.cc \ @@ -224,6 +235,7 @@ OME_HOST_SRC_FILES := \ single_op/task/build_task_utils.cc \ single_op/task/tbe_task_builder.cc \ single_op/task/aicpu_task_builder.cc \ + single_op/task/aicpu_kernel_task_builder.cc \ single_op/single_op.cc \ single_op/single_op_model.cc \ single_op/stream_resource.cc \ @@ -368,7 +380,7 @@ endif LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) -LOCAL_SRC_FILES := ../../out/atc/lib64/stub/ge_ir_build.cc +LOCAL_SRC_FILES := ../../out/ge/lib64/stub/ge_ir_build.cc LOCAL_SHARED_LIBRARIES := diff --git a/src/ge/ge_local_engine/ops_kernel_store/op/ge_deleted_op.cc b/src/ge/ge_local_engine/ops_kernel_store/op/ge_deleted_op.cc index 0f33ae2a..badca5a3 100644 --- a/src/ge/ge_local_engine/ops_kernel_store/op/ge_deleted_op.cc +++ b/src/ge/ge_local_engine/ops_kernel_store/op/ge_deleted_op.cc @@ -61,5 +61,6 @@ REGISTER_OP_CREATOR(SwitchN, GeDeletedOp); REGISTER_OP_CREATOR(RefMerge, GeDeletedOp); REGISTER_OP_CREATOR(RefSwitch, GeDeletedOp); REGISTER_OP_CREATOR(TransShape, GeDeletedOp); +REGISTER_OP_CREATOR(Bitcast, GeDeletedOp); } // namespace ge_local } // namespace ge diff --git a/src/ge/ge_runner.mk b/src/ge/ge_runner.mk index a9cfdd82..a3119b50 100644 --- a/src/ge/ge_runner.mk +++ b/src/ge/ge_runner.mk @@ -23,6 +23,7 @@ LIBGE_LOCAL_SRC_FILES := \ common/formats/utils/formats_trans_utils.cc \ common/fp16_t.cc \ common/ge/plugin_manager.cc\ + common/ge/op_tiling_manager.cc\ common/helper/model_cache_helper.cc \ common/profiling/profiling_manager.cc \ engine_manager/dnnengine_manager.cc \ @@ -77,7 +78,7 @@ LIBGE_LOCAL_SRC_FILES := \ graph/load/new_model_manager/task_info/task_info.cc \ graph/load/new_model_manager/tbe_handle_store.cc \ graph/load/new_model_manager/zero_copy_task.cc \ - graph/load/output/output.cc \ + graph/load/new_model_manager/zero_copy_offset.cc \ graph/manager/graph_context.cc \ graph/manager/graph_manager.cc \ graph/manager/graph_manager_utils.cc \ @@ -91,6 +92,7 @@ LIBGE_LOCAL_SRC_FILES := \ graph/manager/util/rt_context_util.cc \ graph/manager/util/variable_accelerate_ctrl.cc \ graph/optimize/graph_optimize.cc \ + graph/optimize/mem_rw_conflict_optimize.cc \ graph/optimize/optimizer/allreduce_fusion_pass.cc \ graph/optimize/summary_optimize.cc \ graph/partition/engine_place.cc \ @@ -98,9 +100,13 @@ LIBGE_LOCAL_SRC_FILES := \ graph/passes/addn_pass.cc \ graph/passes/aicpu_constant_folding_pass.cc \ graph/passes/assert_pass.cc \ + graph/passes/input_output_connection_identify_pass.cc \ graph/passes/atomic_addr_clean_pass.cc \ + graph/passes/mark_same_addr_pass.cc \ + graph/passes/mark_graph_unknown_status_pass.cc \ graph/partition/dynamic_shape_partition.cc \ graph/passes/base_pass.cc \ + graph/passes/bitcast_pass.cc \ graph/passes/cast_remove_pass.cc \ graph/passes/cast_translate_pass.cc \ graph/passes/common_subexpression_elimination_pass.cc \ @@ -158,8 +164,8 @@ LIBGE_LOCAL_SRC_FILES := \ graph/passes/get_original_format_pass.cc \ graph/passes/guarantee_const_pass.cc \ graph/passes/hccl_memcpy_pass.cc \ - graph/passes/identify_reference_pass.cc \ graph/passes/identity_pass.cc \ + graph/passes/ref_identity_delete_op_pass.cc \ graph/passes/infershape_pass.cc \ graph/passes/isolated_op_remove_pass.cc \ graph/passes/iterator_op_pass.cc \ @@ -191,7 +197,9 @@ LIBGE_LOCAL_SRC_FILES := \ graph/passes/data_pass.cc \ graph/passes/switch_data_edges_bypass.cc \ graph/passes/switch_logic_remove_pass.cc \ - graph/passes/switch_op_pass.cc \ + graph/passes/merge_to_stream_merge_pass.cc \ + graph/passes/switch_to_stream_switch_pass.cc \ + graph/passes/attach_stream_label_pass.cc \ graph/passes/switch_dead_branch_elimination.cc \ graph/passes/replace_transshape_pass.cc \ graph/passes/transop_breadth_fusion_pass.cc \ @@ -211,6 +219,9 @@ LIBGE_LOCAL_SRC_FILES := \ graph/passes/variable_prepare_op_pass.cc \ graph/passes/variable_ref_delete_op_pass.cc \ graph/passes/variable_ref_useless_control_out_delete_pass.cc \ + graph/passes/end_of_sequence_add_control_pass.cc \ + graph/passes/memcpy_addr_async_pass.cc \ + graph/passes/set_input_output_offset_pass.cc \ graph/preprocess/graph_preprocess.cc \ graph/preprocess/insert_op/ge_aipp_op.cc \ graph/preprocess/insert_op/util_insert_aipp_op.cc \ @@ -230,6 +241,7 @@ LIBGE_LOCAL_SRC_FILES := \ single_op/task/op_task.cc \ single_op/task/tbe_task_builder.cc \ single_op/task/aicpu_task_builder.cc \ + single_op/task/aicpu_kernel_task_builder.cc \ hybrid/common/tensor_value.cc \ hybrid/common/npu_memory_allocator.cc \ hybrid/executor/rt_callback_manager.cc \ @@ -239,12 +251,15 @@ LIBGE_LOCAL_SRC_FILES := \ hybrid/executor/hybrid_model_executor.cc \ hybrid/executor/hybrid_model_async_executor.cc \ hybrid/executor/hybrid_execution_context.cc \ + hybrid/executor/subgraph_context.cc \ + hybrid/executor/subgraph_executor.cc \ hybrid/executor/worker/task_compile_engine.cc \ hybrid/executor/worker/shape_inference_engine.cc \ hybrid/executor/worker/execution_engine.cc \ hybrid/model/hybrid_model.cc \ hybrid/model/hybrid_model_builder.cc \ hybrid/model/node_item.cc \ + hybrid/model/graph_item.cc \ hybrid/node_executor/aicore/aicore_node_executor.cc \ hybrid/node_executor/aicore/aicore_op_task.cc \ hybrid/node_executor/aicore/aicore_task_builder.cc \ @@ -253,6 +268,9 @@ LIBGE_LOCAL_SRC_FILES := \ hybrid/node_executor/aicpu/aicpu_node_executor.cc \ hybrid/node_executor/compiledsubgraph/known_node_executor.cc \ hybrid/node_executor/hostcpu/ge_local_node_executor.cc \ + hybrid/node_executor/controlop/control_op_executor.cc \ + hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc \ + hybrid/node_executor/hccl/hccl_node_executor.cc \ hybrid/node_executor/node_executor.cc \ hybrid/node_executor/task_context.cc \ hybrid/hybrid_davinci_model.cc \ @@ -338,6 +356,28 @@ LOCAL_SHARED_LIBRARIES += \ include $(BUILD_HOST_SHARED_LIBRARY) +#compiler for GeRunner +include $(CLEAR_VARS) + +LOCAL_MODULE := stub/libge_runner + +LOCAL_CFLAGS += -DPROTOBUF_INLINE_NOT_IN_HEADERS=0 -DREUSE_MEMORY=1 -O2 +LOCAL_CFLAGS += -DFMK_SUPPORT_DUMP -DDAVINCI_SUPPORT_PROFILING -DDAVINCI_CLOUD +ifeq ($(DEBUG), 1) +LOCAL_CFLAGS += -g -O0 +endif + + +LOCAL_C_INCLUDES := $(RUNNER_LOCAL_C_INCLUDES) + +LOCAL_SRC_FILES := ../../out/ge/lib64/stub/ge_api.cc + + +LOCAL_SHARED_LIBRARIES := + +LOCAL_LDFLAGS := -lrt -ldl + +include $(BUILD_HOST_SHARED_LIBRARY) # add engine_conf.json to host include $(CLEAR_VARS) @@ -407,6 +447,7 @@ LOCAL_CFLAGS += -DFMK_SUPPORT_DUMP -DDAVINCI_SUPPORT_PROFILING -DDAVINCI_CLOUD LOCAL_CFLAGS += -g -O0 LOCAL_C_INCLUDES := $(RUNNER_LOCAL_C_INCLUDES) + LOCAL_SRC_FILES := $(LIBGE_LOCAL_SRC_FILES) LOCAL_SRC_FILES += $(LIBCLIENT_LOCAL_SRC_FILES) diff --git a/src/ge/ge_runtime/model_runner.cc b/src/ge/ge_runtime/model_runner.cc index 59952e39..9961ab4e 100644 --- a/src/ge/ge_runtime/model_runner.cc +++ b/src/ge/ge_runtime/model_runner.cc @@ -49,6 +49,24 @@ bool ModelRunner::LoadDavinciModel(uint32_t device_id, uint64_t session_id, uint return true; } +bool ModelRunner::DistributeTask(uint32_t model_id) { + auto model_iter = runtime_models_.find(model_id); + if (model_iter == runtime_models_.end()) { + GELOGE(PARAM_INVALID, "Model id %u not found.", model_id); + return false; + } + return model_iter->second->DistributeTask(); +} + +bool ModelRunner::LoadModelComplete(uint32_t model_id) { + auto model_iter = runtime_models_.find(model_id); + if (model_iter == runtime_models_.end()) { + GELOGE(PARAM_INVALID, "Model id %u not found.", model_id); + return false; + } + return model_iter->second->LoadComplete(); +} + const std::vector &ModelRunner::GetTaskIdList(uint32_t model_id) const { auto model_iter = runtime_models_.find(model_id); if (model_iter == runtime_models_.end()) { @@ -60,6 +78,38 @@ const std::vector &ModelRunner::GetTaskIdList(uint32_t model_id) const return model_iter->second->GetTaskIdList(); } +const std::vector &ModelRunner::GetStreamIdList(uint32_t model_id) const { + auto model_iter = runtime_models_.find(model_id); + if (model_iter == runtime_models_.end()) { + GELOGE(PARAM_INVALID, "Model id %u not found.", model_id); + static const std::vector empty_ret; + return empty_ret; + } + + return model_iter->second->GetStreamIdList(); +} + +const std::map> &ModelRunner::GetRuntimeInfoMap(uint32_t model_id) const { + auto model_iter = runtime_models_.find(model_id); + if (model_iter == runtime_models_.end()) { + GELOGW("Model id %u not found.", model_id); + static const std::map> empty_ret; + return empty_ret; + } + + return model_iter->second->GetRuntimeInfoMap(); +} + +void *ModelRunner::GetModelHandle(uint32_t model_id) const { + auto model_iter = runtime_models_.find(model_id); + if (model_iter == runtime_models_.end()) { + GELOGW("Model id %u not found.", model_id); + return nullptr; + } + + return model_iter->second->GetModelHandle(); +} + bool ModelRunner::UnloadModel(uint32_t model_id) { auto iter = runtime_models_.find(model_id); if (iter != runtime_models_.end()) { diff --git a/src/ge/ge_runtime/output.cc b/src/ge/ge_runtime/output.cc index 90c33bb4..5153f688 100644 --- a/src/ge/ge_runtime/output.cc +++ b/src/ge/ge_runtime/output.cc @@ -76,7 +76,7 @@ bool Output::CopyRslt(OutputData *rslt, uint32_t data_begin, uint32_t &data_inde DataBuffer data_buf = rslt->blobs[data_begin + data_count]; bool ret = SetDataBuf(data_buf, data_begin, data_count, i, support_mem_share); if (!ret) { - GELOGE(FAILED, "Copy data to host failed. index: %lu, addr: %p", i, v_input_data_addr_[i]); + GELOGE(FAILED, "Copy data to host error. index: %lu, addr: %p", i, v_input_data_addr_[i]); return ret; } data_index = data_begin + data_count; diff --git a/src/ge/ge_runtime/runtime_model.cc b/src/ge/ge_runtime/runtime_model.cc index c89ced91..f0405056 100644 --- a/src/ge/ge_runtime/runtime_model.cc +++ b/src/ge/ge_runtime/runtime_model.cc @@ -28,7 +28,6 @@ namespace ge { namespace model_runner { - RuntimeModel::~RuntimeModel() { GELOGI("RuntimeModel destructor start"); @@ -116,23 +115,34 @@ bool RuntimeModel::InitEvent(uint32_t event_num) { return true; } -bool RuntimeModel::InitLabel(uint32_t batch_num) { - GELOGI("batch number:%u.", batch_num); - for (uint32_t i = 0; (batch_num != 0 && i <= batch_num); ++i) { - rtLabel_t rt_lLabel = nullptr; - rtError_t rt_ret = rtLabelCreate(&rt_lLabel); - if (rt_ret != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt api rtLabelCreate failed, i; %u; ret: 0x%X", i, rt_ret); - return false; +bool RuntimeModel::InitLabel(std::shared_ptr &davinci_model) { + GELOGI("batch number:%u.", davinci_model->GetBatchNum()); + label_list_.resize(davinci_model->GetBatchNum()); + for (auto &task_info : davinci_model->GetTaskInfoList()) { + if (task_info == nullptr) { + GELOGE(PARAM_INVALID, "task_info is null."); + continue; } - if (rt_lLabel == nullptr) { - GELOGE(RT_FAILED, "rtLabel is nullptr!"); + if (task_info->type() != TaskInfoType::LABEL_SET) { + continue; + } + auto label_set_task_info = std::static_pointer_cast(task_info); + + if (label_set_task_info->stream_id() >= stream_list_.size()) { + GELOGE(PARAM_INVALID, "Invalid stream id."); return false; } - label_list_.emplace_back(rt_lLabel); + rtLabel_t rt_label = nullptr; + rtError_t rt_ret = rtLabelCreateEx(&rt_label, stream_list_[label_set_task_info->stream_id()]); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api rtLabelCreate failed, ret: 0x%X", rt_ret); + return false; + } + label_list_[label_set_task_info->label_id()] = rt_label; } + return true; } @@ -164,7 +174,7 @@ bool RuntimeModel::InitResource(std::shared_ptr &davinci_model) { return false; } - if (!InitLabel(davinci_model->GetBatchNum())) { + if (!InitLabel(davinci_model)) { return false; } @@ -209,20 +219,41 @@ bool RuntimeModel::LoadTask() { return false; } task_id_list_.push_back(task_id); + stream_id_list_.push_back(stream_id); + if (task->Args() != nullptr) { + std::shared_ptr runtime_tuple = nullptr; + GE_MAKE_SHARED(runtime_tuple = std::make_shared(task_id, stream_id, task->Args()), return false); + auto emplace_ret = runtime_info_map_.emplace(task->task_name(), runtime_tuple); + if (!emplace_ret.second) { + GELOGW("Task name exist:%s", task->task_name().c_str()); + } + } } if (task_list_.empty()) { GELOGE(FAILED, "Task list is empty"); return false; } - GELOGI("Distribute task succ."); - auto rt_ret = rtModelLoadComplete(rt_model_handle_); + GELOGI("LoadTask succ."); + return true; +} + +bool RuntimeModel::LoadComplete() { + uint32_t task_id = 0; + uint32_t stream_id = 0; + auto rt_ret = rtModelGetTaskId(rt_model_handle_, &task_id, &stream_id); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rtModelGetTaskId failed, ret:0x%X", rt_ret); + return RT_FAILED; + } + task_id_list_.push_back(task_id); + stream_id_list_.push_back(stream_id); + + rt_ret = rtModelLoadComplete(rt_model_handle_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api rtModelLoadComplete failed, ret: 0x%X.", rt_ret); return false; } - - GELOGI("LoadTask succ."); return true; } @@ -252,14 +283,16 @@ bool RuntimeModel::Load(uint32_t device_id, uint64_t session_id, std::shared_ptr } GenerateTask(device_id, session_id, davinci_model); + return status; +} - status = LoadTask(); +bool RuntimeModel::DistributeTask() { + bool status = LoadTask(); if (!status) { GELOGE(FAILED, "DistributeTask failed"); - return status; + return false; } - - return status; + return true; } bool RuntimeModel::Run() { @@ -270,10 +303,14 @@ bool RuntimeModel::Run() { return false; } - GELOGI("Run rtModelExecute success"); + GELOGI("Run rtModelExecute success, ret = 0x%X", ret); ret = rtStreamSynchronize(rt_model_stream_); if (ret != RT_ERROR_NONE) { + if (ret == RT_ERROR_END_OF_SEQUENCE) { + GELOGI("Model stream RT_ERROR_END_OF_SEQUENCE signal received, ret = 0x%X", ret); + return true; + } GELOGE(RT_FAILED, "Model stream sync failed, ret = 0x%X", ret); return false; } @@ -433,7 +470,7 @@ bool RuntimeModel::InitConstantInfo(std::shared_ptr &davinci_model } if (constant->output_tensors[0].size < constant->weight_data.size()) { - GELOGE(PARAM_INVALID, "Output size:%u is less than weight data size:%zu", constant->output_tensors[0].size, + GELOGE(PARAM_INVALID, "Output size:%u less than weight data size:%zu", constant->output_tensors[0].size, constant->weight_data.size()); return false; } @@ -448,11 +485,8 @@ bool RuntimeModel::InitConstantInfo(std::shared_ptr &davinci_model /// The logic of GetShapeSize is wrong, the scaler tensor's GetShapeSize is zero /// and that of unknown shape is zero too. /// Unknown shape will not appear here, so we can use zero judge a tensor is scaler or not. - int64_t elem_num = constant->weight_tensors[0].GetShapeSize(); - if (elem_num == 0 && constant->weight_tensors[0].size == 0) { - elem_num = 1; - } - + int64_t elem_num = + (constant->weight_tensors[0].GetShapeSize() == 0) ? 1 : constant->weight_tensors[0].GetShapeSize(); if (constant->weight_data.size() < sizeof(uint64_t)) { GELOGE(FAILED, "weight_data size is smaller than sizeof(uint64_t)"); return false; @@ -495,5 +529,6 @@ void RuntimeModel::CreateOutput(uint32_t index, const OpInfo &op_info, InputOutp const std::vector &RuntimeModel::GetTaskIdList() const { return task_id_list_; } +const std::vector &RuntimeModel::GetStreamIdList() const { return stream_id_list_; } } // namespace model_runner } // namespace ge diff --git a/src/ge/ge_runtime/runtime_model.h b/src/ge/ge_runtime/runtime_model.h index e8ff4057..d0c466d4 100644 --- a/src/ge/ge_runtime/runtime_model.h +++ b/src/ge/ge_runtime/runtime_model.h @@ -27,7 +27,7 @@ namespace ge { namespace model_runner { - +using RuntimeInfo = std::tuple; class Task; class RuntimeModel { public: @@ -35,7 +35,12 @@ class RuntimeModel { ~RuntimeModel(); bool Load(uint32_t device_id, uint64_t session_id, std::shared_ptr &davinci_model); + bool DistributeTask(); + bool LoadComplete(); const std::vector &GetTaskIdList() const; + const std::vector &GetStreamIdList() const; + const std::map> &GetRuntimeInfoMap() const { return runtime_info_map_; } + rtModel_t GetModelHandle() const { return rt_model_handle_; } bool Run(); bool CopyInputData(const InputData &input_data); bool GetInputOutputDescInfo(bool zero_copy, std::vector *input_desc, @@ -48,7 +53,7 @@ class RuntimeModel { bool LoadTask(); bool InitStream(std::shared_ptr &davinci_model); bool InitEvent(uint32_t event_num); - bool InitLabel(uint32_t batch_num); + bool InitLabel(std::shared_ptr &davinci_model); bool InitDataInfo(std::shared_ptr &davinci_model); bool InitOutputInfo(std::shared_ptr &davinci_model); bool InitConstantInfo(std::shared_ptr &davinci_model); @@ -77,6 +82,8 @@ class RuntimeModel { std::vector> constant_info_list_{}; std::vector task_id_list_{}; + std::vector stream_id_list_{}; + std::map> runtime_info_map_; }; } // namespace model_runner diff --git a/src/ge/ge_runtime/task/aicpu_task.cc b/src/ge/ge_runtime/task/aicpu_task.cc index 4cb71866..9b126ec0 100644 --- a/src/ge/ge_runtime/task/aicpu_task.cc +++ b/src/ge/ge_runtime/task/aicpu_task.cc @@ -85,11 +85,15 @@ bool AicpuTask::Distribute() { return false; } - GELOGI("Distribute AicpuTask start, args_size = %u, io_addrs_num = %u, so_name = %s, kernel_name = %s.", args_size, - io_addrs_num, task_info_->so_name().data(), task_info_->kernel_name().data()); - rt_ret = rtCpuKernelLaunch(reinterpret_cast(task_info_->so_name().data()), - reinterpret_cast(task_info_->kernel_name().data()), 1, args_, args_size, - nullptr, stream_); + input_output_addr_ = reinterpret_cast(reinterpret_cast(args_) + io_addr_offset); + + auto dump_flag = task_info_->dump_flag() ? RT_KERNEL_DUMPFLAG : RT_KERNEL_DEFAULT; + GELOGI( + "Distribute AicpuTask start, args_size = %u, io_addrs_num = %u, so_name = %s, kernel_name = %s, dump_flag = %d.", + args_size, io_addrs_num, task_info_->so_name().data(), task_info_->kernel_name().data(), dump_flag); + rt_ret = rtCpuKernelLaunchWithFlag(reinterpret_cast(task_info_->so_name().data()), + reinterpret_cast(task_info_->kernel_name().data()), 1, args_, + args_size, nullptr, stream_, dump_flag); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); return false; diff --git a/src/ge/ge_runtime/task/aicpu_task.h b/src/ge/ge_runtime/task/aicpu_task.h index f5cdc617..cc21af8a 100644 --- a/src/ge/ge_runtime/task/aicpu_task.h +++ b/src/ge/ge_runtime/task/aicpu_task.h @@ -18,6 +18,7 @@ #define GE_GE_RUNTIME_TASK_AICPU_TASK_H_ #include +#include #include "ge_runtime/task/task.h" namespace ge { @@ -30,12 +31,17 @@ class AicpuTask : public TaskRepeater { bool Distribute() override; + void *Args() override { return input_output_addr_; } + + std::string task_name() const override { return task_info_->op_name(); } + private: static void ReleaseRtMem(void **ptr) noexcept; std::shared_ptr task_info_; void *stream_; void *args_; + void *input_output_addr_; }; } // namespace model_runner } // namespace ge diff --git a/src/ge/ge_runtime/task/hccl_task.cc b/src/ge/ge_runtime/task/hccl_task.cc index 54ae3bf3..3d5f8504 100644 --- a/src/ge/ge_runtime/task/hccl_task.cc +++ b/src/ge/ge_runtime/task/hccl_task.cc @@ -115,7 +115,6 @@ bool HcclTask::Distribute() { rt_ret = rtModelBindStream(rt_model_handle_, stream, RT_HEAD_STREAM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - (void)rtStreamDestroy(stream); return false; } diff --git a/src/ge/ge_runtime/task/label_goto_task.cc b/src/ge/ge_runtime/task/label_goto_task.cc new file mode 100644 index 00000000..d357accb --- /dev/null +++ b/src/ge/ge_runtime/task/label_goto_task.cc @@ -0,0 +1,70 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "ge_runtime/task/label_goto_task.h" +#include "ge_runtime/task/task_factory.h" + +namespace ge { +namespace model_runner { +LabelGotoTask::LabelGotoTask(const ModelContext &model_context, const std::shared_ptr &task_info) + : TaskRepeater(model_context, task_info), + task_info_(task_info), + stream_(nullptr), + label_(nullptr) { + if (task_info_ == nullptr) { + GELOGW("task_info_ is null!"); + return; + } + auto stream_list = model_context.stream_list(); + auto label_list = model_context.label_list(); + uint32_t stream_id = task_info->stream_id(); + uint32_t label_id = task_info->label_id(); + GELOGI("Stream list size:%zu, stream id:%u.", stream_list.size(), stream_id); + GELOGI("Label list size:%zu, label id:%u.", label_list.size(), label_id); + if (stream_id >= stream_list.size() || label_id >= label_list.size()) { + GELOGW("Stream/Label id invalid."); + return; + } + stream_ = stream_list[stream_id]; + label_ = label_list[label_id]; +} + +LabelGotoTask::~LabelGotoTask() {} + +bool LabelGotoTask::Distribute() { + GELOGI("LabelGotoTask Distribute start."); + if (stream_ == nullptr) { + GELOGE(PARAM_INVALID, "stream is null!"); + return false; + } + if (label_ == nullptr) { + GELOGE(PARAM_INVALID, "label is null!"); + return false; + } + rtError_t rt_ret = rtLabelGotoEx(label_, stream_); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + return false; + } + + GELOGI("DistributeTask end."); + return true; +} + +REGISTER_TASK(TaskInfoType::LABEL_GOTO, LabelGotoTask, LabelGotoTaskInfo); + +} // namespace model_runner +} // namespace ge diff --git a/src/ge/ge_runtime/task/label_goto_task.h b/src/ge/ge_runtime/task/label_goto_task.h new file mode 100644 index 00000000..4fd6d1bc --- /dev/null +++ b/src/ge/ge_runtime/task/label_goto_task.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GE_RUNTIME_TASK_LABEL_GOTO_TASK_H_ +#define GE_GE_RUNTIME_TASK_LABEL_GOTO_TASK_H_ + +#include +#include "ge_runtime/task/task.h" + +namespace ge { +namespace model_runner { +class LabelGotoTask : public TaskRepeater { + public: + LabelGotoTask(const ModelContext &model_context, const std::shared_ptr &task_info); + + ~LabelGotoTask() override; + + bool Distribute() override; + + private: + std::shared_ptr task_info_; + void *stream_; + void *label_; +}; +} // namespace model_runner +} // namespace ge + +#endif // GE_GE_RUNTIME_TASK_LABEL_GOTO_TASK_H_ diff --git a/src/ge/ge_runtime/task/label_set_task.cc b/src/ge/ge_runtime/task/label_set_task.cc new file mode 100644 index 00000000..3ab5802c --- /dev/null +++ b/src/ge/ge_runtime/task/label_set_task.cc @@ -0,0 +1,70 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "ge_runtime/task/label_set_task.h" +#include "ge_runtime/task/task_factory.h" + +namespace ge { +namespace model_runner { +LabelSetTask::LabelSetTask(const ModelContext &model_context, const std::shared_ptr &task_info) + : TaskRepeater(model_context, task_info), + task_info_(task_info), + stream_(nullptr), + label_(nullptr) { + if (task_info_ == nullptr) { + GELOGW("task_info_ is null!"); + return; + } + auto stream_list = model_context.stream_list(); + auto label_list = model_context.label_list(); + uint32_t stream_id = task_info->stream_id(); + uint32_t label_id = task_info->label_id(); + GELOGI("Stream list size:%zu, stream id:%u.", stream_list.size(), stream_id); + GELOGI("Label list size:%zu, label id:%u.", label_list.size(), label_id); + if (stream_id >= stream_list.size() || label_id >= label_list.size()) { + GELOGW("Stream/Label id invalid."); + return; + } + stream_ = stream_list[stream_id]; + label_ = label_list[label_id]; +} + +LabelSetTask::~LabelSetTask() {} + +bool LabelSetTask::Distribute() { + GELOGI("LabelSetTask Distribute start."); + if (stream_ == nullptr) { + GELOGE(PARAM_INVALID, "stream is null!"); + return false; + } + if (label_ == nullptr) { + GELOGE(PARAM_INVALID, "label is null!"); + return false; + } + rtError_t rt_ret = rtLabelSet(label_, stream_); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + return false; + } + + GELOGI("DistributeTask end."); + return true; +} + +REGISTER_TASK(TaskInfoType::LABEL_SET, LabelSetTask, LabelSetTaskInfo); + +} // namespace model_runner +} // namespace ge diff --git a/src/ge/ge_runtime/task/label_set_task.h b/src/ge/ge_runtime/task/label_set_task.h new file mode 100644 index 00000000..70bf1584 --- /dev/null +++ b/src/ge/ge_runtime/task/label_set_task.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GE_RUNTIME_TASK_LABEL_SET_TASK_H_ +#define GE_GE_RUNTIME_TASK_LABEL_SET_TASK_H_ + +#include +#include "ge_runtime/task/task.h" + +namespace ge { +namespace model_runner { +class LabelSetTask : public TaskRepeater { + public: + LabelSetTask(const ModelContext &model_context, const std::shared_ptr &task_info); + + ~LabelSetTask() override; + + bool Distribute() override; + + private: + std::shared_ptr task_info_; + void *stream_; + void *label_; +}; +} // namespace model_runner +} // namespace ge + +#endif // GE_GE_RUNTIME_TASK_LABEL_SET_TASK_H_ diff --git a/src/ge/ge_runtime/task/label_switch_task.cc b/src/ge/ge_runtime/task/label_switch_task.cc new file mode 100644 index 00000000..a3c2d41a --- /dev/null +++ b/src/ge/ge_runtime/task/label_switch_task.cc @@ -0,0 +1,131 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "ge_runtime/task/label_switch_task.h" +#include "ge_runtime/task/task_factory.h" + +namespace ge { +namespace model_runner { +LabelSwitchTask::LabelSwitchTask(const ModelContext &model_context, + const std::shared_ptr &task_info) + : TaskRepeater(model_context, task_info), + task_info_(task_info), + stream_(nullptr), + all_label_resource_(), + label_info_(nullptr) { + if (task_info_ == nullptr) { + GELOGW("task_info_ is null!"); + return; + } + + all_label_resource_ = model_context.label_list(); + auto stream_list = model_context.stream_list(); + uint32_t stream_id = task_info->stream_id(); + GELOGI("Stream list size:%zu, stream id:%u.", stream_list.size(), stream_id); + if (stream_id >= stream_list.size()) { + GELOGW("Stream id invalid."); + return; + } + stream_ = stream_list[stream_id]; +} + +LabelSwitchTask::~LabelSwitchTask() { + if (label_info_ != nullptr) { + rtError_t rt_ret = rtFree(label_info_); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtFree fwkOpBuf failed! ret: 0x%X.", rt_ret); + } + label_info_ = nullptr; + } +} + +bool LabelSwitchTask::Distribute() { + GELOGI("LabelSwitchTask Distribute start."); + if (!CheckParamValid()) { + return false; + } + + const std::vector &label_index_list = task_info_->label_list(); + std::vector label_list(task_info_->label_size(), nullptr); + + for (size_t i = 0; i < task_info_->label_size(); ++i) { + uint32_t label_index = label_index_list[i]; + if (label_index >= all_label_resource_.size()) { + GELOGE(PARAM_INVALID, "label %zu index is %u, but there are %zu labels in total.", i, label_index, + all_label_resource_.size()); + return false; + } + label_list[i] = all_label_resource_[label_index]; + GELOGI("Case %zu: label id %zu.", i, label_index); + } + + uint32_t label_info_size = sizeof(rtLabelDevInfo) * task_info_->label_size(); + rtError_t rt_ret = rtMalloc(&label_info_, label_info_size, RT_MEMORY_HBM); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + return false; + } + + rt_ret = rtLabelListCpy(label_list.data(), label_list.size(), label_info_, label_info_size); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + return false; + } + + rt_ret = rtLabelSwitchByIndex(task_info_->cond(), label_list.size(), label_info_, stream_); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + return false; + } + + GELOGI("DistributeTask end."); + return true; +} + +bool LabelSwitchTask::CheckParamValid() { + if (stream_ == nullptr) { + GELOGE(PARAM_INVALID, "stream is null!"); + return false; + } + + if (task_info_->label_list().empty()) { + GELOGE(PARAM_INVALID, "label_list is empty."); + return false; + } + + if (task_info_->label_size() != task_info_->label_list().size()) { + GELOGE(PARAM_INVALID, "label_list size %zu but label_size is %u.", task_info_->label_list().size(), + task_info_->label_size()); + return false; + } + + if (task_info_->label_size() >= UINT32_MAX / sizeof(rtLabelDevInfo)) { + GELOGE(PARAM_INVALID, "label_size %u will overflow.", task_info_->label_size()); + return false; + } + + if (label_info_ != nullptr) { + GELOGE(PARAM_INVALID, "label_info_ has dirty data."); + return false; + } + + return true; +} + +REGISTER_TASK(TaskInfoType::LABEL_SWITCH, LabelSwitchTask, LabelSwitchTaskInfo); + +} // namespace model_runner +} // namespace ge diff --git a/src/ge/ge_runtime/task/label_switch_task.h b/src/ge/ge_runtime/task/label_switch_task.h new file mode 100644 index 00000000..463faa31 --- /dev/null +++ b/src/ge/ge_runtime/task/label_switch_task.h @@ -0,0 +1,44 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GE_RUNTIME_TASK_LABEL_SWITCH_TASK_H_ +#define GE_GE_RUNTIME_TASK_LABEL_SWITCH_TASK_H_ + +#include +#include "ge_runtime/task/task.h" + +namespace ge { +namespace model_runner { +class LabelSwitchTask : public TaskRepeater { + public: + LabelSwitchTask(const ModelContext &model_context, const std::shared_ptr &task_info); + + ~LabelSwitchTask() override; + + bool Distribute() override; + + private: + bool CheckParamValid(); + + std::shared_ptr task_info_; + void *stream_; + std::vector all_label_resource_; + void *label_info_; +}; +} // namespace model_runner +} // namespace ge + +#endif // GE_GE_RUNTIME_TASK_LABEL_SWITCH_TASK_H_ diff --git a/src/ge/ge_runtime/task/stream_switch_task.cc b/src/ge/ge_runtime/task/stream_switch_task.cc index 91141139..2adcb4bd 100644 --- a/src/ge/ge_runtime/task/stream_switch_task.cc +++ b/src/ge/ge_runtime/task/stream_switch_task.cc @@ -51,7 +51,7 @@ bool StreamSwitchTask::Distribute() { } if (static_cast(task_info_->true_stream_id()) >= stream_list_.size()) { - GELOGE(PARAM_INVALID, "true_stream_id %ld must be less than stream_list_ size %zu!", task_info_->true_stream_id(), + GELOGE(PARAM_INVALID, "true_stream_id %ld must less than stream_list_ size %zu!", task_info_->true_stream_id(), stream_list_.size()); return false; } diff --git a/src/ge/ge_runtime/task/task.h b/src/ge/ge_runtime/task/task.h index 7c748a7d..6c4df248 100644 --- a/src/ge/ge_runtime/task/task.h +++ b/src/ge/ge_runtime/task/task.h @@ -18,7 +18,9 @@ #define GE_GE_RUNTIME_TASK_TASK_H_ #include +#include #include +#include #include "runtime/rt_model.h" #include "ge_runtime/model_context.h" #include "ge_runtime/task_info.h" @@ -32,6 +34,10 @@ class Task { virtual ~Task() {} virtual bool Distribute() = 0; + + virtual void *Args() { return nullptr; } + + virtual std::string task_name() const { return ""; } }; template diff --git a/src/ge/ge_runtime/task/tbe_task.cc b/src/ge/ge_runtime/task/tbe_task.cc index 8a3c36a4..e7025ae8 100644 --- a/src/ge/ge_runtime/task/tbe_task.cc +++ b/src/ge/ge_runtime/task/tbe_task.cc @@ -95,15 +95,14 @@ bool TbeTask::Distribute() { return false; } - GELOGI("InitTbeTask end."); GELOGI("DistributeTbeTask start."); - rt_ret = rtKernelLaunch(stub_func_, task_info_->block_dim(), args_, args_size, nullptr, stream_); + auto dump_flag = task_info_->dump_flag() ? RT_KERNEL_DUMPFLAG : RT_KERNEL_DEFAULT; + rt_ret = rtKernelLaunchWithFlag(stub_func_, task_info_->block_dim(), args_, args_size, nullptr, stream_, dump_flag); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api rtKernelLaunch failed, ret: 0x%X", rt_ret); return false; } - - GELOGI("DistributeTbeTask end."); + GELOGI("[DataDump] task name:%s, dump_flag:%d", task_info_->op_name().c_str(), dump_flag); return true; } diff --git a/src/ge/ge_runtime/task/tbe_task.h b/src/ge/ge_runtime/task/tbe_task.h index 994ba5e2..a8ce6268 100644 --- a/src/ge/ge_runtime/task/tbe_task.h +++ b/src/ge/ge_runtime/task/tbe_task.h @@ -30,6 +30,10 @@ class TbeTask : public TaskRepeater { bool Distribute() override; + void *Args() override { return args_; } + + std::string task_name() const override { return task_info_->op_name(); } + private: std::shared_ptr task_info_; void *stream_; diff --git a/src/ge/ge_train.mk b/src/ge/ge_train.mk deleted file mode 100644 index 767ce86b..00000000 --- a/src/ge/ge_train.mk +++ /dev/null @@ -1,333 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -COMMON_LOCAL_SRC_FILES := \ - proto/fusion_model.proto \ - proto/optimizer_priority.proto \ - session/inner_session.cc \ - session/session_manager.cc \ - common/ge/plugin_manager.cc\ - common/fp16_t.cc \ - common/formats/utils/formats_trans_utils.cc \ - common/formats/format_transfers/datatype_transfer.cc \ - common/formats/format_transfers/format_transfer_transpose.cc \ - common/formats/format_transfers/format_transfer_nchw_nc1hwc0.cc \ - common/formats/format_transfers/format_transfer_fractal_z.cc \ - common/formats/format_transfers/format_transfer_fractal_nz.cc \ - common/formats/format_transfers/format_transfer_fractal_zz.cc \ - common/formats/format_transfers/format_transfer_nhwc_nc1hwc0.cc \ - common/formats/format_transfers/format_transfer_nc1hwc0_nchw.cc \ - common/formats/format_transfers/format_transfer_nc1hwc0_nhwc.cc \ - common/formats/format_transfers/format_transfer_hwcn_c1hwncoc0.cc \ - common/formats/format_transfers/format_transfer_c1hwncoc0_hwcn.cc \ - common/formats/format_transfers/format_transfer_fracz_nchw.cc \ - common/formats/format_transfers/format_transfer_fracz_nhwc.cc \ - common/formats/format_transfers/format_transfer_fracz_hwcn.cc \ - common/formats/format_transfers/format_transfer_dhwcn_fracz3D.cc \ - common/formats/format_transfers/format_transfer_dhwnc_fracz3D_transpose.cc \ - common/formats/formats.cc \ - init/gelib.cc \ - engine_manager/dnnengine_manager.cc \ - opskernel_manager/ops_kernel_manager.cc \ - graph/manager/graph_manager.cc \ - graph/manager/graph_manager_utils.cc \ - graph/manager/graph_context.cc \ - graph/preprocess/graph_preprocess.cc \ - graph/preprocess/multi_batch_copy_graph.cc \ - graph/execute/graph_execute.cc \ - graph/load/graph_loader.cc \ - graph/optimize/graph_optimize.cc \ - graph/passes/folding_pass.cc \ - graph/optimize/summary_optimize.cc \ - graph/build/graph_builder.cc \ - graph/partition/engine_place.cc \ - graph/partition/graph_partition.cc \ - graph/partition/dynamic_shape_partition.cc \ - generator/ge_generator.cc \ - generator/generator_api.cc \ - common/profiling/profiling_manager.cc \ - ge_local_engine/engine/host_cpu_engine.cc \ - common/helper/model_cache_helper.cc \ - -OMG_HOST_SRC_FILES := \ - model/ge_model.cc \ - model/ge_root_model.cc \ - graph/common/transop_util.cc \ - graph/manager/graph_var_manager.cc \ - graph/manager/trans_var_data_utils.cc \ - omm/csa_interact.cc \ - graph/passes/pass_manager.cc \ - graph/passes/pass_utils.cc \ - graph/passes/base_pass.cc \ - graph/passes/resource_pair_add_control_pass.cc \ - graph/passes/resource_pair_remove_control_pass.cc \ - graph/passes/constant_folding_pass.cc \ - graph/passes/aicpu_constant_folding_pass.cc \ - graph/passes/reshape_remove_pass.cc \ - graph/passes/reshape_recovery_pass.cc \ - graph/passes/transop_breadth_fusion_pass.cc \ - graph/passes/transop_depth_fusion_pass.cc \ - graph/passes/same_transdata_breadth_fusion_pass.cc \ - graph/passes/transop_without_reshape_fusion_pass.cc \ - graph/passes/compile_nodes_pass.cc \ - graph/passes/transop_nearby_allreduce_fusion_pass.cc \ - graph/passes/variable_prepare_op_pass.cc \ - graph/passes/variable_ref_delete_op_pass.cc \ - graph/passes/variable_ref_useless_control_out_delete_pass.cc \ - graph/passes/variable_op_pass.cc \ - graph/passes/cast_remove_pass.cc \ - graph/passes/replace_transshape_pass.cc \ - graph/passes/transpose_transdata_pass.cc \ - graph/passes/identify_reference_pass.cc \ - graph/passes/variable_format_pass.cc \ - graph/passes/subgraph_pass.cc \ - graph/passes/data_pass.cc \ - graph/passes/net_output_pass.cc \ - graph/passes/constant_fuse_same_pass.cc \ - graph/passes/print_op_pass.cc \ - graph/passes/no_use_reshape_remove_pass.cc \ - graph/passes/iterator_op_pass.cc \ - graph/passes/atomic_addr_clean_pass.cc \ - graph/optimize/optimizer/allreduce_fusion_pass.cc \ - graph/common/omg_util.cc \ - graph/common/bcast.cc \ - graph/passes/dimension_compute_pass.cc \ - graph/passes/dimension_adjust_pass.cc \ - graph/passes/get_original_format_pass.cc \ - graph/passes/shape_operate_op_remove_pass.cc \ - graph/passes/unused_op_remove_pass.cc \ - graph/passes/assert_pass.cc \ - graph/passes/dropout_pass.cc \ - graph/passes/infershape_pass.cc \ - graph/passes/unused_const_pass.cc \ - graph/passes/isolated_op_remove_pass.cc \ - graph/passes/permute_pass.cc \ - graph/passes/ctrl_edge_transfer_pass.cc \ - host_kernels/broadcast_gradient_args_kernel.cc \ - host_kernels/greater_kernel.cc \ - host_kernels/gather_v2_kernel.cc \ - host_kernels/maximum_kernel.cc \ - host_kernels/floormod_kernel.cc \ - host_kernels/floordiv_kernel.cc \ - host_kernels/range_kernel.cc \ - host_kernels/shape_kernel.cc \ - host_kernels/size_kernel.cc \ - host_kernels/shape_n_kernel.cc \ - host_kernels/rank_kernel.cc \ - host_kernels/broadcast_args_kernel.cc \ - host_kernels/fill_kernel.cc \ - host_kernels/empty_kernel.cc \ - host_kernels/expanddims_kernel.cc \ - host_kernels/reshape_kernel.cc \ - host_kernels/squeeze_kernel.cc \ - host_kernels/kernel_utils.cc \ - host_kernels/cast_kernel.cc \ - host_kernels/transdata_kernel.cc \ - host_kernels/transpose_kernel.cc \ - host_kernels/permute_kernel.cc \ - host_kernels/pack_kernel.cc \ - host_kernels/concat_v2_kernel.cc \ - host_kernels/concat_offset_kernel.cc \ - host_kernels/strided_slice_kernel.cc \ - host_kernels/ssd_prior_box_kernel.cc \ - host_kernels/add_kernel.cc \ - host_kernels/unpack_kernel.cc \ - host_kernels/sub_kernel.cc \ - host_kernels/mul_kernel.cc \ - host_kernels/reduce_prod_kernel.cc \ - host_kernels/rsqrt_kernel.cc \ - host_kernels/slice_kernel.cc \ - host_kernels/slice_d_kernel.cc \ - host_kernels/dynamic_stitch_kernel.cc \ - graph/passes/stop_gradient_pass.cc \ - graph/passes/prevent_gradient_pass.cc \ - graph/passes/identity_pass.cc \ - graph/passes/placeholder_with_default_pass.cc \ - graph/passes/snapshot_pass.cc \ - graph/passes/guarantee_const_pass.cc \ - graph/passes/var_is_initialized_op_pass.cc \ - graph/passes/parallel_concat_start_op_pass.cc \ - graph/passes/cast_translate_pass.cc \ - graph/passes/addn_pass.cc \ - graph/passes/common_subexpression_elimination_pass.cc \ - graph/passes/transop_symmetry_elimination_pass.cc \ - graph/passes/save_pass.cc \ - graph/passes/switch_dead_branch_elimination.cc \ - graph/passes/merge_pass.cc \ - graph/passes/prune_pass.cc \ - graph/passes/flow_ctrl_pass.cc \ - graph/passes/control_trigger_pass.cc \ - graph/passes/switch_data_edges_bypass.cc \ - graph/passes/switch_op_pass.cc \ - graph/passes/multi_batch_pass.cc \ - graph/passes/switch_logic_remove_pass.cc \ - graph/passes/next_iteration_pass.cc \ - graph/passes/cond_pass.cc \ - graph/passes/cond_remove_pass.cc \ - graph/passes/for_pass.cc \ - graph/passes/enter_pass.cc \ - graph/passes/hccl_memcpy_pass.cc \ - graph/passes/link_gen_mask_nodes_pass.cc \ - graph/passes/replace_with_empty_const_pass.cc \ - graph/passes/hccl_group_pass.cc \ - -OME_SRC_FILES := \ - graph/manager/graph_mem_allocator.cc \ - graph/manager/graph_caching_allocator.cc \ - graph/manager/model_manager/event_manager.cc \ - graph/manager/util/debug.cc \ - graph/manager/util/rt_context_util.cc \ - graph/manager/util/variable_accelerate_ctrl.cc \ - graph/manager/util/hcom_util.cc \ - graph/load/new_model_manager/model_manager.cc \ - graph/load/new_model_manager/data_inputer.cc \ - graph/load/new_model_manager/davinci_model.cc \ - graph/load/new_model_manager/davinci_model_parser.cc \ - graph/load/new_model_manager/model_utils.cc \ - graph/load/new_model_manager/tbe_handle_store.cc \ - graph/load/new_model_manager/cpu_queue_schedule.cc \ - graph/load/new_model_manager/zero_copy_task.cc \ - graph/load/output/output.cc \ - graph/load/new_model_manager/data_dumper.cc \ - graph/load/new_model_manager/task_info/task_info.cc \ - graph/load/new_model_manager/task_info/event_record_task_info.cc \ - graph/load/new_model_manager/task_info/event_wait_task_info.cc \ - graph/load/new_model_manager/task_info/fusion_start_task_info.cc \ - graph/load/new_model_manager/task_info/fusion_stop_task_info.cc \ - graph/load/new_model_manager/task_info/hccl_task_info.cc \ - graph/load/new_model_manager/task_info/kernel_ex_task_info.cc \ - graph/load/new_model_manager/task_info/kernel_task_info.cc \ - graph/load/new_model_manager/task_info/label_set_task_info.cc \ - graph/load/new_model_manager/task_info/label_switch_by_index_task_info.cc \ - graph/load/new_model_manager/task_info/label_goto_ex_task_info.cc \ - graph/load/new_model_manager/task_info/memcpy_async_task_info.cc \ - graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.cc \ - graph/load/new_model_manager/task_info/profiler_trace_task_info.cc \ - graph/load/new_model_manager/task_info/stream_active_task_info.cc \ - graph/load/new_model_manager/task_info/stream_switch_task_info.cc \ - graph/load/new_model_manager/task_info/stream_switchn_task_info.cc \ - graph/load/new_model_manager/task_info/end_graph_task_info.cc \ - graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc \ - graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc \ - single_op/task/op_task.cc \ - single_op/task/build_task_utils.cc \ - single_op/task/tbe_task_builder.cc \ - single_op/task/aicpu_task_builder.cc \ - single_op/single_op.cc \ - single_op/single_op_model.cc \ - single_op/stream_resource.cc \ - single_op/single_op_manager.cc \ - hybrid/hybrid_davinci_model_stub.cc \ - - -COMMON_LOCAL_C_INCLUDES := \ - proto/om.proto \ - proto/task.proto \ - proto/insert_op.proto \ - proto/ge_ir.proto \ - proto/fwk_adapter.proto \ - proto/op_mapping_info.proto \ - proto/tensorflow/attr_value.proto \ - proto/tensorflow/function.proto \ - proto/tensorflow/graph.proto \ - proto/tensorflow/node_def.proto \ - proto/tensorflow/op_def.proto \ - proto/tensorflow/resource_handle.proto \ - proto/tensorflow/tensor.proto \ - proto/tensorflow/tensor_shape.proto \ - proto/tensorflow/types.proto \ - proto/tensorflow/versions.proto \ - $(LOCAL_PATH) ./ \ - $(TOPDIR)inc \ - $(TOPDIR)inc/external \ - $(TOPDIR)inc/external/graph \ - $(TOPDIR)inc/framework \ - $(TOPDIR)inc/framework/common \ - $(TOPDIR)inc/runtime \ - $(TOPDIR)libc_sec/include \ - $(TOPDIR)ops/built-in/op_proto/inc \ - third_party/json/include \ - third_party/protobuf/include \ - third_party/opencv/include \ - -NEW_OMG_HOST_SRC_FILES := \ - graph/preprocess/insert_op/util_insert_aipp_op.cc \ - graph/preprocess/insert_op/ge_aipp_op.cc \ - graph/build/model_builder.cc \ - graph/build/task_generator.cc \ - graph/build/stream_allocator.cc \ - graph/build/logical_stream_allocator.cc \ - graph/build/stream_graph_optimizer.cc \ - graph/build/run_context.cc \ - graph/build/label_allocator.cc \ - graph/label/label_maker.cc \ - graph/label/if_label_maker.cc \ - graph/label/case_label_maker.cc \ - graph/label/while_label_maker.cc \ - graph/label/partitioned_call_label_maker.cc \ - - - -#compiler for host train -include $(CLEAR_VARS) - -LOCAL_MODULE := libge_train - -LOCAL_CFLAGS += -DPROTOBUF_INLINE_NOT_IN_HEADERS=0 -DREUSE_MEMORY=1 -O2 -LOCAL_CFLAGS += -DDAVINCI_CLOUD -DDAVINCI_TRAIN -DFMK_SUPPORT_DUMP -DDAVINCI_SUPPORT_PROFILING -LOCAL_CFLAGS += -DFMK_SUPPORT_DEBUG -ifeq ($(DEBUG), 1) -LOCAL_CFLAGS += -g -O0 -endif - -LOCAL_C_INCLUDES := $(COMMON_LOCAL_C_INCLUDES) - -LOCAL_SRC_FILES := $(COMMON_LOCAL_SRC_FILES) -LOCAL_SRC_FILES += $(OMG_HOST_SRC_FILES) -LOCAL_SRC_FILES += $(OME_SRC_FILES) -LOCAL_SRC_FILES += $(NEW_OMG_HOST_SRC_FILES) - -LOCAL_STATIC_LIBRARIES := libge_memory \ - -LOCAL_SHARED_LIBRARIES := \ - libc_sec \ - libprotobuf \ - libslog \ - libmmpa \ - libgraph \ - libregister \ - libge_common \ - libhccl \ - libmsprof \ - - -LOCAL_LDFLAGS := -lrt -ldl - -LOCAL_SHARED_LIBRARIES += \ - libruntime \ - libresource \ - -include $(BUILD_HOST_SHARED_LIBRARY) - -# add engine_conf.json to host -include $(CLEAR_VARS) - -LOCAL_MODULE := engine_conf.json - -LOCAL_SRC_FILES := engine_manager/engine_conf.json - -LOCAL_MODULE_CLASS := ETC - -LOCAL_INSTALLED_PATH := $(HOST_OUT_ROOT)/engine_conf.json -include $(BUILD_HOST_PREBUILT) - -# add optimizer_priority.pbtxt to host -include $(CLEAR_VARS) - -LOCAL_MODULE := optimizer_priority.pbtxt - -LOCAL_SRC_FILES := opskernel_manager/optimizer_priority.pbtxt - -LOCAL_MODULE_CLASS := ETC - -LOCAL_INSTALLED_PATH := $(HOST_OUT_ROOT)/optimizer_priority.pbtxt -include $(BUILD_HOST_PREBUILT) diff --git a/src/ge/generator/ge_generator.cc b/src/ge/generator/ge_generator.cc index b01f7591..bc1e78c1 100644 --- a/src/ge/generator/ge_generator.cc +++ b/src/ge/generator/ge_generator.cc @@ -23,15 +23,15 @@ #include "common/util/error_manager/error_manager.h" #include "framework/common/debug/ge_log.h" #include "ge/ge_api.h" -#include "graph/ge_context.h" #include "graph/debug/ge_attr_define.h" +#include "graph/ge_context.h" #include "graph/manager/graph_manager.h" #include "graph/manager/util/rt_context_util.h" #include "graph/opsproto_manager.h" #include "graph/utils/graph_utils.h" #include "graph/utils/type_utils.h" -#include "model/ge_model.h" #include "init/gelib.h" +#include "model/ge_model.h" using std::map; using std::string; @@ -46,6 +46,16 @@ const char *const kFileNameSuffix = "online"; std::map engine_type_map{ {ge::ENGINE_SYS, kEngineNameDefault}, {ge::ENGINE_AICORE, kAIcoreEngine}, {ge::ENGINE_VECTOR, kVectorEngine}}; + +bool ContainsDynamicInpus(const ge::OpDesc &op_desc) { + for (auto &tensor_desc : op_desc.GetAllInputsDescPtr()) { + if (tensor_desc->MutableShape().IsUnknownShape()) { + GELOGI("Contains unknown shape input. set is_dynamic_input to true."); + return true; + } + } + return false; +} } // namespace namespace ge { @@ -55,6 +65,7 @@ static Status CheckEngineTypeSupport(const OpDescPtr &op_desc, OpEngineType engi GELOGI("CheckEngineType: use default engine."); return SUCCESS; } + // get op engine name string op_engine_name; auto iter = engine_type_map.find(engine_type); @@ -65,6 +76,12 @@ static Status CheckEngineTypeSupport(const OpDescPtr &op_desc, OpEngineType engi GELOGE(FAILED, "CheckEngineType: engine type: %d not support", static_cast(engine_type)); return FAILED; } + + if (op_desc->HasAttr(ATTR_NAME_UNREGST_OPPATH)) { + op_desc->SetOpEngineName(op_engine_name); + op_desc->SetOpKernelLibName(op_engine_name); + return SUCCESS; + } // set op engine name and opkernelLib. when engine support std::shared_ptr instance_ptr = ge::GELib::GetInstance(); if ((instance_ptr == nullptr) || (!instance_ptr->InitFlag())) { @@ -195,18 +212,26 @@ static void GetOpsProtoPath(string &opsproto_path) { class GeGenerator::Impl { public: - Status BuildModel(const Graph &graph, const vector &inputs, GraphId &graph_id, GeRootModelPtr &ge_models); + Status BuildModel(const Graph &graph, const vector &inputs, GeRootModelPtr &ge_models); Status SaveModel(const string &file_name_prefix, GeModelPtr &models, ModelBufferData &model); Status SaveParams(GeModelPtr &ge_model, const string &type, const map &attrs, const vector &inputs, const vector &outputs); - Status GenerateInfershapeGraph(const Graph &graph, GraphId &graph_id); + Status GenerateInfershapeGraph(const Graph &graph); GraphManager graph_manager_; SaveParam save_param_; bool is_offline_ = true; + bool is_singleop_unregistered_ = false; + + private: + static std::string Trim(const std::string &str); + bool ParseVersion(const std::string &line, std::string &version); + bool GetVersionFromPath(const std::string &file_path, std::string &version); + bool SetAtcVersionInfo(AttrHolder &obj); + bool SetOppVersionInfo(AttrHolder &obj); }; Status GeGenerator::Initialize(const map &options) { @@ -273,10 +298,9 @@ Status GeGenerator::GenerateOnlineModel(const Graph &graph, const vectorGenerateInfershapeGraph(graph, graph_id); + Status ret = impl_->GenerateInfershapeGraph(graph); if (ret != SUCCESS) { GELOGE(ret, "Dump infershape json failed"); if (impl_->graph_manager_.Finalize() != SUCCESS) { @@ -288,6 +312,124 @@ Status GeGenerator::GenerateInfershapeGraph(const Graph &graph) { return SUCCESS; } +// Remove the space and tab before and after the string +std::string GeGenerator::Impl::Trim(const std::string &str) { + if (str.empty()) { + return str; + } + + std::string::size_type start = str.find_first_not_of(" \t\r\n"); + if (start == std::string::npos) { + return str; + } + + std::string::size_type end = str.find_last_not_of(" \t\r\n") + 1; + return str.substr(start, end); +} + +// Parsing the command line +bool GeGenerator::Impl::ParseVersion(const std::string &line, std::string &version) { + std::string flag = "Version="; + std::string temp = Trim(line); + + if (temp.empty()) { + GELOGW("line is empty."); + return false; + } + + std::string::size_type pos = temp.find(flag); + if (pos == std::string::npos) { + GELOGW("Incorrect line [%s], it must include [%s].", line.c_str(), flag.c_str()); + return false; + } + + if (temp.size() == flag.size()) { + GELOGW("version information is empty. %s", line.c_str()); + return false; + } + + version = temp.substr(pos + flag.size()); + GELOGI("Version=%s", version.c_str()); + + return true; +} + +bool GeGenerator::Impl::GetVersionFromPath(const std::string &file_path, std::string &version) { + // Normalize the path + string resolved_file_path = RealPath(file_path.c_str()); + if (resolved_file_path.empty()) { + GELOGW("Invalid input file path [%s], make sure that the file path is correct.", file_path.c_str()); + return false; + } + std::ifstream fs(resolved_file_path, std::ifstream::in); + if (!fs.is_open()) { + GELOGW("Open %s failed.", file_path.c_str()); + return false; + } + + std::string line; + if (getline(fs, line)) { + if (!ParseVersion(line, version)) { + GELOGW("Parse version failed. content is [%s].", line.c_str()); + fs.close(); + return false; + } + } else { + GELOGW("No version information found in the file path:%s", file_path.c_str()); + fs.close(); + return false; + } + + fs.close(); // close the file + return true; +} + +// Set package version information in the model +bool GeGenerator::Impl::SetAtcVersionInfo(AttrHolder &obj) { + std::string path_base = ge::GELib::GetPath(); + path_base = path_base.substr(0, path_base.rfind('/')); + path_base = path_base.substr(0, path_base.rfind('/') + 1); + + std::string version_path = path_base + "version.info"; + GELOGI("version_path is %s", version_path.c_str()); + std::string version; + if (!GetVersionFromPath(version_path, version)) { + GELOGW("Get atc version information failed!"); + return false; + } + // set version info + if (!ge::AttrUtils::SetStr(obj, ATTR_MODEL_ATC_VERSION, version)) { + GELOGW("Ge model set atc version failed!"); + return false; + } + GELOGI("Ge model set atc version information success."); + return true; +} + +// Set package version information in the model +bool GeGenerator::Impl::SetOppVersionInfo(AttrHolder &obj) { + const char *path_env = std::getenv("ASCEND_OPP_PATH"); + if (path_env == nullptr) { + GELOGW("Get environment variable ASCEND_OPP_PATH failed!"); + return false; + } + std::string version_path = path_env; + version_path += "/version.info"; + GELOGI("version_path is %s", version_path.c_str()); + std::string version; + if (!GetVersionFromPath(version_path, version)) { + GELOGW("Get opp version information failed!"); + return false; + } + // set version info + if (!ge::AttrUtils::SetStr(obj, ATTR_MODEL_OPP_VERSION, version)) { + GELOGW("Ge model set opp version failed!"); + return false; + } + GELOGI("Ge Model set opp version information success."); + return true; +} + Status GeGenerator::GenerateModel(const Graph &graph, const string &file_name_prefix, const vector &inputs, ModelBufferData &model, bool is_offline) { rtContext_t ctx = nullptr; @@ -297,11 +439,11 @@ Status GeGenerator::GenerateModel(const Graph &graph, const string &file_name_pr } else { ge::RtContextUtil::GetInstance().SetNormalModeContext(ctx); } - GraphId graph_id; + GeRootModelPtr ge_root_model = nullptr; GE_CHECK_NOTNULL_EXEC(impl_, return PARAM_INVALID); impl_->is_offline_ = is_offline; - Status ret = impl_->BuildModel(graph, inputs, graph_id, ge_root_model); + Status ret = impl_->BuildModel(graph, inputs, ge_root_model); if (ret != SUCCESS) { GELOGE(ret, "Build model failed."); if (impl_->graph_manager_.Finalize() != SUCCESS) { @@ -315,6 +457,7 @@ Status GeGenerator::GenerateModel(const Graph &graph, const string &file_name_pr string model_name = ""; Status name_ret = model_helper.GetModelNameFromMergedGraphName(ge_root_model->GetRootGraph()->GetName(), model_name); if (name_ret != SUCCESS) { + ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"output"}); GELOGE(FAILED, "Get model_name failed. Param --output is invalid"); return PARAM_INVALID; } @@ -352,6 +495,12 @@ Status GeGenerator::BuildSingleOp(OpDescPtr &op_desc, const vector &in return PARAM_INVALID; } + domi::GetContext().is_dynamic_input = ContainsDynamicInpus(*op_desc); + + if (op_desc->HasAttr(ATTR_NAME_UNREGST_OPPATH)) { + impl_->is_singleop_unregistered_ = true; + } + // 0. Save original attributes. OpDescPtr op_desc_tmp = AttrUtils::CloneOpDesc(op_desc); GE_CHECK_NOTNULL(op_desc_tmp); @@ -368,9 +517,6 @@ Status GeGenerator::BuildSingleOp(OpDescPtr &op_desc, const vector &in // 2. Create ComputeGraph. string name = ge::CurrentTimeInStr() + "_" + model_file_name; ge::ComputeGraphPtr compute_graph = MakeShared(name); - if (compute_graph == nullptr) { - return INTERNAL_ERROR; - } GE_CHECK_NOTNULL_EXEC(compute_graph, return INTERNAL_ERROR); // 3. Add Node to ComputeGraph. @@ -403,16 +549,19 @@ Status GeGenerator::BuildSingleOp(OpDescPtr &op_desc, const vector &in Graph graph = ge::GraphUtils::CreateGraphFromComputeGraph(compute_graph); GELOGI("ATC parser success in single op build."); - GraphId graph_id; GeRootModelPtr ge_root_model = nullptr; GE_CHECK_NOTNULL_EXEC(impl_, return PARAM_INVALID); impl_->is_offline_ = is_offline; - GE_CHK_STATUS_RET_NOLOG(impl_->BuildModel(graph, inputs, graph_id, ge_root_model)); + GE_CHK_STATUS_RET_NOLOG(impl_->BuildModel(graph, inputs, ge_root_model)); map op_attrs = op_desc_tmp->GetAllAttrs(); GE_CHECK_NOTNULL(ge_root_model); GE_CHECK_NOTNULL(ge_root_model->GetRootGraph()); map name_to_ge_model = ge_root_model->GetSubgraphInstanceNameToModel(); - GeModelPtr &ge_model = name_to_ge_model[ge_root_model->GetRootGraph()->GetName()]; + if (name_to_ge_model.empty()) { + GELOGE(PARAM_INVALID, "GetSubgraphInstanceNameToModel is empty."); + return PARAM_INVALID; + } + GeModelPtr &ge_model = name_to_ge_model.begin()->second; GELOGD("The opType in op_desc_tmp is [%s]", op_desc_tmp->GetType().c_str()); GE_CHK_STATUS_RET_NOLOG(impl_->SaveParams(ge_model, op_desc_tmp->GetType(), op_attrs, inputs, outputs)); GE_CHK_STATUS_RET_NOLOG(impl_->SaveModel(model_file_name, ge_model, model_buff)); @@ -464,6 +613,14 @@ Status GeGenerator::Impl::SaveParams(GeModelPtr &ge_model, const string &type, c } Status GeGenerator::Impl::SaveModel(const string &file_name_prefix, GeModelPtr &model, ModelBufferData &model_buff) { + // set atc version + if (!SetAtcVersionInfo(*(model.get()))) { + GELOGW("SetPackageVersionInfo of atc failed!"); + } + // set opp version + if (!SetOppVersionInfo(*(model.get()))) { + GELOGW("SetPackageVersionInfo of ops failed!"); + } ModelHelper model_helper; model_helper.SetSaveMode(is_offline_); Status ret = model_helper.SaveToOmModel(model, save_param_, file_name_prefix, model_buff); @@ -474,7 +631,7 @@ Status GeGenerator::Impl::SaveModel(const string &file_name_prefix, GeModelPtr & return SUCCESS; } -Status GeGenerator::Impl::BuildModel(const Graph &graph, const vector &inputs, GraphId &graph_id, +Status GeGenerator::Impl::BuildModel(const Graph &graph, const vector &inputs, GeRootModelPtr &ge_root_model) { static GraphId id = 0; const std::map options; @@ -493,19 +650,22 @@ Status GeGenerator::Impl::BuildModel(const Graph &graph, const vector return INTERNAL_ERROR; } uint64_t session_id = static_cast(tv.tv_sec * 1000000 + tv.tv_usec); // 1000000us - ret = graph_manager_.BuildGraph(id, inputs, ge_root_model, session_id); + if (is_singleop_unregistered_) { + ret = graph_manager_.BuildGraphForUnregisteredOp(id, inputs, ge_root_model, session_id); + } else { + ret = graph_manager_.BuildGraph(id, inputs, ge_root_model, session_id); + } + if (ret != SUCCESS) { GELOGE(GE_GENERATOR_GRAPH_MANAGER_BUILD_GRAPH_FAILED, "GraphManager build graph fail, graph id: %u", id); return GE_GENERATOR_GRAPH_MANAGER_BUILD_GRAPH_FAILED; } - - graph_id = id; id += 1; return SUCCESS; } -Status GeGenerator::Impl::GenerateInfershapeGraph(const Graph &graph, GraphId &graph_id) { +Status GeGenerator::Impl::GenerateInfershapeGraph(const Graph &graph) { static GraphId id = 0; const std::map options; Status ret = graph_manager_.AddGraph(id, graph, options); @@ -520,11 +680,8 @@ Status GeGenerator::Impl::GenerateInfershapeGraph(const Graph &graph, GraphId &g GELOGE(GE_GENERATOR_GRAPH_MANAGER_BUILD_GRAPH_FAILED, "GraphManager generate graph failed"); return GE_GENERATOR_GRAPH_MANAGER_BUILD_GRAPH_FAILED; } - - graph_id = id; id += 1; return SUCCESS; } - } // namespace ge diff --git a/src/ge/graph/build/graph_builder.cc b/src/ge/graph/build/graph_builder.cc index f2fa4ada..51519023 100644 --- a/src/ge/graph/build/graph_builder.cc +++ b/src/ge/graph/build/graph_builder.cc @@ -18,11 +18,14 @@ #include "common/ge/ge_util.h" #include "common/helper/model_helper.h" #include "common/opskernel/ops_kernel_info_types.h" +#include "graph/build/logical_stream_allocator.h" #include "graph/build/run_context.h" #include "graph/build/stream_graph_optimizer.h" #include "graph/manager/graph_var_manager.h" +#include "graph/passes/mark_same_addr_pass.h" #include "graph/utils/node_utils.h" #include "graph/utils/type_utils.h" +#include "graph/common/ge_call_wrapper.h" #include "init/gelib.h" #include "model/ge_model.h" @@ -54,7 +57,7 @@ Status GraphBuilder::CalcOpParam(const ge::ComputeGraphPtr &graph) { return GE_CLI_GE_NOT_INITIALIZED; } - for (const auto &node_ptr : graph->GetAllNodes()) { + for (const auto &node_ptr : graph->GetNodes(graph->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node_ptr->GetOpDesc()); std::string kernel_lib_name = node_ptr->GetOpDesc()->GetOpKernelLibName(); if (kernel_lib_name.empty()) { @@ -102,11 +105,7 @@ Status GraphBuilder::UpdateParentNodeOutputSize(const ge::ComputeGraphPtr &graph graph->GetName().c_str()); auto parent_op_desc = parent_node_ptr->GetOpDesc(); GE_CHECK_NOTNULL(parent_op_desc); - bool is_unknown_shape = false; - if (!AttrUtils::GetBool(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape)) { - GELOGE(PARAM_INVALID, "Get op %s unknown shape attr failed.", parent_op_desc->GetName().c_str()); - return PARAM_INVALID; - } + bool is_unknown_shape = graph->GetGraphUnknownFlag(); if (is_unknown_shape) { GELOGI("Current graph[%s] is unknown, no need to update parent node[%s] output size.", graph->GetName().c_str(), parent_node_ptr->GetName().c_str()); @@ -121,14 +120,14 @@ Status GraphBuilder::UpdateParentNodeOutputSize(const ge::ComputeGraphPtr &graph for (const auto &in_data_anchor : node_ptr->GetAllInDataAnchors()) { auto index = in_data_anchor->GetIdx(); ge::GeTensorDesc desc_temp = op_desc->GetInputDesc(index); - int64_t size = 0; - GE_IF_BOOL_EXEC(ge::TensorUtils::GetSize(desc_temp, size) != SUCCESS, GELOGI("Get size failed!")); uint32_t parent_index = 0; if (!AttrUtils::GetInt(desc_temp, ATTR_NAME_PARENT_NODE_INDEX, parent_index)) { - GELOGE(INTERNAL_ERROR, "NetOutput input tensor %d, attr %s not found.", index, - ATTR_NAME_PARENT_NODE_INDEX.c_str()); - return INTERNAL_ERROR; + GELOGI("NetOutput input tensor %d, attr %s not found.", index, ATTR_NAME_PARENT_NODE_INDEX.c_str()); + continue; } + + int64_t size = 0; + GE_IF_BOOL_EXEC(ge::TensorUtils::GetSize(desc_temp, size) != SUCCESS, GELOGI("Get size failed!")); ge::GeTensorDesc parent_desc_temp = parent_op_desc->GetOutputDesc(parent_index); ge::TensorUtils::SetSize(parent_desc_temp, size); GE_CHK_STATUS_RET(parent_op_desc->UpdateOutputDesc(parent_index, parent_desc_temp)); @@ -176,7 +175,7 @@ Status GraphBuilder::BuildForKnownShapeGraph(ComputeGraphPtr &comp_graph, auto subgraph_map = graph_partitioner_.GetSubGraphMap(); GE_TIMESTAMP_START(BuildSubgraph); - ge::ModelBuilder builder(comp_graph, subgraph_map, stream_max_parallel_num_, hcom_parallel_, build_mode_); + ge::ModelBuilder builder(session_id, comp_graph, subgraph_map, stream_max_parallel_num_, hcom_parallel_, build_mode_); GE_DUMP(comp_graph, "BeforePreBuildModel"); GE_TIMESTAMP_START(PreBuildModel); GE_CHK_STATUS_RET(builder.PreBuildModel(), "Graph[%s] builder PreBuildModel() return fail.", @@ -229,7 +228,7 @@ Status GraphBuilder::BuildForUnknownShapeGraph(ComputeGraphPtr &comp_graph, GeMo GE_TIMESTAMP_END(CalcOpParam, "GraphBuilder::CalcOpParam"); GE_DUMP(comp_graph, "AfterCalcOpParam"); Graph2SubGraphInfoList subgraph_map; - ge::ModelBuilder builder(comp_graph, subgraph_map, stream_max_parallel_num_, hcom_parallel_, build_mode_); + ge::ModelBuilder builder(session_id, comp_graph, subgraph_map, stream_max_parallel_num_, hcom_parallel_, build_mode_); ModelPtr model_ptr = MakeShared(); if (model_ptr == nullptr) { return MEMALLOC_FAILED; @@ -263,51 +262,41 @@ Status GraphBuilder::BuildForDynamicShapeGraph(ComputeGraphPtr &comp_graph, GeRootModelPtr &ge_root_model_ptr, GeModelPtr &ge_model_ptr, uint64_t session_id) { GELOGI("Start to build BuildForDynamicShape for dynamic shape."); - for (const auto &node : comp_graph->GetDirectNode()) { + // Update Root Graph Data size + for (auto &node : comp_graph->GetDirectNode()) { auto op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); + op_desc->SetStreamId(kInvalidStream); if (node->GetType() == DATA) { GE_CHK_STATUS_RET(CalcDynShapeRootGraphDataSize(op_desc), "Calc dynamic shape root graph data[%s] size failed.", op_desc->GetName().c_str()); } - - // ATTR_NAME_IS_UNKNOWN_SHAPE is set on "graph partion" stage, but afer fusion , the graph may - // be changed so here need to renew. For example , the scene followed: - // (known)partioncall(known) (known)partioncall(known) - // After fusion - // | --> - // (known)Unique(unknown)--->(unknow)Shape(unknown) (known)FuncDef(known) - // if scene like this , it should be process as known shape graph - bool is_unknown_shape = false; - GE_CHK_STATUS_RET(ge::NodeUtils::GetNodeUnknownShapeStatus(*node, is_unknown_shape), - "Get node[%s] shape status failed!", node->GetName().c_str()); - if (!is_unknown_shape) { - GE_CHK_BOOL_EXEC(ge::AttrUtils::SetBool(op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape), return FAILED, - "Renew node [%s] attr[%s] failed!", node->GetName().c_str(), ATTR_NAME_IS_UNKNOWN_SHAPE.c_str()); - GELOGD("renew node [%s] attr[%s] success! value is %d", node->GetName().c_str(), - ATTR_NAME_IS_UNKNOWN_SHAPE.c_str(), is_unknown_shape); + } + // + for (auto &sub_graph : comp_graph->GetAllSubgraphs()) { + // exclude functional subgraph in known subgraph + if (sub_graph->GetParentGraph() != comp_graph && !sub_graph->GetParentGraph()->GetGraphUnknownFlag()) { + continue; } - - vector subgraph_names = op_desc->GetSubgraphInstanceNames(); - for (auto subgraph_name : subgraph_names) { - ComputeGraphPtr subgraph = comp_graph->GetSubgraph(subgraph_name); - bool is_unknown_shape = false; - if (!AttrUtils::GetBool(op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape)) { - GELOGE(PARAM_INVALID, "Get op %s unknown shape attr failed.", op_desc->GetName().c_str()); - return PARAM_INVALID; - } - if (is_unknown_shape) { - // unknown shape build flow - GE_CHK_STATUS_RET(BuildForUnknownShapeGraph(subgraph, ge_model_ptr, session_id), - "Build for unknown shape graph failed."); - } else { - // known shape build flow - GE_CHK_STATUS_RET(BuildForKnownShapeGraph(subgraph, subgraph_ptr_list, ge_model_ptr, session_id), - "Build for known shape graph failed."); + if (sub_graph->GetGraphUnknownFlag()) { + // unknown shape build flow + GE_CHK_STATUS_RET(BuildForUnknownShapeGraph(sub_graph, ge_model_ptr, session_id), + "Build for unknown shape graph failed."); + } else { + // reset functional subgraph parent graph as known subgraph + for (const auto &node : sub_graph->GetDirectNode()) { + for (const auto &sub_graph_name : node->GetOpDesc()->GetSubgraphInstanceNames()) { + auto sub_sub_graph = comp_graph->GetSubgraph(sub_graph_name); + GE_CHK_STATUS_RET(sub_graph->AddSubgraph(sub_sub_graph), "Failed add subgraph to known graph."); + } } - ge_root_model_ptr->SetSubgraphInstanceNameToModel(subgraph_name, ge_model_ptr); + // known shape build flow + GE_CHK_STATUS_RET(BuildForKnownShapeGraph(sub_graph, subgraph_ptr_list, ge_model_ptr, session_id), + "Build for known shape graph failed."); } + ge_root_model_ptr->SetSubgraphInstanceNameToModel(sub_graph->GetName(), ge_model_ptr); } + return SUCCESS; } @@ -327,8 +316,9 @@ Status GraphBuilder::GetTaskInfo(const ge::ModelBuilder &builder, const ModelPtr GELOGE(INTERNAL_ERROR, "Get weight memory size fail."); return INTERNAL_ERROR; } - auto *get_mem_base = - reinterpret_cast(reinterpret_cast(ge::VarManager::Instance(0)->GetVarMemMaxSize())); + + auto var_manager = VarManager::Instance(session_id); + auto *get_mem_base = reinterpret_cast(reinterpret_cast(var_manager->GetVarMemMaxSize())); uint8_t *get_weight_mem_base = get_mem_base; if (weight_size > 0) { get_weight_mem_base = get_mem_base + memory_size; @@ -354,11 +344,8 @@ Status GraphBuilder::GetTaskInfo(const ge::ModelBuilder &builder, const ModelPtr return ret; } GE_DUMP(comp_graph, "AfterOptimizeStreamedSubGraph"); - auto *get_var_mem_base = - reinterpret_cast(reinterpret_cast(ge::VarManager::Instance(0)->GetVarMemLogicBase())); - uint64_t var_size = (ge::VarManager::Instance(session_id)->GetVarMemSize(RT_MEMORY_HBM) > 0) - ? ge::VarManager::Instance(0)->GetVarMemMaxSize() - : 0; + auto *get_var_mem_base = reinterpret_cast(reinterpret_cast(var_manager->GetVarMemLogicBase())); + uint64_t var_size = (var_manager->GetVarMemSize(RT_MEMORY_HBM) > 0) ? var_manager->GetVarMemMaxSize() : 0; TaskGenerator task_generator(get_var_mem_base, var_size); ret = task_generator.GetTaskInfo(*model_ptr, comp_graph, session_id, run_context.GetRunContext()); @@ -368,6 +355,13 @@ Status GraphBuilder::GetTaskInfo(const ge::ModelBuilder &builder, const ModelPtr Status GraphBuilder::SetInputSize(const ge::NodePtr &node_ptr) { // set input_desc.size = src_node.output_desc.size if (node_ptr->GetType() == DATA) { + bool is_unknown_shape = false; + GE_CHK_STATUS_RET(ge::NodeUtils::GetNodeUnknownShapeStatus(*node_ptr, is_unknown_shape), + "Get data node[%s] shape status failed!", node_ptr->GetName().c_str()); + if (is_unknown_shape) { + GELOGD("data node: %s is unknown shape, do not set input size!", node_ptr->GetName().c_str()); + return SUCCESS; + } if (UpdateDataInputSize(node_ptr) != SUCCESS) { GELOGE(FAILED, "Update data input size failed."); return FAILED; @@ -398,7 +392,7 @@ Status GraphBuilder::SetInputSize(const ge::NodePtr &node_ptr) { GE_CHECK_NOTNULL(input_desc); ge::TensorUtils::SetSize(const_cast(*input_desc), size); GE_CHK_STATUS_RET(node_op_desc->UpdateInputDesc(in_data_anchor->GetIdx(), *input_desc)); - GELOGD("%s input desc, dim_size: %zu, mem_size: %u, format: %s, type: %s.", node_ptr->GetName().c_str(), + GELOGD("%s input desc, dim_size: %zu, mem_size: %ld, format: %s, type: %s.", node_ptr->GetName().c_str(), input_desc->GetShape().GetDimNum(), size, TypeUtils::FormatToSerialString(input_desc->GetFormat()).c_str(), TypeUtils::DataTypeToSerialString(input_desc->GetDataType()).c_str()); } @@ -444,6 +438,11 @@ Status GraphBuilder::CalcDynShapeRootGraphDataSize(const ge::OpDescPtr &op_desc) GELOGI("Begin to calc dynamic shape graph data[%s] size.", op_desc->GetName().c_str()); // data op only has one output anchor ge::GeTensorDesc output_desc = op_desc->GetOutputDesc(0); + if (output_desc.MutableShape().IsUnknownShape()) { + GELOGI("No need to update dynamic shape graph data output size for unknown shape data."); + return SUCCESS; + } + int64_t output_size = 0; if (ge::TensorUtils::GetSize(output_desc, output_size) != SUCCESS) { GELOGW("Get size failed!"); diff --git a/src/ge/graph/build/label_allocator.cc b/src/ge/graph/build/label_allocator.cc index 46c092f5..f8fbe28b 100644 --- a/src/ge/graph/build/label_allocator.cc +++ b/src/ge/graph/build/label_allocator.cc @@ -24,7 +24,6 @@ #include "graph/label/label_maker.h" namespace ge { - LabelAllocator::LabelAllocator(const ComputeGraphPtr &graph) : compute_graph_(graph) {} Status LabelAllocator::AssignFunctionalLabels(uint32_t &label_index) { @@ -76,5 +75,4 @@ bool LabelAllocator::CollectFunctionalNode(ComputeGraphPtr &graph, std::setGetOpDesc(), kAttrNameParentOpType, parent_op_type)) { - if ((parent_op_type != CONSTANT) && (parent_op_type != CONSTANTOP)) { - return true; - } - } - } - } - - return false; -} - Status AssignByLabelPass::Run(ComputeGraphPtr graph, const vector &subgraphs, Context &context) { bool changed = false; int64_t &next_stream = context.next_stream; @@ -133,21 +110,6 @@ Status IndependentStreamPass::Run(ComputeGraphPtr graph, const vector &subgraphs, Context &context) { bool changed = false; - if (IsHeadNodeExceeded(subgraphs)) { - int64_t &next_stream = context.next_stream; - for (const SubgraphPtr &subgraph : subgraphs) { - if (!HasAssignedStream(*subgraph)) { - subgraph->stream_id = next_stream; - changed = true; - } - } - if (changed) { - ++next_stream; - return SUCCESS; - } - return NOT_CHANGED; - } - map end_subgraph_map; map pld_subgraph_map; InitEndSubgraphMap(subgraphs, end_subgraph_map); @@ -190,24 +152,6 @@ Status AssignByDependencyPass::Run(ComputeGraphPtr graph, const vector &subgraphs) const { - size_t aicpu_node_num = 0; - for (const SubgraphPtr &subgraph : subgraphs) { - if (subgraph->engine_conf.id == kAICPUEngineName && !HasNonConstInputNode(*subgraph)) { - const SubGraphInfo &subgraph_info = subgraph->subgraph_info; - auto compute_graph = subgraph_info.GetSubGraph(); - aicpu_node_num += compute_graph->GetDirectNode().size() - subgraph_info.GetPld2EndMap().size() - - subgraph_info.GetEnd2PldMap().size(); - if (aicpu_node_num > kHeadNodeMaxNum) { - GELOGI("aicpu_node_num, %zu", aicpu_node_num); - return true; - } - } - } - - return false; -} - void AssignByDependencyPass::InitEndSubgraphMap(const vector &subgraphs, map &end_subgraph_map) { for (const auto &subgraph : subgraphs) { @@ -727,7 +671,7 @@ void LogicalStreamAllocator::RefreshContinuousStreams(const ComputeGraphPtr &gra int64_t stream_num = context_.next_stream; vector stream_has_node(stream_num); - for (const NodePtr &node : graph->GetAllNodes()) { + for (const NodePtr &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { if (node != nullptr) { auto op_desc = node->GetOpDesc(); if (op_desc != nullptr) { @@ -748,7 +692,7 @@ void LogicalStreamAllocator::RefreshContinuousStreams(const ComputeGraphPtr &gra } } - for (const NodePtr &node : graph->GetAllNodes()) { + for (const NodePtr &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { auto op_desc = node->GetOpDesc(); if (op_desc != nullptr) { int64_t stream_id = op_desc->GetStreamId(); diff --git a/src/ge/graph/build/logical_stream_allocator.h b/src/ge/graph/build/logical_stream_allocator.h index 71946630..280a4104 100644 --- a/src/ge/graph/build/logical_stream_allocator.h +++ b/src/ge/graph/build/logical_stream_allocator.h @@ -81,9 +81,6 @@ class LogicalStreamPass { bool HasStreamLabel(const Subgraph &subgraph) const; bool HasAssignedStream(const Subgraph &subgraph) const; - // Determine if the input of the subgraph is a constant. - bool HasNonConstInputNode(const Subgraph &subgraph) const; - private: std::string name_; }; @@ -121,7 +118,6 @@ class AssignByDependencyPass : public LogicalStreamPass { void UpdateAssignedSubgraphs(Context &context); void UpdateReusedSubgraphs(); - bool IsHeadNodeExceeded(const std::vector &subgraphs) const; bool CouldReuse(const SubgraphPtr &subgraph, const SubgraphPtr &pred_subgraph, const std::map &pld_subgraph_map); diff --git a/src/ge/graph/build/memory/block_mem_assigner.cc b/src/ge/graph/build/memory/block_mem_assigner.cc index df7912fa..99b2fd7d 100644 --- a/src/ge/graph/build/memory/block_mem_assigner.cc +++ b/src/ge/graph/build/memory/block_mem_assigner.cc @@ -18,6 +18,7 @@ #include #include +#include "external/ge/ge_api_types.h" #include "framework/common/debug/ge_log.h" #include "graph/anchor.h" #include "graph/buffer.h" @@ -35,11 +36,19 @@ #include "omg/omg_inner_types.h" #include "runtime/mem.h" +using std::map; +using std::pair; +using std::set; +using std::string; +using std::stringstream; +using std::unordered_map; +using std::unordered_set; +using std::vector; + namespace { const char *const kAttrNameWorkspaceReuseFlag = "workspace_reuse_flag"; const char *const kL2FusionDynamicConvergeOp = "l2fusion_dynamic_converge_op"; const char *const kOpNoReuseMem = "no_reuse_mem_flag"; -const char *const kDisableReuseMemory = "ge.exec.disableReuseMemory"; const char *const OP_NO_REUSE_MEM = "OP_NO_REUSE_MEM"; const int kReuseMaxCount = 10; const int kReuseMaxOpNum = 10; @@ -47,13 +56,12 @@ const int kReuseMaxCharNum = 2000; } // namespace namespace ge { -using std::map; -using std::pair; -using std::string; -using std::stringstream; -using std::unordered_map; -using std::unordered_set; -using std::vector; +void AlignMemOffset(size_t &mem_align_size) { + if (mem_align_size <= 0) { + return; + } + mem_align_size = (mem_align_size + MEM_ALIGN_SIZE - 1) / MEM_ALIGN_SIZE * MEM_ALIGN_SIZE; +} void MemoryBlock::SetHeadOffset(size_t offset) { head_offset_ = offset; @@ -92,7 +100,7 @@ void MemoryBlock::Resize() { } else { size_t block_size = (child_block_size > *iter) ? child_block_size : *iter; if ((block_size > 0) && (block_size % MEM_ALIGN_SIZE != 0)) { - block_size = (block_size + MEM_ALIGN_SIZE - 1) / MEM_ALIGN_SIZE * MEM_ALIGN_SIZE; + AlignMemOffset(block_size); } block_size_ = block_size; if (last_continuous_block_) { @@ -101,6 +109,20 @@ void MemoryBlock::Resize() { } } +size_t MemoryBlock::AlignSize() const { + size_t align_block_size = 0; + auto iter = std::max_element(real_size_list_.begin(), real_size_list_.end()); + if (iter == real_size_list_.end()) { + GELOGW("real_size_list_ is empty"); + } else { + align_block_size = *iter; + if ((align_block_size > 0) && (align_block_size % MEM_ALIGN_SIZE != 0)) { + AlignMemOffset(align_block_size); + } + } + return align_block_size; +} + bool MemoryBlock::IsSameLabel(std::string &first_batch_label) { if (node_type_index_list_.empty()) { return false; @@ -133,32 +155,69 @@ bool MemoryBlock::IsSameLabel(std::string &first_batch_label) { } bool CanNotLifeReuse(MemoryBlock *block) { - if (block == nullptr || !block->reuse_mem_ || block->deleted_block_ || block->continuous_block_ || - block->GetLifeEnd() == kMaxLifeTime) { + if ((block == nullptr) || !block->reuse_mem_ || block->deleted_block_) { return true; } return false; } -void MemoryBlock::AddLifeReuseBlock(MemoryBlock *block) { +void MemoryBlock::AddContinuousLifeReuseBlock(MemoryBlock *block, DependStreamLife &total_node_depend_stream_life) { + // continuous memory case:only real_size is maximum can be reused and only one continuous memory in one block + auto it_block = std::max_element(std::begin(block->NoAlignSizeList()), std::end(block->NoAlignSizeList())); + auto it_this = std::max_element(std::begin(NoAlignSizeList()), std::end(NoAlignSizeList())); + if (it_block != std::end(block->NoAlignSizeList()) && it_this != std::end(NoAlignSizeList())) { + if ((continuous_block_ && block->continuous_block_) || (continuous_block_ && (*it_this < *it_block)) || + (block->continuous_block_ && (*it_this > *it_block))) { + GELOGD("Conflict current block size:%zu continuous:%d, reuse block max size:%zu continuous:%d", *it_this, + continuous_block_, *it_block, block->continuous_block_); + return; + } + } + + MemoryBlock *parent = nullptr; + MemoryBlock *child = nullptr; + // merge small block to large block + if (block->GetDependLifeBegin(stream_id_, total_node_depend_stream_life) > GetLifeEnd()) { + if ((block->child_offset_ + AlignSize()) <= *it_block) { + parent = block; + child = this; + } + } + if ((parent != nullptr) && (child != nullptr) && child->child_blocks_.empty()) { + parent->child_blocks_.emplace_back(child); + parent->child_offset_ += child->AlignSize(); + child->deleted_block_ = true; + GELOGI( + "Add continuous block[%p size:%zu, stream id:%ld life time[begin:%zu, end:%zu]] to" + " block[%p size:%zu, stream id:%ld, life time[begin:%zu, end:%zu]]", + child, child->block_size_, child->stream_id_, child->GetLifeBegin(), child->GetLifeEnd(), parent, + parent->block_size_, parent->stream_id_, parent->GetLifeBegin(), parent->GetLifeEnd()); + } +} + +void MemoryBlock::AddLifeReuseBlock(MemoryBlock *block, DependStreamLife &total_node_depend_stream_life) { if (CanNotLifeReuse(this) || CanNotLifeReuse(block)) { return; } + if (block->continuous_block_) { + AddContinuousLifeReuseBlock(block, total_node_depend_stream_life); + return; + } MemoryBlock *parent = nullptr; MemoryBlock *child = nullptr; // merge small block to large block - if ((block->GetLifeBegin() > GetLifeEnd()) && (block->stream_id_ == stream_id_)) { - if ((child_offset_ + block->block_size_) <= block_size_) { + if (block->GetDependLifeBegin(stream_id_, total_node_depend_stream_life) > GetLifeEnd()) { + if ((child_offset_ + block->AlignSize()) <= AlignSize()) { parent = this; child = block; - } else if ((block->child_offset_ + block_size_) <= block->block_size_) { + } else if ((block->child_offset_ + AlignSize()) <= block->AlignSize()) { parent = block; child = this; } } if ((parent != nullptr) && (child != nullptr) && child->child_blocks_.empty()) { parent->child_blocks_.emplace_back(child); - parent->child_offset_ += child->block_size_; + parent->child_offset_ += child->AlignSize(); child->deleted_block_ = true; GELOGI( "Add block[%p size:%zu, stream id:%ld life time[begin:%zu, end:%zu]] to" @@ -181,6 +240,87 @@ size_t MemoryBlock::GetLifeBegin() { return life_time; } +/// |-stream 1-| |-stream 2-| +/// |--block1--| |--block---| +/// |--block2--| |--block---| +/// |--block3--|\ |--block---| +/// |--block---| \ |--block---| +/// |--block---| \|--block---| +/// |--block---| |--block7--| +/// |--block---| |--block---| +/// block7's first node's input node's life begin > block2's life end, block7 can reuse block1~block2 +size_t MemoryBlock::GetDependLifeBegin(int64_t stream_id, DependStreamLife &total_node_depend_stream_life) { + AddDependLifeBegin(total_node_depend_stream_life); + auto it = depend_stream_life_.find(stream_id); + if (it == depend_stream_life_.end()) { + return 0; + } + return it->second; +} + +void AddDependLife(const ge::NodePtr &org_node, const ge::NodePtr &node, int64_t stream_id, + std::map &depend_stream_life, DependStreamLife &total_node_depend_stream_life) { + GE_CHECK_NOTNULL_EXEC(node, return ); + auto node_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL_EXEC(node_desc, return ); + auto node_id = node_desc->GetId(); + auto stream_life = total_node_depend_stream_life.find(node_id); + if (stream_life != total_node_depend_stream_life.end()) { + for (auto &it : stream_life->second) { + if (depend_stream_life.find(it.first) == depend_stream_life.end()) { + depend_stream_life[it.first] = it.second; + } + } + return; + } + + for (const auto &in_anchor : node->GetAllInAnchors()) { + GE_CHECK_NOTNULL_EXEC(in_anchor, continue); + for (auto peer_out_anchor : in_anchor->GetPeerAnchors()) { + GE_CHECK_NOTNULL_EXEC(peer_out_anchor, continue); + auto peer_node = peer_out_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL_EXEC(peer_node, continue); + auto peer_node_desc = peer_node->GetOpDesc(); + GE_CHECK_NOTNULL_EXEC(peer_node_desc, continue); + auto peer_node_stream_id = peer_node_desc->GetStreamId(); + if (peer_node_stream_id < 0) { + continue; + } + size_t peer_node_life_time = peer_node_desc->GetId(); + auto it = depend_stream_life.find(peer_node_stream_id); + if (it == depend_stream_life.end() || peer_node_life_time > it->second) { + depend_stream_life[peer_node_stream_id] = peer_node_life_time; + if (peer_node_stream_id != stream_id) { + GELOGI("Node:%s stream id:%ld depend node:%s stream id:%ld index[%d] life time[%zu].", + org_node->GetName().c_str(), stream_id, peer_node_desc->GetName().c_str(), peer_node_stream_id, + peer_out_anchor->GetIdx(), peer_node_life_time); + } + AddDependLife(org_node, peer_node, stream_id, depend_stream_life, total_node_depend_stream_life); + } + } + } + + // save on node to save next calculation + for (auto &it : depend_stream_life) { + if (total_node_depend_stream_life[node_id].find(it.first) == total_node_depend_stream_life[node_id].end()) { + total_node_depend_stream_life[node_id][it.first] = it.second; + } + } +} + +void MemoryBlock::AddDependLifeBegin(DependStreamLife &total_node_depend_stream_life) { + if (!depend_stream_life_.empty()) { + return; + } + if (!node_type_index_list_.empty()) { + auto node = node_type_index_list_.front().node; + if (node != nullptr) { + AddDependLife(node, node, stream_id_, depend_stream_life_, total_node_depend_stream_life); + } + } + depend_stream_life_[stream_id_] = GetLifeBegin(); +} + size_t MemoryBlock::GetLifeEnd() { if (!node_type_index_list_.empty()) { return node_type_index_list_.back().life_time_end; @@ -249,15 +389,15 @@ string ToString(ge::NodeTypeIndex &x) { string MemoryBlock::String() { stringstream ss; - ss << "Block size: " << Size() << " from " << HeadOffset() << " to " << TailOffset() << ""; - ss << "real_size_list: " << ToString(real_size_list_) << ""; - ss << "ref_count: " << ref_count_ << ""; + ss << "Block size: " << Size() << " from " << HeadOffset() << " to " << TailOffset() << " "; + ss << "real_size_list: " << ToString(real_size_list_) << " "; + ss << "ref_count: " << ref_count_ << " "; ss << "members: "; for (auto x : NodeTypeIndexList()) { - ss << "__node: " << ToString(x) << ""; + ss << "__node: " << ToString(x) << " "; } for (const auto &symbol : SymbolList()) { - ss << "__symbol: " << symbol << ""; + ss << "__symbol: " << symbol << " "; } return ss.str(); } @@ -302,7 +442,7 @@ void BlockMemAssigner::GetOutAndWorkSpaceMem(vector &all_memory_size) { if (iter1 == anchor_to_symbol_.end()) { continue; } - std::string symbol = iter1->second; + const std::string &symbol = iter1->second; auto iter2 = symbol_size_.find(symbol); if (iter2 == symbol_size_.end()) { symbol_size_[symbol] = size; @@ -317,7 +457,7 @@ void BlockMemAssigner::GetOutAndWorkSpaceMem(vector &all_memory_size) { all_memory_size.insert(all_memory_size.end(), temp.begin(), temp.end()); } GELOGI("The last atomic_addr_clean node id: %ld", atomic_addr_clean_id_); - for (auto &pair : symbol_size_) { + for (const auto &pair : symbol_size_) { all_memory_size.emplace_back(pair.second); } sort(all_memory_size.begin(), all_memory_size.end()); @@ -351,7 +491,7 @@ size_t GetBlockSize(size_t size, const vector &ranges) { } GELOGW("Memory needed size:%zu is beyond the biggest block in memory ranges.", size); - return 0; + return size; } bool IsDirectOutputNode(const NodePtr &node, int idx) { @@ -385,34 +525,8 @@ void ReduceReusableBlockCount(const MemoryBlock &mem_block, map &reusable_block_counts, const MemoryBlock &reusable_block, - size_t block_size, size_t real_size, bool continuous, int64_t atomic_addr_clean_id) { + size_t block_size, size_t real_size, bool continuous) { bool can_reuse = false; - - // If node is before atomic_addr_clean node, the continus memory can't be reused. - if (!reusable_block.NodeTypeIndexList().empty()) { - auto node = reusable_block.NodeTypeIndexList()[0].node; - if (node != nullptr) { - auto op_desc = node->GetOpDesc(); - if (op_desc != nullptr) { - if ((op_desc->GetId() < atomic_addr_clean_id) && continuous) { - return false; - } - } - } - } - - // continuous memory case:only real_size is maximum can be reused and only one continuous memory in one block - if (continuous || reusable_block.continuous_block_) { - auto it = - std::max_element(std::begin(reusable_block.NoAlignSizeList()), std::end(reusable_block.NoAlignSizeList())); - if (it != std::end(reusable_block.NoAlignSizeList())) { - GE_IF_BOOL_EXEC((continuous && reusable_block.continuous_block_) || (continuous && (real_size < *it)) || - (reusable_block.continuous_block_ && (real_size > *it)), - GELOGD("Conflict current block size:%zu continuous:%d, reuse block max size:%zu continuous:%d", - real_size, continuous, *it, reusable_block.continuous_block_); - return false;); - } - } if (reusable_block.Size() == block_size) { can_reuse = true; } else { @@ -427,14 +541,6 @@ bool CanReuseBySize(const map &reusable_block_counts, const Me return can_reuse; } -bool CanReuseByStream(const std::unordered_set &reuse_stream, MemoryBlock &reusable_block) { - bool can_reuse = false; - if (reuse_stream.find(reusable_block.stream_id_) != reuse_stream.cend()) { - can_reuse = true; - } - return can_reuse; -} - bool BlockMemAssigner::IsOutNodeSetContinuousInput(const NodePtr &n, uint32_t out_index, std::string &peer_name, uint32_t &peer_input_index) { if (n == nullptr || n->GetAllOutDataAnchors().size() <= 0) { @@ -495,11 +601,11 @@ void BlockMemAssigner::InitReuseFlag() { ge::CONSTANT, ge::CONSTANTOP}; static const std::set kPostReuseTypes = {ge::DATA_TYPE, ge::AIPP_DATA_TYPE, ge::ENTER, ge::REFENTER, ge::NEXTITERATION, ge::REFNEXTITERATION}; - for (auto &pair : symbol_to_anchors_) { + for (const auto &pair : symbol_to_anchors_) { std::string symbol = pair.first; bool pre_reuse_flag = true; bool post_reuse_flag = true; - for (auto &node_index_io : pair.second) { + for (const auto &node_index_io : pair.second) { if (node_index_io.io_type_ == kIn) { continue; } @@ -513,13 +619,13 @@ void BlockMemAssigner::InitReuseFlag() { if (node_index_io.node_->GetOutDataNodes().empty()) { out_flg = true; } - for (auto &in_anchor : out_anchor->GetPeerInDataAnchors()) { + for (const auto &in_anchor : out_anchor->GetPeerInDataAnchors()) { if (IsDirectOutputNode(in_anchor->GetOwnerNode(), in_anchor->GetIdx())) { out_flg = true; break; } } - std::string type = out_anchor->GetOwnerNode()->GetType(); + const std::string &type = out_anchor->GetOwnerNode()->GetType(); pre_reuse_flag = pre_reuse_flag && !out_flg && (kPreReuseTypes.count(type) == 0); post_reuse_flag = post_reuse_flag && (kPostReuseTypes.count(type) == 0); if (!pre_reuse_flag && !post_reuse_flag) { @@ -552,7 +658,7 @@ bool BlockMemAssigner::IsPreReuse(const NodePtr &node, uint32_t out_index) const return false; } - std::string symbol = iter1->second; + const std::string &symbol = iter1->second; auto iter2 = pre_reuse_flag_.find(symbol); if (iter2 == pre_reuse_flag_.end()) { return false; @@ -570,7 +676,7 @@ bool BlockMemAssigner::IsPostReuse(const MemoryBlock *mem_block) const { if (mem_block == nullptr) { return false; } - for (auto &symbol : mem_block->SymbolList()) { + for (const auto &symbol : mem_block->SymbolList()) { auto iter = post_reuse_flag_.find(symbol); if (iter == post_reuse_flag_.end()) { continue; @@ -593,8 +699,7 @@ bool BlockMemAssigner::IsSymbolExist(const NodeIndexIO &node_index_io) { if (iter == anchor_to_symbol_.end()) { return false; } - std::string symbol = iter->second; - return symbol_blocks_.find(symbol) != symbol_blocks_.end(); + return symbol_blocks_.find(iter->second) != symbol_blocks_.end(); } /// @@ -603,15 +708,43 @@ bool BlockMemAssigner::IsSymbolExist(const NodeIndexIO &node_index_io) { /// @return void /// void BlockMemAssigner::PrintSymbolMap() { - for (auto &pair : symbol_to_anchors_) { + for (const auto &pair : symbol_to_anchors_) { GELOGD("symbol=%s, max_size=%zu, pre_reuse=%s, post_reuse=%s", pair.first.c_str(), symbol_size_[pair.first], pre_reuse_flag_[pair.first] ? "true" : "false", post_reuse_flag_[pair.first] ? "true" : "false"); - for (auto &node_index_io : pair.second) { + for (const auto &node_index_io : pair.second) { GELOGD("anchor:%s", node_index_io.ToString().c_str()); } } } +bool BlockMemAssigner::IsContinuousOutput(const NodePtr &n) { + if (n == nullptr) { + GELOGE(FAILED, "Node is null."); + return false; + } + + // Get the continuous output type of the node, default is false + bool is_output_continuous = false; + auto node_desc = n->GetOpDesc(); + if (node_desc == nullptr) { + GELOGE(FAILED, "Node[%s] nodedesc is null.", n->GetName().c_str()); + return false; + } + + // If GetBool fail, is_output_continuous is false. + (void)ge::AttrUtils::GetBool(node_desc, ATTR_NAME_CONTINUOUS_OUTPUT, is_output_continuous); + if (is_output_continuous) { + if (n->GetOwnerComputeGraph() != nullptr) { + string graph_name = n->GetOwnerComputeGraph()->GetName(); + GELOGI("%s name[%s] set continuous, output size[%u].", graph_name.c_str(), n->GetName().c_str(), + n->GetAllOutDataAnchorsSize()); + return true; + } + } + + return false; +} + MemoryBlock *BlockMemAssigner::ApplyMemory(size_t block_size, size_t real_size, size_t no_align_size, MemoryType mem_type, const NodePtr &n, uint32_t out_index, const vector &workspace_reuse_flag, const bool is_op_reuse_mem, @@ -622,15 +755,14 @@ MemoryBlock *BlockMemAssigner::ApplyMemory(size_t block_size, size_t real_size, bool is_reuse_memory = false; string ge_disable_reuse_mem_env = "0"; - (void)ge::GetContext().GetOption(kDisableReuseMemory, ge_disable_reuse_mem_env); + (void)ge::GetContext().GetOption(OPTION_EXEC_DISABLE_REUSED_MEMORY, ge_disable_reuse_mem_env); if (ge_disable_reuse_mem_env != "1") { bool reuse_mem_flag = !((workspace_reuse_flag.size() > out_index) && !workspace_reuse_flag[out_index]); is_reuse_memory = !node_op_desc->HasAttr(kL2FusionDynamicConvergeOp) && !node_op_desc->HasAttr(kOpNoReuseMem) && reuse_mem_flag && is_op_reuse_mem && (IsPreReuse(n, out_index)); auto stream_id = node_op_desc->GetStreamId(); - auto map_iter = reusable_streams_map_.find(stream_id); - if (is_reuse_memory && map_iter != reusable_streams_map_.end()) { - for (auto it = reusable_blocks_.begin(); it != reusable_blocks_.end(); ++it) { + if (is_reuse_memory && !continuous) { + for (auto it = reusable_blocks_[stream_id].begin(); it != reusable_blocks_[stream_id].end(); ++it) { MemoryBlock *reusable_block = *it; if (!IsPostReuse(reusable_block)) { reusable_block->reuse_mem_ = false; @@ -639,11 +771,7 @@ MemoryBlock *BlockMemAssigner::ApplyMemory(size_t block_size, size_t real_size, } // A node can reuse blocks of the same stream and preorder streams - auto id = GetAtomicAddrCleanId(); - if (CanReuseBySize(reusable_block_counts_, *reusable_block, block_size, real_size, continuous, id) && - CanReuseByStream(map_iter->second, *reusable_block)) { - GELOGD("Cross stream mem reuse, target stream:%ld, current stream:%ld", reusable_block->stream_id_, - stream_id); + if (CanReuseBySize(reusable_block_counts_, *reusable_block, block_size, real_size, continuous)) { reusable_block->AddNodeTypeIndex({n, mem_type, out_index, false}, real_size, no_align_size); if (mem_type == kOutput) { auto iter = anchor_to_symbol_.find(NodeIndexIO(n, out_index, kOut).ToString()); @@ -654,7 +782,7 @@ MemoryBlock *BlockMemAssigner::ApplyMemory(size_t block_size, size_t real_size, reusable_block->continuous_block_ = continuous; reusable_block->ref_count_++; ReduceReusableBlockCount(*reusable_block, reusable_block_counts_); - reusable_blocks_.erase(it); + reusable_blocks_[stream_id].erase(it); return reusable_block; } } @@ -683,6 +811,47 @@ MemoryBlock *BlockMemAssigner::ApplyMemory(size_t block_size, size_t real_size, return block; } +MemoryBlock *BlockMemAssigner::ApplyContinuousMemory(const NodePtr &n, const vector &ranges, + const bool is_op_reuse_mem) { + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(n == nullptr, return nullptr, "input node is null."); + auto node_op_desc = n->GetOpDesc(); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(node_op_desc == nullptr, return nullptr, "node_op_desc is null."); + MemoryBlock *block = nullptr; + int64_t total_size = 0; + for (uint32_t index = 0; index < static_cast(node_op_desc->GetOutputsSize()); index++) { + auto output_op_desc = node_op_desc->GetOutputDescPtr(index); + if (output_op_desc == nullptr) { + return nullptr; + } + int64_t size = 0; + if (ge::TensorUtils::GetSize(*output_op_desc, size) != SUCCESS) { + GELOGI("Get size failed"); + return nullptr; + } + size_t align_size = static_cast(size); + AlignMemOffset(align_size); + total_size += align_size; + + // only apply total size in first block + if (index != 0) { + zero_memory_list_.emplace_back(n, kOutput, index); + } + } + + auto block_size = GetBlockSize(total_size, ranges); + GELOGI("Node[%s] continuous out memory size[%ld] block size[%zu]", node_op_desc->GetName().c_str(), total_size, + block_size); + + vector workspace_reuse_flag; + block = ApplyMemory(block_size, total_size, total_size, kOutput, n, 0, workspace_reuse_flag, is_op_reuse_mem, true); + if (block != nullptr) { + // hccl task need align header and tail + block->first_continuous_block_ = true; + block->last_continuous_block_ = true; + } + return block; +} + MemoryBlock *BlockMemAssigner::ApplyOutMemory(const NodePtr &n, uint32_t index, const vector &ranges, const bool is_op_reuse_mem, const bool continuous) { GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(n == nullptr, return nullptr, "input node is null."); @@ -700,7 +869,7 @@ MemoryBlock *BlockMemAssigner::ApplyOutMemory(const NodePtr &n, uint32_t index, "Get no align size failed"); if (IsSymbolExist(node_index_io)) { - std::string symbol = anchor_to_symbol_[node_index_io.ToString()]; + const std::string &symbol = anchor_to_symbol_[node_index_io.ToString()]; block = symbol_blocks_[symbol]; block->AddNodeTypeIndex({n, kOutput, index, true}, size, no_align_size); block->ref_count_++; @@ -923,7 +1092,11 @@ Status BlockMemAssigner::AssignOutputMemoryWithReuse(const NodePtr &node, vector (void)ge::AttrUtils::GetBool(op_desc, ATOMIC_ATTR_IS_ATOMIC_NODE, is_atomic); // Allocate memory for the current node and release node memory of the same size in the workspace GE_IF_BOOL_EXEC(ge_disable_reuse_mem_env_ != "1", - ReleaseMemorys(stream_workspace_blocks_[stream_id], reusable_blocks_);) + ReleaseMemorys(stream_workspace_blocks_[stream_id], reusable_blocks_[stream_id]);) + if (IsContinuousOutput(node)) { + (void)ApplyContinuousMemory(node, ranges, is_op_reuse_mem_); + return SUCCESS; + } for (uint32_t i = 0; i < static_cast(op_desc->GetOutputsSize()); i++) { int64_t size = 0; auto output_op_desc = op_desc->GetOutputDescPtr(i); @@ -950,7 +1123,8 @@ Status BlockMemAssigner::AssignOutputMemoryWithReuse(const NodePtr &node, vector continue; } // atomic can't be reused - if (is_op_reuse_mem_ && out_node_set_continuous_input && is_atomic) { + bool need_change = is_op_reuse_mem_ && out_node_set_continuous_input && is_atomic; + if (need_change) { is_op_reuse_mem_ = false; } MemoryBlock *mem_block = ApplyOutMemory(node, i, ranges, is_op_reuse_mem_, out_node_set_continuous_input); @@ -977,10 +1151,7 @@ Status BlockMemAssigner::AssignOutputMemoryWithReuse(const NodePtr &node, vector /// @return Status result /// void BlockMemAssigner::AssignMemoryWithReuse(vector &ranges) { - // Init reusable streams map - InitReusableStreamMap(); - - (void)ge::GetContext().GetOption(kDisableReuseMemory, ge_disable_reuse_mem_env_); + (void)ge::GetContext().GetOption(OPTION_EXEC_DISABLE_REUSED_MEMORY, ge_disable_reuse_mem_env_); GEEVENT("Reuse memory %s", ge_disable_reuse_mem_env_ == "1" ? "close" : "open"); string op_no_reuse_mem_str; const char *op_no_reuse_mem = std::getenv(OP_NO_REUSE_MEM); @@ -1033,7 +1204,7 @@ void BlockMemAssigner::AssignMemoryWithReuse(vector &ranges) { GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(mem_block == nullptr, continue, "failed to apply memory block."); CheckWorkspaceReuse(workspace_reuse_flag, i, stream_id, mem_block); } - ReleaseInputNodeOutMemory(node_out_blocks_, reusable_blocks_, n); + ReleaseInputNodeOutMemory(node_out_blocks_, reusable_blocks_[stream_id], n); } GELOGD("Assigned memory blocks:"); @@ -1043,8 +1214,8 @@ void BlockMemAssigner::AssignMemoryWithReuse(vector &ranges) { } bool merge_dynamic_batch = false; - GE_IF_BOOL_EXEC(!(ge_disable_reuse_mem_env_ == "1"), merge_dynamic_batch = MergeDynamicBatchBlocks();) - GE_IF_BOOL_EXEC(!merge_dynamic_batch, ReuseBlocksByLifeTime();) + GE_IF_BOOL_EXEC(!(ge_disable_reuse_mem_env_ == "1"), merge_dynamic_batch = MergeDynamicBatchBlocks()); + GE_IF_BOOL_EXEC((!(ge_disable_reuse_mem_env_ == "1") && !merge_dynamic_batch), ReuseBlocksByLifeTime(ranges.size())); AssignContinuousBlocks(); ResizeMemoryBlocks(); @@ -1161,10 +1332,12 @@ static bool CompareBlockIndex(MemoryBlock *left, MemoryBlock *right) { /// @param [in] input blocks need continuous /// @param [out] blocks after continuous order /// @param [in/out] blocks ordered +/// @param [in] input or output /// void ReAssignContinuousBlocks(const std::vector &org_blocks, const std::map block_map, - std::vector &dest_blocks, std::vector &continuous_blocks) { + std::vector &dest_blocks, std::vector &continuous_blocks, + const std::string &type) { for (auto &memory_block : org_blocks) { if (memory_block == nullptr || memory_block->deleted_block_) { continue; @@ -1181,7 +1354,7 @@ void ReAssignContinuousBlocks(const std::vector &org_blocks, for (auto &memory_block : continuous_blocks) { GE_IF_BOOL_EXEC(memory_block == nullptr, continue); - GELOGI("Block continuous input index:%d", memory_block->input_index_); + GELOGI("Block continuous %s index:%d", type.c_str(), memory_block->input_index_); count++; if (count == 1) { memory_block->first_continuous_block_ = true; @@ -1216,22 +1389,37 @@ void BlockMemAssigner::AssignContinuousBlocks() { continuous_block_map.size(), continuous_blocks.size()); continue; } - ReAssignContinuousBlocks(memory_blocks_, continuous_block_map, dest_memory_blocks, continuous_blocks); + ReAssignContinuousBlocks(memory_blocks_, continuous_block_map, dest_memory_blocks, continuous_blocks, "input"); memory_blocks_.swap(dest_memory_blocks); } } -void BlockMemAssigner::ReuseBlocksByLifeTime() { +void BlockMemAssigner::ReuseBlocksByLifeTime(size_t range_size) { + // 1 means block size is same so no need to do this + if (range_size <= 1) { + return; + } for (size_t i = 0; i < memory_blocks_.size(); ++i) { auto parent = memory_blocks_[i]; - if (parent == nullptr || parent->deleted_block_) { + if (parent == nullptr || parent->deleted_block_ || parent->continuous_block_) { continue; } if (parent->reuse_mem_ && !IsPostReuse(parent)) { parent->reuse_mem_ = false; } for (size_t j = i + 1; j < memory_blocks_.size(); ++j) { - parent->AddLifeReuseBlock(memory_blocks_[j]); + auto child = memory_blocks_[j]; + if (child == nullptr) { + continue; + } + // If node is before atomic_addr_clean node, the continus memory can't be reused. + if (!parent->NodeTypeIndexList().empty() && child->continuous_block_) { + auto node = parent->NodeTypeIndexList()[0].node; + if (node == nullptr || node->GetOpDesc() == nullptr || (node->GetOpDesc()->GetId() < GetAtomicAddrCleanId())) { + continue; + } + } + parent->AddLifeReuseBlock(child, total_node_depend_stream_life_); } } } @@ -1318,10 +1506,10 @@ void SetOffsetSize(const NodeTypeIndex &node_type, const MemoryBlock *block, siz } GELOGI( "[IMAS]Set %s name[%s] %s[%u] offset to [%ld] streamid[%ld] size[%zu] realsize[%zu]" - " noalignsize[%zu] life time begin[%zu] life time end[%zu] child[%d] isref[%d].", + " noalignsize[%zu] life time begin[%zu] life time end[%zu] child[%d:%d:%d:%d] isref[%d].", graph_name.c_str(), op_desc->GetName().c_str(), node_type.GetMemType().c_str(), node_type.index, offset, op_desc->GetStreamId(), block->Size(), real_size, no_align_size, op_desc->GetId(), end, child_block, - node_type.ref_input); + block->reuse_mem_, block->continuous_block_, block->deleted_block_, node_type.ref_input); } void SetBlockOpMemOffset(MemoryBlock *block, bool child_block) { @@ -1380,143 +1568,10 @@ Status BlockMemAssigner::Assign() { return SUCCESS; } -void BlockMemAssigner::InitReusableStreamMap() { - // save a stream's id and its first Node and last node. - map> stream_head_tail_node_map; - // save a stream's id and its directly child stream. - map> stream_dependency_map; - // save a stream's id and its occupied memory. - unordered_map stream_mem_map; - - // Find streams's first and last node. - FindHeadAndTailNodesForStream(stream_head_tail_node_map, stream_mem_map); - - // If streamB's first node is the output of streamA's last node, then B depends on A. - FindDependentStream(stream_head_tail_node_map, stream_dependency_map); - - // If a stream has more than one child stream, select the one that occupies the closest memory - for (const auto &iter : stream_dependency_map) { - if (iter.second.empty()) { - continue; - } - int64_t target_size = stream_mem_map[iter.first]; - int64_t min_size_gap = LONG_MAX; - int64_t target_reuse_stream_id = 0; - for (auto id : iter.second) { - if (labs(stream_mem_map[id] - target_size) < min_size_gap) { - target_reuse_stream_id = id; - min_size_gap = labs(stream_mem_map[id] - target_size); - } - } - // If b can reuse a, then b should also be able to reuse all blocks that a can reuse. - reusable_streams_map_[target_reuse_stream_id].insert(reusable_streams_map_[iter.first].begin(), - reusable_streams_map_[iter.first].end()); - } -} - -void BlockMemAssigner::FindHeadAndTailNodesForStream(map> &stream_head_tail_node_map, - unordered_map &stream_mem_map) { - for (const auto &n : compute_graph_->GetAllNodes()) { - GE_IF_BOOL_EXEC(n->GetOpDesc() == nullptr, GELOGW("Op desc is nullptr"); continue); - auto stream_id = n->GetOpDesc()->GetStreamId(); - // traverse to find streams's first and last node. - if (stream_head_tail_node_map.find(stream_id) == stream_head_tail_node_map.end()) { - stream_head_tail_node_map[stream_id] = std::make_pair(n, n); - reusable_streams_map_[stream_id].insert(stream_id); // a node can reuse blocks from same stream. - } else { - stream_head_tail_node_map[stream_id].second = n; - } - - // Accumulate the output size of the node in the stream. - for (size_t i = 0; i < n->GetOpDesc()->GetOutputsSize(); i++) { - int64_t size = 0; - if (ge::TensorUtils::GetSize(*n->GetOpDesc()->GetOutputDescPtr(static_cast(i)), size) != SUCCESS) { - GELOGW("Get output size failed!"); - continue; - } - stream_mem_map[stream_id] += size; - } - // Accumulate the workspace size of the node in the stream. - for (auto size : n->GetOpDesc()->GetWorkspaceBytes()) { - stream_mem_map[stream_id] += size; - } - } -} - -void BlockMemAssigner::FindDependentStream(map> &stream_head_tail_node_map, - map> &stream_dependency_map) { - for (const auto &it1 : stream_head_tail_node_map) { - for (const auto &it2 : stream_head_tail_node_map) { - if (it1 == it2) { - continue; - } - NodePtr pre_node = it1.second.second; - NodePtr post_node = it2.second.first; - std::vector out_nodes; - // Direct link out_node - for (const auto &out_node : pre_node->GetOutNodes()) { - if ((out_node->GetOpDesc() == nullptr) || (post_node->GetOpDesc() == nullptr) || - (pre_node->GetOpDesc() == nullptr)) { - continue; - } - out_nodes.emplace_back(out_node); - } - - FindDependentStreamBetweenGraphs(pre_node, out_nodes); - - for (auto &out_node : out_nodes) { - if (out_node->GetOpDesc()->GetId() == post_node->GetOpDesc()->GetId()) { - stream_dependency_map[pre_node->GetOpDesc()->GetStreamId()].insert(post_node->GetOpDesc()->GetStreamId()); - } - } - } - } -} - -/// -/// @ingroup GE -/// @brief Find dependent link between parent_graph and sub_graph -/// @param [in] pre_node -/// @param [out] out_nodes -/// @return void -/// @author -/// -void BlockMemAssigner::FindDependentStreamBetweenGraphs(const NodePtr &pre_node, std::vector &out_nodes) { - if ((pre_node == nullptr) || (pre_node->GetOpDesc() == nullptr)) { - return; - } - - // FunctionOp & subgraph input - std::vector subgraph_names = pre_node->GetOpDesc()->GetSubgraphInstanceNames(); - for (auto &subgraph_name : subgraph_names) { - ComputeGraphPtr subgraph = compute_graph_->GetSubgraph(subgraph_name); - if (subgraph == nullptr) { - continue; - } - for (auto &node : subgraph->GetDirectNode()) { - OpDescPtr op_desc = node->GetOpDesc(); - if (op_desc == nullptr) { - continue; - } - if (op_desc->HasAttr(ATTR_NAME_PARENT_NODE_INDEX)) { - out_nodes.emplace_back(node); - } - } - } - - // subgraph output & parent_node output - if (NodeUtils::IsSubgraphOutput(pre_node)) { - NodePtr parent_node = pre_node->GetOwnerComputeGraph()->GetParentNode(); - for (const auto &out_node : parent_node->GetOutNodes()) { - out_nodes.emplace_back(out_node); - } - } -} - bool BlockMemAssigner::CheckIsZeroMemNodeType(const string &node_type) const { return (node_type == VARIABLE) || (node_type == CONSTANT) || (node_type == MULTISHAPE) || - (node_type == HCOMBROADCAST) || (node_type == HCOMALLREDUCE) || (node_type == CONSTANTOP) || - (node_type == ASSIGNADD) || (node_type == ASSIGNSUB) || (node_type == ASSIGN) || (node_type == HVDWAIT) || - (node_type == HVDCALLBACKBROADCAST) || (node_type == HVDCALLBACKALLREDUCE); + (node_type == HCOMBROADCAST) || (node_type == CONSTANTOP) || (node_type == ASSIGNADD) || + (node_type == ASSIGNSUB) || (node_type == ASSIGN) || (node_type == HVDWAIT) || + (node_type == HVDCALLBACKBROADCAST); } } // namespace ge diff --git a/src/ge/graph/build/memory/block_mem_assigner.h b/src/ge/graph/build/memory/block_mem_assigner.h index 8ee4506e..3dfba4c5 100644 --- a/src/ge/graph/build/memory/block_mem_assigner.h +++ b/src/ge/graph/build/memory/block_mem_assigner.h @@ -34,6 +34,8 @@ namespace ge { const size_t kMaxLifeTime = 0xffffffff; +using DependStreamLife = std::map>; + enum MemoryType { kOutput, kWorkspace }; struct NodeTypeIndex { @@ -88,6 +90,8 @@ class MemoryBlock { } size_t Size() const { return block_size_; } + size_t AlignSize() const; + void SetHeadOffset(size_t offset); void SetTailOffset(size_t offset); @@ -116,7 +120,9 @@ class MemoryBlock { bool IsSameLabel(std::string &first_batch_label); - void AddLifeReuseBlock(MemoryBlock *block); + void AddContinuousLifeReuseBlock(MemoryBlock *block, DependStreamLife &total_node_depend_stream_life); + + void AddLifeReuseBlock(MemoryBlock *block, DependStreamLife &node_depend_stream_life); void SetLifeTimeEnd(size_t time); @@ -124,6 +130,10 @@ class MemoryBlock { size_t GetLifeEnd(); + void AddDependLifeBegin(DependStreamLife &node_depend_stream_life); + + size_t GetDependLifeBegin(int64_t stream_id, DependStreamLife &node_depend_stream_life); + int ref_count_; int64_t stream_id_; bool deleted_block_; @@ -196,47 +206,6 @@ class BlockMemAssigner : public MemAssigner { /// /// @ingroup GE - /// @brief Traversing the compute_graph_ to find the reuse relationship between streams - /// @param [in] reusable_stream_map map to save stream_id and its reusable stream_ids - /// @return void - /// @author - /// - void InitReusableStreamMap(); - - /// - /// @ingroup GE - /// @brief Traversing the compute_graph_ to find the first and last nodeptr of a stream. - /// @param [in] stream_head_tail_node_map map to save stream_id and its first and last nodeptr. - /// @param [in] stream_mem_map map to save stream_id and its memory capacity. - /// @return void - /// @author - /// - void FindHeadAndTailNodesForStream(std::map> &stream_head_tail_node_map, - std::unordered_map &stream_mem_map); - - /// - /// @ingroup GE - /// @brief Traversing the compute_graph_ to find the reuse relationship between streams. - /// @param [in] stream_head_tail_node_map map to save stream_id and its first and last nodeptr. - /// @param [in] stream_dependency_map map to save stream_id and stream_ids depends on it. - /// @return void - /// @author - /// - void FindDependentStream(std::map> &stream_head_tail_node_map, - std::map> &stream_dependency_map); - - /// - /// @ingroup GE - /// @brief Find dependent link between parent_graph and sub_graph - /// @param [in] pre_node - /// @param [out] out_nodes - /// @return void - /// @author - /// - void FindDependentStreamBetweenGraphs(const NodePtr &pre_node, std::vector &out_nodes); - - /// - /// @ingroup GE /// @brief Determine whether it is the type of zero memory node. /// @param [in] node type. /// @return bool true: is zero memory node; false: is not zero memory node @@ -395,9 +364,13 @@ class BlockMemAssigner : public MemAssigner { /// @return void /// @author /// - void ReuseBlocksByLifeTime(); + void ReuseBlocksByLifeTime(size_t range_size); - std::vector reusable_blocks_; + bool IsContinuousOutput(const NodePtr &n); + + MemoryBlock *ApplyContinuousMemory(const NodePtr &n, const vector &ranges, const bool is_op_reuse_mem); + + std::unordered_map> reusable_blocks_; std::map reusable_block_counts_; @@ -411,9 +384,6 @@ class BlockMemAssigner : public MemAssigner { std::unordered_map node_continuous_input_counts_; - // save stream_id and reusable stream_ids - std::unordered_map> reusable_streams_map_; - // reuse memory vector op_no_reuse_mem_vec_; @@ -426,6 +396,8 @@ class BlockMemAssigner : public MemAssigner { size_t life_time_; int64_t atomic_addr_clean_id_ = 0; + + DependStreamLife total_node_depend_stream_life_; }; } // namespace ge #endif // GE_GRAPH_BUILD_MEMORY_BLOCK_MEM_ASSIGNER_H_ diff --git a/src/ge/graph/build/memory/graph_mem_assigner.cc b/src/ge/graph/build/memory/graph_mem_assigner.cc index c4aca639..c5060dbd 100644 --- a/src/ge/graph/build/memory/graph_mem_assigner.cc +++ b/src/ge/graph/build/memory/graph_mem_assigner.cc @@ -222,9 +222,10 @@ Status GraphMemoryAssigner::ReAssignMemory(bool is_loop_graph, size_t &mem_offse mem_offset = memory_offset_[0].mem_offset_; - if (mem_offset > VarManager::Instance(0)->GetGraphMemoryMaxSize()) { + auto session_id = compute_graph_->GetSessionID(); + if (mem_offset > VarManager::Instance(session_id)->GetGraphMemoryMaxSize()) { GELOGE(ge::FAILED, "Current memoffset %zu is greater than memory manager malloc max size %zu", mem_offset, - VarManager::Instance(0)->GetGraphMemoryMaxSize()); + VarManager::Instance(session_id)->GetGraphMemoryMaxSize()); return ge::FAILED; } return SUCCESS; @@ -292,7 +293,8 @@ Status GraphMemoryAssigner::ReAssignContinuousMemory(bool is_loop_graph) { } else if (is_loop_graph) { GE_CHK_STATUS_RET(SetLoopGraphAtomicAttr(node, mem_clean_start)); } else { - GE_CHK_STATUS_RET(SetAtomicCleanAttr(nullptr, mem_clean_start, mem_clean_size), "SetAtomicCleanAttr failed."); + GE_CHK_STATUS_RET(SetAtomicCleanAttr(nullptr, {mem_clean_start}, {mem_clean_size}), + "SetAtomicCleanAttr failed."); } } } @@ -440,35 +442,33 @@ Status GraphMemoryAssigner::AssignContinuousOutputMemory(const ge::NodePtr &node GE_IF_BOOL_EXEC(out_op_desc == nullptr, GELOGE(ge::FAILED, "out_op_desc is null."); return ge::FAILED); vector output_list = out_op_desc->GetOutputOffset(); - if (out_op_desc->GetOutputsSize() > output_list.size()) { + if ((out_op_desc->GetOutputsSize() > output_list.size()) || (output_list.size() == 0)) { GELOGE(ge::FAILED, "The size %zu of node output desc is more than output_list's size %zu.", out_op_desc->GetOutputsSize(), output_list.size()); return ge::FAILED; } - memory_offset_[0].mem_offset_ += MEM_ALIGN_SIZE; + size_t mem_offset = output_list[0]; for (auto &out_data_anchor : node->GetAllOutDataAnchors()) { - output_list[out_data_anchor->GetIdx()] = memory_offset_[0].mem_offset_; - size_t pre_mem_offset = memory_offset_[0].mem_offset_; - + output_list[out_data_anchor->GetIdx()] = mem_offset; int64_t tensor_desc_size = 0; if (ge::TensorUtils::GetSize(*(out_op_desc->GetOutputDescPtr(out_data_anchor->GetIdx())), tensor_desc_size) != ge::SUCCESS) { GELOGE(FAILED, "GetSize failed."); return FAILED; } - memory_offset_[0].mem_offset_ += tensor_desc_size; - - AlignMemOffset(MEM_ALIGN_SIZE); + mem_offset += tensor_desc_size; + if (mem_offset <= 0) { + return FAILED; + } + mem_offset = (mem_offset + MEM_ALIGN_SIZE - 1) / MEM_ALIGN_SIZE * MEM_ALIGN_SIZE; GELOGI( - "[IMAS]Continuous output : Set %s name[%s] output[%d] offset to [%zu] stream_id[%ld] size[%zu] " + "[IMAS]Continuous output : Set %s name[%s] output[%d] offset to [%zu] stream_id[%ld] size[%ld] " "real_size[%ld].", node->GetOwnerComputeGraph()->GetName().c_str(), out_op_desc->GetName().c_str(), out_data_anchor->GetIdx(), - pre_mem_offset, out_op_desc->GetStreamId(), (memory_offset_[0].mem_offset_ - pre_mem_offset), tensor_desc_size); + output_list[out_data_anchor->GetIdx()], out_op_desc->GetStreamId(), tensor_desc_size, tensor_desc_size); } - out_op_desc->SetOutputOffset(output_list); - memory_offset_[0].mem_offset_ += MEM_ALIGN_SIZE; return ge::SUCCESS; } @@ -808,14 +808,12 @@ Status GraphMemoryAssigner::ReAssignVirtualNodesMemory(map(memory_offset_[0].mem_offset_); GELOGI("Begin to reAssign atomic memory, atomic initial address mem_offset = %zu!", memory_offset_[0].mem_offset_); + vector connect_netoutput_nodes; for (auto &node : compute_graph_->GetAllNodes()) { auto node_op_desc = node->GetOpDesc(); if (node_op_desc == nullptr) { @@ -838,36 +836,20 @@ Status GraphMemoryAssigner::ReAssignAtomicMemory(bool is_loop_graph) { return ge::PARAM_INVALID; } - // Atomic op memory start addr of loop graph - int64_t loop_graph_atomic_mem_start = static_cast(memory_offset_[0].mem_offset_); - - // Reassign atomic node output memory - Status ret = AssignAtomicOutputMemory(node); - if (ret != SUCCESS) { - GELOGE(ret, "Assign atomic output memory failed, node is %s.", node_op_desc->GetName().c_str()); - return ret; + vector is_connect_netoutput; + // If GetBool fail, attr is_connect_netoutput is an empty vector. + (void)ge::AttrUtils::GetListInt(node_op_desc, ATTR_NAME_NODE_CONNECT_OUTPUT, is_connect_netoutput); + if (!is_connect_netoutput.empty()) { + connect_netoutput_nodes.emplace_back(node); + continue; } - // Check atomic workspace - map> sub_node_workspace_info; - sub_node_workspace_info = node_op_desc->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, sub_node_workspace_info); - if (!sub_node_workspace_info.empty()) { - bool is_fusion_node = false; - // If GetBool fail, is_fusion_node is false. - (void)ge::AttrUtils::GetBool(node_op_desc, ATOMIC_ATTR_IS_FUSION_NODE, is_fusion_node); - - if (is_fusion_node) { - // Assign fusion atomic node workspace memory - ret = AssignFusionAtomicWorkspaceMemory(node_op_desc, sub_node_workspace_info); - } else { - // Assign single ordinary atomic node workspace memory, not include fusion node - ret = AssignOrdinaryAtomicWorkspaceMemory(node_op_desc, sub_node_workspace_info); - } - - if (ret != SUCCESS) { - GELOGE(ret, "Assign atomic workspace memory failed, node is %s.", node_op_desc->GetName().c_str()); - return ret; - } + // Atomic op memory start addr of loop graph + int64_t loop_graph_atomic_mem_start = static_cast(memory_offset_[0].mem_offset_); + vector mem_offset_end; + if (AssignAtomicOutputAndWorkspaceMemory(node, mem_offset_end) != SUCCESS) { + GELOGE(FAILED, "Assign atomic output and workspace memory failed, node is %s.", node->GetName().c_str()); + return FAILED; } /// In networks with loop op, atomic op uses atomic_addr_clean op independently, @@ -882,10 +864,77 @@ Status GraphMemoryAssigner::ReAssignAtomicMemory(bool is_loop_graph) { // Set the address attr of atomic clean operator int64_t atomic_mem_size = memory_offset_[0].mem_offset_ - atomic_mem_start; if (atomic_mem_size != 0) { - GE_CHK_STATUS_RET(SetAtomicCleanAttr(nullptr, atomic_mem_start, atomic_mem_size), "SetAtomicCleanAttr failed."); + GE_CHK_STATUS_RET(SetAtomicCleanAttr(nullptr, {atomic_mem_start}, {atomic_mem_size}), + "SetAtomicCleanAttr failed."); } } + if (AssignConnectNetOutputAtomicMemory(connect_netoutput_nodes) != SUCCESS) { + GELOGE(FAILED, "Failed to assign memory of nodes that connect to netoutput."); + return FAILED; + } + + return SUCCESS; +} + +Status GraphMemoryAssigner::AssignAtomicOutputAndWorkspaceMemory(const ge::NodePtr &node, + vector &mem_offset_end) { + auto node_op_desc = node->GetOpDesc(); + // Assign atomic node output memory + Status ret = AssignAtomicOutputMemory(node, mem_offset_end); + if (ret != SUCCESS) { + GELOGE(ret, "Failed to assign atomic output memory, node is %s.", node_op_desc->GetName().c_str()); + return ret; + } + + // Check and assign atomic node workspace memory + map> atomic_workspace_info; + atomic_workspace_info = node_op_desc->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, atomic_workspace_info); + if (!atomic_workspace_info.empty()) { + bool is_fusion_node = false; + // If GetBool fail, is_fusion_node is false. + (void)ge::AttrUtils::GetBool(node_op_desc, ATOMIC_ATTR_IS_FUSION_NODE, is_fusion_node); + + if (is_fusion_node) { + // Assign fusion atomic node workspace memory + ret = AssignFusionAtomicWorkspaceMemory(node_op_desc, atomic_workspace_info, mem_offset_end); + } else { + // Assign single ordinary atomic node workspace memory, not include fusion node + ret = AssignOrdinaryAtomicWorkspaceMemory(node_op_desc, atomic_workspace_info, mem_offset_end); + } + if (ret != SUCCESS) { + GELOGE(ret, "Assign atomic workspace memory failed, node is %s.", node_op_desc->GetName().c_str()); + return ret; + } + } + + return SUCCESS; +} + +Status GraphMemoryAssigner::AssignConnectNetOutputAtomicMemory(vector &connect_netoutput_nodes) { + for (auto &node : connect_netoutput_nodes) { + GE_CHECK_NOTNULL(node); + if (node->GetOpDesc() == nullptr) { + GELOGW("Current node %s op desc is nullptr, memory assignment is skipped.", node->GetName().c_str()); + continue; + } + + // Atomic memory start addr + int64_t original_atomic_mem_start = static_cast(memory_offset_[0].mem_offset_); + GELOGD("Start to assign memory of atomic node, node name: %s, node type: %s, mem_offset: %ld.", + node->GetName().c_str(), node->GetOpDesc()->GetType().c_str(), original_atomic_mem_start); + vector mem_offset_end; + if (AssignAtomicOutputAndWorkspaceMemory(node, mem_offset_end) != SUCCESS) { + GELOGE(FAILED, "Assign atomic output and workspace memory failed, node is %s.", node->GetName().c_str()); + return FAILED; + } + + // All atomic nodes use atomic_addr_clean op independently, so we need to set the attr separately. + if (SetIndependentAtomicAttr(node, original_atomic_mem_start, mem_offset_end) != SUCCESS) { + GELOGE(FAILED, "Failed to set atomic attr separately."); + return FAILED; + } + } return SUCCESS; } @@ -970,9 +1019,10 @@ bool GraphMemoryAssigner::CheckInputIsSupportAtomic(const ge::NodePtr &node) { return true; } -Status GraphMemoryAssigner::AssignAtomicOutputMemory(const ge::NodePtr &node) { +Status GraphMemoryAssigner::AssignAtomicOutputMemory(const ge::NodePtr &node, vector &mem_offset_end) { auto op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(op_desc == nullptr, GELOGE(ge::FAILED, "op_desc is null."); return ge::FAILED); + mem_offset_end.clear(); GELOGD("Begin to assign atomic output memory, node = %s.", op_desc->GetName().c_str()); vector atomic_output_index; @@ -995,24 +1045,9 @@ Status GraphMemoryAssigner::AssignAtomicOutputMemory(const ge::NodePtr &node) { // If the input of the cascade op needs to clear the atomic addr, there is no need to clear it separately here bool is_assigned_mem = false; - if (static_cast(output_index) >= node->GetAllOutDataAnchors().size()) { - GELOGE(ge::PARAM_INVALID, "Output index %ld is more than the size of node's AllOutDataAnchors.", output_index); - return ge::PARAM_INVALID; - } - auto out_data_anchor = node->GetAllOutDataAnchors().at(output_index); - GE_CHECK_NOTNULL(out_data_anchor); - auto input_anchors = out_data_anchor->GetPeerInDataAnchors(); - for (auto &input_anchor : input_anchors) { - auto output_node = input_anchor->GetOwnerNode(); - - /// Get input atomic attr of peer output op, if atomic_input_index[0] = -1, indicates that the atomic address - /// has been assigned - vector atomic_input_index; - (void)ge::AttrUtils::GetListInt(output_node->GetOpDesc(), ATOMIC_ATTR_INPUT_INDEX, atomic_input_index); - if (!atomic_input_index.empty() && (atomic_input_index[0] == kAllInputAddrIsAtomic)) { - is_assigned_mem = true; - break; - } + if (GetMemoryAssignmentStatus(node, output_index, is_assigned_mem) != SUCCESS) { + GELOGE(ge::FAILED, "Failed to get memory assignment of node %s.", node->GetName().c_str()); + return ge::FAILED; } // If you have already assigned an atomic address, skip it, and you don't need to reassign it. @@ -1037,6 +1072,7 @@ Status GraphMemoryAssigner::AssignAtomicOutputMemory(const ge::NodePtr &node) { memory_offset_[0].mem_offset_ += size; AlignMemOffset(MEM_ALIGN_SIZE); + mem_offset_end.emplace_back(memory_offset_[0].mem_offset_); } op_desc->SetOutputOffset(output_list); @@ -1044,8 +1080,33 @@ Status GraphMemoryAssigner::AssignAtomicOutputMemory(const ge::NodePtr &node) { return ge::SUCCESS; } +Status GraphMemoryAssigner::GetMemoryAssignmentStatus(const ge::NodePtr &node, int64_t output_index, + bool &is_mem_assigned) { + if (static_cast(output_index) >= node->GetAllOutDataAnchors().size()) { + GELOGE(ge::PARAM_INVALID, "Output index %ld is more than the size of node's AllOutDataAnchors.", output_index); + return ge::PARAM_INVALID; + } + auto out_data_anchor = node->GetAllOutDataAnchors().at(output_index); + GE_CHECK_NOTNULL(out_data_anchor); + auto input_anchors = out_data_anchor->GetPeerInDataAnchors(); + for (auto &input_anchor : input_anchors) { + auto output_node = input_anchor->GetOwnerNode(); + + /// Get input atomic attr of peer output op, if atomic_input_index[0] = -1, indicates that the atomic address + /// has been assigned + vector atomic_input_index; + (void)ge::AttrUtils::GetListInt(output_node->GetOpDesc(), ATOMIC_ATTR_INPUT_INDEX, atomic_input_index); + if (!atomic_input_index.empty() && (atomic_input_index[0] == kAllInputAddrIsAtomic)) { + is_mem_assigned = true; + break; + } + } + return SUCCESS; +} + Status GraphMemoryAssigner::AssignOrdinaryAtomicWorkspaceMemory(const ge::OpDescPtr &op_desc, - map> &workspace_info) { + map> &workspace_info, + vector &mem_offset_end) { GELOGI("Begin to reassign normal atomic memory, node = %s.", op_desc->GetName().c_str()); vector workspace_vector = op_desc->GetWorkspace(); @@ -1077,6 +1138,7 @@ Status GraphMemoryAssigner::AssignOrdinaryAtomicWorkspaceMemory(const ge::OpDesc op_desc->GetStreamId(), workspace_size, workspace_size); memory_offset_[0].mem_offset_ += workspace_size; + mem_offset_end.emplace_back(memory_offset_[0].mem_offset_); } } op_desc->SetWorkspace(workspace_vector); @@ -1085,7 +1147,8 @@ Status GraphMemoryAssigner::AssignOrdinaryAtomicWorkspaceMemory(const ge::OpDesc } Status GraphMemoryAssigner::AssignFusionAtomicWorkspaceMemory(const ge::OpDescPtr &op_desc, - map> &workspace_info) { + map> &workspace_info, + vector &mem_offset_end) { GELOGI("Begin to reassign fusion atomic memory, node = %s.", op_desc->GetName().c_str()); map> sub_node_workspace_offset; @@ -1107,6 +1170,7 @@ Status GraphMemoryAssigner::AssignFusionAtomicWorkspaceMemory(const ge::OpDescPt op_desc->GetStreamId(), workspace_size, workspace_size); memory_offset_[0].mem_offset_ += workspace_size; + mem_offset_end.emplace_back(memory_offset_[0].mem_offset_); index_offset.insert(std::make_pair(workspace_index, workspace_offset)); } sub_node_workspace_offset.insert(std::make_pair(iter.first, index_offset)); @@ -1222,10 +1286,16 @@ ge::Status GraphMemoryAssigner::UpdateOpInputOffset(const NodePtr &node, vector< peer_out_anchor->GetOwnerNode()->GetOpDesc()->GetName().c_str(), peer_out_anchor->GetIdx(), input_list.back()); } else { + int64_t output_offset = output_list.at(peer_out_anchor->GetIdx()); + if (peer_out_anchor->GetOwnerNode()->GetType() == CONSTANT) { + GeTensorDesc tensor_desc = tmp_op_desc->GetInputDesc(input_index); + GE_CHK_STATUS(TensorUtils::GetDataOffset(tensor_desc, output_offset)); + } + GELOGI("node[%s] input[%d] is set from node[%s] out index[%d] offset[%ld]", tmp_op_desc->GetName().c_str(), input_index, peer_out_anchor->GetOwnerNode()->GetOpDesc()->GetName().c_str(), peer_out_anchor->GetIdx(), - output_list.at(peer_out_anchor->GetIdx())); - input_list.emplace_back(output_list.at(peer_out_anchor->GetIdx())); + output_offset); + input_list.emplace_back(output_offset); } } } @@ -1264,7 +1334,7 @@ ge::Status GraphMemoryAssigner::UpdateOpInputOffset(const NodePtr &node) const { } } } - } else if (node->GetType() == DATA) { + } else if (node->GetType() == DATA_TYPE) { if (UpdateConstArgsOffset(node, input_list) != SUCCESS) { GELOGE(FAILED, "Update data: %s args offset failed.", node->GetName().c_str()); return FAILED; @@ -1280,6 +1350,47 @@ ge::Status GraphMemoryAssigner::UpdateOpInputOffset(const NodePtr &node) const { return SUCCESS; } +Status GraphMemoryAssigner::SetIndependentAtomicAttr(const ge::NodePtr &node, int64_t atomic_mem_start, + const vector &mem_offset_end) { + GELOGD("Start to set independent atomic attr, atomic_addr_clean memory offset start is %ld", atomic_mem_start); + + // Parsing offset and size vectors + vector memory_offset_start; + vector memory_offset_size; + memory_offset_start.emplace_back(atomic_mem_start); + for (size_t i = 0; i < mem_offset_end.size(); ++i) { + memory_offset_start.emplace_back(mem_offset_end[i]); + // Number 1 means element index + auto size = memory_offset_start[i + 1] - memory_offset_start[i]; + memory_offset_size.emplace_back(size); + } + memory_offset_start.pop_back(); + + const auto &in_control_anchor = node->GetInControlAnchor(); + if (!memory_offset_size.empty() && in_control_anchor != nullptr) { + for (auto &peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) { + if (peer_out_control_anchor == nullptr) { + continue; + } + auto peer_out_node = peer_out_control_anchor->GetOwnerNode(); + auto peer_out_node_desc = peer_out_node->GetOpDesc(); + if (peer_out_node_desc == nullptr) { + continue; + } + + GELOGD("Current node memory_offset vector size is %zu, node name %s, node type is %s.", memory_offset_size.size(), + peer_out_node_desc->GetName().c_str(), peer_out_node_desc->GetType().c_str()); + if (peer_out_node_desc->GetType() == ATOMICADDRCLEAN) { + if (SetAtomicCleanAttr(peer_out_node, memory_offset_start, memory_offset_size) != SUCCESS) { + GELOGE(FAILED, "Set atomic clean attr failed."); + return FAILED; + } + } + } + } + return SUCCESS; +} + Status GraphMemoryAssigner::SetLoopGraphAtomicAttr(const ge::NodePtr &node, int64_t atomic_mem_start) { // set the address attr of atomic clean operator for loop graph int64_t atomic_mem_size = memory_offset_[0].mem_offset_ - atomic_mem_start; @@ -1301,7 +1412,7 @@ Status GraphMemoryAssigner::SetLoopGraphAtomicAttr(const ge::NodePtr &node, int6 peer_out_node_desc->GetType().c_str()); if (peer_out_node_desc->GetType() == ATOMICADDRCLEAN) { - GE_CHK_STATUS_EXEC(SetAtomicCleanAttr(peer_out_node, atomic_mem_start, atomic_mem_size), + GE_CHK_STATUS_EXEC(SetAtomicCleanAttr(peer_out_node, {atomic_mem_start}, {atomic_mem_size}), GELOGE(FAILED, "SetAtomicCleanAttr failed."); return FAILED); } @@ -1310,8 +1421,8 @@ Status GraphMemoryAssigner::SetLoopGraphAtomicAttr(const ge::NodePtr &node, int6 return SUCCESS; } -ge::Status GraphMemoryAssigner::SetAtomicCleanAttr(const NodePtr &n, int64_t atomic_mem_start, - int64_t atomic_mem_size) { +ge::Status GraphMemoryAssigner::SetAtomicCleanAttr(const NodePtr &n, const vector &atomic_mem_start, + const vector &atomic_mem_size) { for (ge::NodePtr &node : compute_graph_->GetAllNodes()) { auto node_op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue); @@ -1320,15 +1431,15 @@ ge::Status GraphMemoryAssigner::SetAtomicCleanAttr(const NodePtr &n, int64_t ato ((n == nullptr) && (node_op_desc->GetType() == ATOMICADDRCLEAN))) { vector workspace_vector = node_op_desc->GetWorkspace(); vector workspace_byte_vector = node_op_desc->GetWorkspaceBytes(); - workspace_vector.emplace_back(atomic_mem_start); - workspace_byte_vector.emplace_back(atomic_mem_size); + workspace_vector.insert(workspace_vector.end(), atomic_mem_start.begin(), atomic_mem_start.end()); + workspace_byte_vector.insert(workspace_byte_vector.end(), atomic_mem_size.begin(), atomic_mem_size.end()); node_op_desc->SetWorkspace(workspace_vector); node_op_desc->SetWorkspaceBytes(workspace_byte_vector); std::vector mem_start_vector; // If GetListInt fail, mem_start_vector is empty. (void)ge::AttrUtils::GetListInt(node_op_desc, ATTR_NAME_AUTOMIC_ADD_START, mem_start_vector); - mem_start_vector.emplace_back(atomic_mem_start); + mem_start_vector.insert(mem_start_vector.end(), atomic_mem_start.begin(), atomic_mem_start.end()); GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(node_op_desc, ATTR_NAME_AUTOMIC_ADD_START, mem_start_vector), GELOGE(FAILED, "SetListInt failed."); return FAILED); @@ -1336,16 +1447,26 @@ ge::Status GraphMemoryAssigner::SetAtomicCleanAttr(const NodePtr &n, int64_t ato std::vector mem_size_vector; // If GetListInt fail, mem_size_vector is empty. (void)ge::AttrUtils::GetListInt(node_op_desc, ATTR_NAME_AUTOMIC_ADD_MEM_SIZE, mem_size_vector); - mem_size_vector.emplace_back(atomic_mem_size); + mem_size_vector.insert(mem_size_vector.end(), atomic_mem_size.begin(), atomic_mem_size.end()); GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(node_op_desc, ATTR_NAME_AUTOMIC_ADD_MEM_SIZE, mem_size_vector), GELOGE(FAILED, "SetListInt failed."); return FAILED); - GELOGI( - "[IMAS]SetAtomicCleanAttr : Set %s name[%s] output[%d] offset to [%ld] streamid[%ld] size[%ld] " - "realsize[%ld].", - node->GetOwnerComputeGraph()->GetName().c_str(), node_op_desc->GetName().c_str(), 0, atomic_mem_start, - node->GetOpDesc()->GetStreamId(), atomic_mem_size, atomic_mem_size); + std::stringstream ss; + for (auto iter : atomic_mem_start) { + ss << iter << " "; + } + string atomic_mem_start_str = ss.str(); + ss.clear(); + ss.str(""); + for (auto iter : atomic_mem_size) { + ss << iter << " "; + } + string atomic_mem_size_str = ss.str(); + + GELOGI("[IMAS]SetAtomicCleanAttr : Set graph[%s] atomic_node[%s] output offset [%s] size[%s] streamid[%ld]", + node->GetOwnerComputeGraph()->GetName().c_str(), node_op_desc->GetName().c_str(), + atomic_mem_start_str.c_str(), atomic_mem_size_str.c_str(), node->GetOpDesc()->GetStreamId()); } } return SUCCESS; diff --git a/src/ge/graph/build/memory/graph_mem_assigner.h b/src/ge/graph/build/memory/graph_mem_assigner.h index 67008918..afe9a4fa 100644 --- a/src/ge/graph/build/memory/graph_mem_assigner.h +++ b/src/ge/graph/build/memory/graph_mem_assigner.h @@ -147,22 +147,33 @@ class GraphMemoryAssigner { /// bool CheckInputIsSupportAtomic(const ge::NodePtr &node); - ge::Status AssignAtomicOutputMemory(const ge::NodePtr &node); + ge::Status GetMemoryAssignmentStatus(const ge::NodePtr &node, int64_t output_index, bool &is_mem_assigned); + + ge::Status AssignAtomicOutputMemory(const ge::NodePtr &node, std::vector &mem_offset_end); ge::Status AssignOrdinaryAtomicWorkspaceMemory(const ge::OpDescPtr &op_desc, - std::map> &workspace_info); + std::map> &workspace_info, + std::vector &mem_offset_end); ge::Status AssignFusionAtomicWorkspaceMemory(const ge::OpDescPtr &op_desc, - std::map> &workspace_info); + std::map> &workspace_info, + std::vector &mem_offset_end); + + ge::Status AssignAtomicOutputAndWorkspaceMemory(const ge::NodePtr &node, std::vector &mem_offset_end); + ge::Status AssignConnectNetOutputAtomicMemory(vector &connect_netoutput_nodes); + + ge::Status SetIndependentAtomicAttr(const ge::NodePtr &node, int64_t atomic_mem_start, + const std::vector &mem_offset_end); /// /// @brief set loop graph atomic attr - /// @param node + /// @param node, atomic memory assignment start offset /// @param atomic_mem_start: atomic op memory start address /// ge::Status SetLoopGraphAtomicAttr(const ge::NodePtr &node, int64_t atomic_mem_start); - ge::Status SetAtomicCleanAttr(const ge::NodePtr &n, int64_t atomic_mem_start, int64_t atomic_mem_size); + ge::Status SetAtomicCleanAttr(const ge::NodePtr &n, const std::vector &atomic_mem_start, + const std::vector &atomic_mem_size); void AlignMemOffset(const int64_t &mem_align_size); diff --git a/src/ge/graph/build/memory/var_mem_assign_util.cc b/src/ge/graph/build/memory/var_mem_assign_util.cc index 111adc7a..a352cf65 100644 --- a/src/ge/graph/build/memory/var_mem_assign_util.cc +++ b/src/ge/graph/build/memory/var_mem_assign_util.cc @@ -299,21 +299,33 @@ Status VarMemAssignUtil::SetOutTransNodeToAssign(const ge::NodePtr &node, const Status VarMemAssignUtil::AssignMemory2HasRefAttrNode(ge::ComputeGraphPtr &compute_graph) { for (const ge::NodePtr &n : compute_graph->GetAllNodes()) { string ref_var_src_var_name; - GE_CHECK_NOTNULL(n->GetOpDesc()); - bool is_ref = ge::AttrUtils::GetStr(n->GetOpDesc(), REF_VAR_SRC_VAR_NAME, ref_var_src_var_name); - GE_IF_BOOL_EXEC(is_ref, - GE_CHK_STATUS_RET(AssignData2VarRef(n, ref_var_src_var_name, compute_graph->GetSessionID()))); + auto op_desc = n->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + for (uint32_t idx = 0; idx < op_desc->GetOutputsSize(); idx += 1) { + const auto out_desc = op_desc->MutableOutputDesc(idx); + if (ge::AttrUtils::GetStr(out_desc, REF_VAR_SRC_VAR_NAME, ref_var_src_var_name)) { + GE_CHK_STATUS_RET(AssignData2VarRef(n, ref_var_src_var_name, compute_graph->GetSessionID(), idx)); + } + } } return SUCCESS; } Status VarMemAssignUtil::AssignData2VarRef(const ge::NodePtr &has_ref_attr_node, const string &src_var_name, - uint64_t session_id) { - if (!TransOpUtil::IsTransOp(has_ref_attr_node)) { - return SUCCESS; - } + uint64_t session_id, uint32_t out_index) { // Get ref_var_src_var address - ge::NodePtr var_ref_src_var = has_ref_attr_node->GetOwnerComputeGraph()->FindNode(src_var_name); + auto root_graph = GraphUtils::FindRootGraph(has_ref_attr_node->GetOwnerComputeGraph()); + GE_CHECK_NOTNULL(root_graph); + ge::NodePtr var_ref_src_var = root_graph->FindNode(src_var_name); + if (var_ref_src_var == nullptr) { + for (auto sub_graph : root_graph->GetAllSubgraphs()) { + auto node_ptr = sub_graph->FindNode(src_var_name); + if (node_ptr != nullptr) { + var_ref_src_var = node_ptr; + break; + } + } + } GE_IF_BOOL_EXEC(var_ref_src_var == nullptr || var_ref_src_var->GetOpDesc() == nullptr, return FAILED); GeTensorDesc src_tensor_desc = var_ref_src_var->GetOpDesc()->GetOutputDesc(0); uint8_t *dev_ptr = nullptr; @@ -322,14 +334,8 @@ Status VarMemAssignUtil::AssignData2VarRef(const ge::NodePtr &has_ref_attr_node, vector ref_attr_node_output_list = has_ref_attr_node->GetOpDesc()->GetOutputOffset(); GE_CHECK_SIZE(ref_attr_node_output_list.size()); - int out_index = 0; - bool is_get = ge::AttrUtils::GetInt(var_ref_src_var->GetOpDesc(), REF_VAR_PRE_PEER_OUT_INDEX, out_index); - if (!is_get) { - GELOGI("%s failed to get attr [REF_VAR_PRE_PEER_OUT_INDEX]", var_ref_src_var->GetName().c_str()); - } - - GE_CHK_BOOL_RET_STATUS(static_cast(out_index) < ref_attr_node_output_list.size(), FAILED, - "out_index %d >= ref_attr_node_output_list.size() %zu", out_index, + GE_CHK_BOOL_RET_STATUS(out_index < ref_attr_node_output_list.size(), FAILED, + "out_index %u >= ref_attr_node_output_list.size() %zu", out_index, ref_attr_node_output_list.size()); ref_attr_node_output_list[out_index] = static_cast(reinterpret_cast(dev_ptr)); diff --git a/src/ge/graph/build/memory/var_mem_assign_util.h b/src/ge/graph/build/memory/var_mem_assign_util.h index 036fed06..cb38af29 100644 --- a/src/ge/graph/build/memory/var_mem_assign_util.h +++ b/src/ge/graph/build/memory/var_mem_assign_util.h @@ -46,8 +46,8 @@ class VarMemAssignUtil { static Status DealTransNode(const ge::NodePtr &final_trans_node); static Status DealExportTransNode(const ge::NodePtr &node, const ge::NodePtr &final_trans_node); - static Status AssignData2VarRef(const ge::NodePtr &variable_ref, const std::string &src_var_name, - uint64_t session_id); + static Status AssignData2VarRef(const ge::NodePtr &variable_ref, const std::string &src_var_name, uint64_t session_id, + uint32_t out_index); static Status SetOutTransNodeToAssign(const ge::NodePtr &node, const ge::NodePtr &final_trans_node, size_t index); }; diff --git a/src/ge/graph/build/model_builder.cc b/src/ge/graph/build/model_builder.cc index 62abd4ab..5435eb7b 100644 --- a/src/ge/graph/build/model_builder.cc +++ b/src/ge/graph/build/model_builder.cc @@ -15,10 +15,10 @@ */ #include "graph/build/model_builder.h" +#include #include #include #include -#include #include "common/ge/ge_util.h" #include "framework/common/debug/ge_log.h" #include "graph/anchor.h" @@ -27,6 +27,7 @@ #include "graph/build/label_allocator.h" #include "graph/build/stream_allocator.h" #include "graph/common/omg_util.h" +#include "graph/common/ge_call_wrapper.h" #include "graph/debug/ge_attr_define.h" #include "graph/ge_attr_value.h" #include "graph/ge_context.h" @@ -41,10 +42,12 @@ #include "graph/utils/op_desc_utils.h" #include "graph/utils/tensor_utils.h" #include "graph/utils/type_utils.h" +#include "graph/passes/memcpy_addr_async_pass.h" #include "init/gelib.h" #include "memory/memory_assigner.h" #include "omg/version.h" #include "register/op_registry.h" +#include "graph/passes/set_input_output_offset_pass.h" using std::map; using std::set; @@ -85,9 +88,11 @@ bool IsGeLocalOp(const ge::ConstOpDescPtr &op_desc) { } // namespace namespace ge { -ModelBuilder::ModelBuilder(ge::ComputeGraphPtr compute_graph, const Graph2SubGraphInfoList &subgraphs, - const map &stream_max_parallel_num, bool hcom_parallel, int mode) - : mem_offset_(0), +ModelBuilder::ModelBuilder(uint64_t session_id, ge::ComputeGraphPtr compute_graph, + const Graph2SubGraphInfoList &subgraphs, const map &stream_max_parallel_num, + bool hcom_parallel, int mode) + : session_id_(session_id), + mem_offset_(0), weight_offset_(kWeightsStartOffset), compute_graph_(std::move(compute_graph)), subgraphs_(subgraphs), @@ -242,7 +247,7 @@ Status ModelBuilder::SetInputOutputDesc() { Status ret; GELOGI("Start to SetInputOutputDesc."); - for (const ge::NodePtr &n : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto node_op_desc = n->GetOpDesc(); GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue); @@ -291,7 +296,7 @@ Status ModelBuilder::SetInputOutputDesc() { } void ModelBuilder::AddNodeInputProperty() { - for (const ge::NodePtr &node : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto node_op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(node_op_desc == nullptr, GELOGW("node_op_desc is nullptr!"); return ); vector src_name_list; @@ -318,7 +323,7 @@ void ModelBuilder::AddNodeInputProperty() { node_op_desc->SetSrcIndex(src_index_list); } - for (const ge::NodePtr &node : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto node_op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(node_op_desc == nullptr, GELOGW("node_op_desc is nullptr!"); return ); GE_IF_BOOL_EXEC(node_op_desc->GetType() == NETOUTPUT, continue); @@ -356,7 +361,7 @@ void ModelBuilder::AddNodeInputProperty() { Status ModelBuilder::AdjustInputTensorFlag() { GELOGI("Start to AdjustInputTensorFlag."); - for (const ge::NodePtr &n : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { if ((n->GetType() == DATA_TYPE) || (n->GetType() == AIPP_DATA_TYPE)) { GELOGD("Data node: %s.", n->GetName().c_str()); for (const auto &anchor : n->GetAllOutDataAnchors()) { @@ -432,6 +437,21 @@ Status ModelBuilder::BuildModelDef(ge::Model &model) { GE_CHK_BOOL_EXEC(ge::AttrUtils::SetBool(&model, ATTR_NAME_SWITCH_FOR_L1_FUSION, is_l1_fusion_enable_), GELOGE(FAILED, "SetBool of ATTR_NAME_SWITCH_FOR_L1_FUSION failed."); return FAILED); + const DumpProperties &dump_properties = PropertiesManager::Instance().GetDumpProperties(session_id_); + bool is_op_debug = dump_properties.IsOpDebugOpen(); + GELOGI("Get op debug:%d", is_op_debug); + if (is_op_debug) { + if (!ge::AttrUtils::SetBool(&model, ATTR_OP_DEBUG_FLAG, is_op_debug)) { + GELOGE(FAILED, "SetBool of ATTR_OP_DEBUG_FLAG failed."); + return FAILED; + } + uint32_t op_debug_mode = dump_properties.GetOpDebugMode(); + GELOGI("Get op debug mode:%d", op_debug_mode); + if (!ge::AttrUtils::SetInt(&model, ATTR_OP_DEBUG_MODE, op_debug_mode)) { + GELOGE(FAILED, "SetBool of ATTR_OP_DEBUG_MODE failed."); + return FAILED; + } + } model.SetName(compute_graph_->GetName()); model.SetGraph(ge::GraphUtils::CreateGraphFromComputeGraph(compute_graph_)); @@ -448,7 +468,7 @@ Status ModelBuilder::BuildModelDef(ge::Model &model) { } void ModelBuilder::ClearOriginalFormat() { - for (const ge::NodePtr &n : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto node_op_desc = n->GetOpDesc(); if (node_op_desc != nullptr) { if (node_op_desc->HasAttr(ATTR_NAME_FORMAT)) { @@ -487,7 +507,7 @@ Status ModelBuilder::MergeWeights() { weight_buffer_ = buffer; auto base_addr = weight_buffer_.GetData(); - for (const ge::NodePtr &node : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(op_desc == nullptr, continue); if (node->GetType() != CONSTANT) { @@ -514,7 +534,7 @@ Status ModelBuilder::MergeWeights() { auto weight_data = weight->MutableData(); // copy const op weight data to buffer - GELOGI("Move weight data to buffer, name: %s offset: %ld", node->GetName().c_str(), offset); + GELOGI("Move to buffer, name: %s offset: %ld size: %zu", node->GetName().c_str(), offset, weight_data.size()); ge::TensorUtils::SetWeightSize(weight->MutableTensorDesc(), static_cast(weight_data.size())); if ((offset == 0) || (weight_data.size() == 0)) { GELOGI("Size or offset is 0. size: %lu offset: %ld", weight_data.size(), offset); @@ -527,8 +547,8 @@ Status ModelBuilder::MergeWeights() { weight_data.size()); return FAILED; } - uintptr_t dst_ptr = (uintptr_t)base_addr + offset; - uintptr_t src_ptr = (uintptr_t)weight_data.data(); + uintptr_t dst_ptr = reinterpret_cast(base_addr) + offset; + uintptr_t src_ptr = reinterpret_cast(weight_data.data()); size_t left_size = weight_data.size(); while (left_size > SECUREC_MEM_MAX_LEN) { auto err = memcpy_s(reinterpret_cast(dst_ptr), SECUREC_MEM_MAX_LEN, reinterpret_cast(src_ptr), @@ -565,7 +585,7 @@ Status ModelBuilder::SaveDataToModel(ge::Model &model, ge::GeModel &ge_model) { // Add TBE Kernels std::set name_set; - for (const ge::NodePtr &n : compute_graph_->GetAllNodes()) { + for (const ge::NodePtr &n : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto node_op_desc = n->GetOpDesc(); GE_IF_BOOL_EXEC(node_op_desc == nullptr, continue); TBEKernelPtr tbe_kernel = node_op_desc->TryGetExtAttr(ge::OP_EXTATTR_NAME_TBE_KERNEL, TBEKernelPtr()); @@ -650,16 +670,40 @@ Status ModelBuilder::BuildModelForGetTask(ge::Model &model) { GE_CHK_STATUS_RET(label_allocator.AssignFunctionalLabels(label_num_), "Assign label failed."); GE_TIMESTAMP_END(AssignFunctionalLabels, "ModelBuilder::AssignFunctionalLabels"); + // Add memcpy_addr_async node. + rtFeatureType_t feature_type = FEATURE_TYPE_MEMCPY; + int32_t feature_info = MEMCPY_INFO_SUPPORT_ZEROCOPY; + int64_t value = 0; + rtError_t rt_ret = rtGetRtCapability(feature_type, feature_info, &value); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtGetRtCapability failed."); + return RT_FAILED; + } else { + if (value == RT_CAPABILITY_SUPPORT) { + GE_TIMESTAMP_START(AddMemcpyAddrAsyncNode); + MemcpyAddrAsyncPass memcpy_addr; + GE_CHK_STATUS_RET(memcpy_addr.Run(compute_graph_), "Add memcpy_addr_async node failed."); + GE_TIMESTAMP_END(AddMemcpyAddrAsyncNode, "MemcpyAddrAsyncPass::Run."); + } else { + GELOGW("rtGetRtCapability not support memcpy_addr_async."); + } + } + GE_TIMESTAMP_START(AssignMemory); MemoryAssigner mem_assigner(compute_graph_); GE_CHK_STATUS_RET(mem_assigner.AssignMemory(is_loop_graph_, mem_offset_, zero_copy_mem_size_), "Assign Memory Failed!"); GE_TIMESTAMP_END(AssignMemory, "GraphBuilder::AssignMemory"); + GE_TIMESTAMP_START(SetInputOutputOffset); + SetInputOutputOffsetPass input_output_offset; + GE_CHK_STATUS_RET(input_output_offset.Run(compute_graph_), "Set input output offset failed."); + GE_TIMESTAMP_END(SetInputOutputOffset, "SetInputOutputOffsetPass::Run."); + // Compile single op in graph build stage GE_TIMESTAMP_START(CompileSingleOp); GE_CHK_STATUS_RET(CompileSingleOp(), "ATC builder CompileSingleOp() return fail."); - GE_TIMESTAMP_END(CompileSingleOp, "GraphBuilder::CompileSingleOp"); + GE_TIMESTAMP_EVENT_END(CompileSingleOp, "GraphBuilder::CompileSingleOp"); // Refresh real streams and insert event nodes. GE_TIMESTAMP_START(RefreshRealStream); @@ -700,7 +744,7 @@ Status ModelBuilder::CompileSingleOp() { GE_TIMESTAMP_CALLNUM_START(BatchCompileOp); std::unordered_map> node_vector_map; - for (auto &node : compute_graph_->GetAllNodes()) { + for (auto &node : compute_graph_->GetNodes(compute_graph_->GetGraphUnknownFlag())) { auto op_desc = node->GetOpDesc(); if (op_desc == nullptr) { continue; @@ -737,7 +781,7 @@ Status ModelBuilder::CompileSingleOp() { GE_CHECK_NOTNULL(kernel_info); GE_TIMESTAMP_RESTART(BatchCompileOp); auto ret = kernel_info->CompileOp(node_vector); - GEEVENT("[GEPERFTRACE] The node size of compile op of %s is %zu", kernel_lib_name.c_str(), node_vector.size()); + GELOGI("[GEPERFTRACE] The node size of compile op of %s is %zu", kernel_lib_name.c_str(), node_vector.size()); GE_TIMESTAMP_ADD(BatchCompileOp); if (ret != ge::SUCCESS) { GELOGE(ret, "Compile op failed, kernel lib name is %s", kernel_lib_name.c_str()); diff --git a/src/ge/graph/build/model_builder.h b/src/ge/graph/build/model_builder.h index 21e611ee..86b34c6d 100644 --- a/src/ge/graph/build/model_builder.h +++ b/src/ge/graph/build/model_builder.h @@ -37,7 +37,7 @@ namespace ge { class ModelBuilder { public: - ModelBuilder(ge::ComputeGraphPtr whole_graph, const Graph2SubGraphInfoList &subgraphs, + ModelBuilder(uint64_t session_id, ge::ComputeGraphPtr whole_graph, const Graph2SubGraphInfoList &subgraphs, const std::map &stream_max_parallel_num, bool hcom_parallel, int mode = static_cast(domi::BuildMode::GEN_TASK_WITHOUT_FUSION)); @@ -82,6 +82,8 @@ class ModelBuilder { Status CompileSingleOp(); + uint64_t session_id_; + size_t mem_offset_; size_t weight_offset_; diff --git a/src/ge/graph/build/run_context.cc b/src/ge/graph/build/run_context.cc index f2a41271..cece31ea 100644 --- a/src/ge/graph/build/run_context.cc +++ b/src/ge/graph/build/run_context.cc @@ -173,5 +173,4 @@ Status RunContextUtil::CreateRunContext(Model &model, const ComputeGraphPtr &gra } RunContext &RunContextUtil::GetRunContext() { return run_context_; } - } // namespace ge diff --git a/src/ge/graph/build/stream_allocator.cc b/src/ge/graph/build/stream_allocator.cc index f6323434..5c82f461 100644 --- a/src/ge/graph/build/stream_allocator.cc +++ b/src/ge/graph/build/stream_allocator.cc @@ -146,12 +146,6 @@ Status StreamAllocator::RefreshRealStream(int64_t &stream_num, int64_t &event_nu return status; } - status = AddActiveEntryStream(); - if (status != SUCCESS) { - GELOGE(status, "AddActiveEntryStream failed!"); - return status; - } - status = RefreshContinuousEvents(); if (status != SUCCESS) { GELOGE(status, "RefreshContinuousEvents failed!"); @@ -167,7 +161,7 @@ Status StreamAllocator::RefreshRealStream(int64_t &stream_num, int64_t &event_nu DumpEvents(); GE_DUMP(whole_graph_, "AfterRefreshRealStream"); - for (const NodePtr &node : whole_graph_->GetAllNodes()) { + for (const NodePtr &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node->GetOpDesc()); auto stream_id = node->GetOpDesc()->GetStreamId(); if (stream_id == kInvalidStream) { @@ -199,7 +193,7 @@ Status StreamAllocator::AssignSingleStream() { } int64_t task_count = 0; - for (const NodePtr &node : whole_graph_->GetAllNodes()) { + for (const NodePtr &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { string op_type = node->GetType(); if (IsHcclOp(op_type)) { task_count += kTaskNumPerHcclNode; @@ -236,7 +230,7 @@ Status StreamAllocator::AssignSingleStream() { } Status StreamAllocator::SetActiveStreamsByLabel() { - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); string stream_label; @@ -248,7 +242,7 @@ Status StreamAllocator::SetActiveStreamsByLabel() { } } - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node->GetOpDesc()); vector activated_label_list; if (!AttrUtils::GetListStr(node->GetOpDesc(), ATTR_NAME_ACTIVE_LABEL_LIST, activated_label_list) || @@ -326,7 +320,7 @@ Status StreamAllocator::SetActiveStreamsForSubgraphs() { // Insert the send/recv event id to the graph Status StreamAllocator::InsertSyncEvents() { - for (const auto &cur_node : whole_graph_->GetAllNodes()) { + for (const auto &cur_node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { // Take the adjacent points, then judge whether need to insert the event for (const OutDataAnchorPtr &anchor : cur_node->GetAllOutDataAnchors()) { for (const InDataAnchorPtr &peer_in_anchor : anchor->GetPeerInDataAnchors()) { @@ -380,6 +374,11 @@ Status StreamAllocator::InsertOneEventInTwoNodes(const NodePtr &cur_node, const return SUCCESS; } + if ((cur_node->GetType() == ENTER) || (cur_node->GetType() == REFENTER)) { + GELOGD("No need to insert event after enter_node %s.", cur_node->GetName().c_str()); + return SUCCESS; + } + if (next_stream_id == kInvalidStream) { GELOGE(FAILED, "Stream id of next_node %s should not be %ld", next_node->GetName().c_str(), kInvalidStream); return FAILED; @@ -446,7 +445,7 @@ Status StreamAllocator::InsertEventsForSubgraph() { Status StreamAllocator::OptimizeSyncEvents() { map> stream_nodes; - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node->GetOpDesc()); int64_t stream_id = node->GetOpDesc()->GetStreamId(); stream_nodes[stream_id].emplace_back(node); @@ -613,6 +612,33 @@ bool StreamAllocator::IsRecvNodeActivatedBySendNode(const NodePtr &send_node_ptr AttrUtils::HasAttr(activate_stream_node->GetOpDesc(), ATTR_NAME_IS_LOOP_ACTIVE)) { return false; } + + /// + /// stream_0 --> stream_2 --> stream_3 --> stream_4 + /// /\ | + /// | \/ + /// | stream_1 --> stream_5 --> stream_6 --> stream_7 + /// | /\ | | + /// | | \/ | + /// | |---------- stream_8 | + /// | | + /// |-----------------------------------------------------------| + /// + /// Exit1(S7) Exit2(S7) Exit3(S7) + /// \ / | + /// AddN(S1) NextIteration(S7) + /// | | + /// NextIteration(S1) / + /// | / + /// | / + /// StreamActive(S7) + /// + /// Event between Exit1/Exit2 and AddN should not be optimized + /// + if (IsActiveAfterNextIteration(activate_stream_node)) { + continue; + } + visited_nodes.insert(activate_stream_node); // nodes in stream link to streamActivate no need to add event before activated node for (const auto &pre_activate_stream_node : activate_stream_node->GetInNodes()) { @@ -640,6 +666,18 @@ bool StreamAllocator::IsRecvNodeActivatedBySendNode(const NodePtr &send_node_ptr return false; } +bool StreamAllocator::IsActiveAfterNextIteration(const NodePtr &active_node_ptr) const { + if ((active_node_ptr == nullptr) || active_node_ptr->GetInControlNodes().empty()) { + return false; + } + for (const auto &in_node : active_node_ptr->GetInControlNodes()) { + if ((in_node->GetType() != NEXTITERATION) && (in_node->GetType() != REFNEXTITERATION)) { + return false; + } + } + return true; +} + // Split the stream according to the maximum number of nodes in the stream. Status StreamAllocator::SplitStreams(vector> &split_streams) { if (enable_single_stream_ || stream_num_ == 0) { @@ -671,7 +709,7 @@ Status StreamAllocator::SplitStreams(vector> &split_streams) { GE_CHK_STATUS_RET(GetMaxStreamAndTask(false, max_stream_count, max_task_count), "Get max stream and task count failed."); - for (const auto &cur_node : whole_graph_->GetAllNodes()) { + for (const auto &cur_node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(cur_node); auto op_desc = cur_node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); @@ -774,42 +812,23 @@ bool StreamAllocator::NeedSpiltNewStream(int64_t stream_node_num, int64_t max_no Status StreamAllocator::UpdateActiveStreams(const vector> &split_streams) { UpdateLabelStreams(split_streams); - for (auto &node : whole_graph_->GetAllNodes()) { + for (auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { if ((node->GetType() == STREAMSWITCH) || (node->GetType() == STREAMSWITCHN)) { - if (InsertActiveNodesAfterSwitch(node) != SUCCESS) { - GELOGE(FAILED, "Insert active nodes after switch node failed."); + if (UpdateActiveStreamsForSwitchNode(node) != SUCCESS) { + GELOGE(FAILED, "Update active streams for switch node: %s failed.", node->GetName().c_str()); return FAILED; } } else { - vector active_streams; - GE_CHECK_NOTNULL(node->GetOpDesc()); - if (AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { - vector new_active_streams = active_streams; - for (const uint32_t logical_stream : active_streams) { - if (static_cast(logical_stream) >= split_streams.size()) { - GELOGE(FAILED, "logical stream is out of range."); - return FAILED; - } - const set &new_split_streams = split_streams[logical_stream]; - if (!new_split_streams.empty()) { - for (int64_t split_stream : new_split_streams) { - new_active_streams.emplace_back(static_cast(split_stream)); - GELOGI("Add stream %ld to active_stream_list of node %s of graph %s", split_stream, - node->GetName().c_str(), node->GetOwnerComputeGraph()->GetName().c_str()); - } - } - } - if (!AttrUtils::SetListInt(node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, new_active_streams)) { - GELOGE(FAILED, "Set active streams for node %s failed.", node->GetName().c_str()); - return FAILED; - } + if (UpdateActiveStreamsForActiveNode(split_streams, node) != SUCCESS) { + GELOGE(FAILED, "Update active streams for active node: %s failed.", node->GetName().c_str()); + return FAILED; } } } Status status = UpdateActiveStreamsForSubgraphs(); if (status != SUCCESS) { - GELOGE(status, "SetActiveStreamsForSubgraph failed!"); + GELOGE(status, "Update active streams for subgraphs failed!"); return status; } @@ -840,7 +859,7 @@ void StreamAllocator::UpdateLabelStreams(const vector> &split_strea } } -Status StreamAllocator::InsertActiveNodesAfterSwitch(NodePtr &switch_node) { +Status StreamAllocator::UpdateActiveStreamsForSwitchNode(NodePtr &switch_node) { vector active_nodes; if (InsertActiveNodesAfterSwitch(switch_node, active_nodes) != SUCCESS) { GELOGE(FAILED, "Insert active nodes after node %s failed.", switch_node->GetName().c_str()); @@ -906,6 +925,38 @@ Status StreamAllocator::InsertActiveNodesAfterSwitch(NodePtr &switch_node, vecto return SUCCESS; } +Status StreamAllocator::UpdateActiveStreamsForActiveNode(const vector> &split_streams, NodePtr &node) { + GE_CHECK_NOTNULL(node->GetOpDesc()); + vector active_streams; + if (AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { + vector new_active_streams = active_streams; + for (uint32_t logical_stream : active_streams) { + if (static_cast(logical_stream) >= split_streams.size()) { + GELOGE(FAILED, "logical stream is out of range."); + return FAILED; + } + const set &new_split_streams = split_streams[logical_stream]; + for (int64_t split_stream : new_split_streams) { + for (const auto &node_stream : node_split_stream_map_) { + if (split_stream == node_stream.second) { + if (node_stream.first->GetOwnerComputeGraph() == node->GetOwnerComputeGraph()) { + new_active_streams.emplace_back(static_cast(split_stream)); + GELOGI("Add stream %ld to active_stream_list of node %s of graph %s", split_stream, + node->GetName().c_str(), node->GetOwnerComputeGraph()->GetName().c_str()); + } + break; + } + } + } + } + if (!AttrUtils::SetListInt(node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, new_active_streams)) { + GELOGE(FAILED, "Set active streams for node %s failed.", node->GetName().c_str()); + return FAILED; + } + } + return SUCCESS; +} + Status StreamAllocator::UpdateActiveStreamsForSubgraphs() const { // Update active stream list for active nodes for (auto &node_stream_pair : node_split_stream_map_) { @@ -926,14 +977,19 @@ Status StreamAllocator::UpdateActiveStreamsForSubgraphs() const { } const auto &active_node = it->second; GE_CHECK_NOTNULL(active_node); - auto op_desc = active_node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); + auto active_op = active_node->GetOpDesc(); + GE_CHECK_NOTNULL(active_op); vector active_streams; - (void)AttrUtils::GetListInt(op_desc, ATTR_NAME_ACTIVE_STREAM_LIST, active_streams); + (void)AttrUtils::GetListInt(active_op, ATTR_NAME_ACTIVE_STREAM_LIST, active_streams); set new_active_streams(active_streams.begin(), active_streams.end()); - new_active_streams.emplace(static_cast(node_stream_pair.second)); + // specific_activated_streams_ has already contained new split activated stream + int64_t new_split_stream = node_stream_pair.second; + if (IsActivated(new_split_stream)) { + continue; + } + new_active_streams.emplace(static_cast(new_split_stream)); active_streams.assign(new_active_streams.begin(), new_active_streams.end()); - if (!AttrUtils::SetListInt(op_desc, ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { + if (!AttrUtils::SetListInt(active_op, ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { GELOGE(FAILED, "Set active streams for node %s failed.", active_node->GetName().c_str()); return FAILED; } @@ -942,6 +998,20 @@ Status StreamAllocator::UpdateActiveStreamsForSubgraphs() const { return SUCCESS; } +bool StreamAllocator::IsActivated(int64_t stream_id) const { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { + auto op_desc = node->GetOpDesc(); + vector active_streams; + if (op_desc == nullptr || !AttrUtils::GetListInt(op_desc, ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { + continue; + } + if (std::find(active_streams.begin(), active_streams.end(), stream_id) != active_streams.end()) { + return true; + } + } + return false; +} + Status StreamAllocator::SetActiveStreamsForLoop() { vector loop_active_streams; for (int64_t stream_id = 0; stream_id < stream_num_; stream_id++) { @@ -950,7 +1020,7 @@ Status StreamAllocator::SetActiveStreamsForLoop() { } } // Set the stream that needs to be activated - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node->GetOpDesc()); bool is_loop_active = false; if (AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_IS_LOOP_ACTIVE, is_loop_active) && is_loop_active) { @@ -973,7 +1043,7 @@ Status StreamAllocator::SetActiveStreamsForLoop() { } Status StreamAllocator::CheckStreamActived() const { - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_CHECK_NOTNULL(node->GetOpDesc()); vector active_streams; if (AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, active_streams)) { @@ -989,108 +1059,6 @@ Status StreamAllocator::CheckStreamActived() const { return SUCCESS; } -// Add active entry stream for special env. -Status StreamAllocator::AddActiveEntryStream() { - auto gelib = GELib::GetInstance(); - bool head_stream = (gelib == nullptr) ? false : gelib->HeadStream(); - GELOGI("Configured head stream: %u", head_stream); - if (!head_stream) { - return SUCCESS; - } - - // Collect streams active by StreamSwitch/StreamActive node. - std::set deactive_stream; - for (ge::NodePtr &node : whole_graph_->GetAllNodes()) { - GE_CHECK_NOTNULL(node->GetOpDesc()); - Status ret = CollectDeactiveStream(node->GetOpDesc(), deactive_stream); - if (ret != SUCCESS) { - return ret; - } - } - - // Collect default active stream, Add to active entry stream. - std::vector active_stream_list; - for (int64_t stream_id = 0; stream_id < stream_num_; ++stream_id) { - if (deactive_stream.count(stream_id) == 0) { - active_stream_list.push_back(stream_id); - } - } - - int64_t new_stream_id = stream_num_; - stream_num_++; - return InsertActiveEntryStream(active_stream_list, new_stream_id); -} - -// Collect deactive stream from flowctrl op. -Status StreamAllocator::CollectDeactiveStream(const OpDescPtr &op_desc, std::set &deactive_streams) const { - GE_CHECK_NOTNULL(op_desc); - std::string op_type = op_desc->GetType(); - if (op_type == STREAMSWITCH) { - std::vector active_stream_list; - // If GetListInt fail, active_stream_list is empty. - (void)ge::AttrUtils::GetListInt(op_desc, ATTR_NAME_ACTIVE_STREAM_LIST, active_stream_list); - if (active_stream_list.size() != kMaxSwitchStreamNum) { - GELOGE(INTERNAL_ERROR, "Stream num of switch true branch must be %u.", kMaxSwitchStreamNum); - return INTERNAL_ERROR; - } - - deactive_streams.insert(active_stream_list[0]); - GELOGI("Flowctrl_op node:%s, flowctrl stream id:%u.", op_desc->GetName().c_str(), active_stream_list[0]); - } else if (op_type == STREAMACTIVE) { - if (op_desc->HasAttr(ATTR_NAME_SWITCH_BRANCH_NODE_LABEL)) { - std::vector active_stream_list; - if (!AttrUtils::GetListInt(op_desc, ATTR_NAME_ACTIVE_STREAM_LIST, active_stream_list)) { - GELOGE(INTERNAL_ERROR, "StreamActiveOp get attr ACTIVE_STREAM fail."); - return INTERNAL_ERROR; - } - - for (uint32_t deactive_stream : active_stream_list) { - deactive_streams.insert(deactive_stream); - GELOGI("Flowctrl_op node:%s, flowctrl stream id:%u.", op_desc->GetName().c_str(), deactive_stream); - } - } - } - - return SUCCESS; -} - -// Insert StreamActive Op for Entry Stream. -Status StreamAllocator::InsertActiveEntryStream(const std::vector &active_streams, int64_t stream_id) { - string node_name = whole_graph_->GetName() + "_ActiveEntryStream_" + string(STREAMACTIVE); - OpDescPtr op_desc = ge::MakeShared(node_name, STREAMACTIVE); - if (op_desc == nullptr) { - GELOGE(FAILED, "Failed to new opdesc."); - return FAILED; - } - GELOGI("Create StreamActive op:%s.", op_desc->GetName().c_str()); - - GE_CHK_BOOL_EXEC( - AttrUtils::SetListStr(op_desc, ATTR_NAME_DATA_DUMP_ORIGIN_OP_NAMES, std::move(std::vector())), - GELOGE(FAILED, "SetListStr failed."); - return FAILED); - - NodePtr active_node = whole_graph_->AddNodeFront(op_desc); - GE_IF_BOOL_EXEC(active_node == nullptr, - GELOGE(FAILED, "Create StreamActive op: %s failed.", op_desc->GetName().c_str()); - return INTERNAL_ERROR); - GE_CHECK_NOTNULL(active_node->GetOpDesc()); - // Add one stream for ActiveEntryStream Task. - active_node->GetOpDesc()->SetStreamId(stream_id); - - GE_CHK_BOOL_EXEC(AttrUtils::SetBool(op_desc, "is_aicpu_stream", true), GELOGE(FAILED, "SetBool failed."); - return FAILED); - GE_CHK_BOOL_EXEC(AttrUtils::SetListInt(active_node->GetOpDesc(), ATTR_NAME_ACTIVE_STREAM_LIST, active_streams), - GELOGE(FAILED, "SetListInt failed."); - return FAILED); - - std::vector group_names; - GE_CHK_BOOL_EXEC(AttrUtils::SetListStr(active_node->GetOpDesc(), ATTR_NAME_SWITCH_BRANCH_NODE_LABEL, group_names), - GELOGE(FAILED, "SetLisStr failed."); - return FAILED); - - return SUCCESS; -} - // Refresh events to continuous events Status StreamAllocator::RefreshContinuousEvents() { // Establish a mapping relationship from old to new event id @@ -1136,7 +1104,7 @@ Status StreamAllocator::RefreshContinuousEvents() { // Insert the real send/recv node in the graph Status StreamAllocator::InsertSyncEventNodes() { - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { // Add the node corresponding to the recv event vector recv_event_id_list; GetRecvEventIdList(node, recv_event_id_list); @@ -1223,7 +1191,7 @@ Status StreamAllocator::ReorderEventNodes() const { void StreamAllocator::DumpEvents() { map> after_refresh_stream_nodes; - for (const auto &node : whole_graph_->GetAllNodes()) { + for (const auto &node : whole_graph_->GetNodes(whole_graph_->GetGraphUnknownFlag())) { GE_IF_BOOL_EXEC(node->GetOpDesc() == nullptr, continue); int64_t stream_id = node->GetOpDesc()->GetStreamId(); after_refresh_stream_nodes[stream_id].emplace_back(node); diff --git a/src/ge/graph/build/stream_allocator.h b/src/ge/graph/build/stream_allocator.h index ae79430a..a5326a39 100644 --- a/src/ge/graph/build/stream_allocator.h +++ b/src/ge/graph/build/stream_allocator.h @@ -55,22 +55,21 @@ class StreamAllocator { Status OptimizeByStreamActivate(); // Determine if the successor node of RecvNode is directly or indirectly activated by the SendNode precursor node bool IsRecvNodeActivatedBySendNode(const NodePtr &send_node_ptr, const NodePtr &recv_node_ptr) const; + bool IsActiveAfterNextIteration(const NodePtr &active_node_ptr) const; Status SplitStreams(std::vector> &split_streams); bool NeedSpiltNewStream(int64_t stream_node_num, int64_t max_node_num_one_stream, const OpDescPtr &op_desc) const; - Status UpdateActiveStreams(const std::vector> &splited_streams); + Status UpdateActiveStreams(const std::vector> &split_streams); void UpdateLabelStreams(const std::vector> &split_streams); - Status InsertActiveNodesAfterSwitch(NodePtr &switch_node); + Status UpdateActiveStreamsForSwitchNode(NodePtr &switch_node); Status InsertActiveNodesAfterSwitch(NodePtr &switch_nodes, std::vector &switch_active_nodes); + Status UpdateActiveStreamsForActiveNode(const std::vector> &split_streams, NodePtr &node); Status UpdateActiveStreamsForSubgraphs() const; + bool IsActivated(int64_t stream_id) const; Status SetActiveStreamsForLoop(); Status CheckStreamActived() const; - Status AddActiveEntryStream(); - Status CollectDeactiveStream(const OpDescPtr &op_desc, std::set &deactive_streams) const; - Status InsertActiveEntryStream(const std::vector &active_streams, int64_t stream_id); - Status RefreshContinuousEvents(); Status InsertSyncEventNodes(); diff --git a/src/ge/graph/build/task_generator.cc b/src/ge/graph/build/task_generator.cc index 2ce4e89d..41a845a2 100644 --- a/src/ge/graph/build/task_generator.cc +++ b/src/ge/graph/build/task_generator.cc @@ -29,6 +29,7 @@ #include "graph/utils/node_utils.h" #include "graph/utils/tensor_utils.h" #include "graph/utils/type_utils.h" +#include "graph/common/ge_call_wrapper.h" #include "init/gelib.h" using domi::LogTimeStampDef; @@ -47,7 +48,6 @@ const char *const kIsOutputVar = "OUTPUT_IS_VAR"; const char *const kProfilingMode = "PROFILING_MODE"; const char *const kProfilingFpPoint = "FP_POINT"; const char *const kProfilingBpPoint = "BP_POINT"; -const char *const kOffOptimize = "off_optimize"; const uint32_t kProfilingArStep = 2; const uint64_t kProfilingFpStartLogid = 1; const uint64_t kProfilingBpEndLogid = 2; @@ -75,21 +75,7 @@ Status TaskGenerator::GetTaskInfo(Model &model, ComputeGraphPtr &graph, uint64_t std::vector task_def_list; std::map op_name_map; GE_DUMP(graph, "GenerateTaskBefore"); - bool is_unknown_shape = false; - NodePtr parent_node = graph->GetParentNode(); - if (parent_node != nullptr) { - auto op_desc = parent_node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - (void)AttrUtils::GetBool(op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape); - } - Status ret = SUCCESS; - if (is_unknown_shape) { - GELOGI("Beign to generate unknown shape task. Graph name is %s.", graph->GetName().c_str()); - ret = GenerateUnknownShapeTask(run_context, graph, task_def_list, op_name_map); - } else { - GELOGI("Beign to generate known shape task. Graph name is %s.", graph->GetName().c_str()); - ret = GenerateTask(run_context, graph, task_def_list, op_name_map); - } + Status ret = GenerateTask(run_context, graph, task_def_list, op_name_map); GE_DUMP(graph, "GenerateTaskAfter"); if (ret != SUCCESS) { @@ -109,7 +95,7 @@ Status TaskGenerator::GetTaskInfo(Model &model, ComputeGraphPtr &graph, uint64_t GELOGE(FAILED, "SetListStr failed."); return FAILED); - GELOGI("Generate task success, task_def_list.size:%zu, op_name_map.size:%zu", task_def_list.size(), + GELOGI("Call GenerateTask Success, task_def_list.size:%zu, op_name_map.size:%zu", task_def_list.size(), op_name_map.size()); // Init and serialize model_task_def @@ -131,7 +117,7 @@ Status TaskGenerator::GetTaskInfo(Model &model, ComputeGraphPtr &graph, uint64_t return ret; } - GELOGI("Get TaskInfo success. session id is %lu", session_id); + GELOGI("Get TaskInfo success. session_id=%lu", session_id); return SUCCESS; } @@ -198,7 +184,7 @@ Status TaskGenerator::UpdateOpIsVarAttr(const OpDescPtr &op_desc, uint64_t sessi Status TaskGenerator::SaveFusionNodes(map> &fusion_nodes, ComputeGraphPtr &graph) { std::map nodes_with_group_attr; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); int64_t group_id = kInvalidGroupId; @@ -249,12 +235,13 @@ Status TaskGenerator::SaveFusionNodes(map> &fusion Status TaskGenerator::GenerateTask(RunContext &run_context, ComputeGraphPtr &graph, vector &task_def_list, map &op_name_map) { + GELOGD("Beign to generate task, graph name is %s.", graph->GetName().c_str()); std::shared_ptr ge_lib = GELib::GetInstance(); if ((ge_lib == nullptr) || !ge_lib->InitFlag()) { GELOGE(GE_CLI_GE_NOT_INITIALIZED, "GenerateTask failed."); return GE_CLI_GE_NOT_INITIALIZED; } - GE_CHK_STATUS_RET(MarkNodeAndSetIndex(graph), "Mark node and set index failed."); + GE_CHK_STATUS_RET(MarkNodeAndSetIndex(graph), "MarkNodeAndSetIndex failed."); ProfilingPoint profiling_point; vector all_reduce_nodes; GE_CHK_STATUS_RET(FindProfilingTaskIndex(graph, profiling_point, all_reduce_nodes)); @@ -264,15 +251,21 @@ Status TaskGenerator::GenerateTask(RunContext &run_context, ComputeGraphPtr &gra GE_TIMESTAMP_CALLNUM_START(GenerateTask); // map store fusion nodes map> fusion_nodes; - string buffer_optimize = kOffOptimize; + string buffer_optimize = "off_optimize"; (void)ge::GetContext().GetOption(BUFFER_OPTIMIZE, buffer_optimize); - if (buffer_optimize != kOffOptimize) { + if (buffer_optimize != "off_optimize") { GE_CHK_STATUS_RET(SaveFusionNodes(fusion_nodes, graph)); } std::unordered_set fusion_nodes_seen; int64_t group_key; uint32_t node_index = 0; - for (auto &node : graph->GetAllNodes()) { + rtStream_t stream = nullptr; + bool is_unknown_shape = graph->GetGraphUnknownFlag(); + if (is_unknown_shape) { + GE_CHK_STATUS_RET(SetUnknownShapeStream(run_context, stream), "Set unknown shape stream failed."); + } + + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); node_index++; @@ -302,7 +295,6 @@ Status TaskGenerator::GenerateTask(RunContext &run_context, ComputeGraphPtr &gra GELOGI("Node[name:%s, type:%s] does not need to generate task.", name.c_str(), type.c_str()); continue; } - OpsKernelInfoStorePtr kernel_info_store = ops_kernel_manager.GetOpsKernelInfoStore(op_kernel_lib_name); if (kernel_info_store == nullptr) { GELOGE(INTERNAL_ERROR, "No ops kernel store found. node:%s(%s), op_kernel_lib_name=%s.", name.c_str(), @@ -311,18 +303,17 @@ Status TaskGenerator::GenerateTask(RunContext &run_context, ComputeGraphPtr &gra } GE_CHK_STATUS_RET(UpdateAnchorStatus(node), "Call UpdateAnchorStatus node:%s(%s) failed", name.c_str(), type.c_str()); - int64_t op_id = op_desc->GetId(); - int64_t stream_id = op_desc->GetStreamId(); - if (stream_id < 0 || stream_id >= static_cast(run_context.graphStreamList.size())) { - GELOGE(INTERNAL_ERROR, "node[name:%s(%s), id:%ld] stream id is invalid, stream list size=%zu", name.c_str(), - type.c_str(), op_id, run_context.graphStreamList.size()); - return INTERNAL_ERROR; - } - // Profiling task size_t task_list_size_before = task_def_list.size(); GE_CHK_STATUS_RET(InsertProfilingTaskBefore(op_desc, profiling_point, all_reduce_nodes, node_index, task_def_list)); - run_context.stream = run_context.graphStreamList[stream_id]; + int64_t op_id = op_desc->GetId(); + // Compatible with dynamic shape scenes, the default is 0 + int64_t stream_id = 0; + if (!is_unknown_shape) { + stream_id = op_desc->GetStreamId(); + GE_CHK_STATUS_RET(SetKnownShapeStream(run_context, stream_id), "node[name:%s(%s), id:%ld] stream id is invalid.", + name.c_str(), type.c_str(), op_id); + } GELOGD("Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task.", op_kernel_lib_name.c_str(), name.c_str(), type.c_str(), op_id, stream_id); GE_TIMESTAMP_RESTART(GenerateTask); @@ -355,131 +346,14 @@ Status TaskGenerator::GenerateTask(RunContext &run_context, ComputeGraphPtr &gra GE_CHECK_NOTNULL(task_def_ptr); task_def_ptr->set_ops_kernel_store_ptr(reinterpret_cast(ops_kernel_info_store_ptr)); } - GELOGD("Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task finished, generate %zu task(s).", op_kernel_lib_name.c_str(), name.c_str(), type.c_str(), op_id, stream_id, task_list_size_after - task_list_size_before); } - GE_TIMESTAMP_CALLNUM_END(GenerateTask, "GraphBuild::GenerateTask"); - return SUCCESS; -} - -Status TaskGenerator::GenerateUnknownShapeTask(RunContext &run_context, ComputeGraphPtr &graph, - vector &task_def_list, - map &op_name_map) { - std::shared_ptr ge_lib = GELib::GetInstance(); - if ((ge_lib == nullptr) || !ge_lib->InitFlag()) { - GELOGE(GE_CLI_GE_NOT_INITIALIZED, "GenerateTask failed."); - return GE_CLI_GE_NOT_INITIALIZED; - } - GE_CHK_STATUS_RET(MarkNodeAndSetIndex(graph), "Mark node and set index failed."); - ProfilingPoint profiling_point; - vector all_reduce_nodes; - GE_CHK_STATUS_RET(FindProfilingTaskIndex(graph, profiling_point, all_reduce_nodes)); - - const OpsKernelManager &ops_kernel_manager = ge_lib->OpsKernelManagerObj(); - - GE_TIMESTAMP_CALLNUM_START(GenerateTask); - // map store fusion nodes - map> fusion_nodes; - string buffer_optimize = kOffOptimize; - (void)ge::GetContext().GetOption(BUFFER_OPTIMIZE, buffer_optimize); - if (buffer_optimize != kOffOptimize) { - GE_CHK_STATUS_RET(SaveFusionNodes(fusion_nodes, graph)); - } - std::unordered_set fusion_nodes_seen; - int64_t group_key; - uint32_t node_index = 0; - rtStream_t stream = nullptr; - GE_CHK_RT_RET(rtStreamCreate(&stream, 0)); - run_context.stream = stream; - if (rtModelBindStream(run_context.model, stream, 0) != RT_ERROR_NONE) { - GELOGE(FAILED, "Call rt api failed."); - GE_CHK_RT(rtStreamDestroy(stream)); - return FAILED; - } - for (auto &node : graph->GetAllNodes()) { - OpDescPtr op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - node_index++; - string name = node->GetName(); - string type = node->GetType(); - bool attr_notask = false; - bool get_attr_notask_flag = ge::AttrUtils::GetBool(op_desc, ATTR_NAME_NOTASK, attr_notask); - GE_IF_BOOL_EXEC(get_attr_notask_flag && attr_notask, - GELOGI("Node[name:%s, type:%s] does not need to generate task.", name.c_str(), type.c_str()); - continue); - - GE_CHK_STATUS_RET(UpdateOpIsVarAttr(op_desc, graph->GetSessionID())); - string op_kernel_lib_name = op_desc->GetOpKernelLibName(); - // For fusion ddb pass, task def must be continuous. - // Part2: Call - auto fusion_task_info = - FusionTaskInfo{run_context, graph, node, op_desc, node_index, ge_lib, - ops_kernel_manager, task_def_list, op_name_map, profiling_point, all_reduce_nodes}; - GE_CHK_STATUS_RET(GenerateTaskForFusionNode(fusion_task_info, fusion_nodes, fusion_nodes_seen), - "Call GenerateTaskForFusionNode node:%s(%s) failed", name.c_str(), type.c_str()); - // continue directly - if (ge::AttrUtils::GetInt(op_desc, ATTR_NAME_FUSION_GROUP_KEY, group_key)) { - GELOGI("Fusion node[name:%s, type:%s] do not need generate task again.", name.c_str(), type.c_str()); - continue; - } - if (op_kernel_lib_name.empty()) { - GELOGI("Node[name:%s, type:%s] does not need to generate task.", name.c_str(), type.c_str()); - continue; - } - OpsKernelInfoStorePtr kernel_info_store = ops_kernel_manager.GetOpsKernelInfoStore(op_kernel_lib_name); - if (kernel_info_store == nullptr) { - GELOGE(INTERNAL_ERROR, "No ops kernel store found. node:%s(%s), op_kernel_lib_name=%s.", name.c_str(), - type.c_str(), op_kernel_lib_name.c_str()); - return INTERNAL_ERROR; - } - GE_CHK_STATUS_RET(UpdateAnchorStatus(node), "Call UpdateAnchorStatus node:%s(%s) failed", name.c_str(), - type.c_str()); - int64_t op_id = op_desc->GetId(); - int64_t stream_id = op_desc->GetStreamId(); - // Profiling task - size_t task_list_size_before = task_def_list.size(); - GE_CHK_STATUS_RET(InsertProfilingTaskBefore(op_desc, profiling_point, all_reduce_nodes, node_index, task_def_list)); - - GELOGD("Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task.", op_kernel_lib_name.c_str(), - name.c_str(), type.c_str(), op_id, stream_id); - GE_TIMESTAMP_RESTART(GenerateTask); - auto ret = kernel_info_store->GenerateTask(*node, run_context, task_def_list); - GE_TIMESTAMP_ADD(GenerateTask); - if (ret != SUCCESS) { - GELOGE(ret, "Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task failed.", - op_kernel_lib_name.c_str(), name.c_str(), type.c_str(), op_id, stream_id); - return ret; - } - // Profiling task - GE_CHK_STATUS_RET(InsertProfilingTaskAfter(op_desc, profiling_point, all_reduce_nodes, node_index, task_def_list)); - size_t task_list_size_after = task_def_list.size(); - // If tasks is reduced - if (task_list_size_after < task_list_size_before) { - GELOGE(FAILED, "Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task. but task num from %zu to %zu.", - op_kernel_lib_name.c_str(), name.c_str(), type.c_str(), op_id, stream_id, task_list_size_before, - task_list_size_after); - return FAILED; - } - - // Reset stream id to ge stream id, as graph load must use ge stream to reassign stream - void *ops_kernel_info_store_ptr = kernel_info_store.get(); - for (size_t idx = task_list_size_before; idx < task_list_size_after; ++idx) { - op_name_map[idx] = name; - // Set opsKernelInfoStorePtr and op_index, the two fields be use in DistributeTask and InitTaskInfo - TaskDef *task_def_ptr = &task_def_list[idx]; - GE_CHECK_NOTNULL(task_def_ptr); - task_def_ptr->set_ops_kernel_store_ptr(reinterpret_cast(ops_kernel_info_store_ptr)); - } - - GELOGD("Call %s to generate node[name:%s(%s), id:%ld, stream_id:%ld] task finished, generate %zu task(s).", - op_kernel_lib_name.c_str(), name.c_str(), type.c_str(), op_id, stream_id, - task_list_size_after - task_list_size_before); + if (is_unknown_shape) { + GE_CHK_STATUS_RET(DestroyUnknownShapeStream(run_context, stream), "Destory unknown shape stream failed."); } - GE_CHK_RT(rtModelUnbindStream(run_context.model, stream)); - GE_CHK_RT(rtStreamDestroy(stream)); - GE_TIMESTAMP_CALLNUM_END(GenerateTask, "GraphBuild::GenerateTask"); + GE_TIMESTAMP_CALLNUM_EVENT_END(GenerateTask, "GraphBuild::GenerateTask"); return SUCCESS; } @@ -628,7 +502,11 @@ Status TaskGenerator::MarkNodeAndSetIndex(ComputeGraphPtr &graph) { return GE_CLI_GE_NOT_INITIALIZED; } - const auto all_nodes = graph->GetAllNodes(); + const auto all_nodes = graph->GetNodes(graph->GetGraphUnknownFlag()); + if (all_nodes.empty()) { + GELOGE(GE_GRAPH_GRAPH_NODE_NULL, "Graph's node is empty"); + return GE_GRAPH_GRAPH_NODE_NULL; + } int64_t node_index = 0; for (auto &node : all_nodes) { @@ -715,7 +593,7 @@ Status TaskGenerator::AutoFindFpOpIndex(const ComputeGraphPtr &graph, ProfilingP OpDescPtr fp_op_desc = nullptr; uint32_t current_idx = 0; uint32_t first_fp = 0; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); string op_kernel_lib_name = op_desc->GetOpKernelLibName(); @@ -742,7 +620,7 @@ Status TaskGenerator::AutoFindFpOpIndex(const ComputeGraphPtr &graph, ProfilingP return SUCCESS; } GELOGI("Find fp_op_desc is %s, id is %ld", fp_op_desc->GetName().c_str(), fp_op_desc->GetId()); - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); current_idx++; @@ -763,7 +641,7 @@ Status TaskGenerator::AutoFindBpOpIndex(const ComputeGraphPtr &graph, ProfilingP uint32_t last_bp = 0; uint32_t iter_end = 0; uint32_t current_idx = 0; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); current_idx++; @@ -807,7 +685,7 @@ Status TaskGenerator::AutoFindBpOpIndex(const ComputeGraphPtr &graph, ProfilingP GE_CHECK_NOTNULL(bp_op_desc); current_idx = 0; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); current_idx++; @@ -826,7 +704,7 @@ Status TaskGenerator::FindFpOfEnv(const ComputeGraphPtr &graph, const std::strin GELOGI("Start FindFpOfEnv"); uint32_t current_idx = 0; uint32_t first_fp = 0; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(node->GetOpDesc()); current_idx++; @@ -851,7 +729,7 @@ Status TaskGenerator::FindBpOfEnv(const ComputeGraphPtr &graph, const std::strin uint32_t current_idx = 0; uint32_t iter_end = 0; uint32_t last_bp = 0; - for (auto &node : graph->GetAllNodes()) { + for (auto &node : graph->GetNodes(graph->GetGraphUnknownFlag())) { OpDescPtr op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(node->GetOpDesc()); current_idx++; @@ -927,10 +805,10 @@ Status TaskGenerator::FindProfilingTaskIndex(const ComputeGraphPtr &graph, Profi bool train_graph = graph->GetNeedIteration(); if (profiling_point.fp_index == 0 && train_graph) { - GELOGE(FAILED, "First forward op name can't be found in graph for training trace."); + GELOGW("First forward op name can't be found in graph for training trace."); } if (profiling_point.bp_index == 0 && train_graph) { - GELOGE(FAILED, "Last backward op name can't be found in graph for training trace."); + GELOGW("Last backward op name can't be found in graph for training trace."); } return SUCCESS; } @@ -1068,4 +946,31 @@ bool TaskGenerator::IsProfPoint(const OpDescPtr &op, const std::string &name) { return false; } +Status TaskGenerator::SetUnknownShapeStream(RunContext &run_context, rtStream_t &stream) { + GE_CHK_RT_RET(rtStreamCreate(&stream, 0)); + run_context.stream = stream; + rtError_t rt_ret = rtModelBindStream(run_context.model, stream, 0); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(FAILED, "Call rt api failed, ret: 0x%X", rt_ret); + GE_CHK_RT_RET(rtStreamDestroy(stream)); + return FAILED; + } + return SUCCESS; +} + +Status TaskGenerator::DestroyUnknownShapeStream(RunContext &run_context, rtStream_t &stream) { + GE_CHK_RT(rtModelUnbindStream(run_context.model, stream)); + GE_CHK_RT_RET(rtStreamDestroy(stream)); + return SUCCESS; +} + +Status TaskGenerator::SetKnownShapeStream(RunContext &run_context, int64_t stream_id) { + if (stream_id < 0 || stream_id >= static_cast(run_context.graphStreamList.size())) { + GELOGE(INTERNAL_ERROR, "Stream id[%ld] is invalid, stream list size=%zu", stream_id, + run_context.graphStreamList.size()); + return INTERNAL_ERROR; + } + run_context.stream = run_context.graphStreamList[stream_id]; + return SUCCESS; +} } // namespace ge diff --git a/src/ge/graph/build/task_generator.h b/src/ge/graph/build/task_generator.h index 02721e00..b2ca4470 100644 --- a/src/ge/graph/build/task_generator.h +++ b/src/ge/graph/build/task_generator.h @@ -94,18 +94,6 @@ class TaskGenerator { std::map &op_name_map); /// - /// call engine to generate unknown shape task. - /// @param run_context run context - /// @param graph compute graph - /// @param task_def_list task def list generate by engine - /// @param op_name_map relation of task index and op - /// @return SUCCESS:seccess - /// Other: failed - /// - Status GenerateUnknownShapeTask(RunContext &run_context, ComputeGraphPtr &graph, - std::vector &task_def_list, std::map &op_name_map); - - /// /// AddModelTaskToModel /// @param model_task_def model task /// @param model_def model @@ -154,6 +142,12 @@ class TaskGenerator { Status SaveFusionNodes(map> &fusion_nodes, ComputeGraphPtr &graph); + Status SetUnknownShapeStream(RunContext &run_context, rtStream_t &stream); + + Status DestroyUnknownShapeStream(RunContext &run_context, rtStream_t &stream); + + Status SetKnownShapeStream(RunContext &run_context, int64_t stream_id); + uint8_t *var_mem_base_ = nullptr; uint64_t var_mem_size_ = 0; }; diff --git a/src/ge/graph/common/ge_call_wrapper.h b/src/ge/graph/common/ge_call_wrapper.h index a21d642e..305c6c15 100644 --- a/src/ge/graph/common/ge_call_wrapper.h +++ b/src/ge/graph/common/ge_call_wrapper.h @@ -18,6 +18,43 @@ #define GE_GE_CALL_WRAPPER_H_ #include "framework/common/debug/ge_log.h" +/*lint --emacro((773),GE_TIMESTAMP_START)*/ +/*lint -esym(773,GE_TIMESTAMP_START)*/ +#define GE_TIMESTAMP_START(stage) uint64_t startUsec_##stage = ge::GetCurrentTimestap() + +#define GE_TIMESTAMP_END(stage, stage_name) \ + do { \ + uint64_t endUsec_##stage = ge::GetCurrentTimestap(); \ + GELOGI("[GEPERFTRACE] The time cost of %s is [%lu] micro second.", (stage_name), \ + (endUsec_##stage - startUsec_##stage)); \ + } while (0); + +#define GE_TIMESTAMP_EVENT_END(stage, stage_name) \ + do { \ + uint64_t endUsec_##stage = ge::GetCurrentTimestap(); \ + GEEVENT("[GEPERFTRACE] The time cost of %s is [%lu] micro second.", (stage_name), \ + (endUsec_##stage - startUsec_##stage)); \ + } while (0); + +#define GE_TIMESTAMP_CALLNUM_START(stage) \ + uint64_t startUsec_##stage = ge::GetCurrentTimestap(); \ + uint64_t call_num_of##stage = 0; \ + uint64_t time_of##stage = 0 + +#define GE_TIMESTAMP_RESTART(stage) (startUsec_##stage = ge::GetCurrentTimestap()) + +#define GE_TIMESTAMP_ADD(stage) \ + time_of##stage += ge::GetCurrentTimestap() - startUsec_##stage; \ + call_num_of##stage++ + +#define GE_TIMESTAMP_CALLNUM_END(stage, stage_name) \ + GELOGI("[GEPERFTRACE] The time cost of %s is [%lu] micro second, call num is %lu", (stage_name), time_of##stage, \ + call_num_of##stage) + +#define GE_TIMESTAMP_CALLNUM_EVENT_END(stage, stage_name) \ + GEEVENT("[GEPERFTRACE] The time cost of %s is [%lu] micro second, call num is %lu", (stage_name), time_of##stage, \ + call_num_of##stage) + #define RUN_WITH_TIMESTAMP_NAME(var_name, prefix, func, ...) \ do { \ GE_TIMESTAMP_START(var_name); \ @@ -29,10 +66,23 @@ } \ } while (0) +#define RUN_WITH_PERF_TIMESTAMP_NAME(var_name, prefix, func, ...) \ + do { \ + GE_TIMESTAMP_START(var_name); \ + auto ret_inner_macro = func(__VA_ARGS__); \ + GE_TIMESTAMP_EVENT_END(var_name, #prefix "::" #func) \ + if (ret_inner_macro != ge::SUCCESS) { \ + GELOGE(ret_inner_macro, "Failed to process " #prefix "_" #func); \ + return ret_inner_macro; \ + } \ + } while (0) + #define JOIN_NAME_INNER(a, b) a##b #define JOIN_NAME(a, b) JOIN_NAME_INNER(a, b) #define COUNTER_NAME(a) JOIN_NAME(a, __COUNTER__) #define GE_RUN(prefix, func, ...) \ RUN_WITH_TIMESTAMP_NAME(COUNTER_NAME(ge_timestamp_##prefix), prefix, func, __VA_ARGS__) +#define GE_RUN_PERF(prefix, func, ...) \ + RUN_WITH_PERF_TIMESTAMP_NAME(COUNTER_NAME(ge_timestamp_##prefix), prefix, func, __VA_ARGS__) #endif // GE_GE_CALL_WRAPPER_H_ diff --git a/src/ge/graph/execute/graph_execute.cc b/src/ge/graph/execute/graph_execute.cc index b021ce55..1bebd382 100644 --- a/src/ge/graph/execute/graph_execute.cc +++ b/src/ge/graph/execute/graph_execute.cc @@ -86,10 +86,10 @@ Status GraphExecutor::SetGraphContext(GraphContextPtr graph_context_ptr) { return SUCCESS; } -Status GraphExecutor::SetDynamicSize(uint32_t model_id, const std::vector &batch_num) { +Status GraphExecutor::SetDynamicSize(uint32_t model_id, const std::vector &batch_num, int32_t dynamic_type) { auto model_manager = ge::ModelManager::GetInstance(); GE_CHECK_NOTNULL(model_manager); - Status ret = model_manager->SetDynamicSize(model_id, batch_num); + Status ret = model_manager->SetDynamicSize(model_id, batch_num, dynamic_type); if (ret != SUCCESS) { GELOGE(FAILED, "SetDynamicSize failed"); return ret; @@ -120,7 +120,7 @@ Status GraphExecutor::FreeInOutBuffer() { } } -Status GraphExecutor::MallocInOutBuffer(const std::vector &buffer_size, std::vector &data_addr) { +Status GraphExecutor::MallocInOutBuffer(const std::vector &buffer_size, std::vector &data_addr) { if (malloc_flag_) { auto all_size_same = true; if (buffer_size.size() == buffer_size_.size()) { @@ -169,7 +169,7 @@ Status GraphExecutor::PrepareInputData(const std::vector &input_tensor graph_input_data.timestamp = 0; std::size_t inputSize = input_tensor.size(); std::size_t output_size = output_desc.size(); - std::vector bufferSizeVec; + std::vector bufferSizeVec; std::vector addrVec; for (std::size_t i = 0; i < inputSize; ++i) { @@ -211,7 +211,7 @@ Status GraphExecutor::PrepareInputData(const std::vector &input_tensor for (std::size_t j = 0; j < output_size; j++) { auto desc = output_desc[j]; - uint32_t buffer_size = desc.size; + uint64_t buffer_size = desc.size; DataBuffer out_data_buf; out_data_buf.data = reinterpret_cast(addrVec[inputSize + j]); @@ -225,6 +225,13 @@ Status GraphExecutor::PrepareInputData(const std::vector &input_tensor Status GraphExecutor::SyncExecuteModel(uint32_t model_id, const std::vector &input_tensor, std::vector &output_tensor) { + auto model_manager = ge::ModelManager::GetInstance(); + GE_CHECK_NOTNULL(model_manager); + if (model_manager->IsDynamicShape(model_id)) { + GELOGI("[ExecuteGraph] GetInputOutputDescInfo via dynamic shape model executor, modelId=%u", model_id); + return model_manager->SyncExecuteModel(model_id, input_tensor, output_tensor); + } + // Prepare input and output std::vector inputs_desc; std::vector output_desc; @@ -479,12 +486,14 @@ Status GraphExecutor::GetInputOutputDescInfo(const uint32_t model_id, vector> &batch_info) { +Status GraphExecutor::GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type) { auto model_manager = ge::ModelManager::GetInstance(); GE_CHECK_NOTNULL(model_manager); - Status ret = model_manager->GetDynamicBatchInfo(model_id, batch_info); + Status ret = model_manager->GetDynamicBatchInfo(model_id, batch_info, dynamic_type); if (ret != SUCCESS) { GELOGE(ret, "GetDynamicBatchInfo failed."); return ret; @@ -492,12 +501,30 @@ Status GraphExecutor::GetDynamicBatchInfo(uint32_t model_id, std::vector &batch_info) { +/// +/// @ingroup ge +/// @brief Get combined dynamic dims info +/// @param [in] model_id +/// @param [out] batch_info +/// @return execute result +/// +Status GraphExecutor::GetCombinedDynamicDims(uint32_t model_id, std::vector> &batch_info) { auto model_manager = ge::ModelManager::GetInstance(); GE_CHECK_NOTNULL(model_manager); - Status ret = model_manager->GetCurShape(model_id, batch_info); + Status ret = model_manager->GetCombinedDynamicDims(model_id, batch_info); if (ret != SUCCESS) { - GELOGE(FAILED, "GetCurShape failed"); + GELOGE(ret, "GetCombinedDynamicDims failed."); + return ret; + } + return SUCCESS; +} + +Status GraphExecutor::GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type) { + auto model_manager = ge::ModelManager::GetInstance(); + GE_CHECK_NOTNULL(model_manager); + Status ret = model_manager->GetCurShape(model_id, batch_info, dynamic_type); + if (ret != SUCCESS) { + GELOGE(ret, "GetCurShape failed"); return ret; } return SUCCESS; @@ -575,5 +602,4 @@ Status GraphExecutor::GetAllAippInputOutputDims(uint32_t model_id, uint32_t inde return SUCCESS; } - } // namespace ge diff --git a/src/ge/graph/execute/graph_execute.h b/src/ge/graph/execute/graph_execute.h index 0518cf11..f79a2e29 100644 --- a/src/ge/graph/execute/graph_execute.h +++ b/src/ge/graph/execute/graph_execute.h @@ -56,7 +56,7 @@ class GraphExecutor { Status SetGraphContext(GraphContextPtr graph_context_ptr); - static Status SetDynamicSize(uint32_t model_id, const std::vector &batch_num); + static Status SetDynamicSize(uint32_t model_id, const std::vector &batch_num, int32_t dynamic_type); void SetTrainFlag(bool is_train_graph); @@ -80,11 +80,22 @@ class GraphExecutor { /// @brief Get dynamic batch_info /// @param [in] model_id /// @param [out] batch_info + /// @param [out] dynamic_type /// @return execute result /// - static Status GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info); + static Status GetDynamicBatchInfo(uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type); - static Status GetCurShape(const uint32_t model_id, std::vector &batch_info); + /// + /// @ingroup ge + /// @brief Get combined dynamic dims info + /// @param [in] model_id + /// @param [out] batch_info + /// @return execute result + /// + static Status GetCombinedDynamicDims(uint32_t model_id, std::vector> &batch_info); + + static Status GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type); static Status GetModelAttr(uint32_t model_id, std::vector &dynamic_output_shape_info); @@ -110,7 +121,7 @@ class GraphExecutor { Status FreeInOutBuffer(); - Status MallocInOutBuffer(const std::vector &buffer_size, std::vector &data_addr); + Status MallocInOutBuffer(const std::vector &buffer_size, std::vector &data_addr); bool init_flag_; @@ -129,7 +140,7 @@ class GraphExecutor { bool malloc_flag_; std::vector buffer_addr_; - std::vector buffer_size_; + std::vector buffer_size_; }; } // namespace ge diff --git a/src/ge/graph/label/while_label_maker.cc b/src/ge/graph/label/while_label_maker.cc index 6601abd1..c5e0abb7 100644 --- a/src/ge/graph/label/while_label_maker.cc +++ b/src/ge/graph/label/while_label_maker.cc @@ -104,12 +104,11 @@ Status WhileOpLabelMaker::Run(uint32_t &label_index) { GE_CHECK_NOTNULL(cond_out_desc); GeTensorDesc pred_desc = cond_out_desc->GetInputDesc(kCondOutputIndex); - GeTensorDesc cond_desc(GeShape(pred_desc.GetShape().GetDims()), pred_desc.GetFormat(), DT_INT32); // false ==> 0 ==> switch_labels[0] ==> body_leave_index // true ==> 1 ==> switch_labels[1] ==> body_enter_name const std::vector switch_labels = {body_leave_index, body_enter_index}; - NodePtr switch_node = AddLabelSwitchLeave(cond_graph, cond_leave_name, cond_desc, switch_labels); + NodePtr switch_node = AddLabelSwitchLeave(cond_graph, cond_leave_name, pred_desc, switch_labels); if (switch_node == nullptr) { GELOGE(INTERNAL_ERROR, "Subgraph: %s add label switch failed.", cond_graph->GetName().c_str()); return FAILED; diff --git a/src/ge/graph/load/graph_loader.cc b/src/ge/graph/load/graph_loader.cc index 1f4cbcf9..d181f3a5 100644 --- a/src/ge/graph/load/graph_loader.cc +++ b/src/ge/graph/load/graph_loader.cc @@ -36,20 +36,20 @@ GraphLoader::~GraphLoader() = default; Status GraphLoader::UnloadModel(uint32_t model_id) { auto model_manager = ModelManager::GetInstance(); GE_CHECK_NOTNULL(model_manager); - GELOGI("UnLoad model begin, model_id:%u.", model_id); + GELOGI("UnLoad model begin, model id:%u.", model_id); Status ret = model_manager->Stop(model_id); if (ret != SUCCESS) { - GELOGE(ret, "UnloadModel: Stop failed."); + GELOGE(ret, "UnloadModel: Stop failed. model id:%u", model_id); } ret = model_manager->Unload(model_id); if (ret != SUCCESS) { - GELOGE(ret, "UnloadModel: Unload failed."); + GELOGE(ret, "UnloadModel: Unload failed. model id:%u", model_id); CsaInteract::GetInstance().WriteErrorCode(ret, ERROR_MODULE_FMK, JOBSUBSTATE_GRAPH_UNLOAD); return ret; } - GELOGI("UnLoad model success, model_id:%u.", model_id); + GELOGI("UnLoad model success, model id:%u.", model_id); return SUCCESS; } @@ -123,14 +123,14 @@ Status GraphLoader::LoadDataFromFile(const std::string &path, const std::string Status ret; try { if (!CheckInputPathValid(path)) { - GELOGE(PARAM_INVALID, "model path is invalid: %s", path.c_str()); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_PATH_INVALID, "model path is invalid: %s", path.c_str()); + return GE_EXEC_MODEL_PATH_INVALID; } GELOGI("Load model begin, model path is: %s", path.c_str()); if (!key_path.empty() && !CheckInputPathValid(key_path)) { - GELOGE(PARAM_INVALID, "decrypt_key path is invalid: %s", key_path.c_str()); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_KEY_PATH_INVALID, "decrypt_key path is invalid: %s", key_path.c_str()); + return GE_EXEC_MODEL_KEY_PATH_INVALID; } ret = DavinciModelParser::LoadFromFile(path.c_str(), key_path.c_str(), priority, model_data); @@ -350,7 +350,8 @@ Status GraphLoader::GetMemoryInfo(int64_t &free) { return RT_FAILED; } // Add small page memory size - free = static_cast(free_mem + VarManager::Instance(0)->GetUseMaxMemorySize() - total_mem); + free = + static_cast(free_mem + VarManager::Instance(GetContext().SessionId())->GetUseMaxMemorySize() - total_mem); GELOGI("GetMemoryInfo free[%zu], total[%zu], return free[%ld]", free_mem, total_mem, free); return SUCCESS; } diff --git a/src/ge/graph/load/new_model_manager/cpu_queue_schedule.cc b/src/ge/graph/load/new_model_manager/cpu_queue_schedule.cc index 06111015..01e1cfa8 100644 --- a/src/ge/graph/load/new_model_manager/cpu_queue_schedule.cc +++ b/src/ge/graph/load/new_model_manager/cpu_queue_schedule.cc @@ -16,6 +16,7 @@ #include "graph/load/new_model_manager/cpu_queue_schedule.h" #include "common/debug/ge_log.h" +#include "common/debug/log.h" namespace { const uint32_t kCoreDim = 1; // for rtCpuKernelLaunch @@ -58,7 +59,7 @@ Status CpuTaskModelDequeue::Init(uint32_t queue_id, uintptr_t &in_mbuf) { rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } in_mbuf = reinterpret_cast(args_) + sizeof(MbufQueueInfo); GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) @@ -69,7 +70,7 @@ Status CpuTaskModelDequeue::Init(uint32_t queue_id, uintptr_t &in_mbuf) { status = rtMemcpy(args_, args_size_, &queue_info, sizeof(MbufQueueInfo), RT_MEMCPY_HOST_TO_DEVICE); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } return SUCCESS; @@ -84,7 +85,7 @@ Status CpuTaskModelDequeue::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskModelDequeue, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch ModelDequeue failed, status: 0x%X", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch model dequeue task success."); @@ -98,24 +99,24 @@ Status CpuTaskModelDequeue::Distribute() { /// @param [in] outside_addrs: model input/output memory addr /// @return: 0 for success / others for failed /// -Status CpuTaskZeroCopy::Init(std::vector &mbuf_list, - std::map> &outside_addrs) { +Status CpuTaskZeroCopy::Init(std::vector &mbuf_list, std::map &outside_addrs) { if ((args_ != nullptr) || (args_size_ > 0)) { GELOGE(FAILED, "Task already initialized, size: %u", args_size_); return FAILED; } args_size_ = sizeof(AddrMapInfo); - rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; - } + GE_CHK_RT_RET(rtMalloc(&args_, args_size_, RT_MEMORY_HBM)); GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) AddrMapInfo addr_map_info; - for (const auto &addrs : outside_addrs) { - addr_map_info.addr_num += addrs.second.size(); + for (auto &addrs : outside_addrs) { + auto &addrs_mapping_list = addrs.second.GetOutsideAddrs(); + GE_CHK_BOOL_EXEC(!addrs_mapping_list.empty(), return PARAM_INVALID, "not set outside_addrs"); + std::map> virtual_args_addrs = addrs_mapping_list[0]; + for (const auto &virtual_args_addr : virtual_args_addrs) { + addr_map_info.addr_num += virtual_args_addr.second.size(); + } } GELOGI("addr_map_info.addr_num is %u", addr_map_info.addr_num); @@ -123,38 +124,31 @@ Status CpuTaskZeroCopy::Init(std::vector &mbuf_list, size_t index = 0; vector src_addrs; vector dst_addrs; - for (const auto &addrs : outside_addrs) { - for (size_t i = 0; i < addrs.second.size(); ++i) { - src_addrs.push_back(mbuf_list.at(index)); - dst_addrs.push_back(reinterpret_cast(reinterpret_cast(addrs.second.at(i)))); + for (auto &addrs : outside_addrs) { + auto &addrs_mapping_list = addrs.second.GetOutsideAddrs(); + GE_CHK_BOOL_EXEC(!addrs_mapping_list.empty(), return PARAM_INVALID, "not set outside_addrs"); + std::map> virtual_args_addrs = addrs_mapping_list[0]; + for (const auto &virtual_args_addr : virtual_args_addrs) { + for (size_t i = 0; i < virtual_args_addr.second.size(); ++i) { + src_addrs.push_back(mbuf_list.at(index)); + dst_addrs.push_back(reinterpret_cast(reinterpret_cast(virtual_args_addr.second.at(i)))); + } } index++; } // malloc mem for src_addrs/dst_addrs, and copy data of src_addrs/dst_addrs - status = rtMalloc(&src_addr_, src_addrs.size() * sizeof(uint64_t), RT_MEMORY_HBM); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; - } - status = rtMemcpy(src_addr_, src_addrs.size() * sizeof(uint64_t), src_addrs.data(), - src_addrs.size() * sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; - } + GE_CHK_RT_RET(rtMalloc(&src_addr_, src_addrs.size() * sizeof(uint64_t), RT_MEMORY_HBM)); + rtError_t status = rtMemcpy(src_addr_, src_addrs.size() * sizeof(uint64_t), src_addrs.data(), + src_addrs.size() * sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE); + GE_IF_BOOL_EXEC(status != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy error, ret: Ox%X", status); + return RT_ERROR_TO_GE_STATUS(status);) - status = rtMalloc(&dst_addr_, dst_addrs.size() * sizeof(uint64_t), RT_MEMORY_HBM); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; - } + GE_CHK_RT_RET(rtMalloc(&dst_addr_, dst_addrs.size() * sizeof(uint64_t), RT_MEMORY_HBM)); status = rtMemcpy(dst_addr_, dst_addrs.size() * sizeof(uint64_t), dst_addrs.data(), dst_addrs.size() * sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; - } + GE_IF_BOOL_EXEC(status != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy error, ret: Ox%X", status); + return RT_ERROR_TO_GE_STATUS(status);) // src_addr_list is init to src_addr, which is the point to src_addrs if (!src_addrs.empty() && !dst_addrs.empty()) { @@ -164,10 +158,8 @@ Status CpuTaskZeroCopy::Init(std::vector &mbuf_list, } status = rtMemcpy(args_, args_size_, &addr_map_info, sizeof(AddrMapInfo), RT_MEMCPY_HOST_TO_DEVICE); - if (status != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; - } + GE_IF_BOOL_EXEC(status != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy error, ret: Ox%X", status); + return RT_ERROR_TO_GE_STATUS(status);) return SUCCESS; } @@ -180,7 +172,7 @@ Status CpuTaskZeroCopy::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskZeroCopy, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch ZeroCopy failed, status: 0x%X", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch zero copy task success."); @@ -225,7 +217,7 @@ Status CpuTaskPrepareOutput::Init(uintptr_t addr, uint32_t size, uintptr_t in_mb rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } out_mbuf = reinterpret_cast(args_) + sizeof(PrepareOutputInfo); GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) @@ -239,7 +231,7 @@ Status CpuTaskPrepareOutput::Init(uintptr_t addr, uint32_t size, uintptr_t in_mb status = rtMemcpy(args_, args_size_, &prepare, sizeof(PrepareOutputInfo), RT_MEMCPY_HOST_TO_DEVICE); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } return SUCCESS; @@ -254,7 +246,7 @@ Status CpuTaskPrepareOutput::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskPrepareOutput, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch PrepareOutput failed, status: 0x%X", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch prepare output task success."); @@ -279,7 +271,7 @@ Status CpuTaskModelEnqueue::Init(uint32_t queue_id, uintptr_t out_mbuf) { rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) @@ -289,7 +281,7 @@ Status CpuTaskModelEnqueue::Init(uint32_t queue_id, uintptr_t out_mbuf) { status = rtMemcpy(args_, args_size_, &queue_info, args_size_, RT_MEMCPY_HOST_TO_DEVICE); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } return SUCCESS; @@ -304,7 +296,7 @@ Status CpuTaskModelEnqueue::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskModelEnqueue, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch ModelEnqueue failed, status: 0x%X", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch model enqueue task success."); @@ -336,10 +328,10 @@ Status CpuTaskActiveEntry::Distribute() { rtError_t ret = rtStreamActive(active_stream_, stream_); if (ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt StreamActive failed, ret: 0x%X", ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(ret); } - GELOGI("Cpu kernel launch wait end task success."); + GELOGI("Cpu kernel launch active entry task success."); return SUCCESS; } @@ -359,14 +351,14 @@ Status CpuTaskWaitEndGraph::Init(uint32_t model_id) { rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) status = rtMemcpy(args_, args_size_, &model_id, args_size_, RT_MEMCPY_HOST_TO_DEVICE); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } return SUCCESS; @@ -381,7 +373,7 @@ Status CpuTaskWaitEndGraph::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskWaitEndGraph, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch WaitEndGraph failed, status: 0x%X", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch wait end task success."); @@ -404,14 +396,14 @@ Status CpuTaskModelRepeat::Init(uint32_t model_id) { rtError_t status = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt malloc failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "args data.", args_size_) status = rtMemcpy(args_, args_size_, &model_id, args_size_, RT_MEMCPY_HOST_TO_DEVICE); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt memcpy failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } return SUCCESS; @@ -426,7 +418,7 @@ Status CpuTaskModelRepeat::Distribute() { rtError_t status = rtCpuKernelLaunch(nullptr, kCpuTaskModelRepeat, kCoreDim, args_, args_size_, nullptr, stream_); if (status != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt CpuKernelLaunch ModelRepeat failed, status: 0x%x", status); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(status); } GELOGI("Cpu kernel launch repeat task success."); diff --git a/src/ge/graph/load/new_model_manager/cpu_queue_schedule.h b/src/ge/graph/load/new_model_manager/cpu_queue_schedule.h index c4ae4df5..cea00613 100644 --- a/src/ge/graph/load/new_model_manager/cpu_queue_schedule.h +++ b/src/ge/graph/load/new_model_manager/cpu_queue_schedule.h @@ -22,6 +22,7 @@ #include "common/ge_inner_error_codes.h" #include "graph/load/new_model_manager/task_info/task_info.h" +#include "graph/load/new_model_manager/zero_copy_offset.h" #include "runtime/kernel.h" namespace ge { @@ -93,7 +94,7 @@ class CpuTaskZeroCopy : public CpuTaskInfo { ~CpuTaskZeroCopy() override; Status Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) override { return SUCCESS; } - Status Init(std::vector &mbuf_list, std::map> &outside_addrs); + Status Init(std::vector &mbuf_list, std::map &outside_addrs); Status Distribute() override; diff --git a/src/ge/graph/load/new_model_manager/data_dumper.cc b/src/ge/graph/load/new_model_manager/data_dumper.cc index 653a3fa1..7194264d 100644 --- a/src/ge/graph/load/new_model_manager/data_dumper.cc +++ b/src/ge/graph/load/new_model_manager/data_dumper.cc @@ -21,7 +21,6 @@ #include #include -#include "common/debug/log.h" #include "common/properties_manager.h" #include "framework/common/debug/ge_log.h" #include "framework/common/util.h" @@ -37,9 +36,36 @@ namespace { const uint32_t kAicpuLoadFlag = 1; const uint32_t kAicpuUnloadFlag = 0; +const int64_t kOpDebugSize = 2048; +const int64_t kOpDebugShape = 2048; +const int8_t kDecimal = 10; +const uint32_t kAddrLen = sizeof(void *); const char *const kDumpOutput = "output"; const char *const kDumpInput = "input"; const char *const kDumpAll = "all"; + +// parse for format like nodename:input:index +static bool ParseNameIndex(const std::string &node_name_index, std::string &node_name, std::string &input_or_output, + size_t &index) { + auto sep = node_name_index.rfind(':'); + if (sep == std::string::npos) { + return false; + } + auto index_str = node_name_index.substr(sep + 1); + index = static_cast(std::strtol(index_str.c_str(), nullptr, kDecimal)); + auto node_name_without_index = node_name_index.substr(0, sep); + sep = node_name_without_index.rfind(':'); + if (sep == std::string::npos) { + return false; + } + node_name = node_name_without_index.substr(0, sep); + input_or_output = node_name_without_index.substr(sep + 1); + return !(input_or_output != kDumpInput && input_or_output != kDumpOutput); +} + +static bool IsTensorDescWithSkipDumpAddrType(bool has_mem_type_attr, vector v_memory_type, size_t i) { + return has_mem_type_attr && (v_memory_type[i] == RT_MEMORY_L1); +} } // namespace static int32_t GetIrDataType(ge::DataType data_type) { @@ -138,6 +164,13 @@ void DataDumper::SaveEndGraphId(uint32_t task_id, uint32_t stream_id) { end_graph_stream_id_ = stream_id; } +void DataDumper::SaveOpDebugId(uint32_t task_id, uint32_t stream_id, void *op_debug_addr, bool is_op_debug) { + op_debug_task_id_ = task_id; + op_debug_stream_id_ = stream_id; + op_debug_addr_ = op_debug_addr; + is_op_debug_ = is_op_debug; +} + void DataDumper::SaveDumpTask(uint32_t task_id, uint32_t stream_id, const std::shared_ptr &op_desc, uintptr_t args) { if (op_desc == nullptr) { @@ -202,56 +235,121 @@ static void SetOpMappingLoopAddr(uintptr_t step_id, uintptr_t loop_per_iter, uin } } -Status DataDumper::DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task) { - GELOGI("Start dump output"); - if (inner_dump_info.is_task) { - // tbe or aicpu op - const auto &output_descs = inner_dump_info.op->GetAllOutputsDesc(); - const auto input_size = inner_dump_info.op->GetAllInputsDesc().size(); - const std::vector output_addrs = ModelUtils::GetOutputDataAddrs(runtime_param_, inner_dump_info.op, false); - if (output_descs.size() != output_addrs.size()) { - GELOGE(PARAM_INVALID, "Invalid output desc addrs size %zu, op %s has %zu output desc.", output_addrs.size(), - inner_dump_info.op->GetName().c_str(), output_descs.size()); - return PARAM_INVALID; - } +Status DataDumper::GenerateOutput(aicpu::dump::Output &output, const OpDesc::Vistor &tensor_descs, + const uintptr_t &addr, size_t index) { + output.set_data_type(static_cast(GetIrDataType(tensor_descs.at(index).GetDataType()))); + output.set_format(static_cast(tensor_descs.at(index).GetFormat())); - for (size_t i = 0; i < output_descs.size(); ++i) { - aicpu::dump::Output output; - output.set_data_type(static_cast(GetIrDataType(output_descs.at(i).GetDataType()))); - output.set_format(static_cast(output_descs.at(i).GetFormat())); + for (auto dim : tensor_descs.at(index).GetShape().GetDims()) { + output.mutable_shape()->add_dim(dim); + } + int64_t output_size = 0; + if (TensorUtils::GetTensorSizeInBytes(tensor_descs.at(index), output_size) != SUCCESS) { + GELOGE(PARAM_INVALID, "Get output size filed"); + return PARAM_INVALID; + } + GELOGD("Get output size in dump is %ld", output_size); + std::string origin_name; + int32_t origin_output_index = -1; + (void)AttrUtils::GetStr(&tensor_descs.at(index), ATTR_NAME_DATA_DUMP_ORIGIN_NAME, origin_name); + (void)AttrUtils::GetInt(&tensor_descs.at(index), ATTR_NAME_DATA_DUMP_ORIGIN_OUTPUT_INDEX, origin_output_index); + output.set_size(output_size); + output.set_original_name(origin_name); + output.set_original_output_index(origin_output_index); + output.set_original_output_format(static_cast(tensor_descs.at(index).GetOriginFormat())); + output.set_original_output_data_type(static_cast(tensor_descs.at(index).GetOriginDataType())); + output.set_address(static_cast(addr)); + return SUCCESS; +} - for (auto dim : output_descs.at(i).GetShape().GetDims()) { - output.mutable_shape()->add_dim(dim); - } +Status DataDumper::DumpRefOutput(const DataDumper::InnerDumpInfo &inner_dump_info, aicpu::dump::Output &output, + size_t i, const std::string &node_name_index) { + std::string dump_op_name; + std::string input_or_output; + size_t index; + // parser and find which node's input or output tensor desc is chosen for dump info + if (!ParseNameIndex(node_name_index, dump_op_name, input_or_output, index)) { + GELOGE(PARAM_INVALID, "Op [%s] output desc[%zu] with invalid ATTR_DATA_DUMP_REF attr[%s].", + inner_dump_info.op->GetName().c_str(), i, node_name_index.c_str()); + return PARAM_INVALID; + } + GE_CHECK_NOTNULL(compute_graph_); + auto replace_node = compute_graph_->FindNode(dump_op_name); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(replace_node == nullptr, + "Op [%s] output desc[%zu] with invalid ATTR_DATA_DUMP_REF attr[%s]," + " cannot find redirect node[%s].", + inner_dump_info.op->GetName().c_str(), i, node_name_index.c_str(), + dump_op_name.c_str()); + auto replace_opdesc = replace_node->GetOpDesc(); + GE_CHECK_NOTNULL(replace_opdesc); + auto iter = ref_info_.find(replace_opdesc); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(iter == ref_info_.end(), + "Op [%s] output desc[%zu] cannot find any saved redirect node[%s]'s info.", + inner_dump_info.op->GetName().c_str(), i, replace_opdesc->GetName().c_str()); + GE_CHECK_NOTNULL(iter->second); + auto addr = reinterpret_cast(iter->second); + if (input_or_output == kDumpInput) { + const auto &replace_input_descs = replace_opdesc->GetAllInputsDesc(); + addr += kAddrLen * index; + GE_CHK_STATUS_RET(GenerateOutput(output, replace_input_descs, addr, index), "Generate output failed"); + } else if (input_or_output == kDumpOutput) { + const auto &replace_output_descs = replace_opdesc->GetAllOutputsDesc(); + const auto replace_input_size = replace_opdesc->GetAllInputsDesc().size(); + addr += (index + replace_input_size) * kAddrLen; + GE_CHK_STATUS_RET(GenerateOutput(output, replace_output_descs, addr, index), "Generate output failed"); + } + GELOGD("Op [%s] output desc[%zu] dump info is replaced by node[%s] [%s] tensor_desc [%zu]", + inner_dump_info.op->GetName().c_str(), i, dump_op_name.c_str(), input_or_output.c_str(), index); + return SUCCESS; +} - int64_t output_size = 0; - if (TensorUtils::GetTensorSizeInBytes(output_descs.at(i), output_size) != SUCCESS) { - GELOGE(PARAM_INVALID, "Get output size filed"); - return PARAM_INVALID; - } - GELOGI("Get output size in dump is %ld", output_size); - std::string origin_name; - int32_t origin_output_index = -1; - (void)AttrUtils::GetStr(&output_descs.at(i), ATTR_NAME_DATA_DUMP_ORIGIN_NAME, origin_name); - (void)AttrUtils::GetInt(&output_descs.at(i), ATTR_NAME_DATA_DUMP_ORIGIN_OUTPUT_INDEX, origin_output_index); - GE_IF_BOOL_EXEC(output_size <= 0, GELOGE(PARAM_INVALID, "Output size %ld is less than zero", output_size); - return PARAM_INVALID) - output.set_size(output_size); - output.set_original_name(origin_name); - output.set_original_output_index(origin_output_index); - output.set_original_output_format(static_cast(output_descs.at(i).GetOriginFormat())); - output.set_original_output_data_type(static_cast(output_descs.at(i).GetOriginDataType())); - output.set_address(static_cast(inner_dump_info.args + (i + input_size) * sizeof(void *))); - - task.mutable_output()->Add(std::move(output)); +Status DataDumper::DumpOutputWithTask(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task) { + const auto &output_descs = inner_dump_info.op->GetAllOutputsDesc(); + const std::vector output_addrs = ModelUtils::GetOutputDataAddrs(runtime_param_, inner_dump_info.op); + if (output_descs.size() != output_addrs.size()) { + GELOGE(PARAM_INVALID, "Invalid output desc addrs size %zu, op %s has %zu output desc.", output_addrs.size(), + inner_dump_info.op->GetName().c_str(), output_descs.size()); + return PARAM_INVALID; + } + std::vector v_memory_type; + bool has_mem_type_attr = ge::AttrUtils::GetListInt(inner_dump_info.op, ATTR_NAME_OUTPUT_MEM_TYPE_LIST, v_memory_type); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(has_mem_type_attr && (v_memory_type.size() != output_descs.size()), + "DumpOutputWithTask[%s], output size[%zu], output memory type size[%zu]", + inner_dump_info.op->GetName().c_str(), output_descs.size(), + v_memory_type.size()); + + for (size_t i = 0; i < output_descs.size(); ++i) { + aicpu::dump::Output output; + std::string node_name_index; + const auto &output_desc = output_descs.at(i); + // check dump output tensor desc is redirected by attr ATTR_DATA_DUMP_REF + if (AttrUtils::GetStr(&output_desc, ATTR_DATA_DUMP_REF, node_name_index)) { + GE_CHK_STATUS_RET(DumpRefOutput(inner_dump_info, output, i, node_name_index), "DumpRefOutput failed"); + } else { + GE_IF_BOOL_EXEC( + IsTensorDescWithSkipDumpAddrType(has_mem_type_attr, v_memory_type, i), + GELOGD("DumpOutputWithTask[%s] output[%zu] is l1 addr, skip it", inner_dump_info.op->GetName().c_str(), i); + continue;); + + const auto input_size = inner_dump_info.op->GetInputsSize(); + auto addr = inner_dump_info.args + (i + input_size) * kAddrLen; + GE_CHK_STATUS_RET(GenerateOutput(output, output_descs, addr, i), "Generate output failed"); } - return SUCCESS; + task.mutable_output()->Add(std::move(output)); } + return SUCCESS; +} +Status DataDumper::DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task) { + GELOGI("Start dump output"); + if (inner_dump_info.is_task) { + // tbe or aicpu op, these ops are with task + return DumpOutputWithTask(inner_dump_info, task); + } // else data, const or variable op aicpu::dump::Output output; auto output_tensor = inner_dump_info.op->GetOutputDescPtr(inner_dump_info.output_anchor_index); - const std::vector output_addrs = ModelUtils::GetOutputDataAddrs(runtime_param_, inner_dump_info.op, false); + const std::vector output_addrs = ModelUtils::GetOutputDataAddrs(runtime_param_, inner_dump_info.op); if (output_tensor == nullptr) { GELOGE(PARAM_INVALID, "output_tensor is null, index: %d, size: %zu.", inner_dump_info.output_anchor_index, inner_dump_info.op->GetOutputsSize()); @@ -269,9 +367,6 @@ Status DataDumper::DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump: int32_t origin_output_index = -1; (void)AttrUtils::GetStr(output_tensor, ATTR_NAME_DATA_DUMP_ORIGIN_NAME, origin_name); (void)AttrUtils::GetInt(output_tensor, ATTR_NAME_DATA_DUMP_ORIGIN_OUTPUT_INDEX, origin_output_index); - GE_IF_BOOL_EXEC(inner_dump_info.data_size <= 0, - GELOGE(PARAM_INVALID, "The size of data %ld is less than zero", inner_dump_info.data_size); - return PARAM_INVALID) output.set_size(inner_dump_info.data_size); output.set_original_name(origin_name); output.set_original_output_index(origin_output_index); @@ -282,7 +377,7 @@ Status DataDumper::DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump: GELOGE(FAILED, "Index is out of range."); return FAILED; } - auto data_addr = inner_dump_info.args + sizeof(void *) * static_cast(inner_dump_info.input_anchor_index); + auto data_addr = inner_dump_info.args + kAddrLen * static_cast(inner_dump_info.input_anchor_index); output.set_address(static_cast(data_addr)); task.mutable_output()->Add(std::move(output)); @@ -290,37 +385,98 @@ Status DataDumper::DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump: return SUCCESS; } +Status DataDumper::GenerateInput(aicpu::dump::Input &input, const OpDesc::Vistor &tensor_descs, + const uintptr_t &addr, size_t index) { + input.set_data_type(static_cast(GetIrDataType(tensor_descs.at(index).GetDataType()))); + input.set_format(static_cast(tensor_descs.at(index).GetFormat())); + + for (auto dim : tensor_descs.at(index).GetShape().GetDims()) { + input.mutable_shape()->add_dim(dim); + } + int64_t input_size = 0; + if (AttrUtils::GetInt(tensor_descs.at(index), ATTR_NAME_INPUT_ORIGIN_SIZE, input_size)) { + GELOGI("Get aipp input size according to attr is %ld", input_size); + } else if (TensorUtils::GetTensorSizeInBytes(tensor_descs.at(index), input_size) != SUCCESS) { + GELOGE(PARAM_INVALID, "Get input size filed"); + return PARAM_INVALID; + } + GELOGD("Get input size in dump is %ld", input_size); + input.set_size(input_size); + input.set_address(static_cast(addr)); + return SUCCESS; +} + +Status DataDumper::DumpRefInput(const DataDumper::InnerDumpInfo &inner_dump_info, aicpu::dump::Input &input, size_t i, + const std::string &node_name_index) { + std::string dump_op_name; + std::string input_or_output; + size_t index; + // parser and find which node's input or output tensor desc is chosen for dump info + if (!ParseNameIndex(node_name_index, dump_op_name, input_or_output, index)) { + GELOGE(PARAM_INVALID, "Op [%s] input desc[%zu] with invalid ATTR_DATA_DUMP_REF attr[%s].", + inner_dump_info.op->GetName().c_str(), i, node_name_index.c_str()); + return PARAM_INVALID; + } + GE_CHECK_NOTNULL(compute_graph_); + auto replace_node = compute_graph_->FindNode(dump_op_name); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(replace_node == nullptr, + "Op [%s] input desc[%zu] with invalid ATTR_DATA_DUMP_REF attr[%s]," + " cannot find redirect node[%s].", + inner_dump_info.op->GetName().c_str(), i, node_name_index.c_str(), + dump_op_name.c_str()); + auto replace_opdesc = replace_node->GetOpDesc(); + GE_CHECK_NOTNULL(replace_opdesc); + auto iter = ref_info_.find(replace_opdesc); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(iter == ref_info_.end(), + "Op [%s] input desc[%zu] cannot find any saved redirect node[%s]'s info.", + inner_dump_info.op->GetName().c_str(), i, replace_opdesc->GetName().c_str()); + GE_CHECK_NOTNULL(iter->second); + auto addr = reinterpret_cast(iter->second); + if (input_or_output == kDumpInput) { + const auto &replace_input_descs = replace_opdesc->GetAllInputsDesc(); + addr += kAddrLen * index; + GE_CHK_STATUS_RET(GenerateInput(input, replace_input_descs, addr, index), "Generate input failed"); + } else if (input_or_output == kDumpOutput) { + const auto &replace_output_descs = replace_opdesc->GetAllOutputsDesc(); + const auto replace_input_size = replace_opdesc->GetAllInputsDesc().size(); + addr += (index + replace_input_size) * kAddrLen; + GE_CHK_STATUS_RET(GenerateInput(input, replace_output_descs, addr, index), "Generate input failed"); + } + GELOGD("Op [%s] input desc[%zu] dump info is replaced by node[%s] [%s] tensor_desc [%zu]", + inner_dump_info.op->GetName().c_str(), i, dump_op_name.c_str(), input_or_output.c_str(), index); + return SUCCESS; +} + Status DataDumper::DumpInput(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task) { GELOGI("Start dump input"); const auto &input_descs = inner_dump_info.op->GetAllInputsDesc(); - const std::vector input_addrs = ModelUtils::GetInputDataAddrs(runtime_param_, inner_dump_info.op, false); + const std::vector input_addrs = ModelUtils::GetInputDataAddrs(runtime_param_, inner_dump_info.op); if (input_descs.size() != input_addrs.size()) { GELOGE(PARAM_INVALID, "Invalid input desc addrs size %zu, op %s has %zu input desc.", input_addrs.size(), inner_dump_info.op->GetName().c_str(), input_descs.size()); return PARAM_INVALID; } + std::vector v_memory_type; + bool has_mem_type_attr = ge::AttrUtils::GetListInt(inner_dump_info.op, ATTR_NAME_INPUT_MEM_TYPE_LIST, v_memory_type); + GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(has_mem_type_attr && (v_memory_type.size() != input_descs.size()), + "DumpInput[%s], input size[%zu], input memory type size[%zu]", + inner_dump_info.op->GetName().c_str(), input_descs.size(), v_memory_type.size()); for (size_t i = 0; i < input_descs.size(); ++i) { aicpu::dump::Input input; - input.set_data_type(static_cast(GetIrDataType(input_descs.at(i).GetDataType()))); - input.set_format(static_cast(input_descs.at(i).GetFormat())); - - for (auto dim : input_descs.at(i).GetShape().GetDims()) { - input.mutable_shape()->add_dim(dim); + std::string node_name_index; + // check dump input tensor desc is redirected by attr ATTR_DATA_DUMP_REF + if (AttrUtils::GetStr(&input_descs.at(i), ATTR_DATA_DUMP_REF, node_name_index)) { + GE_CHK_STATUS_RET(DumpRefInput(inner_dump_info, input, i, node_name_index), "DumpRefInput failed"); + // normal dump without attr + } else { + GE_IF_BOOL_EXEC(IsTensorDescWithSkipDumpAddrType(has_mem_type_attr, v_memory_type, i), + GELOGD("DumpInput[%s] input[%zu] is l1 addr, skip it", inner_dump_info.op->GetName().c_str(), i); + continue;); + + auto addr = inner_dump_info.args + kAddrLen * i; + GE_CHK_STATUS_RET(GenerateInput(input, input_descs, addr, i), "Generate input failed"); } - - int64_t input_size = 0; - if (AttrUtils::GetInt(&input_descs.at(i), ATTR_NAME_INPUT_ORIGIN_SIZE, input_size)) { - GELOGI("Get aipp input size according to attr is %ld", input_size); - } else if (TensorUtils::GetTensorSizeInBytes(input_descs.at(i), input_size) != SUCCESS) { - GELOGE(PARAM_INVALID, "Get input size filed"); - return PARAM_INVALID; - } - GELOGI("Get input size in dump is %ld", input_size); - GE_IF_BOOL_EXEC(input_size <= 0, GELOGE(PARAM_INVALID, "Input size %ld is less than zero", input_size); - return PARAM_INVALID;) - input.set_size(input_size); - input.set_address(static_cast(inner_dump_info.args + sizeof(void *) * i)); task.mutable_input()->Add(std::move(input)); } return SUCCESS; @@ -331,8 +487,8 @@ Status DataDumper::ExecuteLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_in size_t proto_size = op_mapping_info.ByteSizeLong(); bool ret = op_mapping_info.SerializeToString(&proto_str); if (!ret || proto_size == 0) { - GELOGE(FAILED, "Protobuf SerializeToString failed, proto size %zu.", proto_size); - return FAILED; + GELOGE(PARAM_INVALID, "Protobuf SerializeToString failed, proto size %zu.", proto_size); + return PARAM_INVALID; } if (dev_mem_load_ != nullptr) { @@ -343,20 +499,20 @@ Status DataDumper::ExecuteLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_in rtError_t rt_ret = rtMalloc(&dev_mem_load_, proto_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtMalloc failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "load dump information.", proto_size) rt_ret = rtMemcpy(dev_mem_load_, proto_size, proto_str.c_str(), proto_size, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtMemcpy failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtDatadumpInfoLoad(dev_mem_load_, proto_size); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtDatadumpInfoLoad failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } load_flag_ = true; @@ -369,8 +525,8 @@ Status DataDumper::ExecuteUnLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_ size_t proto_size = op_mapping_info.ByteSizeLong(); bool ret = op_mapping_info.SerializeToString(&proto_str); if (!ret || proto_size == 0) { - GELOGE(FAILED, "Protobuf SerializeToString failed, proto size %zu.", proto_size); - return FAILED; + GELOGE(PARAM_INVALID, "Protobuf SerializeToString failed, proto size %zu.", proto_size); + return PARAM_INVALID; } if (dev_mem_unload_ != nullptr) { @@ -381,83 +537,87 @@ Status DataDumper::ExecuteUnLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_ rtError_t rt_ret = rtMalloc(&dev_mem_unload_, proto_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtMalloc failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "unload dump information.", proto_size) rt_ret = rtMemcpy(dev_mem_unload_, proto_size, proto_str.c_str(), proto_size, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtMemcpy failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtDatadumpInfoLoad(dev_mem_unload_, proto_size); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtDatadumpInfoLoad failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } load_flag_ = false; GELOGI("UnloadDumpInfo success, proto size is: %zu.", proto_size); return SUCCESS; } + Status DataDumper::LoadDumpInfo() { std::string dump_list_key; PrintCheckLog(dump_list_key); if (op_list_.empty()) { - return SUCCESS; + GELOGW("op_list_ is empty"); } aicpu::dump::OpMappingInfo op_mapping_info; - auto dump_path = PropertiesManager::Instance().GetDumpOutputPath(); - op_mapping_info.set_dump_path(PropertiesManager::Instance().GetDumpOutputPath() + std::to_string(device_id_) + "/"); + auto dump_path = dump_properties_.GetDumpPath() + std::to_string(device_id_) + "/"; + op_mapping_info.set_dump_path(dump_path); op_mapping_info.set_model_name(dump_list_key); op_mapping_info.set_model_id(model_id_); op_mapping_info.set_flag(kAicpuLoadFlag); - op_mapping_info.set_dump_step(PropertiesManager::Instance().GetDumpStep()); + op_mapping_info.set_dump_step(dump_properties_.GetDumpStep()); SetOpMappingLoopAddr(global_step_, loop_per_iter_, loop_cond_, op_mapping_info); - GELOGI("Dump step is %s and dump path is %s in load dump info", PropertiesManager::Instance().GetDumpStep().c_str(), + GELOGI("Dump step is %s and dump path is %s in load dump info", dump_properties_.GetDumpStep().c_str(), dump_path.c_str()); for (const auto &op_iter : op_list_) { - aicpu::dump::Task task; auto op_desc = op_iter.op; + GELOGD("Op %s in model %s begin to add task in op_mapping_info", op_desc->GetName().c_str(), dump_list_key.c_str()); + aicpu::dump::Task task; task.set_end_graph(false); task.set_task_id(op_iter.task_id); task.set_stream_id(op_iter.stream_id); task.mutable_op()->set_op_name(op_desc->GetName()); task.mutable_op()->set_op_type(op_desc->GetType()); - if (PropertiesManager::Instance().GetDumpMode() == kDumpOutput) { - if (DumpOutput(op_iter, task) != SUCCESS) { - GELOGE(FAILED, "Dump output failed"); - return FAILED; + if (dump_properties_.GetDumpMode() == kDumpOutput) { + Status ret = DumpOutput(op_iter, task); + if (ret != SUCCESS) { + GELOGE(ret, "Dump output failed"); + return ret; } op_mapping_info.mutable_task()->Add(std::move(task)); continue; } - if (PropertiesManager::Instance().GetDumpMode() == kDumpInput) { + if (dump_properties_.GetDumpMode() == kDumpInput) { if (op_iter.is_task) { - if (DumpInput(op_iter, task) != SUCCESS) { - GELOGE(FAILED, "Dump input failed"); - return FAILED; + Status ret = DumpInput(op_iter, task); + if (ret != SUCCESS) { + GELOGE(ret, "Dump input failed"); + return ret; } } op_mapping_info.mutable_task()->Add(std::move(task)); continue; } - if (PropertiesManager::Instance().GetDumpMode() == kDumpAll) { + if (dump_properties_.GetDumpMode() == kDumpAll) { auto ret = DumpOutput(op_iter, task); if (ret != SUCCESS) { - GELOGE(FAILED, "Dump output failed when in dumping all"); - return FAILED; + GELOGE(ret, "Dump output failed when in dumping all"); + return ret; } if (op_iter.is_task) { ret = DumpInput(op_iter, task); if (ret != SUCCESS) { - GELOGE(FAILED, "Dump input failed when in dumping all"); - return FAILED; + GELOGE(ret, "Dump input failed when in dumping all"); + return ret; } } op_mapping_info.mutable_task()->Add(std::move(task)); @@ -467,19 +627,22 @@ Status DataDumper::LoadDumpInfo() { SetEndGraphIdToAicpu(end_graph_task_id_, end_graph_stream_id_, op_mapping_info); - auto ret = ExecuteLoadDumpInfo(op_mapping_info); - if (ret != SUCCESS) { - GELOGE(FAILED, "Execute load dump info failed"); - return FAILED; + SetOpDebugIdToAicpu(op_debug_task_id_, op_debug_stream_id_, op_debug_addr_, op_mapping_info); + + if (!op_list_.empty() || is_op_debug_) { + auto ret = ExecuteLoadDumpInfo(op_mapping_info); + if (ret != SUCCESS) { + GELOGE(ret, "Execute load dump info failed"); + return ret; + } } return SUCCESS; } void DataDumper::SetEndGraphIdToAicpu(uint32_t task_id, uint32_t stream_id, aicpu::dump::OpMappingInfo &op_mapping_info) { - if (PropertiesManager::Instance().GetDumpMode() == kDumpOutput || - PropertiesManager::Instance().GetDumpMode() == kDumpInput || - PropertiesManager::Instance().GetDumpMode() == kDumpAll) { + if (dump_properties_.GetDumpMode() == kDumpOutput || dump_properties_.GetDumpMode() == kDumpInput || + dump_properties_.GetDumpMode() == kDumpAll) { GELOGI("Add end_graph_info to aicpu, task_id is %u, stream_id is %u", end_graph_task_id_, end_graph_stream_id_); aicpu::dump::Task task; task.set_end_graph(true); @@ -491,6 +654,37 @@ void DataDumper::SetEndGraphIdToAicpu(uint32_t task_id, uint32_t stream_id, } } +void DataDumper::SetOpDebugIdToAicpu(uint32_t task_id, uint32_t stream_id, void *op_debug_addr, + aicpu::dump::OpMappingInfo &op_mapping_info) { + if (is_op_debug_) { + GELOGI("add op_debug_info to aicpu, task_id is %u, stream_id is %u", task_id, stream_id); + aicpu::dump::Task task; + task.set_end_graph(false); + task.set_task_id(task_id); + task.set_stream_id(stream_id); + task.mutable_op()->set_op_name(NODE_NAME_OP_DEBUG); + task.mutable_op()->set_op_type(OP_TYPE_OP_DEBUG); + + // set output + aicpu::dump::Output output; + output.set_data_type(DT_UINT8); + output.set_format(FORMAT_ND); + + output.mutable_shape()->add_dim(kOpDebugShape); + + output.set_original_name(NODE_NAME_OP_DEBUG); + output.set_original_output_index(0); + output.set_original_output_format(FORMAT_ND); + output.set_original_output_data_type(DT_UINT8); + // due to lhisi virtual addr bug, cannot use args now + output.set_address(static_cast(reinterpret_cast(op_debug_addr))); + output.set_size(kOpDebugSize); + + task.mutable_output()->Add(std::move(output)); + op_mapping_info.mutable_task()->Add(std::move(task)); + } +} + Status DataDumper::UnloadDumpInfo() { if (!load_flag_) { GELOGI("No need to UnloadDumpInfo."); @@ -510,22 +704,24 @@ Status DataDumper::UnloadDumpInfo() { } auto ret = ExecuteUnLoadDumpInfo(op_mapping_info); if (ret != SUCCESS) { - GELOGE(FAILED, "Execute unload dump info failed"); - return FAILED; + GELOGE(ret, "Execute unload dump info failed"); + return ret; } return SUCCESS; } void DataDumper::PrintCheckLog(string &dump_list_key) { - std::set model_list = PropertiesManager::Instance().GetAllDumpModel(); + std::set model_list = dump_properties_.GetAllDumpModel(); if (model_list.empty()) { GELOGI("No model need dump."); return; } - GELOGI("%zu op need dump in %s.", op_list_.size(), model_name_.c_str()); bool not_find_by_omname = model_list.find(om_name_) == model_list.end(); bool not_find_by_modelname = model_list.find(model_name_) == model_list.end(); + dump_list_key = not_find_by_omname ? model_name_ : om_name_; + GELOGI("%zu op need dump in %s.", op_list_.size(), dump_list_key.c_str()); + if (model_list.find(DUMP_ALL_MODEL) == model_list.end()) { if (not_find_by_omname && not_find_by_modelname) { std::string model_list_str; @@ -533,12 +729,12 @@ void DataDumper::PrintCheckLog(string &dump_list_key) { model_list_str += "[" + model + "]."; } - GELOGW("Model %s will not be set to dump, dump list: %s", model_name_.c_str(), model_list_str.c_str()); + GELOGW("Model %s will not be set to dump, dump list: %s", dump_list_key.c_str(), model_list_str.c_str()); return; } } - dump_list_key = not_find_by_omname ? model_name_ : om_name_; - std::set config_dump_op_list = PropertiesManager::Instance().GetDumpPropertyValue(dump_list_key); + + std::set config_dump_op_list = dump_properties_.GetPropertyValue(dump_list_key); std::set dump_op_list; for (auto &inner_dump_info : op_list_) { // oplist value OpDescPtr is not nullptr diff --git a/src/ge/graph/load/new_model_manager/data_dumper.h b/src/ge/graph/load/new_model_manager/data_dumper.h index ee5b3241..0648a8ce 100644 --- a/src/ge/graph/load/new_model_manager/data_dumper.h +++ b/src/ge/graph/load/new_model_manager/data_dumper.h @@ -23,7 +23,9 @@ #include #include "framework/common/ge_inner_error_codes.h" +#include "common/properties_manager.h" #include "graph/node.h" +#include "graph/compute_graph.h" #include "proto/ge_ir.pb.h" #include "proto/op_mapping_info.pb.h" #include "runtime/mem.h" @@ -44,7 +46,9 @@ class DataDumper { device_id_(0), global_step_(0), loop_per_iter_(0), - loop_cond_(0) {} + loop_cond_(0), + compute_graph_(nullptr), + ref_info_() {} ~DataDumper(); @@ -56,6 +60,10 @@ class DataDumper { void SetDeviceId(uint32_t device_id) { device_id_ = device_id; } + void SetComputeGraph(const ComputeGraphPtr &compute_graph) { compute_graph_ = compute_graph; }; + + void SetRefInfo(const std::map &ref_info) { ref_info_ = ref_info; }; + void SetLoopAddr(void *global_step, void *loop_per_iter, void *loop_cond); void SaveDumpInput(const std::shared_ptr &node); @@ -65,11 +73,15 @@ class DataDumper { void SaveEndGraphId(uint32_t task_id, uint32_t stream_id); void SetOmName(const std::string &om_name) { om_name_ = om_name; } + void SaveOpDebugId(uint32_t task_id, uint32_t stream_id, void *op_debug_addr, bool is_op_debug); Status LoadDumpInfo(); Status UnloadDumpInfo(); + void SetDumpProperties(const DumpProperties &dump_properties) { dump_properties_ = dump_properties; } + const DumpProperties &GetDumpProperties() const { return dump_properties_; } + private: void ReleaseDevMem(void **ptr) noexcept; @@ -97,12 +109,32 @@ class DataDumper { uintptr_t global_step_; uintptr_t loop_per_iter_; uintptr_t loop_cond_; + ComputeGraphPtr compute_graph_; + std::map ref_info_; + + uint32_t op_debug_task_id_ = 0; + uint32_t op_debug_stream_id_ = 0; + void *op_debug_addr_ = nullptr; + bool is_op_debug_ = false; + + DumpProperties dump_properties_; Status DumpOutput(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task); + Status DumpRefOutput(const DataDumper::InnerDumpInfo &inner_dump_info, aicpu::dump::Output &output, size_t i, + const std::string &node_name_index); + Status DumpOutputWithTask(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task); Status DumpInput(const InnerDumpInfo &inner_dump_info, aicpu::dump::Task &task); + Status DumpRefInput(const DataDumper::InnerDumpInfo &inner_dump_info, aicpu::dump::Input &input, size_t i, + const std::string &node_name_index); Status ExecuteLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_info); void SetEndGraphIdToAicpu(uint32_t task_id, uint32_t stream_id, aicpu::dump::OpMappingInfo &op_mapping_info); + void SetOpDebugIdToAicpu(uint32_t task_id, uint32_t stream_id, void *op_debug_addr, + aicpu::dump::OpMappingInfo &op_mapping_info); Status ExecuteUnLoadDumpInfo(aicpu::dump::OpMappingInfo &op_mapping_info); + Status GenerateInput(aicpu::dump::Input &input, const OpDesc::Vistor &tensor_descs, + const uintptr_t &addr, size_t index); + Status GenerateOutput(aicpu::dump::Output &output, const OpDesc::Vistor &tensor_descs, + const uintptr_t &addr, size_t index); }; struct DataDumper::InnerDumpInfo { uint32_t task_id; diff --git a/src/ge/graph/load/new_model_manager/davinci_model.cc b/src/ge/graph/load/new_model_manager/davinci_model.cc index a8a11fd9..5af366a5 100644 --- a/src/ge/graph/load/new_model_manager/davinci_model.cc +++ b/src/ge/graph/load/new_model_manager/davinci_model.cc @@ -36,13 +36,13 @@ #include "common/scope_guard.h" #include "common/thread_pool.h" #include "framework/common/debug/ge_log.h" +#include "graph/common/ge_call_wrapper.h" #include "graph/compute_graph.h" #include "graph/debug/ge_attr_define.h" #include "graph/ge_context.h" #include "graph/graph.h" #include "graph/load/new_model_manager/cpu_queue_schedule.h" #include "graph/load/new_model_manager/tbe_handle_store.h" -#include "graph/load/output/output.h" #include "graph/manager/graph_mem_allocator.h" #include "graph/manager/graph_var_manager.h" #include "graph/manager/trans_var_data_utils.h" @@ -58,6 +58,7 @@ #include "runtime/dev.h" #include "runtime/event.h" #include "runtime/mem.h" +#include "runtime/rt_model.h" #include "runtime/stream.h" #include "securec.h" @@ -78,9 +79,8 @@ namespace { const uint32_t kDataIndex = 0; const uint32_t kOutputNum = 1; const uint32_t kTrueBranchStreamNum = 1; -const uint32_t kThreadNum = 1; +const uint32_t kThreadNum = 16; const uint32_t kAddrLen = sizeof(void *); -const char *const kNeedDestroySpecifiedAicpuKernel = "need_destroy_specified_aicpu_kernel"; const int kDecimal = 10; const int kBytes = 8; const uint32_t kDataMemAlignSizeCompare = 64; @@ -89,10 +89,10 @@ const char *const kDefaultBatchLable = "Batch_default"; inline bool IsDataOp(const std::string &node_type) { return node_type == DATA_TYPE || node_type == AIPP_DATA_TYPE || node_type == ANN_DATA_TYPE; } -inline bool IsCallDumpInputOp(const OpDescPtr &op_desc) { - bool skip_task_generate = false; - (void)ge::AttrUtils::GetBool(op_desc, ATTR_NO_TASK_AND_DUMP_NEEDED, skip_task_generate); - return skip_task_generate; +inline bool IsNoTaskAndDumpNeeded(const OpDescPtr &op_desc) { + bool save_dump_info = false; + (void)ge::AttrUtils::GetBool(op_desc, ATTR_NO_TASK_AND_DUMP_NEEDED, save_dump_info); + return save_dump_info; } } // namespace @@ -125,10 +125,10 @@ DavinciModel::DavinciModel(int32_t priority, const std::shared_ptrGetModelTaskDefPtr(); return SUCCESS; } +/// +/// @ingroup ge +/// @brief Reduce memory usage after task sink. +/// @return: void +/// +void DavinciModel::Shrink() { + ge_model_.reset(); // delete object. + + // Old dump need op list, clear when closed. + char *ge_dump_env = std::getenv("DUMP_OP"); + int dump_op_switch = (ge_dump_env != nullptr) ? std::strtol(ge_dump_env, nullptr, kDecimal) : 0; + if (dump_op_switch == 0) { + op_list_.clear(); + } +} + Status DavinciModel::InitModelMem(void *dev_ptr, size_t mem_size, void *weight_ptr, size_t weight_size) { if (is_model_has_inited_) { - GELOGI("call InitModelMem more than once ."); + GELOGE(FAILED, "call InitModelMem more than once ."); return FAILED; } is_model_has_inited_ = true; - std::size_t data_size = TotalMemSize(); - ge::Buffer weights = ge_model_->GetWeight(); - uint8_t *weights_addr = weights.GetData(); + std::size_t data_size = TotalMemSize(); + const Buffer &weights = ge_model_->GetWeight(); std::size_t weights_size = weights.GetSize(); - GE_CHECK_LE(weights_size, ALLOC_MEMORY_MAX_SIZE); if ((dev_ptr != nullptr) && (mem_size < TotalMemSize())) { @@ -257,7 +287,8 @@ Status DavinciModel::InitModelMem(void *dev_ptr, size_t mem_size, void *weight_p if (TotalMemSize() && mem_base_ == nullptr) { mem_base_ = MallocFeatureMapMem(data_size); if (mem_base_ == nullptr) { - return FAILED; + GELOGE(GE_EXEC_ALLOC_FEATURE_MAP_MEM_FAILED, "Alloc feature map memory failed. size: %zu", data_size); + return GE_EXEC_ALLOC_FEATURE_MAP_MEM_FAILED; } GELOGI("[IMAS]InitModelMem graph_%u MallocMemory type[F] memaddr[%p] mem_size[%zu]", runtime_param_.graph_id, mem_base_, data_size); @@ -274,17 +305,18 @@ Status DavinciModel::InitModelMem(void *dev_ptr, size_t mem_size, void *weight_p if (weight_ptr == nullptr) { weights_mem_base_ = MallocWeightsMem(weights_size); if (weights_mem_base_ == nullptr) { - return FAILED; + GELOGE(GE_EXEC_ALLOC_FEATURE_MAP_MEM_FAILED, "Alloc weight memory failed. size: %zu", weights_size); + return GE_EXEC_ALLOC_WEIGHT_MEM_FAILED; } is_inner_weight_base_ = true; } GELOGI("[IMAS]InitModelMem graph_%u MallocMemory type[W] memaddr[%p] mem_size[%zu]", runtime_param_.graph_id, weights_mem_base_, weights_size); - GE_CHK_RT_RET(rtMemcpy(weights_mem_base_, weights_size, weights_addr, weights_size, RT_MEMCPY_HOST_TO_DEVICE)) + GE_CHK_RT_RET(rtMemcpy(weights_mem_base_, weights_size, weights.GetData(), weights_size, RT_MEMCPY_HOST_TO_DEVICE)); GELOGI("copy weights data to device"); } - GE_CHK_STATUS_RET(InitVariableMem(), "init variable mem failed."); + GE_CHK_STATUS_RET(InitVariableMem(), "Init variable memory failed."); runtime_param_.mem_base = mem_base_; runtime_param_.weight_base = weights_mem_base_; return SUCCESS; @@ -296,7 +328,7 @@ Status DavinciModel::InitVariableMem() { if (TotalVarMemSize() && var_mem_base_ == nullptr) { Status ret = VarManager::Instance(session_id_)->MallocVarMemory(TotalVarMemSize()); if (ret != SUCCESS) { - GELOGE(ret, "Malloc Var Memory Fail."); + GELOGE(ret, "Malloc variable memory failed."); return ret; } var_mem_base_ = VarManager::Instance(session_id_)->GetVarMemoryBase(RT_MEMORY_HBM); @@ -335,19 +367,15 @@ void DavinciModel::InitRuntimeParams() { session_id_ = runtime_param_.session_id; GELOGI( - "InitRuntimeParams(), memory_size:%lu, weight_size:%lu, session_id:%u, var_size:%lu, logic_var_base:%lu, " - "logic_mem_base:%lu.", - runtime_param_.mem_size, runtime_param_.weight_size, runtime_param_.session_id, runtime_param_.var_size, - runtime_param_.logic_var_base, runtime_param_.logic_mem_base); - - GELOGI("InitRuntimeParams(), stream_num:%lu, event_num:%u, label_num:%u", runtime_param_.stream_num, - runtime_param_.event_num, runtime_param_.label_num); + "InitRuntimeParams(), session_id:%u, stream_num:%lu, event_num:%u, label_num:%u, " + "logic_mem_base:0x%lx, logic_weight_base:0x%lx, logic_var_base:0x%lx, " + "memory_size:%lu, weight_size:%lu, var_size:%lu", + runtime_param_.session_id, runtime_param_.stream_num, runtime_param_.event_num, runtime_param_.label_num, + runtime_param_.logic_mem_base, runtime_param_.logic_weight_base, runtime_param_.logic_var_base, + runtime_param_.mem_size, runtime_param_.weight_size, runtime_param_.var_size); } void DavinciModel::CheckHasHcomOp() { - // definiteness queue schedule, all stream by TS. - GE_IF_BOOL_EXEC(!input_queue_ids_.empty() || !output_queue_ids_.empty(), return ); - Graph graph = ge_model_->GetGraph(); auto compute_graph = GraphUtils::GetComputeGraph(graph); if (compute_graph == nullptr) { @@ -363,11 +391,6 @@ void DavinciModel::CheckHasHcomOp() { (op_desc->GetType() == HVDCALLBACKBROADCAST) || (op_desc->GetType() == HVDWAIT)), uint32_t stream_id = static_cast(op_desc->GetStreamId()); (void)hcom_streams_.emplace(stream_id); GELOGD("hcom stream: %u.", stream_id); continue); - - bool is_aicpu_stream = false; - GE_IF_BOOL_EXEC(AttrUtils::GetBool(op_desc, "is_aicpu_stream", is_aicpu_stream) && is_aicpu_stream, - uint32_t stream_id = static_cast(op_desc->GetStreamId()); - (void)aicpu_streams_.emplace(stream_id); GELOGD("aicpu stream: %u.", stream_id); continue); } } @@ -378,20 +401,13 @@ void DavinciModel::CheckHasHcomOp() { /// Status DavinciModel::BindModelStream() { // Stream not in active_stream_indication_ is active stream. - if (!input_queue_ids_.empty() || !output_queue_ids_.empty()) { - // Asynchronous Queue, need add S0, deactive all model stream. + if ((!input_queue_ids_.empty() || !output_queue_ids_.empty()) || (deploy_type_ == AICPU_DEPLOY_CROSS_THREAD)) { for (size_t i = 0; i < stream_list_.size(); ++i) { if (active_stream_indication_.count(i) == 0) { active_stream_list_.push_back(stream_list_[i]); active_stream_indication_.insert(i); // deactive all model stream. } } - } else { - for (size_t i = 0; i < stream_list_.size(); ++i) { - if (active_stream_indication_.count(i) == 0) { - active_stream_list_.push_back(stream_list_[i]); - } - } } for (size_t i = 0; i < stream_list_.size(); ++i) { @@ -409,23 +425,29 @@ Status DavinciModel::BindModelStream() { Status DavinciModel::DoTaskSink() { // task sink is supported as model_task_def is set - if (model_task_def_) { - GELOGI("do task_sink."); - GE_CHK_STATUS_RET(BindModelStream(), "Bind model stream failed."); + const auto &model_task_def = ge_model_->GetModelTaskDefPtr(); + if (model_task_def == nullptr) { + return SUCCESS; + } - if (known_node_) { - GE_CHK_STATUS_RET(MallocKnownArgs(), "Mallloc known node args failed."); - } + GE_CHK_RT_RET(rtGetAicpuDeploy(&deploy_type_)); + GELOGI("do task_sink. AiCpu deploy type is: %x.", deploy_type_); - GE_CHK_STATUS_RET(InitTaskInfo(*model_task_def_.get()), "InitTaskInfo failed."); + GE_CHK_STATUS_RET(BindModelStream(), "Bind model stream failed."); - GE_CHK_STATUS_RET(LoadWithQueue(), "LoadWithQueue failed."); + if (known_node_) { + GE_CHK_STATUS_RET(MallocKnownArgs(), "Mallloc known node args failed."); + } - GE_CHK_STATUS_RET(DistributeTask(), "Distribute failed."); + GE_CHK_STATUS_RET(InitTaskInfo(*model_task_def.get()), "InitTaskInfo failed."); - GE_CHK_RT_RET(rtModelLoadComplete(rt_model_handle_)); - } + GE_CHK_STATUS_RET(InitEntryTask(), "InitEntryTask failed."); + + GE_CHK_STATUS_RET(DistributeTask(), "Distribute failed."); + GE_CHK_RT_RET(rtModelLoadComplete(rt_model_handle_)); + + SetCopyOnlyOutput(); return SUCCESS; } @@ -438,17 +460,98 @@ Status DavinciModel::SetTSDevice() { rtError_t rt_ret = rtSetTSDevice(core_type); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "SetTSDevice failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; } +Status DavinciModel::OpDebugRegister() { + bool is_op_debug = false; + (void)ge::AttrUtils::GetBool(ge_model_, ATTR_OP_DEBUG_FLAG, is_op_debug); + GELOGD("The value of op_debug in ge_model_ is %d.", is_op_debug); + if (is_op_debug) { + debug_reg_mutex_.lock(); + rtError_t rt_ret = rtMalloc(&op_debug_addr_, kOpDebugMemorySize, RT_MEMORY_DDR); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } + + uint64_t debug_addrs_tmp = static_cast(reinterpret_cast(op_debug_addr_)); + + // For data dump, aicpu needs the pointer to pointer that save the real debug address. + rt_ret = rtMalloc(&p2p_debug_addr_, kDebugP2pSize, RT_MEMORY_HBM); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } + rt_ret = rtMemcpy(p2p_debug_addr_, sizeof(uint64_t), &debug_addrs_tmp, sizeof(uint64_t), RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtMemcpy to p2p_addr error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } + + uint32_t op_debug_mode = 0; + (void)ge::AttrUtils::GetInt(ge_model_, ATTR_OP_DEBUG_MODE, op_debug_mode); + GELOGD("The value of op_debug_mode in ge_model_ is %u.", op_debug_mode); + uint32_t debug_task_id = 0; + uint32_t debug_stream_id = 0; + rt_ret = rtDebugRegister(rt_model_handle_, op_debug_mode, op_debug_addr_, &debug_stream_id, &debug_task_id); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtDebugRegister error, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } + GELOGI("debug_task_id:%d, debug_stream_id:%u", debug_task_id, debug_stream_id); + is_op_debug_reg_ = true; + + data_dumper_.SaveOpDebugId(debug_task_id, debug_stream_id, p2p_debug_addr_, is_op_debug); + } + + return SUCCESS; +} + +void DavinciModel::OpDebugUnRegister() { + GELOGI("OpDebugUnRegister, is_op_debug_reg_ = %d", is_op_debug_reg_); + if (is_op_debug_reg_) { + debug_reg_mutex_.unlock(); + rtError_t rt_ret = RT_ERROR_NONE; + if (rt_model_handle_ != nullptr) { + rt_ret = rtDebugUnRegister(rt_model_handle_); + if (rt_ret != RT_ERROR_NONE) { + GELOGW("rtDebugUnRegister failed, ret: 0x%X", rt_ret); + } + } + + if (op_debug_addr_ != nullptr) { + rt_ret = rtFree(op_debug_addr_); + if (rt_ret != RT_ERROR_NONE) { + GELOGW("rtFree failed, ret: 0x%X", rt_ret); + } + op_debug_addr_ = nullptr; + } + + if (p2p_debug_addr_ != nullptr) { + rt_ret = rtFree(p2p_debug_addr_); + if (rt_ret != RT_ERROR_NONE) { + GELOGW("rtFree failed, ret: 0x%X", rt_ret); + } + p2p_debug_addr_ = nullptr; + } + is_op_debug_reg_ = false; + } + return; +} + // initialize op sequence and call initialization function of each op respectively Status DavinciModel::Init(void *dev_ptr, size_t mem_size, void *weight_ptr, size_t weight_size) { // validating params GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(priority_ < 0 || priority_ > 7, return PARAM_INVALID, "Priority must between 0-7, now is %d", priority_); GE_CHK_BOOL_RET_STATUS(ge_model_ != nullptr, PARAM_INVALID, "GeModel is null."); + Graph graph = ge_model_->GetGraph(); + ComputeGraphPtr compute_graph = GraphUtils::GetComputeGraph(graph); + GE_CHK_BOOL_RET_STATUS(compute_graph != nullptr, INTERNAL_ERROR, "Get compute graph is nullptr."); + // Initializing runtime_param_ InitRuntimeParams(); @@ -477,8 +580,6 @@ Status DavinciModel::Init(void *dev_ptr, size_t mem_size, void *weight_ptr, size if (hcom_streams_.find(i) != hcom_streams_.end()) { GE_CHK_RT_RET(rtStreamCreateWithFlags(&stream, priority_, stream_flags | RT_STREAM_FORCE_COPY)); - } else if (aicpu_streams_.find(i) != aicpu_streams_.end()) { - GE_CHK_RT_RET(rtStreamCreateWithFlags(&stream, priority_, stream_flags | RT_STREAM_AICPU)); } else { GE_CHK_RT_RET(rtStreamCreateWithFlags(&stream, priority_, stream_flags)); } @@ -499,35 +600,36 @@ Status DavinciModel::Init(void *dev_ptr, size_t mem_size, void *weight_ptr, size // create model_handle to load model GE_CHK_RT_RET(rtModelCreate(&rt_model_handle_, 0)); GE_CHK_RT_RET(rtModelGetId(rt_model_handle_, &runtime_model_id_)); + // inference will use default graph_id 0; + runtime_param_.graph_id = compute_graph->GetGraphID(); - Graph graph = ge_model_->GetGraph(); - compute_graph_ = GraphUtils::GetComputeGraph(graph); - GE_CHK_BOOL_RET_STATUS(compute_graph_ != nullptr, INTERNAL_ERROR, "Get compute graph is nullptr."); - - runtime_param_.graph_id = compute_graph_->GetGraphID(); + // op debug register + GE_CHK_STATUS_RET(OpDebugRegister(), "OpDebugRegister failed"); GE_TIMESTAMP_START(TransAllVarData); - GE_CHK_STATUS_RET(TransAllVarData(compute_graph_, runtime_param_.graph_id), "TransAllVarData failed."); + GE_CHK_STATUS_RET(TransAllVarData(compute_graph, runtime_param_.graph_id), "TransAllVarData failed."); GE_TIMESTAMP_END(TransAllVarData, "GraphLoader::TransAllVarData"); - GE_CHK_STATUS_RET(CopyVarData(compute_graph_), "copy var data failed."); + GE_CHK_STATUS_RET(TransVarDataUtils::CopyVarData(compute_graph, session_id_, device_id_), "copy var data failed."); GE_TIMESTAMP_START(InitModelMem); - GELOGI("known_node is %d", known_node_); + GELOGI("Known node is %d", known_node_); if (!known_node_) { GE_CHK_STATUS_RET_NOLOG(InitModelMem(dev_ptr, mem_size, weight_ptr, weight_size)); data_inputer_ = new (std::nothrow) DataInputer(); - GE_CHK_BOOL_RET_STATUS(data_inputer_ != nullptr, INTERNAL_ERROR, "data_inputer_ is nullptr."); + GE_CHK_BOOL_RET_STATUS(data_inputer_ != nullptr, MEMALLOC_FAILED, "data_inputer_ is nullptr."); } GE_TIMESTAMP_END(InitModelMem, "GraphLoader::InitModelMem"); - for (const ge::NodePtr &node : compute_graph_->GetDirectNode()) { - GE_IF_BOOL_EXEC(node->GetOpDesc() == nullptr, continue); - GE_IF_BOOL_EXEC(node->GetOpDesc()->GetType() != VARIABLE, continue); + for (const ge::NodePtr &node : compute_graph->GetDirectNode()) { + auto op_desc = node->GetOpDesc(); + GE_IF_BOOL_EXEC(op_desc == nullptr, continue); + GetFixedAddrAttr(op_desc); + GE_IF_BOOL_EXEC(op_desc->GetType() != VARIABLE, continue); GE_IF_BOOL_EXEC(IsBroadCastOpData(node), - (void)ge::AttrUtils::SetStr(node->GetOpDesc(), VAR_ATTR_VAR_IS_BROADCAST, "var_is_restore");); + (void)ge::AttrUtils::SetStr(op_desc, VAR_ATTR_VAR_IS_BROADCAST, "var_is_restore");); } // for profiling - op_name_map_ = compute_graph_->GetGraphOpName(); + op_name_map_ = compute_graph->GetGraphOpName(); vector op_name; GE_IF_BOOL_EXEC(ge::AttrUtils::GetListStr(ge_model_, ATTR_MODEL_TASK_INDEX_OP_NAME, op_name), @@ -536,14 +638,12 @@ Status DavinciModel::Init(void *dev_ptr, size_t mem_size, void *weight_ptr, size for (size_t idx = 0; idx < op_name.size(); idx++) { op_name_map_[idx] = op_name[idx]; } - GELOGI("infer profiling: op_name_size(%zu)", op_name.size()); + GELOGI("Infer profiling: op_name_size(%zu)", op_name.size()); } - if (InitNodes(compute_graph_) != SUCCESS) { - return FAILED; - } + GE_CHK_STATUS_RET(InitNodes(compute_graph), "Init nodes failed"); - SetDataDumperArgs(); + SetDataDumperArgs(compute_graph); GE_TIMESTAMP_START(DoTaskSink); auto ret = DoTaskSink(); GE_TIMESTAMP_END(DoTaskSink, "GraphLoader::DoTaskSink"); @@ -551,22 +651,23 @@ Status DavinciModel::Init(void *dev_ptr, size_t mem_size, void *weight_ptr, size /// In zero copy model, if a aicpu operator is connected to the first or last layer, before model execution, /// the aicpu opertor needs to destroy history record, and update operator memory address. /// The model with specified aicpu operators is only marked here, and destruction is in ModelManager::ExecuteModel(). - if (MarkSpecifiedAicpuKernel() != SUCCESS) { - GELOGE(FAILED, "Mark model with specified aicpu operators failed."); - return FAILED; - } + need_destroy_aicpu_kernel_ = IsAicpuKernelConnectSpecifiedLayer(); + (void)ge::AttrUtils::GetListStr(ge_model_, ATTR_MODEL_OUT_NODES_NAME, out_node_name_); // collect profiling for ge if (ProfilingManager::Instance().ProfilingOn()) { std::vector compute_graph_desc_info; - Status ret1 = GetComputeGraphInfo(compute_graph_desc_info); + Status ret1 = GetComputeGraphInfo(compute_graph, compute_graph_desc_info); if (ret1 != SUCCESS) { GELOGE(ret1, "GetComputeGraphInfo failed."); return ret1; } ProfilingManager::Instance().ReportProfilingData(GetTaskDescInfo(), compute_graph_desc_info); + GE_CHK_STATUS(SinkModelProfile(), "Sink model profile failed."); } - GELOGI("davinci model init success."); + + Shrink(); + GELOGI("Davinci model init success."); return ret; } @@ -623,26 +724,14 @@ bool DavinciModel::IsAicpuKernelConnectSpecifiedLayer() { return false; } -/// -/// @ingroup ge -/// @brief mark ge model with specified aicpu operators . -/// @return Status -/// -Status DavinciModel::MarkSpecifiedAicpuKernel() { - bool result = IsAicpuKernelConnectSpecifiedLayer(); - if (!result) { - // No aicpu operator needing destroy. - GELOGD("No specified aicpu operator that connects to data or netoutput."); - return SUCCESS; - } - bool ret = ge::AttrUtils::SetBool(ge_model_, kNeedDestroySpecifiedAicpuKernel, result); - if (!ret) { - GELOGW("Add attr[%s] in ge model failed, and may lead to specified aicpu operators destruction failure.", - kNeedDestroySpecifiedAicpuKernel); +Status DavinciModel::UpdateSessionId(uint64_t session_id) { + GE_CHECK_NOTNULL(ge_model_); + if (!AttrUtils::SetInt(ge_model_, MODEL_ATTR_SESSION_ID, static_cast(session_id))) { + GELOGW("Set attr[%s] failed in updating session_id.", MODEL_ATTR_SESSION_ID.c_str()); } - GELOGI("Mark ge model success, the model has specified aicpu operators, ge model name: %s.", - ge_model_->GetName().c_str()); + + GELOGD("Update session id: %lu.", session_id); return SUCCESS; } @@ -689,12 +778,6 @@ Status DavinciModel::InitNodes(const ComputeGraphPtr &compute_graph) { continue; } - if (IsCallDumpInputOp(op_desc)) { - GELOGI("node[%s] is no task op , call SaveDumpInput to save it's output node info", op_desc->GetName().c_str()); - data_dumper_.SaveDumpInput(node); - continue; - } - if (op_desc->GetType() == NETOUTPUT) { if (InitNetOutput(node) != SUCCESS) { GELOGE(PARAM_INVALID, "NetOutput init failed, Name: %s", op_desc->GetName().c_str()); @@ -712,6 +795,29 @@ Status DavinciModel::InitNodes(const ComputeGraphPtr &compute_graph) { continue; } + if (IsNoTaskAndDumpNeeded(op_desc)) { + GELOGD("node[%s] without task, and save op_desc and addr for dump", op_desc->GetName().c_str()); + const RuntimeParam &rts_param = GetRuntimeParam(); + const vector input_data_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc); + const vector output_data_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc); + const vector workspace_data_addrs = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc); + vector tensor_device_addrs; + tensor_device_addrs.insert(tensor_device_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + tensor_device_addrs.insert(tensor_device_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); + tensor_device_addrs.insert(tensor_device_addrs.end(), workspace_data_addrs.begin(), workspace_data_addrs.end()); + void *addr = nullptr; + auto size = kAddrLen * tensor_device_addrs.size(); + GE_CHK_RT_RET(rtMalloc(&addr, size, RT_MEMORY_HBM)); + + rtError_t rt_ret = rtMemcpy(addr, size, tensor_device_addrs.data(), size, RT_MEMCPY_HOST_TO_DEVICE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtMemcpy error, ret: 0x%X", rt_ret); + GE_CHK_RT(rtFree(addr)); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } + saved_task_addrs_.emplace(op_desc, addr); + } + GE_TIMESTAMP_RESTART(InitTbeHandle); uint32_t run_mode = static_cast(domi::ImplyType::INVALID); if (AttrUtils::GetInt(op_desc, ATTR_NAME_IMPLY_TYPE, run_mode) && @@ -724,9 +830,10 @@ Status DavinciModel::InitNodes(const ComputeGraphPtr &compute_graph) { op_desc->GetName().c_str(), op_desc->GetType().c_str()); continue;); - if (InitTbeHandle(op_desc) != SUCCESS) { - GELOGE(PARAM_INVALID, "TBE init failed. %s", op_desc->GetName().c_str()); - return PARAM_INVALID; + Status status = InitTbeHandle(op_desc); + if (status != SUCCESS) { + GELOGE(status, "TBE init failed. %s", op_desc->GetName().c_str()); + return status; } } GE_TIMESTAMP_ADD(InitTbeHandle); @@ -741,7 +848,6 @@ Status DavinciModel::InitNodes(const ComputeGraphPtr &compute_graph) { /// @brief Data Op Initialize. /// @param [in] NodePtr: Data Op. /// @param [in/out] data_op_index: NetOutput addr size info. -/// @param [in/out] input_data_info: Data index and addr info {index, {size, addr}}. /// @return Status Status DavinciModel::InitDataOp(const NodePtr &node, uint32_t &data_op_index) { // op_desc Checked by Init: Data, valid. @@ -757,31 +863,39 @@ Status DavinciModel::InitDataOp(const NodePtr &node, uint32_t &data_op_index) { } data_op_list_.push_back(op_desc); - ConstGeTensorDescPtr input_desc = op_desc->GetInputDescPtr(kDataIndex); - if (input_desc != nullptr && input_desc->GetFormat() != FORMAT_FILTER_HWCK) { - data_op_input_tensor_desc_map_[op_desc->GetName()] = input_desc; - } - - ConstGeTensorDescPtr output_desc = op_desc->GetOutputDescPtr(kDataIndex); - if (output_desc != nullptr && output_desc->GetFormat() != FORMAT_FRACTAL_Z) { - data_op_output_tensor_desc_map_[op_desc->GetName()] = output_desc; - } // Make information for copy input data. const vector output_size_list = ModelUtils::GetOutputSize(op_desc); - const vector virtual_addr_list = ModelUtils::GetOutputDataAddrs(runtime_param_, op_desc, false); - if (output_size_list.empty() || virtual_addr_list.empty() || (output_size_list.size() != virtual_addr_list.size())) { - GELOGE(PARAM_INVALID, "Data[%s] init failed: Output size is %zu, Output addr is %zu", op_desc->GetName().c_str(), - output_size_list.size(), virtual_addr_list.size()); + const vector virtual_addr_list = ModelUtils::GetOutputDataAddrs(runtime_param_, op_desc); + const vector output_offset_list = op_desc->GetOutputOffset(); + if (output_offset_list.size() != virtual_addr_list.size()) { + GELOGE(PARAM_INVALID, "virtual_addr size:%zu should be equal to offset size:%zu.", virtual_addr_list.size(), + output_offset_list.size()); return PARAM_INVALID; } - auto data_index = data_op_index; if (AttrUtils::GetInt(op_desc, ATTR_NAME_INDEX, data_index)) { GELOGI("ge_train: get new index %u, old %u", data_index, data_op_index); } - input_data_info_[data_index] = {output_size_list[kDataIndex], virtual_addr_list[kDataIndex]}; - SetInputOutsideAddr(virtual_addr_list); + bool fusion_flag = false; + ZeroCopyOffset zero_copy_offset; + Status ret = zero_copy_offset.InitInputDataInfo(output_size_list, virtual_addr_list, op_desc, fusion_flag); + if (ret != SUCCESS) { + GELOGE(PARAM_INVALID, "InitDataInfo of input_info %s failed.", op_desc->GetName().c_str()); + return PARAM_INVALID; + } + new_input_data_info_[data_index] = zero_copy_offset; + + for (size_t index = 0; index < virtual_addr_list.size(); ++index) { + void *addr = virtual_addr_list.at(index); + if (new_input_outside_addrs_.find(addr) != new_input_outside_addrs_.end()) { + continue; + } + zero_copy_offset.SetInputOutsideAddrs(output_offset_list, addr, index, fusion_flag, real_virtual_addrs_); + new_input_outside_addrs_[addr] = zero_copy_offset; + } + + GELOGI("SetInputOutsideAddr success."); data_op_index++; if (InitInputZeroCopyNodes(node) != SUCCESS) { GELOGE(PARAM_INVALID, "Input zero copy nodes init failed!"); @@ -830,6 +944,7 @@ Status DavinciModel::InitInputZeroCopyNodes(const NodePtr &node) { Status DavinciModel::InitNetOutput(const NodePtr &node) { // node->GetOpDesc Checked by Init: NetOutput, valid. auto op_desc = node->GetOpDesc(); + // excludes the function op sub graph, e.g. case,if if (known_node_) { output_op_list_.push_back(op_desc); return SUCCESS; @@ -845,7 +960,12 @@ Status DavinciModel::InitNetOutput(const NodePtr &node) { output_op_list_.push_back(op_desc); // Make information for copy output data. const vector input_size_list = ModelUtils::GetInputSize(op_desc); - const vector virtual_addr_list = ModelUtils::GetInputDataAddrs(runtime_param_, op_desc, false); + const vector virtual_addr_list = ModelUtils::GetInputDataAddrs(runtime_param_, op_desc); + const vector input_offset_list = op_desc->GetInputOffset(); + if (input_offset_list.size() != virtual_addr_list.size()) { + GELOGE(PARAM_INVALID, "virtual_addr size should be equal to offset size."); + return PARAM_INVALID; + } if (input_size_list.empty() && virtual_addr_list.empty()) { GELOGI("NetOutput[%s] is empty.", op_desc->GetName().c_str()); return SUCCESS; @@ -856,12 +976,38 @@ Status DavinciModel::InitNetOutput(const NodePtr &node) { return PARAM_INVALID; } - size_t num = output_data_info_.size(); + size_t num = new_output_data_info_.size(); + bool fusion_flag = false; + for (size_t idx = 0; idx < input_size_list.size(); ++idx) { - output_data_info_[num + idx] = {input_size_list[idx], virtual_addr_list[idx]}; + ZeroCopyOffset zero_copy_offset; + Status ret = zero_copy_offset.InitOutputDataInfo(input_size_list, virtual_addr_list, op_desc, idx, fusion_flag); + if (ret != SUCCESS) { + GELOGE(PARAM_INVALID, "InitDataInfo of input_info %s failed.", op_desc->GetName().c_str()); + return PARAM_INVALID; + } + new_output_data_info_[num + idx] = zero_copy_offset; + void *addr = virtual_addr_list.at(idx); + int64_t input_offset = input_offset_list.at(idx); + if (new_output_outside_addrs_.find(addr) != new_output_outside_addrs_.end()) { + continue; + } + vector tensor_addrs; + zero_copy_offset.SetOutputOutsideAddrs(input_offset, fusion_flag, addr, tensor_addrs); + auto rslt = new_output_outside_addrs_.insert(std::pair(addr, zero_copy_offset)); + if (!rslt.second) { + GELOGI("same output_tensor_addr %p to different input_tensor of %s", addr, op_desc->GetName().c_str()); + DisableZeroCopy(addr); + } + + for (size_t i = 0; i < tensor_addrs.size(); ++i) { + void *real_addr = tensor_addrs.at(i); + DisableZeroCopy(real_addr); + real_virtual_addrs_.emplace_back(real_addr); + } + GELOGI("SetOutputOutsideAddr success."); } - SetOutputOutsideAddr(virtual_addr_list); if (InitOutputZeroCopyNodes(node) != SUCCESS) { GELOGE(PARAM_INVALID, "Output zero copy nodes init failed!"); return PARAM_INVALID; @@ -968,8 +1114,8 @@ Status DavinciModel::InitVariable(const OpDescPtr &op_desc) { Status DavinciModel::SetQueIds(const std::vector &input_queue_ids, const std::vector &output_queue_ids) { if (input_queue_ids.empty() && output_queue_ids.empty()) { - GELOGE(PARAM_INVALID, "Para is empty"); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_QUEUE_ID_INVALID, "Param is empty"); + return GE_EXEC_MODEL_QUEUE_ID_INVALID; } input_queue_ids_ = input_queue_ids; @@ -989,32 +1135,28 @@ Status DavinciModel::LoadWithQueue() { return SUCCESS; } - if (input_queue_ids_.size() != input_data_info_.size()) { - GELOGE(PARAM_INVALID, "Input queue ids not match model: input_queue=%zu input_data=%zu", input_queue_ids_.size(), - input_data_info_.size()); - return PARAM_INVALID; + if (input_queue_ids_.size() != new_input_data_info_.size()) { + GELOGE(GE_EXEC_MODEL_QUEUE_ID_INVALID, "Input queue ids not match model: input_queue=%zu input_data=%zu", + input_queue_ids_.size(), new_input_data_info_.size()); + return GE_EXEC_MODEL_QUEUE_ID_INVALID; } - if (output_queue_ids_.size() != output_data_info_.size()) { - GELOGE(PARAM_INVALID, "Output queue ids not match model: output_queue=%zu output_data=%zu", - output_queue_ids_.size(), output_data_info_.size()); - return PARAM_INVALID; + if (output_queue_ids_.size() != new_output_data_info_.size()) { + GELOGE(GE_EXEC_MODEL_QUEUE_ID_INVALID, "Output queue ids not match model: output_queue=%zu output_data=%zu", + output_queue_ids_.size(), new_output_data_info_.size()); + return GE_EXEC_MODEL_QUEUE_ID_INVALID; } - // create stream instance which rt_model_handel is running on, this is S0. - GE_CHK_RT_RET(rtStreamCreateWithFlags(&rt_model_stream_, priority_, RT_STREAM_AICPU)); - is_inner_model_stream_ = true; - GE_CHK_RT_RET(rtModelBindStream(rt_model_handle_, rt_model_stream_, RT_HEAD_STREAM)); - + GE_CHK_STATUS_RET(AddHeadStream(), "Add head stream failed."); // Binding input_queue and Data Op. GE_CHK_STATUS_RET(BindInputQueue(), "Launch bind input queue failed."); - GE_CHK_STATUS_RET(CpuTaskModelZeroCopy(input_mbuf_list_, input_outside_addrs_), "Launch zero copy failed."); + GE_CHK_STATUS_RET(CpuTaskModelZeroCopy(input_mbuf_list_, new_input_outside_addrs_), "Launch zero copy failed."); // Binding output_queue and NetOutput Op. GE_CHK_STATUS_RET(BindOutputQueue(), "Launch bind output queue failed."); - GE_CHK_STATUS_RET(CpuTaskModelZeroCopy(output_mbuf_list_, output_outside_addrs_), "Launch zero copy failed."); + GE_CHK_STATUS_RET(CpuTaskModelZeroCopy(output_mbuf_list_, new_output_outside_addrs_), "Launch zero copy failed."); - GE_CHK_STATUS_RET(CpuActiveStream(active_stream_list_), "Launch active entry stream failed."); + GE_CHK_STATUS_RET(CpuActiveStream(), "Launch active entry stream failed."); GE_CHK_STATUS_RET(CpuWaitEndGraph(), "Launch wait end graph failed."); GE_CHK_STATUS_RET(BindEnqueue(), "Launch enqueue failed."); GE_CHK_STATUS_RET(CpuModelRepeat(), "Launch model repeat failed."); @@ -1028,20 +1170,26 @@ Status DavinciModel::LoadWithQueue() { Status DavinciModel::BindInputQueue() { // Caller checked: input_queue_ids_.size() == input_size_list_.size() != input_addr_list_.size() for (size_t i = 0; i < input_queue_ids_.size(); ++i) { - auto it = input_data_info_.find(i); - if (it == input_data_info_.end()) { - GELOGE(FAILED, "Input not match: tensor num=%zu, Queue id index=%zu", input_data_info_.size(), i); + auto it = new_input_data_info_.find(i); + if (it == new_input_data_info_.end()) { + GELOGE(FAILED, "Input not match: tensor num=%zu, Queue id index=%zu", new_input_data_info_.size(), i); return FAILED; } uint32_t queue_id = input_queue_ids_[i]; - uint32_t data_size = static_cast(it->second.first); - uintptr_t data_addr = reinterpret_cast(it->second.second); + if (it->second.GetDataInfo().empty()) { + GELOGE(INTERNAL_ERROR, "the %zu input_queue not set data_info.", i); + return INTERNAL_ERROR; + } + uint32_t data_size = static_cast(it->second.GetDataInfo().at(0).first); + uintptr_t data_addr = reinterpret_cast(it->second.GetDataInfo().at(0).second); GELOGI("BindInputToQueue: graph_%u index[%zu] queue id[%u] output addr[0x%lx] output size[%u]", runtime_param_.graph_id, i, queue_id, data_addr, data_size); - if (rtModelBindQueue(rt_model_handle_, queue_id, RT_MODEL_INPUT_QUEUE) != RT_ERROR_NONE) { - return INTERNAL_ERROR; + rtError_t rt_ret = rtModelBindQueue(rt_model_handle_, queue_id, RT_MODEL_INPUT_QUEUE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rtModelBindQueue failed, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } if (CpuModelDequeue(queue_id) != SUCCESS) { @@ -1058,16 +1206,17 @@ Status DavinciModel::BindInputQueue() { /// @return: 0 for success / others for failed Status DavinciModel::CpuModelDequeue(uint32_t queue_id) { GELOGI("Set CpuKernel model dequeue task enter."); - std::shared_ptr dequeue_task = MakeShared(rt_model_stream_); + std::shared_ptr dequeue_task = MakeShared(rt_entry_stream_); if (dequeue_task == nullptr) { - GELOGE(FAILED, "Make CpuTaskModelDequeue task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskModelDequeue task failed."); + return MEMALLOC_FAILED; } // Get DataOp Output address and bind to queue. uintptr_t in_mbuf = 0; - if (dequeue_task->Init(queue_id, in_mbuf) != SUCCESS) { - return FAILED; + Status status = dequeue_task->Init(queue_id, in_mbuf); + if (status != SUCCESS) { + return status; } cpu_task_list_.push_back(dequeue_task); @@ -1077,16 +1226,18 @@ Status DavinciModel::CpuModelDequeue(uint32_t queue_id) { } Status DavinciModel::CpuTaskModelZeroCopy(std::vector &mbuf_list, - std::map> &outside_addrs) { + std::map &outside_addrs) { GELOGI("Set CpuKernel model zero_copy task enter."); - std::shared_ptr zero_copy = MakeShared(rt_model_stream_); + std::shared_ptr zero_copy = MakeShared(rt_entry_stream_); if (zero_copy == nullptr) { - GELOGE(FAILED, "Make CpuTaskZeroCopy task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskZeroCopy task failed."); + return MEMALLOC_FAILED; } - if (zero_copy->Init(mbuf_list, outside_addrs) != SUCCESS) { - return FAILED; + // mdc zero_copy not support l2 fusion + Status status = zero_copy->Init(mbuf_list, outside_addrs); + if (status != SUCCESS) { + return status; } cpu_task_list_.push_back(zero_copy); GELOGI("Set CpuKernel model zero_copy task success."); @@ -1099,23 +1250,31 @@ Status DavinciModel::CpuTaskModelZeroCopy(std::vector &mbuf_list, Status DavinciModel::BindOutputQueue() { // Caller checked: input_queue_ids_.size() == input_size_list_.size() != input_addr_list_.size() for (size_t i = 0; i < output_queue_ids_.size(); ++i) { - auto it = output_data_info_.find(i); - if (it == output_data_info_.end()) { - GELOGE(FAILED, "Output not match: tensor num=%zu, Queue id index=%zu", output_data_info_.size(), i); + auto it = new_output_data_info_.find(i); + if (it == new_output_data_info_.end()) { + GELOGE(FAILED, "Output not match: tensor num=%zu, Queue id index=%zu", new_output_data_info_.size(), i); return FAILED; } uint32_t queue_id = output_queue_ids_[i]; - uint32_t data_size = static_cast(it->second.first); - uintptr_t data_addr = reinterpret_cast(it->second.second); + if (it->second.GetDataInfo().empty()) { + GELOGE(INTERNAL_ERROR, "the %zu output_queue not set data_info.", i); + return INTERNAL_ERROR; + } + uint32_t data_size = static_cast(it->second.GetDataInfo().at(0).first); + uintptr_t data_addr = reinterpret_cast(it->second.GetDataInfo().at(0).second); GELOGI("BindOutputToQueue: graph_%u index[%zu] queue id[%u] input addr[0x%lx] input size[%u]", runtime_param_.graph_id, i, queue_id, data_addr, data_size); - if (rtModelBindQueue(rt_model_handle_, queue_id, RT_MODEL_OUTPUT_QUEUE) != RT_ERROR_NONE) { - return INTERNAL_ERROR; + rtError_t rt_ret = rtModelBindQueue(rt_model_handle_, queue_id, RT_MODEL_OUTPUT_QUEUE); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rtModelBindQueue failed, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } - if (CpuModelPrepareOutput(data_addr, data_size) != SUCCESS) { - return INTERNAL_ERROR; + + Status status = CpuModelPrepareOutput(data_addr, data_size); + if (status != SUCCESS) { + return status; } } @@ -1124,7 +1283,6 @@ Status DavinciModel::BindOutputQueue() { /// @ingroup ge /// @brief definiteness queue schedule, bind output queue to task. -/// @param [in] queue_id: output queue id from user. /// @param [in] addr: NetOutput Op input tensor address. /// @param [in] size: NetOutput Op input tensor size. /// @return: 0 for success / others for failed @@ -1135,10 +1293,10 @@ Status DavinciModel::CpuModelPrepareOutput(uintptr_t addr, uint32_t size) { return FAILED; } - std::shared_ptr prepare_output = MakeShared(rt_model_stream_); + std::shared_ptr prepare_output = MakeShared(rt_entry_stream_); if (prepare_output == nullptr) { - GELOGE(FAILED, "Make CpuTaskPrepareOutput task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskPrepareOutput task failed."); + return MEMALLOC_FAILED; } uintptr_t out_mbuf = 0; @@ -1155,25 +1313,22 @@ Status DavinciModel::CpuModelPrepareOutput(uintptr_t addr, uint32_t size) { /// /// @ingroup ge /// @brief definiteness queue schedule, active original model stream. -/// @param [in] streams: streams will active by S0. /// @return: 0 for success / others for failed /// -Status DavinciModel::CpuActiveStream(const std::vector &stream_list) { - GELOGI("Set CpuKernel active stream task:%zu enter.", stream_list.size()); - for (auto s : stream_list) { - std::shared_ptr active_entry = MakeShared(rt_model_stream_); - if (active_entry == nullptr) { - GELOGE(FAILED, "Make CpuTaskActiveEntry task failed."); - return FAILED; - } - - if (active_entry->Init(s) != SUCCESS) { - return FAILED; - } +Status DavinciModel::CpuActiveStream() { + GELOGI("Set CpuKernel active stream task enter."); + std::shared_ptr active_entry = MakeShared(rt_entry_stream_); + if (active_entry == nullptr) { + GELOGE(MEMALLOC_FAILED, "Make CpuTaskActiveEntry task failed."); + return MEMALLOC_FAILED; + } - cpu_task_list_.push_back(active_entry); + Status status = active_entry->Init(rt_head_stream_); + if (status != SUCCESS) { + return status; } + cpu_task_list_.push_back(active_entry); GELOGI("Set CpuKernel active stream task success."); return SUCCESS; } @@ -1183,14 +1338,15 @@ Status DavinciModel::CpuActiveStream(const std::vector &stream_list) /// @return: 0 for success / others for failed Status DavinciModel::CpuWaitEndGraph() { GELOGI("Set CpuKernel wait end graph task enter."); - std::shared_ptr wait_endgraph = MakeShared(rt_model_stream_); + std::shared_ptr wait_endgraph = MakeShared(rt_entry_stream_); if (wait_endgraph == nullptr) { - GELOGE(FAILED, "Make CpuTaskWaitEndGraph task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskWaitEndGraph task failed."); + return MEMALLOC_FAILED; } - if (wait_endgraph->Init(runtime_model_id_) != SUCCESS) { - return FAILED; + Status status = wait_endgraph->Init(runtime_model_id_); + if (status != SUCCESS) { + return status; } cpu_task_list_.push_back(wait_endgraph); @@ -1200,9 +1356,9 @@ Status DavinciModel::CpuWaitEndGraph() { Status DavinciModel::BindEnqueue() { for (size_t i = 0; i < output_queue_ids_.size(); ++i) { - auto it = output_data_info_.find(i); - if (it == output_data_info_.end()) { - GELOGE(FAILED, "Output not match: tensor num=%zu, Queue id index=%zu", output_data_info_.size(), i); + auto it = new_output_data_info_.find(i); + if (it == new_output_data_info_.end()) { + GELOGE(FAILED, "Output not match: tensor num=%zu, Queue id index=%zu", new_output_data_info_.size(), i); return FAILED; } @@ -1216,14 +1372,15 @@ Status DavinciModel::BindEnqueue() { Status DavinciModel::CpuModelEnqueue(uint32_t queue_id, uintptr_t out_mbuf) { GELOGI("Set CpuKernel model enqueue task enter."); - std::shared_ptr model_enqueue = MakeShared(rt_model_stream_); + std::shared_ptr model_enqueue = MakeShared(rt_entry_stream_); if (model_enqueue == nullptr) { - GELOGE(FAILED, "Make CpuTaskModelEnqueue task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskModelEnqueue task failed."); + return MEMALLOC_FAILED; } - if (model_enqueue->Init(queue_id, out_mbuf) != SUCCESS) { - return FAILED; + Status status = model_enqueue->Init(queue_id, out_mbuf); + if (status != SUCCESS) { + return status; } cpu_task_list_.push_back(model_enqueue); GELOGI("Set CpuKernel model enqueue task enter."); @@ -1235,14 +1392,15 @@ Status DavinciModel::CpuModelEnqueue(uint32_t queue_id, uintptr_t out_mbuf) { /// @return: 0 for success / others for failed Status DavinciModel::CpuModelRepeat() { GELOGI("Set CpuKernel repeat task enter."); - std::shared_ptr model_repeat = MakeShared(rt_model_stream_); + std::shared_ptr model_repeat = MakeShared(rt_entry_stream_); if (model_repeat == nullptr) { - GELOGE(FAILED, "Make CpuTaskModelRepeat task failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make CpuTaskModelRepeat task failed."); + return MEMALLOC_FAILED; } - if (model_repeat->Init(runtime_model_id_) != SUCCESS) { - return FAILED; + Status status = model_repeat->Init(runtime_model_id_); + if (status != SUCCESS) { + return status; } cpu_task_list_.push_back(model_repeat); @@ -1285,43 +1443,29 @@ Status DavinciModel::GetInputOutputDescInfo(vector &input_d /// @ingroup ge /// @brief Get dynamic batch_info /// @param [out] batch_info +/// @param [out] dynamic_type /// @return execute result /// -Status DavinciModel::GetDynamicBatchInfo(std::vector> &batch_info) { - for (auto &iter : op_list_) { - OpDescPtr op_desc = iter.second; - if (op_desc == nullptr) { - GELOGE(FAILED, "op_desc is null, index=%u.", iter.first); - return FAILED; - } - - if (op_desc->GetType() != STREAMSWITCHN) { - continue; - } +Status DavinciModel::GetDynamicBatchInfo(std::vector> &batch_info, int32_t &dynamic_type) const { + dynamic_type = dynamic_type_; + batch_info = batch_info_; - batch_info.clear(); - uint32_t batch_num = 0; - if (!AttrUtils::GetInt(op_desc, ATTR_NAME_BATCH_NUM, batch_num)) { - GELOGE(FAILED, "Failed to get attr ATTR_NAME_BATCH_NUM, StreamSwitchN: %s.", op_desc->GetName().c_str()); - return FAILED; - } - std::vector batch_shape; - for (uint32_t i = 0; i < batch_num; i++) { - batch_shape.clear(); - const std::string attr_name = ATTR_NAME_PRED_VALUE + "_" + std::to_string(i); - if (!AttrUtils::GetListInt(op_desc, attr_name, batch_shape)) { - GELOGE(FAILED, "Failed to get attr ATTR_NAME_PRED_VALUE, StreamSwitchN: %s.", op_desc->GetName().c_str()); - return FAILED; - } - batch_info.emplace_back(batch_shape); - } - break; - } return SUCCESS; } /// /// @ingroup ge +/// @brief Get combined dynamic dims info +/// @param [out] batch_info +/// @return None +/// +void DavinciModel::GetCombinedDynamicDims(std::vector> &batch_info) const { + batch_info.clear(); + batch_info = combined_batch_info_; +} + +/// +/// @ingroup ge /// @brief Get AIPP input info /// @param [in] index /// @param [out] aipp_info @@ -1355,7 +1499,7 @@ Status DavinciModel::GetAIPPInfo(uint32_t index, AippConfigInfo &aipp_info) { return SUCCESS; } -void DavinciModel::SetDynamicSize(const std::vector &batch_num) { +void DavinciModel::SetDynamicSize(const std::vector &batch_num, int32_t dynamic_type) { batch_size_.clear(); if (batch_num.empty()) { GELOGD("User has not set dynammic data"); @@ -1363,9 +1507,11 @@ void DavinciModel::SetDynamicSize(const std::vector &batch_num) { for (size_t i = 0; i < batch_num.size(); i++) { batch_size_.emplace_back(batch_num[i]); } + + dynamic_type_ = dynamic_type; } -void DavinciModel::GetCurShape(std::vector &batch_info) { +void DavinciModel::GetCurShape(std::vector &batch_info, int32_t &dynamic_type) { if (batch_size_.empty()) { GELOGD("User does not set dynamic size"); } @@ -1373,6 +1519,8 @@ void DavinciModel::GetCurShape(std::vector &batch_info) { GELOGI("Start to get current shape"); batch_info.emplace_back(batch_size_[i]); } + + dynamic_type = dynamic_type_; } void DavinciModel::GetModelAttr(std::vector &dynamic_output_shape_info) { @@ -1529,7 +1677,7 @@ void DavinciModel::CreateOutput(uint32_t index, OpDescPtr &op_desc, InputOutputD int64_t tensor_size = 0; (void)TensorUtils::CalcTensorMemSize(shape, format, data_type, tensor_size); // no need to check value - output.size = static_cast(tensor_size); + output.size = static_cast(tensor_size); output.data_type = op_desc->GetInputDescPtr(index)->GetDataType(); } @@ -1538,9 +1686,6 @@ Status DavinciModel::GetOutputDescInfo(vector &output_desc, for (size_t i = 0; i < output_op_list_.size(); i++) { auto &op_desc = output_op_list_[i]; uint32_t out_size = static_cast(op_desc->GetInputsSize()); - // get real out nodes from model - vector out_node_name; - (void)ge::AttrUtils::GetListStr(ge_model_, ATTR_MODEL_OUT_NODES_NAME, out_node_name); for (uint32_t index = 0; index < out_size; index++) { string output_name; InputOutputDescInfo output; @@ -1552,11 +1697,11 @@ Status DavinciModel::GetOutputDescInfo(vector &output_desc, GE_CHK_BOOL_RET_STATUS(src_name.size() > index && src_index.size() > index, INTERNAL_ERROR, "construct output_name failed."); // forward compatbility, if old om has no out_node_name, need to return output follow origin way - if (out_size == out_node_name.size()) { + if (out_size == out_node_name_.size()) { // neweast plan, the index will add to name during generate model. - bool contains_colon = out_node_name[index].find(":") != std::string::npos; + bool contains_colon = out_node_name_[index].find(":") != std::string::npos; output_name = - contains_colon ? out_node_name[index] : out_node_name[index] + ":" + std::to_string(src_index[index]); + contains_colon ? out_node_name_[index] : out_node_name_[index] + ":" + std::to_string(src_index[index]); } else { output_name = std::string("output_") + std::to_string(index) + "_" + src_name[index] + "_" + std::to_string(src_index[index]); @@ -1581,27 +1726,28 @@ ge::Format DavinciModel::GetFormat() { Status DavinciModel::CopyInputData(const InputData &input_data, bool device_data) { rtMemcpyKind_t kind = device_data ? RT_MEMCPY_DEVICE_TO_DEVICE : RT_MEMCPY_HOST_TO_DEVICE; const std::vector &blobs = input_data.blobs; - for (const auto &data : input_data_info_) { + for (const auto &data : new_input_data_info_) { if (data.first >= blobs.size()) { GELOGE(FAILED, "Blobs not match: blobs=%zu, tensor=%zu, index=%u, size=%ld", blobs.size(), - input_data_info_.size(), data.first, data.second.first); + new_input_data_info_.size(), data.first, data.second.GetDataInfo().at(0).first); return FAILED; } const DataBuffer &data_buf = blobs[data.first]; - void *mem_addr = data.second.second; - uint32_t mem_size = static_cast(data.second.first); - GE_CHK_BOOL_RET_STATUS(mem_size >= data_buf.length, PARAM_INVALID, - "input data size(%u) does not match model required size(%u), ret failed.", data_buf.length, - mem_size); - - GELOGI("[IMAS]CopyPlainData memcpy graph_%u type[F] input[%u] dst[%p] src[%p] mem_size[%u] datasize[%u]", - runtime_param_.graph_id, data.first, mem_addr, data_buf.data, mem_size, data_buf.length); if (data_buf.length == 0) { GELOGW("No data need to memcpy!"); return SUCCESS; } - GE_CHK_RT_RET(rtMemcpy(mem_addr, mem_size, data_buf.data, data_buf.length, kind)); + uint64_t data_size = data.second.GetDataSize(); + GE_CHK_BOOL_RET_STATUS(data_size >= data_buf.length, PARAM_INVALID, + "input data size(%lu) does not match model required size(%lu), ret failed.", data_buf.length, + data_size); + void *mem_addr = data.second.GetBasicAddr(); + void *data_buf_addr = reinterpret_cast(reinterpret_cast(data_buf.data)); + uint64_t data_buf_length = data_buf.length; + GELOGI("[IMAS]CopyPlainData memcpy graph_%lu type[F] input[%lu] dst[%p] src[%p] mem_size[%lu] datasize[%lu]", + runtime_param_.graph_id, data.first, mem_addr, data_buf_addr, data_size, data_buf_length); + GE_CHK_RT_RET(rtMemcpy(mem_addr, data_size, data_buf_addr, data_buf_length, kind)); } return SUCCESS; @@ -1643,15 +1789,9 @@ inline int64_t SumSize(const vector &size_list) { } Status DavinciModel::SinkModelProfile() { - // not support non-sink model - GE_CHK_BOOL_EXEC(this->model_task_def_ != nullptr, return SUCCESS); - // profiling plugin must be registered Msprof::Engine::Reporter *reporter = PluginImpl::GetPluginReporter(); - if (reporter == nullptr) { - GELOGI("Profiling report is nullptr!"); - return SUCCESS; - } + GE_IF_BOOL_EXEC(reporter == nullptr, GELOGI("Profiling report is nullptr!"); return SUCCESS); GELOGI("Start collect model load profiling data."); @@ -1663,15 +1803,19 @@ Status DavinciModel::SinkModelProfile() { return FAILED, "Sink model tag memcpy error."); // Model Header - string name = this->Name(); - int32_t name_len = name.size(); + string name; + if (!om_name_.empty()) { + name = om_name_; + } else { + name = name_; + } + size_t name_len = name.size(); // phy device id uint32_t phy_device_id = 0; rtError_t rt_ret = rtGetDevicePhyIdByIndex(device_id_, &phy_device_id); - if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "runtime get phy_device_id failed, current phy_device_id:%d", phy_device_id); - return FAILED; - } + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, + GELOGE(rt_ret, "runtime get phy_device_id failed, current phy_device_id:%u", phy_device_id); + return FAILED); reporter_data.deviceId = phy_device_id; reporter_data.data = (unsigned char *)&name_len; reporter_data.dataLen = sizeof(int32_t); @@ -1708,7 +1852,6 @@ Status DavinciModel::SinkModelProfile() { for (int32_t i = 0; i < task_num; i++) { auto task = task_list_[i]; auto fusion_op_info = task->GetFusionOpInfo(); - // when type is RT_MODEL_TASK_KERNEL, ctx is not null if (fusion_op_info != nullptr) { uint32_t op_num = fusion_op_info->original_op_names.size(); @@ -1827,15 +1970,9 @@ Status DavinciModel::SinkModelProfile() { } Status DavinciModel::SinkTimeProfile(const InputData ¤t_data) { - // not support non-sink model - GE_CHK_BOOL_EXEC(this->model_task_def_ != nullptr, return SUCCESS); - // profiling plugin must be registered Msprof::Engine::Reporter *reporter = PluginImpl::GetPluginReporter(); - if (reporter == nullptr) { - GELOGI("Profiling report is nullptr!"); - return SUCCESS; - } + GE_IF_BOOL_EXEC(reporter == nullptr, GELOGI("Profiling report is nullptr!"); return SUCCESS); Msprof::Engine::ReporterData reporter_data{}; // report model data tag name @@ -1850,15 +1987,19 @@ Status DavinciModel::SinkTimeProfile(const InputData ¤t_data) { // device id uint32_t phy_device_id = 0; rtError_t rt_ret = rtGetDevicePhyIdByIndex(device_id_, &phy_device_id); - if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "runtime get phy_device_id failed, current phy_device_id:%d", phy_device_id); - return FAILED; - } + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, + GELOGE(rt_ret, "runtime get phy_device_id failed, current phy_device_id:%u", phy_device_id); + return FAILED); reporter_data.deviceId = phy_device_id; // Model Header - string name = this->Name(); - int32_t name_len = name.size(); + string name; + if (!om_name_.empty()) { + name = om_name_; + } else { + name = name_; + } + size_t name_len = name.size(); reporter_data.data = (unsigned char *)&name_len; reporter_data.dataLen = sizeof(int32_t); GE_CHK_BOOL_EXEC(reporter->Report(&reporter_data) == SUCCESS, return FAILED, "Reporter data fail, model id:%u.", @@ -1936,79 +2077,62 @@ void DavinciModel::SetProfileTime(ModelProcStage stage, int64_t endTime) { /// @ingroup ge /// @brief send Output Op result to upper layer /// @already malloced in ModelLoad, no need to malloc again -/// @param [in] sink_op Sink Op +/// @param [in] data_id: the index of output_data +/// @param [in/out] output_data: real user output_data +/// @param [in] kind: the kind of rtMemcpy /// @return Status result /// @author /// -Status DavinciModel::CopyOutputData(uint32_t data_id, OutputData &output_data) { - Status ret = SUCCESS; +Status DavinciModel::CopyOutputData(uint32_t data_id, OutputData &output_data, rtMemcpyKind_t kind) { if (output_op_list_.empty()) { - ret = SyncVarData(); - } else { - output_data.index = data_id; - output_data.model_id = model_id_; - GE_CHK_BOOL_RET_STATUS(output_data.blobs.size() == output_data_info_.size(), INTERNAL_ERROR, - "output buffer size[%zu] not equal output_size_list[%zu] size!", output_data.blobs.size(), - output_data_info_.size()); - - // index of data in output_data - uint32_t output_data_index = 0; - for (auto &op_desc : output_op_list_) { - ret = CopyOutputDataToUser(op_desc, output_data.blobs, output_data_index); - GE_CHK_BOOL_EXEC(ret == SUCCESS, break, "Copy output data to model ret failed, index:%u, model id:%u", - output_data.index, output_data.model_id); - } + Status ret = SyncVarData(); + DumpOpInputOutput(); + return ret; } - (void)DumpOpInputOutput(); // dump, not care result. - return ret; -} - -Status DavinciModel::CopyOutputDataToUser(OpDescPtr &op_desc, std::vector &blobs, uint32_t &data_index) { - Output model_output(op_desc, this); - - GE_CHK_BOOL_RET_STATUS(model_output.Init() == SUCCESS, PARAM_INVALID, "make shared model_output failed"); - - vector v_output_size; - vector v_output_data_addr; - model_output.GetOutputData(v_output_data_addr, v_output_size); - - // for all output tensor, copy output data from op to designated position - for (size_t i = 0; i < v_output_size.size(); ++i) { - GE_CHK_BOOL_RET_STATUS(data_index < blobs.size(), PARAM_INVALID, - "The blobs size:%zu, data_op size:%zu, curr output size:%zu", blobs.size(), - data_op_list_.size(), v_output_size.size()); + output_data.index = data_id; + output_data.model_id = model_id_; + if (output_data.blobs.size() != new_output_data_info_.size()) { + GELOGE(FAILED, "Output data buffer num=%zu not equal model data num=%zu", output_data.blobs.size(), + new_output_data_info_.size()); + return FAILED; + } - DataBuffer &data_buf = blobs[data_index]; - data_index++; + std::vector &blobs = output_data.blobs; + for (const auto &output : new_output_data_info_) { + if (output.first >= blobs.size()) { + GELOGE(FAILED, "Blobs not match: blobs=%zu, tensor=%zu, index=%u, size=%ld", blobs.size(), + new_input_data_info_.size(), output.first, output.second.GetDataInfo().at(0).first); + return FAILED; + } - uint32_t size = data_buf.length; - GE_CHK_BOOL_RET_STATUS(size <= v_output_size[i], PARAM_INVALID, - "Model output data size(%u) does not match required size(%u).", v_output_size[i], - data_buf.length); + DataBuffer &buffer = blobs[output.first]; + uint64_t mem_size = static_cast(output.second.GetDataSize()); + if ((buffer.length == 0) || (mem_size == 0)) { + GELOGI("Length of data is zero, No need copy. output tensor index=%u", output.first); + continue; + } + if (buffer.length < mem_size) { + GELOGE(FAILED, "Tensor data size=%lu, buffer size=%u", mem_size, buffer.length); + return FAILED; + } else if (buffer.length > mem_size) { + GELOGW("Tensor data size=%lu, buffer size=%u", mem_size, buffer.length); + } - if (copy_only_addrs_.count(v_output_data_addr[i]) == 0) { - GELOGI("[ZCPY] This addr[%p] has already feed by zero copy.", v_output_data_addr[i]); + if ((kind == RT_MEMCPY_DEVICE_TO_DEVICE) && (copy_only_addrs_.count(output.second.GetBasicAddr()) == 0)) { continue; // Skip: Feed by zero copy. } - GELOGI( - "CopyOutputDataToUser memcpy graph_%u type[F] name[%s] output[%lu] dst[%p] src[%p] mem_size[%u] datasize[%u]", - runtime_param_.graph_id, op_desc->GetName().c_str(), i, data_buf.data, v_output_data_addr[i], data_buf.length, - v_output_size[i]); - GE_CHK_RT_RET(rtMemcpy(data_buf.data, size, v_output_data_addr[i], size, RT_MEMCPY_DEVICE_TO_DEVICE)); - } + uint64_t data_size = output.second.GetDataSize(); + uint64_t buffer_length = buffer.length; + void *buffer_addr = reinterpret_cast(reinterpret_cast(buffer.data)); - return SUCCESS; -} - -Status DavinciModel::SyncDataAndDump() { - Status ret = SUCCESS; - if (output_op_list_.empty()) { - ret = SyncVarData(); + GELOGI("[IMAS]CopyPlainData memcpy graph_%u type[F] output[%u] memaddr[%p] mem_size[%lu] datasize[%u]", + runtime_param_.graph_id, output.first, output.second.GetBasicAddr(), data_size, buffer_length); + GE_CHK_RT_RET(rtMemcpy(buffer_addr, buffer_length, output.second.GetBasicAddr(), data_size, kind)); } - (void)DumpOpInputOutput(); // dump, not care result. - return ret; + DumpOpInputOutput(); + return SUCCESS; } Status DavinciModel::GenOutputTensorInfo(const OpDescPtr &op_desc, uint32_t data_index, OutputData *output_data, @@ -2042,13 +2166,13 @@ Status DavinciModel::GenOutputTensorInfo(const OpDescPtr &op_desc, uint32_t data GELOGE(GE_GRAPH_MALLOC_FAILED, "Malloc buffer failed."); return GE_GRAPH_MALLOC_FAILED; } - output_data->blobs.push_back({data_buf.get(), static_cast(out_buffer_size_vec[i]), false}); + output_data->blobs.push_back({data_buf.get(), static_cast(out_buffer_size_vec[i]), false}); ge::OutputTensorInfo output; output.dims = shape_info_vec[i]; output.data = std::move(data_buf); output.length = out_buffer_size_vec[i]; outputs.emplace_back(std::move(output)); - GELOGI("Output index:%zu, data_length:%u.", i, output.length); + GELOGI("Output index:%zu, data_length:%lu.", i, output.length); } return SUCCESS; } @@ -2057,7 +2181,10 @@ Status DavinciModel::GenOutputTensorInfo(const OpDescPtr &op_desc, uint32_t data /// @ingroup ge /// @brief send Output Op result to upper layer /// @already malloced in ModelLoad, no need to malloc again -/// @param [in] sink_op Sink Op +/// @param [in] data_id: the index of output_data +/// @param [in] rslt_flg: result flag +/// @param [in] seq_end_flag: sequence end flag +/// @param [out] output_data: real user output_data /// @return Status result /// @author /// @@ -2088,20 +2215,17 @@ Status DavinciModel::ReturnResult(uint32_t data_id, const bool rslt_flg, const b // copy output data from op to designated position for (auto &op_desc : output_op_list_) { - Output model_output(op_desc, this); - if (model_output.Init() != SUCCESS || GenOutputTensorInfo(op_desc, data_index, output_data, outputs) != SUCCESS) { + if (GenOutputTensorInfo(op_desc, data_index, output_data, outputs) != SUCCESS) { return INTERNAL_ERROR; } + data_index += op_desc->GetInputsSize(); + } - Status ret = model_output.CopyResult(*output_data, data_index, data_index, false); - if (ret != SUCCESS) { - GELOGE(INTERNAL_ERROR, "CopyResult failed, op name: %s", op_desc->GetName().c_str()); - GE_CHK_STATUS(listener_->OnComputeDone(model_id_, data_id, INTERNAL_ERROR, outputs), "OnComputeDone failed"); - return INTERNAL_ERROR; - } + if (CopyOutputData(data_id, *output_data, RT_MEMCPY_DEVICE_TO_HOST) != SUCCESS) { + GE_CHK_STATUS(listener_->OnComputeDone(model_id_, data_id, INTERNAL_ERROR, outputs), "OnComputeDone failed"); + return INTERNAL_ERROR; } - GE_IF_BOOL_EXEC((DumpOpInputOutput() != SUCCESS), GELOGW("dump op failed, model_id: %u", model_id_);); if (seq_end_flag) { GELOGW("End of sequence, model id: %u", model_id_); GE_CHK_STATUS(listener_->OnComputeDone(model_id_, data_id, END_OF_SEQUENCE, outputs), "OnCompute Done failed."); @@ -2114,6 +2238,7 @@ Status DavinciModel::ReturnResult(uint32_t data_id, const bool rslt_flg, const b /// /// @ingroup ge /// @brief return not output to upper layer for cloud case +/// @param [in] data_id /// @return Status result /// Status DavinciModel::ReturnNoOutput(uint32_t data_id) { @@ -2125,7 +2250,7 @@ Status DavinciModel::ReturnNoOutput(uint32_t data_id) { op_desc->GetName().c_str()); } - GE_IF_BOOL_EXEC((DumpOpInputOutput() != SUCCESS), GELOGW("dump op failed, model_id: %u", model_id_);); + DumpOpInputOutput(); GE_CHK_BOOL_EXEC(listener_ != nullptr, return PARAM_INVALID, "listener_ is null!"); std::vector outputs; GE_CHK_STATUS(listener_->OnComputeDone(model_id_, data_id, SUCCESS, outputs), "OnComputeDone failed."); @@ -2135,41 +2260,40 @@ Status DavinciModel::ReturnNoOutput(uint32_t data_id) { /// /// @ingroup ge /// @brief dump all op input and output information -/// @param [in] op_list model_id -/// @return Status result +/// @return void /// -Status DavinciModel::DumpOpInputOutput() { +void DavinciModel::DumpOpInputOutput() { + char *ge_dump_env = std::getenv("DUMP_OP"); + int dump_op_switch = (ge_dump_env != nullptr) ? std::strtol(ge_dump_env, nullptr, kDecimal) : 0; + if (dump_op_switch == 0) { + GELOGI("need to set DUMP_OP for dump op input and output"); + return; + } + if (op_list_.empty()) { - GELOGW("op_list is empty."); - return FAILED; + GELOGW("op list is empty"); + return; } - char *ge_dump_env = getenv("DUMP_OP"); - int dump_op_switch = - (ge_dump_env != nullptr) ? std::strtol(ge_dump_env, nullptr, kDecimal) : 0; // 10 for decimal number - if (dump_op_switch != 0) { - int64_t cnt = 1; - for (auto it : op_list_) { - if (maxDumpOpNum_ != 0 && cnt > maxDumpOpNum_) { - GELOGW("dump op cnt > maxDumpOpNum, maxDumpOpNum: %ld.", maxDumpOpNum_); - return SUCCESS; - } - Status ret = DumpSingleOpInputOutput(it.second); - cnt++; - if (ret != SUCCESS) { - GELOGE(FAILED, "dump single op failed, model_id: %u", model_id_); - return FAILED; - } + + int64_t cnt = 1; + for (auto it : op_list_) { + if (maxDumpOpNum_ != 0 && cnt > maxDumpOpNum_) { + GELOGW("dump op cnt > maxDumpOpNum, maxDumpOpNum: %ld", maxDumpOpNum_); + return; + } + + cnt++; + if (DumpSingleOpInputOutput(it.second) != SUCCESS) { + GELOGW("dump single op failed, model_id: %u", model_id_); + return; } - } else { - GELOGW("need to set DUMP_OP for dump op input and output."); } - return SUCCESS; } /// /// @ingroup ge /// @brief dump single op input and output information -/// @param [in] dump_op model_id +/// @param [in] op_def: the op_desc which will be dump /// @return Status result /// Status DavinciModel::DumpSingleOpInputOutput(const OpDescPtr &op_def) { @@ -2185,7 +2309,7 @@ Status DavinciModel::DumpSingleOpInputOutput(const OpDescPtr &op_def) { } } const vector input_size_vec = ModelUtils::GetInputSize(op_def); - const vector input_addr_vec = ModelUtils::GetInputDataAddrs(runtime_param_, op_def, false); + const vector input_addr_vec = ModelUtils::GetInputDataAddrs(runtime_param_, op_def); vector v_memory_type; bool has_mem_type_attr = ge::AttrUtils::GetListInt(op_def, ATTR_NAME_INPUT_MEM_TYPE_LIST, v_memory_type); GELOGD("DumpSingleOp[%s], input size[%zu], input memory type size[%zu]", op_def->GetName().c_str(), @@ -2208,7 +2332,7 @@ Status DavinciModel::DumpSingleOpInputOutput(const OpDescPtr &op_def) { } const vector output_size_vec = ModelUtils::GetOutputSize(op_def); - const vector output_addr_vec = ModelUtils::GetOutputDataAddrs(runtime_param_, op_def, false); + const vector output_addr_vec = ModelUtils::GetOutputDataAddrs(runtime_param_, op_def); v_memory_type.clear(); has_mem_type_attr = ge::AttrUtils::GetListInt(op_def, ATTR_NAME_OUTPUT_MEM_TYPE_LIST, v_memory_type); GELOGD("DumpSingleOp[%s], output size[%zu], output memory type size[%zu]", op_def->GetName().c_str(), @@ -2278,7 +2402,7 @@ void *DavinciModel::Run(DavinciModel *model) { ret != SUCCESS, (void)model->ReturnResult(current_data.index, false, false, data_wrapper->GetOutput()); CsaInteract::GetInstance().StoreInternalErrorCode(ret, ERROR_MODULE_FMK, JOBSUBSTATE_GRAPH_EXEC); continue, "Copy input data to model failed."); // [No need to check value] - GE_TIMESTAMP_END(Model_SyncVarData, "Model Run SyncVarData"); + GE_IF_BOOL_EXEC(model->is_first_execute_, GE_TIMESTAMP_EVENT_END(Model_SyncVarData, "Model Run SyncVarData")); GELOGI("Copy input data, model id:%u", model_id); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), model->SetProfileTime(MODEL_PRE_PROC_START)); @@ -2324,7 +2448,7 @@ void *DavinciModel::Run(DavinciModel *model) { CsaInteract::GetInstance().WriteErrorCode(rt_ret, ERROR_MODULE_RUNTIME, JOBSUBSTATE_GRAPH_EXEC); continue); GELOGI("rtModelExecute end"); - GE_TIMESTAMP_END(rtModelExecute, "GraphExcute::rtModelExecute"); + GE_IF_BOOL_EXEC(model->is_first_execute_, GE_TIMESTAMP_EVENT_END(rtModelExecute, "GraphExcute::rtModelExecute")); GE_TIMESTAMP_START(rtStreamSynchronize); GELOGI("rtStreamSynchronize start."); @@ -2339,7 +2463,8 @@ void *DavinciModel::Run(DavinciModel *model) { CsaInteract::GetInstance().StoreInternalErrorCode(rt_ret, ERROR_MODULE_RUNTIME, JOBSUBSTATE_GRAPH_EXEC); continue); GELOGI("rtStreamSynchronize end."); - GE_TIMESTAMP_END(rtStreamSynchronize, "GraphExcute::Wait for rtStreamSynchronize"); + GE_IF_BOOL_EXEC(model->is_first_execute_, + GE_TIMESTAMP_EVENT_END(rtStreamSynchronize, "GraphExcute::Wait for rtStreamSynchronize")); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), model->SetProfileTime(MODEL_INFER_END)); } @@ -2350,11 +2475,13 @@ void *DavinciModel::Run(DavinciModel *model) { (void)model->ReturnResult(current_data.index, rslt_flg, false, data_wrapper->GetOutput())) // copy output data from device to host for variable graph GE_IF_BOOL_EXEC(model->output_op_list_.empty(), (void)model->ReturnNoOutput(current_data.index)); - GE_TIMESTAMP_END(ReturnResult3, "GraphExcute::CopyDataFromDeviceToHost"); + GE_IF_BOOL_EXEC(model->is_first_execute_, + GE_TIMESTAMP_EVENT_END(ReturnResult3, "GraphExcute::CopyDataFromDeviceToHost")); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), model->SetProfileTime(MODEL_AFTER_PROC_END)); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), (void)model->SinkTimeProfile(current_data)); model->iterator_count_++; + model->is_first_execute_ = false; GELOGI("run iterator count is %lu", model->iterator_count_); } @@ -2407,7 +2534,7 @@ Status DavinciModel::ModelRunStart() { is_inner_model_stream_ = true; string opt = "0"; - (void)ge::GetContext().GetOption("ge.maxDumpOpNum", opt); // option may not be set up, no need to check value + (void)ge::GetContext().GetOption(OPTION_GE_MAX_DUMP_OP_NUM, opt); // option may not be set up, no need to check value int64_t maxDumpOpNum = std::strtol(opt.c_str(), nullptr, kDecimal); maxDumpOpNum_ = maxDumpOpNum; @@ -2450,27 +2577,41 @@ void DavinciModel::UnbindTaskSinkStream() { // destroy stream that is bound with rt_model GE_LOGW_IF(rtStreamDestroy(rt_model_stream_) != RT_ERROR_NONE, "Destroy stream for rt_model failed.") } - return; + + if (is_pure_head_stream_ && rt_head_stream_ != nullptr) { + GE_LOGW_IF(rtModelUnbindStream(rt_model_handle_, rt_head_stream_) != RT_ERROR_NONE, "Unbind stream failed!"); + GE_LOGW_IF(rtStreamDestroy(rt_head_stream_) != RT_ERROR_NONE, "Destroy stream for rt_model failed."); + rt_head_stream_ = nullptr; + } + + if (rt_entry_stream_ != nullptr) { + GE_LOGW_IF(rtModelUnbindStream(rt_model_handle_, rt_entry_stream_) != RT_ERROR_NONE, "Unbind stream failed!"); + GE_LOGW_IF(rtStreamDestroy(rt_entry_stream_) != RT_ERROR_NONE, "Destroy stream for rt_model failed."); + rt_entry_stream_ = nullptr; + } } Status DavinciModel::CreateKnownZeroCopyMap(const vector &inputs, const vector &outputs) { GELOGI("DavinciModel::CreateKnownZeroCopyMap in."); - if (inputs.size() != data_op_list_.size()) { - GELOGE(FAILED, "input data addr %u is not equal to input op number %u.", inputs.size(), data_op_list_.size()); + if (inputs.size() > data_op_list_.size()) { + GELOGE(FAILED, "input data addr %u should less than input op number %u.", inputs.size(), data_op_list_.size()); return FAILED; } - for (size_t i = 0; i < data_op_list_.size(); ++i) { + // remove zero copy addr in last iteration + knonw_input_data_info_.clear(); + knonw_output_data_info_.clear(); + for (size_t i = 0; i < inputs.size(); ++i) { const vector addr_list = ModelUtils::GetOutputDataAddrs(runtime_param_, data_op_list_[i]); knonw_input_data_info_[addr_list[kDataIndex]] = inputs[i]; GELOGI("DavinciModel::CreateKnownZeroCopyMap input %d,v addr %p,p addr %p .", i, addr_list[kDataIndex], inputs[i]); } - if (output_op_list_.size() != kOutputNum) { - GELOGE(FAILED, "output op num is %u, not equal %u.", outputs.size(), kOutputNum); - return FAILED; + if (output_op_list_.size() < kOutputNum) { + GELOGW("output op num in graph is %u.", output_op_list_.size()); + return SUCCESS; } const vector addr_list = ModelUtils::GetInputDataAddrs(runtime_param_, output_op_list_[kDataIndex]); - if (outputs.size() != addr_list.size()) { - GELOGE(FAILED, "output data addr %u is not equal to output op number %u.", outputs.size(), addr_list.size()); + if (outputs.size() > addr_list.size()) { + GELOGE(FAILED, "output data addr %u should less than output op number %u.", outputs.size(), addr_list.size()); return FAILED; } for (size_t i = 0; i < addr_list.size(); ++i) { @@ -2481,30 +2622,20 @@ Status DavinciModel::CreateKnownZeroCopyMap(const vector &inputs, const return SUCCESS; } -Status DavinciModel::UpdateKnownZeroCopyAddr(vector &io_addrs, uint32_t args_offset) { - for (size_t i = 0; i < io_addrs.size(); ++i) { - auto it_in = knonw_input_data_info_.find(io_addrs[i]); +Status DavinciModel::UpdateKnownZeroCopyAddr() { + for (size_t i = 0; i < total_io_addrs_.size(); ++i) { + auto it_in = knonw_input_data_info_.find(total_io_addrs_[i]); if (it_in != knonw_input_data_info_.end()) { - GELOGI("DavinciModel::UpdateKnownZeroCopyAddr input %d,v addr %p,p addr %p .", i, io_addrs[i], - knonw_input_data_info_.at(io_addrs[i])); - io_addrs[i] = knonw_input_data_info_.at(io_addrs[i]); + GELOGI("DavinciModel::UpdateKnownZeroCopyAddr input %d,v addr %p,p addr %p .", i, total_io_addrs_[i], + knonw_input_data_info_.at(total_io_addrs_[i])); + total_io_addrs_[i] = knonw_input_data_info_.at(total_io_addrs_[i]); } - auto it_out = knonw_output_data_info_.find(io_addrs[i]); + auto it_out = knonw_output_data_info_.find(total_io_addrs_[i]); if (it_out != knonw_output_data_info_.end()) { - GELOGI("DavinciModel::UpdateKnownZeroCopyAddr output %d,v addr %p,p addr %p .", i, io_addrs[i], - knonw_output_data_info_.at(io_addrs[i])); - io_addrs[i] = knonw_output_data_info_.at(io_addrs[i]); - } - } - // may args_size is equal to src_args_size? - uint32_t src_args_size = io_addrs.size() * sizeof(uint64_t); - GELOGI("DavinciModel::UpdateKnownZeroCopyAddr args host %p, src_args_size %u, args_offset %u", args_host_, - src_args_size, args_offset); - errno_t sec_ret = - memcpy_s(static_cast(args_host_) + args_offset, src_args_size, io_addrs.data(), src_args_size); - if (sec_ret != EOK) { - GELOGE(FAILED, "Call memcpy_s failed, ret: %d", sec_ret); - return FAILED; + GELOGI("DavinciModel::UpdateKnownZeroCopyAddr output %d,v addr %p,p addr %p .", i, total_io_addrs_[i], + knonw_output_data_info_.at(total_io_addrs_[i])); + total_io_addrs_[i] = knonw_output_data_info_.at(total_io_addrs_[i]); + } } GELOGI("DavinciModel::UpdateKnownZeroCopyAddr success."); return SUCCESS; @@ -2514,20 +2645,31 @@ Status DavinciModel::UpdateKnownNodeArgs(const vector &inputs, const vec GELOGI("DavinciModel::UpdateKnownNodeArgs in"); GE_CHK_STATUS_RET(CreateKnownZeroCopyMap(inputs, outputs), "DavinciModel::UpdateKnownNodeArgs create map for input/output zero copy."); - for (size_t task_index = 0; task_index < task_list_.size(); ++task_index) { - auto &task = task_list_[task_index]; - if (task != nullptr) { - Status ret = task->UpdateArgs(); - if (ret != SUCCESS) { - GELOGE(FAILED, "task %d created by davinci model is nullptr.", task_index); - return FAILED; + if (!base_addr_not_changed_) { + total_io_addrs_.clear(); + orig_total_io_addrs_.clear(); + for (size_t task_index = 0; task_index < task_list_.size(); ++task_index) { + auto &task = task_list_[task_index]; + if (task != nullptr) { + Status ret = task->UpdateArgs(); + if (ret != SUCCESS) { + GELOGE(FAILED, "task %d created by davinci model is nullptr.", task_index); + return FAILED; + } } } + // cache latest iterator io addr + orig_total_io_addrs_ = total_io_addrs_; + } else { + total_io_addrs_ = orig_total_io_addrs_; } - GELOGI("DavinciModel::UpdateKnownNodeArgs device args %p, size %u, host args %p, size %u", args_, total_args_size_, - args_host_, total_args_size_); - // copy continuous args from host to device - Status rt_ret = rtMemcpy(args_, total_args_size_, args_host_, total_args_size_, RT_MEMCPY_HOST_TO_DEVICE); + GE_CHK_STATUS_RET(UpdateKnownZeroCopyAddr(), "DavinciModel::UpdateKnownZeroCopyAddr failed."); + + uint32_t total_addr_size = total_io_addrs_.size() * sizeof(uint64_t); + GELOGI("DavinciModel::UpdateKnownNodeArgs device args %p, dst size %u, src size %u", args_, total_args_size_, + total_addr_size); + + Status rt_ret = rtMemcpy(args_, total_args_size_, total_io_addrs_.data(), total_addr_size, RT_MEMCPY_HOST_TO_DEVICE); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy error, ret: Ox%X", rt_ret); return FAILED;) GELOGI("DavinciModel::UpdateKnownNodeArgs success"); @@ -2535,12 +2677,14 @@ Status DavinciModel::UpdateKnownNodeArgs(const vector &inputs, const vec } Status DavinciModel::InitTaskInfo(domi::ModelTaskDef &model_task_def) { - GELOGI("InitTaskInfo in,task size %d", model_task_def.task().size()); + GELOGI("InitTaskInfo in, task size %zu", model_task_def.task().size()); task_list_.resize(model_task_def.task_size()); for (int i = 0; i < model_task_def.task_size(); ++i) { // dynamic shape will create task_list_ before const domi::TaskDef &task = model_task_def.task(i); - task_list_[i] = TaskInfoFactory::Instance().Create(static_cast(task.type())); + if (this->task_list_[i] == nullptr) { + task_list_[i] = TaskInfoFactory::Instance().Create(static_cast(task.type())); + } GE_CHECK_NOTNULL(task_list_[i]); Status ret = task_list_[i]->Init(task, this); if (ret != SUCCESS) { @@ -2554,13 +2698,14 @@ Status DavinciModel::InitTaskInfo(domi::ModelTaskDef &model_task_def) { Status DavinciModel::MallocKnownArgs() { GELOGI("DavinciModel::MallocKnownArgs in"); - if (model_task_def_->task_size() == 0) { + const auto &model_task_def = ge_model_->GetModelTaskDefPtr(); + if (model_task_def->task_size() == 0) { GELOGW("DavinciModel::MallocKnownArgs davincimodel has no task info."); return SUCCESS; } - task_list_.resize(model_task_def_->task_size()); - for (int32_t i = 0; i < model_task_def_->task_size(); ++i) { - const domi::TaskDef &taskdef = model_task_def_->task(i); + task_list_.resize(model_task_def->task_size()); + for (int32_t i = 0; i < model_task_def->task_size(); ++i) { + const domi::TaskDef &taskdef = model_task_def->task(i); task_list_[i] = TaskInfoFactory::Instance().Create(static_cast(taskdef.type())); GE_CHECK_NOTNULL(task_list_[i]); Status ret = task_list_[i]->CalculateArgs(taskdef, this); @@ -2573,15 +2718,21 @@ Status DavinciModel::MallocKnownArgs() { rtError_t rt_ret = rtMalloc(&args_, total_args_size_, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtMalloc failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } - // malloc args host memory - rt_ret = rtMallocHost(&args_host_, total_args_size_); - if (rt_ret != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rtMallocHost failed, ret: 0x%X", rt_ret); - return RT_FAILED; + + // malloc fixed addr memory, eg: rts op + if (total_fixed_addr_size_ != 0) { + GELOGI("Begin to allocate fixed addr."); + rt_ret = rtMalloc(&fixed_addrs_, total_fixed_addr_size_, RT_MEMORY_HBM); + if (rt_ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Call rtMalloc failed, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); + } } - GELOGI("DavinciModel::MallocKnownArgs success, total args size %u.", total_args_size_); + + GELOGI("DavinciModel::MallocKnownArgs success, total args size %u. total fixed addr size %ld", total_args_size_, + total_fixed_addr_size_); return SUCCESS; } @@ -2597,26 +2748,28 @@ Status DavinciModel::DistributeTask() { task_desc_info_.clear(); bool flag = GetL1FusionEnableOption(); - char *skt_enable_env = getenv("SKT_ENABLE"); - int64_t env_flag = (skt_enable_env != nullptr) ? strtol(skt_enable_env, nullptr, 10) : 0; + char *skt_enable_env = std::getenv("SKT_ENABLE"); + int64_t env_flag = (skt_enable_env != nullptr) ? std::strtol(skt_enable_env, nullptr, kDecimal) : 0; if (env_flag != 0) { flag = true; } + const auto &model_task_def = ge_model_->GetModelTaskDefPtr(); for (size_t task_index = 0; task_index < task_list_.size(); ++task_index) { auto &task = task_list_.at(task_index); GE_CHK_STATUS_RET(task->Distribute(), "Task[%zu] distribute fail", task_index); // for data dump if (reinterpret_cast(task->GetDumpArgs()) != nullptr) { - auto op_index = std::max(model_task_def_->task(task_index).kernel().context().op_index(), - model_task_def_->task(task_index).kernel_ex().op_index()); + auto op_index = std::max(model_task_def->task(task_index).kernel().context().op_index(), + model_task_def->task(task_index).kernel_ex().op_index()); OpDescPtr op = GetOpByIndex(op_index); if (op == nullptr) { GELOGE(PARAM_INVALID, "Op index %u is null, op list size %zu.", op_index, op_list_.size()); return PARAM_INVALID; } - if (PropertiesManager::Instance().IsLayerNeedDump(name_, om_name_, op->GetName())) { + bool call_dump = GetDumpProperties().IsLayerNeedDump(name_, om_name_, op->GetName()) && task->CallSaveDumpInfo(); + if (call_dump) { SaveDumpTask(task->GetTaskID(), task->GetStreamId(), op, task->GetDumpArgs()); } } @@ -2631,8 +2784,13 @@ Status DavinciModel::DistributeTask() { // else task index is found in op_name_map_ TaskDescInfo task_desc_info; string op_name = op_name_map_[task_index]; + if (!om_name_.empty()) { + task_desc_info.model_name = om_name_; + } else { + task_desc_info.model_name = name_; + } task_desc_info.op_name = op_name; - task_desc_info.block_dim = model_task_def_->task(task_index).kernel().block_dim(); + task_desc_info.block_dim = model_task_def->task(task_index).kernel().block_dim(); task_desc_info.task_id = task->GetTaskID(); task_desc_info.stream_id = task->GetStreamId(); task_desc_info_.emplace_back(task_desc_info); @@ -2653,7 +2811,7 @@ Status DavinciModel::DistributeTask() { } void DavinciModel::SetEndGraphId(uint32_t task_id, uint32_t stream_id) { - auto all_dump_model = PropertiesManager::Instance().GetAllDumpModel(); + auto all_dump_model = GetDumpProperties().GetAllDumpModel(); bool findByOmName = all_dump_model.find(om_name_) != all_dump_model.end(); bool findByModelName = all_dump_model.find(name_) != all_dump_model.end(); if (all_dump_model.find(ge::DUMP_ALL_MODEL) != all_dump_model.end() || findByOmName || findByModelName) { @@ -2664,35 +2822,23 @@ void DavinciModel::SetEndGraphId(uint32_t task_id, uint32_t stream_id) { /// /// @ingroup ge -/// @brief Save Data address info for ZeroCopy. -/// @param [in] const std::vector &outside_addrs +/// @brief Set copy only for No task feed NetOutput address. /// @return None. /// -void DavinciModel::SetInputOutsideAddr(const std::vector &outside_addrs) { - for (auto addr : outside_addrs) { - if (input_outside_addrs_.find(addr) != input_outside_addrs_.end()) { - continue; - } - - (void)input_outside_addrs_.emplace(std::pair>(addr, {})); - GELOGI("SetInputOutsideAddr success."); - } -} - -/// -/// @ingroup ge -/// @brief Save NetOutput address info for ZeroCopy. -/// @param [in] const std::vector &outside_addrs -/// @return None. -/// -void DavinciModel::SetOutputOutsideAddr(const std::vector &outside_addrs) { - for (auto addr : outside_addrs) { - if (output_outside_addrs_.find(addr) != output_outside_addrs_.end()) { - continue; +void DavinciModel::SetCopyOnlyOutput() { + for (const auto &output_outside_addrs : new_output_outside_addrs_) { + ZeroCopyOffset output_outside = output_outside_addrs.second; + for (uint32_t out_count = 0; out_count < output_outside.GetAddrCount(); ++out_count) { + auto &addrs_mapping_list = output_outside.GetOutsideAddrs(); + std::map> virtual_args_addrs = addrs_mapping_list[out_count]; + for (const auto &virtual_args_addr : virtual_args_addrs) { + const auto &args_addrs = virtual_args_addr.second; + if (args_addrs.empty()) { // No task feed Output addr, Need copy directly. + GELOGI("[ZCPY] just copy %p to netoutput.", virtual_args_addr.first); + copy_only_addrs_.insert(virtual_args_addr.first); + } + } } - DisableZeroCopy(addr); // Data to NetOutput directly. - (void)output_outside_addrs_.emplace(std::pair>(addr, {})); - GELOGI("SetOutputOutsideAddr success."); } } @@ -2703,13 +2849,13 @@ void DavinciModel::SetOutputOutsideAddr(const std::vector &outside_addrs /// @return None. /// void DavinciModel::DisableZeroCopy(const void *addr) { - auto it = input_outside_addrs_.find(addr); - if (it == input_outside_addrs_.end()) { + if (find(real_virtual_addrs_.begin(), real_virtual_addrs_.end(), addr) == real_virtual_addrs_.end()) { return; } // Data link to RTS Op directly. std::lock_guard lock(outside_addrs_mutex_); + GELOGI("[ZCPY] disable zero copy of %p.", addr); copy_only_addrs_.insert(addr); } @@ -2718,35 +2864,37 @@ void DavinciModel::DisableZeroCopy(const void *addr) { /// @brief Save outside address used info for ZeroCopy. /// @param [in] const OpDescPtr &op_desc: current op desc /// @param [in] const std::vector &outside_addrs: address of task -/// @param [in] const char *args_offset: arguments address save the address. +/// @param [in] const void *info: task args +/// @param [in] const char *args: task args +/// @param [in] size_t size: size of task args +/// @param [in] size_t offset: offset of task args /// @return None. /// void DavinciModel::SetZeroCopyAddr(const OpDescPtr &op_desc, const std::vector &outside_addrs, const void *info, void *args, size_t size, size_t offset) { // Internal call has ensured that op_desc is not nullptr + GELOGI("[ZCPY] SetZeroCopyAddr for %s.", op_desc->GetName().c_str()); size_t nums = outside_addrs.size(); ZeroCopyTask zero_copy_task(op_desc->GetName(), static_cast(args), size); for (size_t i = 0; i < nums; ++i) { std::lock_guard lock(outside_addrs_mutex_); - const uintptr_t addr_val = reinterpret_cast(outside_addrs[i]); - void *args_val = static_cast(args) + offset + i * kAddrLen; - auto it = input_outside_addrs_.find(outside_addrs[i]); - if (it != input_outside_addrs_.end()) { - GE_CHK_STATUS(zero_copy_task.SetTaskArgsOffset(addr_val, offset + i * kAddrLen), "Input args invalid."); - it->second.push_back(args_val); - SetBatchLabelAddr(op_desc, reinterpret_cast(args_val)); - GELOGI("[ZCPY] %s set copy input: %zu, addr: 0x%lx, args: %p, size: %zu, offset: %zu.", - op_desc->GetName().c_str(), i, addr_val, args, size, offset + i * kAddrLen); - continue; + + for (auto &input_outside_addrs : new_input_outside_addrs_) { + ZeroCopyOffset &input_outside = input_outside_addrs.second; + bool ret = input_outside.SetOutsideAddrsValue(zero_copy_task, outside_addrs[i], args, offset + i * kAddrLen); + if (ret) { + void *args_val = static_cast(args) + offset + i * kAddrLen; + SetBatchLabelAddr(op_desc, reinterpret_cast(args_val)); + } } - it = output_outside_addrs_.find(outside_addrs[i]); - if (it != output_outside_addrs_.end()) { - GE_CHK_STATUS(zero_copy_task.SetTaskArgsOffset(addr_val, offset + i * kAddrLen), "Output args invalid."); - it->second.push_back(args_val); - SetBatchLabelAddr(op_desc, reinterpret_cast(args_val)); - GELOGI("[ZCPY] %s set copy output: %zu, args: %p, addr: 0x%lx.", op_desc->GetName().c_str(), i, args, addr_val); - continue; + for (auto &output_outside_addrs : new_output_outside_addrs_) { + ZeroCopyOffset &output_outside = output_outside_addrs.second; + bool ret = output_outside.SetOutsideAddrsValue(zero_copy_task, outside_addrs[i], args, offset + i * kAddrLen); + if (ret) { + void *args_val = static_cast(args) + offset + i * kAddrLen; + SetBatchLabelAddr(op_desc, reinterpret_cast(args_val)); + } } } @@ -2794,7 +2942,7 @@ bool DavinciModel::CheckInputAndModelSize(const int64_t &input_size, const int64 if (input_size > op_size) { GELOGW( - "Input size [%u] is bigger than om size need [%u]," + "Input size [%u] is bigger than om size need [%u], " "MAY cause inference result ERROR, please check model input", input_size, op_size); } @@ -2834,12 +2982,13 @@ bool DavinciModel::CheckInputAndModelSize(const int64_t &input_size, const int64 /// @return SUCCESS handle successfully / PARAM_INVALID for failed /// Status DavinciModel::CopyModelData(const InputData &input_data, OutputData &output_data, bool is_dynamic) { - if (UpdateIoTaskArgs(input_data_info_, true, input_data.blobs, is_dynamic, input_data.batch_label) != SUCCESS) { + if (UpdateIoTaskArgs(new_input_data_info_, true, input_data.blobs, is_dynamic, input_data.batch_label) != SUCCESS) { GELOGE(PARAM_INVALID, "[ZCPY] Update input data to model failed."); return PARAM_INVALID; } - if (UpdateIoTaskArgs(output_data_info_, false, output_data.blobs, is_dynamic, input_data.batch_label) != SUCCESS) { + if (UpdateIoTaskArgs(new_output_data_info_, false, output_data.blobs, is_dynamic, input_data.batch_label) != + SUCCESS) { GELOGE(PARAM_INVALID, "[ZCPY] Update output data to model failed."); return PARAM_INVALID; } @@ -2863,7 +3012,7 @@ Status DavinciModel::CopyModelData(const InputData &input_data, OutputData &outp /// @param [in] batch_label: batch label for multi-batch scenes /// @return SUCCESS handle successfully / others handle failed /// -Status DavinciModel::UpdateIoTaskArgs(const map> &data_info, bool is_input, +Status DavinciModel::UpdateIoTaskArgs(const std::map &data_info, bool is_input, const vector &blobs, bool is_dynamic, const string &batch_label) { string input_or_output = "input"; is_input ? input_or_output = "input" : input_or_output = "output"; @@ -2879,8 +3028,6 @@ Status DavinciModel::UpdateIoTaskArgs(const map> input_or_output.c_str(), data.first, blobs.size()); return FAILED; } - int64_t size = data.second.first; // size of tensor. - void *addr = data.second.second; // addr of tensor. const DataBuffer &buffer = blobs[data.first]; // index of data. if (buffer.data == nullptr) { @@ -2888,30 +3035,38 @@ Status DavinciModel::UpdateIoTaskArgs(const map> return FAILED; } - GELOGI("[ZCPY] Copy Blobs: %u, addr: %p, size: %ld, data: %p, length: %u.", data.first, data.second.second, - data.second.first, buffer.data, buffer.length); - if (!CheckInputAndModelSize(buffer.length, size, is_dynamic)) { + if (!CheckInputAndModelSize(buffer.length, data.second.GetDataSize(), is_dynamic)) { GELOGE(FAILED, "Check input size and model size failed"); return FAILED; } - // For input data, just copy for rts task. - if (copy_only_addrs_.count(addr) > 0) { + void *basic_addr = data.second.GetBasicAddr(); + uint64_t data_size = data.second.GetDataSize(); + if (copy_only_addrs_.count(basic_addr) > 0) { if (is_input) { - GELOGI("[IMAS] Find addr %p need direct copy from user malloc input %p.", addr, buffer.data); - if (rtMemcpy(addr, size, buffer.data, buffer.length, RT_MEMCPY_DEVICE_TO_DEVICE) != RT_ERROR_NONE) { + GELOGI("[IMAS] Find addr %p need direct copy from user malloc input %p", basic_addr, buffer.data); + if (rtMemcpy(basic_addr, data_size, buffer.data, buffer.length, RT_MEMCPY_DEVICE_TO_DEVICE) != RT_ERROR_NONE) { GELOGE(FAILED, "Non-zero copy data node copy failed"); return FAILED; } } - GELOGI("No need to exeucte zero copy task because this addr %p need direct copy.", addr); + GELOGI("No need to exeucte zero copy task because this addr %p need direct copy.", basic_addr); continue; } - for (ZeroCopyTask &task : zero_copy_tasks_) { - uintptr_t addr_val = reinterpret_cast(addr); - if (task.UpdateTaskParam(addr_val, buffer, zero_copy_batch_label_addrs_, batch_label) != SUCCESS) { - return FAILED; + for (size_t count = 0; count < data.second.GetDataCount(); ++count) { + int64_t size = data.second.GetDataInfo().at(count).first; + void *addr = data.second.GetDataInfo().at(count).second; + void *buffer_addr = + reinterpret_cast(reinterpret_cast(buffer.data) + data.second.GetRelativeOffset().at(count)); + GELOGI("[ZCPY] Copy blobs_index %u, virtual_addr: %p, size: %ld, user_data_addr: %p", data.first, addr, size, + buffer_addr); + // For input data, just copy for rts task. + for (ZeroCopyTask &task : zero_copy_tasks_) { + uintptr_t addr_val = reinterpret_cast(addr); + if (task.UpdateTaskParam(addr_val, buffer_addr, zero_copy_batch_label_addrs_, batch_label) != SUCCESS) { + return FAILED; + } } } } @@ -3160,6 +3315,32 @@ Status DavinciModel::InitStreamSwitchN(const OpDescPtr &op_desc) { GELOGI("StreamSwitchNOp node:%s, active_stream_id=%u.", op_desc->GetName().c_str(), active_stream_list[j]); } + (void)AttrUtils::GetInt(op_desc, ATTR_DYNAMIC_TYPE, dynamic_type_); + + batch_info_.clear(); + combined_batch_info_.clear(); + uint32_t batch_num = 0; + if (!AttrUtils::GetInt(op_desc, ATTR_NAME_BATCH_NUM, batch_num)) { + GELOGE(FAILED, "Failed to get attr ATTR_NAME_BATCH_NUM, StreamSwitchN: %s.", op_desc->GetName().c_str()); + return FAILED; + } + + for (uint32_t i = 0; i < batch_num; i++) { + std::vector batch_shape; + const std::string attr_name = ATTR_NAME_PRED_VALUE + "_" + std::to_string(i); + if (!AttrUtils::GetListInt(op_desc, attr_name, batch_shape)) { + GELOGE(FAILED, "Failed to get attr ATTR_NAME_PRED_VALUE, StreamSwitchN: %s.", op_desc->GetName().c_str()); + batch_info_.clear(); + return FAILED; + } + batch_info_.emplace_back(batch_shape); + batch_shape.clear(); + const string attr_combined_batch = ATTR_NAME_COMBINED_BATCH + "_" + std::to_string(i); + if (AttrUtils::GetListInt(op_desc, attr_combined_batch, batch_shape)) { + combined_batch_info_.emplace_back(batch_shape); + } + } + return SUCCESS; } @@ -3178,20 +3359,6 @@ bool DavinciModel::IsBroadCastOpData(const ge::NodePtr &var_node) { return false; } -void DavinciModel::InitZeroCopyUtil(bool is_dynamic_batch, bool &input_zero_copy, bool &output_zero_copy) { - if (!is_dynamic_batch) { - zero_copy_batch_label_addrs_.clear(); - } - - for (const auto &addrs : output_outside_addrs_) { - const auto &used_list = addrs.second; - if (used_list.empty()) { - output_zero_copy = false; - break; - } - } -} - /// /// @ingroup ge /// @brief Init model stream for NN model. @@ -3239,14 +3406,14 @@ Status DavinciModel::NnExecute(rtStream_t stream, bool async_mode, const InputDa GELOGI("Model Run begin, model id:%u, data index:%u, flag:%d.", model_id_, input_data.index, is_async_mode_); GE_CHK_STATUS_RET(InitModelStream(stream), "Init model stream failed."); - bool input_use_zero_copy = true; - bool output_use_zero_copy = true; - bool is_dynamic_batch = input_data.is_dynamic_batch; - InitZeroCopyUtil(is_dynamic_batch, input_use_zero_copy, output_use_zero_copy); + if (!input_data.is_dynamic_batch) { + zero_copy_batch_label_addrs_.clear(); + } GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_PRE_PROC_START)); - Status ret = CopyModelData(input_data, output_data, is_dynamic_batch); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return INTERNAL_ERROR, "Copy input data to model failed."); + Status ret = CopyModelData(input_data, output_data, input_data.is_dynamic_batch); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Copy input data to model failed. model id: %u", + model_id_); GELOGI("current_data.index=%u", input_data.index); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_PRE_PROC_END)); @@ -3255,15 +3422,15 @@ Status DavinciModel::NnExecute(rtStream_t stream, bool async_mode, const InputDa GELOGD("rtModelExecute do"); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_INFER_START)); rtError_t rt_ret = rtModelExecute(rt_model_handle_, rt_model_stream_, 0); - GE_CHK_RT_EXEC(rt_ret, return INTERNAL_ERROR); + GE_CHK_RT_EXEC(rt_ret, return RT_ERROR_TO_GE_STATUS(rt_ret)); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_INFER_END)); GELOGI("rtModelExecute end"); } if (!is_async_mode_) { GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_AFTER_PROC_START)); - ret = CopyOutputData(input_data.index, output_data); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return INTERNAL_ERROR, "Copy Output data to user failed."); + ret = CopyOutputData(input_data.index, output_data, RT_MEMCPY_DEVICE_TO_DEVICE); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Copy Output data to user failed."); GE_IF_BOOL_EXEC(ProfilingManager::Instance().ProfilingOn(), SetProfileTime(MODEL_AFTER_PROC_END)); } @@ -3273,11 +3440,61 @@ Status DavinciModel::NnExecute(rtStream_t stream, bool async_mode, const InputDa return SUCCESS; } +// Add active entry stream for special env. +Status DavinciModel::AddHeadStream() { + if (active_stream_list_.empty()) { + GELOGE(INTERNAL_ERROR, "Active stream is empty, stream list size: %zu, stream indication size: %zu.", + stream_list_.size(), active_stream_indication_.size()); + return INTERNAL_ERROR; + } + + if (active_stream_list_.size() == 1) { + GELOGI("Just one active stream, take as head stream."); + rt_head_stream_ = active_stream_list_[0]; + is_pure_head_stream_ = false; + } else { + // Create stream which rt_model_handel running on, this is S0, TS stream. + GELOGI("Multiple active stream: %zu, create head stream.", active_stream_list_.size()); + GE_CHK_RT_RET(rtStreamCreateWithFlags(&rt_head_stream_, priority_, RT_STREAM_PERSISTENT)); + GE_CHK_RT_RET(rtModelBindStream(rt_model_handle_, rt_head_stream_, RT_INVALID_FLAG)); // Not active. + is_pure_head_stream_ = true; + + for (auto s : active_stream_list_) { + std::shared_ptr active_entry = MakeShared(rt_head_stream_); + if (active_entry == nullptr) { + GELOGE(MEMALLOC_FAILED, "Make CpuTaskActiveEntry task failed."); + return MEMALLOC_FAILED; + } + + Status status = active_entry->Init(s); + if (status != SUCCESS) { + return status; + } + + cpu_task_list_.emplace_back(active_entry); + } + } + + // Create entry stream active head stream. AICPU stream. + GE_CHK_RT_RET(rtStreamCreateWithFlags(&rt_entry_stream_, priority_, RT_STREAM_AICPU)); + GE_CHK_RT_RET(rtModelBindStream(rt_model_handle_, rt_entry_stream_, RT_HEAD_STREAM)); + return SUCCESS; +} + +Status DavinciModel::InitEntryTask() { + if (deploy_type_ == AICPU_DEPLOY_CROSS_THREAD) { + GE_CHK_STATUS_RET(AddHeadStream(), "Add head stream failed."); + return CpuActiveStream(); + } else { + return LoadWithQueue(); + } +} + uint8_t *DavinciModel::MallocFeatureMapMem(size_t data_size) { uint8_t *mem_base = nullptr; const string purpose("feature map,used for op input and output."); if (std::getenv(kEnvGeuseStaticMemory) != nullptr) { - data_size = static_cast(VarManager::Instance(0)->GetGraphMemoryMaxSize()); + data_size = static_cast(VarManager::Instance(session_id_)->GetGraphMemoryMaxSize()); string memory_key = std::to_string(0) + "_f"; mem_base = MemManager::Instance(RT_MEMORY_HBM)->MallocMemory(purpose, memory_key, data_size, GetDeviceId()); } else { @@ -3341,7 +3558,7 @@ Status DavinciModel::TransAllVarData(ComputeGraphPtr &graph, uint32_t graph_id) rtError_t rt_ret = rtCtxGetCurrent(&ctx); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Failed to get current context, error_code is: 0x%X.", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } std::vector variable_node_list; @@ -3362,12 +3579,14 @@ Status DavinciModel::TransAllVarData(ComputeGraphPtr &graph, uint32_t graph_id) return SUCCESS; } -void DavinciModel::SetDataDumperArgs() { +void DavinciModel::SetDataDumperArgs(const ComputeGraphPtr &compute_graph) { GELOGI("set data dumper args, name: %s, id: %u.", name_.c_str(), model_id_); data_dumper_.SetModelName(name_); data_dumper_.SetModelId(model_id_); data_dumper_.SetMemory(runtime_param_); data_dumper_.SetOmName(om_name_); + data_dumper_.SetComputeGraph(compute_graph); + data_dumper_.SetRefInfo(saved_task_addrs_); int32_t device_id = 0; rtError_t rt_ret = rtGetDevice(&device_id); @@ -3423,18 +3642,9 @@ void DavinciModel::ReuseHcclFollowStream(int64_t remain_cap, int64_t &index) { } } -Status DavinciModel::CopyVarData(ComputeGraphPtr &compute_graph) { - return TransVarDataUtils::CopyVarData(compute_graph, session_id_, device_id_); -} - -Status DavinciModel::GetComputeGraphInfo(std::vector &compute_graph_desc_info) { +Status DavinciModel::GetComputeGraphInfo(const ComputeGraphPtr &graph, vector &graph_desc_info) { GELOGI("GetComputeGraphInfo start."); - if (compute_graph_ == nullptr) { - GELOGE(FAILED, "compute_graph_ is nullptr"); - return FAILED; - } - - for (auto &node : compute_graph_->GetAllNodes()) { + for (auto &node : graph->GetAllNodes()) { ComputeGraphDescInfo compute_graph_info; auto op_desc = node->GetOpDesc(); if (op_desc == nullptr) { @@ -3445,6 +3655,11 @@ Status DavinciModel::GetComputeGraphInfo(std::vector &comp auto op_mode = static_cast(domi::ImplyType::INVALID); if (AttrUtils::GetInt(op_desc, ATTR_NAME_IMPLY_TYPE, op_mode) && op_mode == static_cast(domi::ImplyType::TVM)) { + if (!om_name_.empty()) { + compute_graph_info.model_name = om_name_; + } else { + compute_graph_info.model_name = name_; + } compute_graph_info.op_name = op_desc->GetName(); compute_graph_info.op_type = op_desc->GetType(); @@ -3462,12 +3677,18 @@ Status DavinciModel::GetComputeGraphInfo(std::vector &comp compute_graph_info.output_data_type.emplace_back(output_desc.GetDataType()); } - compute_graph_desc_info.emplace_back(compute_graph_info); + graph_desc_info.emplace_back(compute_graph_info); } } GELOGI("GetComputeGraphInfo end."); return SUCCESS; } +void DavinciModel::SetTotalFixedAddrsSize(string tensor_name, int64_t fix_addr_size) { + if (tensor_name_to_fixed_addr_size_.find(tensor_name) == tensor_name_to_fixed_addr_size_.end()) { + tensor_name_to_fixed_addr_size_[tensor_name] = total_fixed_addr_size_; + total_fixed_addr_size_ += fix_addr_size; + } +} Status DavinciModel::GetOrigInputInfo(uint32_t index, OriginInputInfo &orig_input_info) { GE_CHK_BOOL_RET_STATUS(index < data_op_list_.size(), PARAM_INVALID, "Index %u is invalid.", index); @@ -3534,7 +3755,8 @@ Status DavinciModel::GetAllAippInputOutputDims(uint32_t index, std::vectorGetInputDescPtr(kDataIndex)), data_input_size); GELOGD( - "GetAllAippInputOutputDims related Data[%d]: tensor_name is %s, dim_num is %u, tensor_size: %zu, format: %s, " + "GetAllAippInputOutputDims related Data[%d]: tensor_name is %s, dim_num is %u, tensor_size: %zu, format: " + "%s, " "data_type: %s, shape: %s .", index, data_op->GetName().c_str(), data_input_desc->GetShape().GetDimNum(), data_input_size, TypeUtils::FormatToSerialString(data_input_desc->GetFormat()).c_str(), @@ -3556,4 +3778,23 @@ Status DavinciModel::GetAllAippInputOutputDims(uint32_t index, std::vectorHasAttr(ATTR_DYNAMIC_SHAPE_FIXED_ADDR) && op_desc->HasAttr(ATTR_DYNAMIC_SHAPE_FIXED_ADDR_INDEX)) { + string tensor_name; + (void)AttrUtils::GetStr(op_desc, ATTR_DYNAMIC_SHAPE_FIXED_ADDR, tensor_name); + int64_t index = -1; + (void)AttrUtils::GetInt(op_desc, ATTR_DYNAMIC_SHAPE_FIXED_ADDR_INDEX, index); + if (index >= 0) { + tensor_name_to_peer_output_index_[tensor_name] = index; + } + } +} } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/davinci_model.h b/src/ge/graph/load/new_model_manager/davinci_model.h index 8123b0b8..cb7e4528 100644 --- a/src/ge/graph/load/new_model_manager/davinci_model.h +++ b/src/ge/graph/load/new_model_manager/davinci_model.h @@ -28,13 +28,15 @@ #include "common/helper/model_helper.h" #include "common/helper/om_file_helper.h" #include "common/opskernel/ge_task_info.h" +#include "common/properties_manager.h" #include "common/types.h" #include "framework/common/util.h" #include "graph/debug/ge_attr_define.h" +#include "graph/load/new_model_manager/aipp_utils.h" #include "graph/load/new_model_manager/data_dumper.h" #include "graph/load/new_model_manager/data_inputer.h" #include "graph/load/new_model_manager/model_utils.h" -#include "graph/load/new_model_manager/aipp_utils.h" +#include "graph/load/new_model_manager/zero_copy_offset.h" #include "graph/load/new_model_manager/zero_copy_task.h" #include "graph/model.h" #include "graph/node.h" @@ -47,6 +49,10 @@ #include "task_info/task_info.h" namespace ge { +// op debug need 2048 bits buffer +const size_t kOpDebugMemorySize = 2048UL; +const size_t kDebugP2pSize = 8UL; + typedef enum tagModelProcStage { MODEL_LOAD_START = 1, MODEL_LOAD_END, @@ -171,13 +177,6 @@ class DavinciModel { // get session id uint64_t SessionId() const { return runtime_param_.session_id; } - vector GetOpDesc() { - vector opDescVector; - GE_IF_BOOL_EXEC(AttrUtils::GetListOpDesc(GetGeModel(), MODEL_ATTR_FUSION_MODEL_DEF, opDescVector), - GELOGI("get opDesc of opDescVector")); - return opDescVector; - } - // get model priority int32_t Priority() const { return priority_; } @@ -248,15 +247,9 @@ class DavinciModel { /// Format GetFormat(); - rtModel_t GetRtModelHandle() { - rtModel_t res = rt_model_handle_; - return res; - } + rtModel_t GetRtModelHandle() const { return rt_model_handle_; } - rtStream_t GetRtModelStream() { - rtModel_t res = rt_model_stream_; - return res; - } + rtStream_t GetRtModelStream() const { return rt_model_stream_; } uint64_t GetRtBaseAddr() const { return runtime_param_.logic_mem_base; } @@ -293,11 +286,20 @@ class DavinciModel { /// @ingroup ge /// @brief Get dynamic batch_info /// @param [out] batch_info + /// @param [out] dynamic_type /// @return execute result /// - Status GetDynamicBatchInfo(std::vector> &batch_info); + Status GetDynamicBatchInfo(std::vector> &batch_info, int32_t &dynamic_type) const; + + /// + /// @ingroup ge + /// @brief Get combined dynamic dims info + /// @param [out] batch_info + /// @return None + /// + void GetCombinedDynamicDims(std::vector> &batch_info) const; - void GetCurShape(std::vector &batch_info); + void GetCurShape(std::vector &batch_info, int32_t &dynamic_type); void GetModelAttr(std::vector &dynamic_output_shape_info); @@ -344,10 +346,9 @@ class DavinciModel { /// /// @ingroup ge /// @brief dump all op input and output information - /// @param [in] op_list model_id - /// @return Status + /// @return void /// - Status DumpOpInputOutput(); + void DumpOpInputOutput(); /// /// @ingroup ge @@ -403,7 +404,9 @@ class DavinciModel { /// uint32_t GetDeviceId() const { return device_id_; } - GeModelPtr GetGeModel() { return ge_model_; } + bool NeedDestroyAicpuKernel() const { return need_destroy_aicpu_kernel_; } + + Status UpdateSessionId(uint64_t session_id); const RuntimeParam &GetRuntimeParam() { return runtime_param_; } @@ -423,7 +426,7 @@ class DavinciModel { void SetZeroCopyAddr(const OpDescPtr &op_desc, const std::vector &outside_addrs, const void *info, void *args, size_t size, size_t offset); - void SetDynamicSize(const std::vector &batch_num); + void SetDynamicSize(const std::vector &batch_num, int32_t dynamic_type); bool GetL1FusionEnableOption() { return is_l1_fusion_enable_; } @@ -463,12 +466,29 @@ class DavinciModel { void *cur_args = static_cast(args_) + offset; return cur_args; } + void SetTotalIOAddrs(vector &io_addrs) { + total_io_addrs_.insert(total_io_addrs_.end(), io_addrs.begin(), io_addrs.end()); + } + void SetTotalFixedAddrsSize(string tensor_name, int64_t fix_addr_size); + int64_t GetFixedAddrsSize(string tensor_name); + void *GetCurrentFixedAddr(int64_t offset) const { + void *cur_addr = static_cast(fixed_addrs_) + offset; + return cur_addr; + } + + uint32_t GetFixedAddrOutputIndex(string tensor_name) { + if (tensor_name_to_peer_output_index_.find(tensor_name) != tensor_name_to_peer_output_index_.end()) { + return tensor_name_to_peer_output_index_[tensor_name]; + } + return UINT32_MAX; + } void SetKnownNode(bool known_node) { known_node_ = known_node; } bool IsKnownNode() { return known_node_; } Status MallocKnownArgs(); Status UpdateKnownNodeArgs(const vector &inputs, const vector &outputs); Status CreateKnownZeroCopyMap(const vector &inputs, const vector &outputs); - Status UpdateKnownZeroCopyAddr(vector &io_addrs, uint32_t args_offset); + Status UpdateKnownZeroCopyAddr(); + void SetKnownNodeAddrNotChanged(bool base_addr_not_changed) { base_addr_not_changed_ = base_addr_not_changed; } Status GetOrigInputInfo(uint32_t index, OriginInputInfo &orig_input_info); Status GetAllAippInputOutputDims(uint32_t index, std::vector &input_dims, @@ -477,6 +497,9 @@ class DavinciModel { // om file name void SetOmName(string om_name) { om_name_ = om_name; } + void SetDumpProperties(const DumpProperties &dump_properties) { data_dumper_.SetDumpProperties(dump_properties); } + const DumpProperties &GetDumpProperties() const { return data_dumper_.GetDumpProperties(); } + private: // memory address of weights uint8_t *weights_mem_base_; @@ -493,8 +516,6 @@ class DavinciModel { struct timeInfo time_info_; int32_t dataInputTid; - void InitZeroCopyUtil(bool is_dynamic_batch, bool &input_zero_copy, bool &output_zero_copy); - /// /// @ingroup ge /// @brief Save Batch label Info. @@ -506,22 +527,6 @@ class DavinciModel { /// /// @ingroup ge - /// @brief Save Data address info for ZeroCopy. - /// @param [in] const std::vector &outside_addrs - /// @return None. - /// - void SetInputOutsideAddr(const std::vector &outside_addrs); - - /// - /// @ingroup ge - /// @brief Save NetOutput address info for ZeroCopy. - /// @param [in] const std::vector &outside_addrs - /// @return None. - /// - void SetOutputOutsideAddr(const std::vector &outside_addrs); - - /// - /// @ingroup ge /// @brief Copy Check input size and model op size. /// @param [in] const int64_t &input_size: input size. /// @param [in] const int64_t &op_size: model op size. @@ -532,6 +537,13 @@ class DavinciModel { /// /// @ingroup ge + /// @brief Set copy only for No task feed NetOutput address. + /// @return None. + /// + void SetCopyOnlyOutput(); + + /// + /// @ingroup ge /// @brief Copy Input/Output to model for direct use. /// @param [in] const InputData &input_data: user input data info. /// @param [in/out] OutputData &output_data: user output data info. @@ -550,19 +562,15 @@ class DavinciModel { /// @param [in] batch_label: batch label for multi-batch scenes /// @return SUCCESS handle successfully / others handle failed /// - Status UpdateIoTaskArgs(const map> &data_info, bool is_input, + Status UpdateIoTaskArgs(const std::map &data_info, bool is_input, const vector &blobs, bool is_dynamic, const string &batch_label); Status CopyInputData(const InputData &input_data, bool device_data = false); - Status CopyOutputData(uint32_t data_id, OutputData &output_data); - - Status CopyOutputDataToUser(OpDescPtr &op_desc, std::vector &blobs, uint32_t &data_index); + Status CopyOutputData(uint32_t data_id, OutputData &output_data, rtMemcpyKind_t kind); Status SyncVarData(); - Status SyncDataAndDump(); - Status InitModelMem(void *dev_ptr, size_t memsize, void *weight_ptr, size_t weightsize); void CreateInputDimsInfo(const OpDescPtr &op_desc, Format format, InputOutputDescInfo &input); @@ -589,7 +597,12 @@ class DavinciModel { bool IsAicpuKernelConnectSpecifiedLayer(); - Status MarkSpecifiedAicpuKernel(); + /// + /// @ingroup ge + /// @brief Reduce memory usage after task sink. + /// @return: void + /// + void Shrink(); /// /// @ingroup ge @@ -691,8 +704,7 @@ class DavinciModel { /// Status BindInputQueue(); - Status CpuTaskModelZeroCopy(std::vector &mbuf_list, - std::map> &outside_addrs); + Status CpuTaskModelZeroCopy(std::vector &mbuf_list, std::map &outside_addrs); /// /// @ingroup ge @@ -725,10 +737,9 @@ class DavinciModel { /// /// @ingroup ge /// @brief definiteness queue schedule, active original model stream. - /// @param [in] streams: streams will active by S0. /// @return: 0 for success / others for fail /// - Status CpuActiveStream(const std::vector &stream_list); + Status CpuActiveStream(); /// /// @ingroup ge @@ -746,6 +757,9 @@ class DavinciModel { /// Status CpuModelRepeat(); + Status InitEntryTask(); + Status AddHeadStream(); + /// /// @ingroup ge /// @brief set ts device. @@ -753,6 +767,10 @@ class DavinciModel { /// Status SetTSDevice(); + Status OpDebugRegister(); + + void OpDebugUnRegister(); + void CheckHasHcomOp(); Status DoTaskSink(); @@ -760,17 +778,17 @@ class DavinciModel { void CreateOutput(uint32_t index, OpDescPtr &op_desc, InputOutputDescInfo &output, uint32_t &format_result); Status TransAllVarData(ComputeGraphPtr &graph, uint32_t graph_id); - Status CopyVarData(ComputeGraphPtr &graph); // get desc info of graph for profiling - Status GetComputeGraphInfo(vector &compute_graph_desc_info); + Status GetComputeGraphInfo(const ComputeGraphPtr &graph, vector &graph_desc_info); - void SetDataDumperArgs(); + void SetDataDumperArgs(const ComputeGraphPtr &compute_graph); Status GenOutputTensorInfo(const OpDescPtr &op_desc, uint32_t data_index, OutputData *output_data, std::vector &outputs); void ParseAIPPInfo(std::string in_out_info, InputOutputDims &dims_info); + void GetFixedAddrAttr(const OpDescPtr &op_desc); bool is_model_has_inited_; uint32_t model_id_; @@ -783,6 +801,9 @@ class DavinciModel { uint32_t version_; GeModelPtr ge_model_; + bool need_destroy_aicpu_kernel_{false}; + vector out_node_name_; + map op_list_; // data op_desc @@ -792,8 +813,12 @@ class DavinciModel { vector variable_op_list_; - std::map> input_data_info_; // Virtual address from Data output. - std::map> output_data_info_; // Virtual address from NetOutput input. + std::map new_input_data_info_; + std::map new_output_data_info_; + std::map new_input_outside_addrs_; + std::map new_output_outside_addrs_; + + std::vector real_virtual_addrs_; // output op: save cce op actual needed memory size vector output_memory_size_list_; @@ -825,9 +850,7 @@ class DavinciModel { std::mutex outside_addrs_mutex_; std::vector zero_copy_tasks_; // Task used Data or NetOutput addr. std::set copy_only_addrs_; // Address need copy to original place. - // {node_addr, {addr_in_task_args}} - std::map> input_outside_addrs_; // Key is virtual address from Data. - std::map> output_outside_addrs_; // Key is virtual address from NetOutput. + // {op_id, batch_label} std::map zero_copy_op_id_batch_label_; // {batch_label, addrs} @@ -843,6 +866,11 @@ class DavinciModel { bool is_async_mode_; // For NN execute, Async mode use rtMemcpyAsync on rt_model_stream_. + bool is_pure_head_stream_{false}; + rtStream_t rt_head_stream_{nullptr}; + rtStream_t rt_entry_stream_{nullptr}; + rtAicpuDeployType_t deploy_type_{AICPU_DEPLOY_RESERVED}; + // ACL queue schedule, save queue ids for Init. std::vector cpu_task_list_; std::vector input_queue_ids_; // input queue ids created by caller. @@ -850,10 +878,6 @@ class DavinciModel { std::vector input_mbuf_list_; // input mbuf created by dequeue task. std::vector output_mbuf_list_; // output mbuf created by dequeue task. - // save input/output tensor descriptor in maps - std::map data_op_input_tensor_desc_map_; - std::map data_op_output_tensor_desc_map_; - uint64_t session_id_; uint32_t device_id_; @@ -864,8 +888,6 @@ class DavinciModel { std::vector active_stream_list_; std::set active_stream_indication_; - std::shared_ptr model_task_def_; - std::set aicpu_streams_; std::set hcom_streams_; RuntimeParam runtime_param_; @@ -877,22 +899,44 @@ class DavinciModel { // for profiling task and graph info std::map op_name_map_; std::vector task_desc_info_; - ComputeGraphPtr compute_graph_; int64_t maxDumpOpNum_; // for data dump DataDumper data_dumper_; uint64_t iterator_count_; bool is_l1_fusion_enable_; + std::map saved_task_addrs_; bool known_node_ = false; uint32_t total_args_size_ = 0; void *args_ = nullptr; void *args_host_ = nullptr; + void *fixed_addrs_ = nullptr; + int64_t total_fixed_addr_size_ = 0; std::map knonw_input_data_info_; std::map knonw_output_data_info_; + vector total_io_addrs_; + vector orig_total_io_addrs_; + bool base_addr_not_changed_ = false; + + vector> batch_info_; + std::vector> combined_batch_info_; + int32_t dynamic_type_ = 0; vector batch_size_; + // key: input tensor name, generally rts op; + // value: the fixed addr of input anchor, same as the peer output anchor addr of the peer op + std::map tensor_name_to_fixed_addr_size_; + + // key: input tensor name, generally rts op; value: the peer output anchor of the peer op + std::map tensor_name_to_peer_output_index_; + // if model is first execute + bool is_first_execute_; + // for op debug + std::mutex debug_reg_mutex_; + bool is_op_debug_reg_ = false; + void *op_debug_addr_ = nullptr; + void *p2p_debug_addr_ = nullptr; bool is_new_model_desc_{false}; }; } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/model_manager.cc b/src/ge/graph/load/new_model_manager/model_manager.cc index d98ad8de..51b5b028 100644 --- a/src/ge/graph/load/new_model_manager/model_manager.cc +++ b/src/ge/graph/load/new_model_manager/model_manager.cc @@ -22,8 +22,9 @@ #include "common/profiling/profiling_manager.h" #include "common/properties_manager.h" #include "framework/common/debug/ge_log.h" -#include "graph/debug/ge_attr_define.h" #include "framework/common/util.h" +#include "graph/common/ge_call_wrapper.h" +#include "graph/debug/ge_attr_define.h" #include "graph/load/new_model_manager/davinci_model.h" #include "graph/load/new_model_manager/davinci_model_parser.h" #include "model/ge_root_model.h" @@ -33,9 +34,10 @@ thread_local uint32_t device_count = 0; namespace { const int kCmdParSize = 2; const int kDumpCmdPairSize = 2; -const char *const kNeedDestroySpecifiedAicpuKernel = "need_destroy_specified_aicpu_kernel"; } // namespace +DumpProperties ModelManager::dump_properties_; + std::shared_ptr ModelManager::GetInstance() { static const std::shared_ptr instance_ptr = shared_ptr(new (std::nothrow) ModelManager(), ModelManager::FinalizeForPtr); @@ -68,11 +70,11 @@ Status ModelManager::KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType op_type, u auto kernel_size = sizeof(uint64_t) * (v_aicpu_kernel.size()); rtError_t rt_ret = rtMalloc(&aicpu_kernel_addr, kernel_size, RT_MEMORY_HBM); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); - return RT_FAILED;) + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy(aicpu_kernel_addr, kernel_size, v_aicpu_kernel.data(), kernel_size, RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy to input_output_addr_ error: 0x%X", rt_ret); - GE_CHK_RT(rtFree(aicpu_kernel_addr)); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy to input_output_addr_ error: 0x%X", rt_ret); + GE_CHK_RT(rtFree(aicpu_kernel_addr)); return RT_ERROR_TO_GE_STATUS(rt_ret);) uint64_t kernel_id_addr = static_cast(reinterpret_cast(aicpu_kernel_addr)); param_base.fwkKernelBase.fwk_kernel.kernelID = kernel_id_addr; // In the scene of loading once and running many times, the kernel needs to be destroyed many times, @@ -82,64 +84,64 @@ Status ModelManager::KernelLaunchEx(aicpu::FWKAdapter::FWKOperateType op_type, u rtError_t rt_ret = rtMalloc(&(devicebase), sizeof(STR_FWK_OP_KERNEL), RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "malloc device memory failed."); + GELOGE(RT_FAILED, "malloc device memory failed. ret: 0x%X", rt_ret); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(devicebase, sizeof(STR_FWK_OP_KERNEL), ¶m_base, sizeof(STR_FWK_OP_KERNEL), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "memory copy to device failed."); + GELOGE(RT_FAILED, "memory copy to device failed. ret: 0x%X", rt_ret); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rtStream_t stream = nullptr; rt_ret = rtStreamCreate(&stream, 0); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "create stream failed."); + GELOGE(RT_FAILED, "create stream failed. ret: 0x%X", rt_ret); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtKernelLaunchEx(devicebase, sizeof(STR_FWK_OP_KERNEL), 0, stream); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "rtKernelLaunchEx failed."); + GELOGE(RT_FAILED, "rtKernelLaunchEx failed. ret: 0x%X", rt_ret); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtStreamSynchronize(stream); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "rtStreamSynchronize failed."); + GELOGE(RT_FAILED, "rtStreamSynchronize failed. ret: 0x%X", rt_ret); GE_IF_BOOL_EXEC(aicpu_kernel_addr != nullptr, GE_CHK_RT(rtFree(aicpu_kernel_addr))); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } if (aicpu_kernel_addr != nullptr) { rt_ret = rtFree(aicpu_kernel_addr); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "free memory failed."); + GELOGE(RT_FAILED, "free memory failed. ret: 0x%X", rt_ret); GE_CHK_RT(rtFree(devicebase)); GE_CHK_RT(rtStreamDestroy(stream)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } rt_ret = rtFree(devicebase); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "free memory failed."); + GELOGE(RT_FAILED, "free memory failed. ret: 0x%X", rt_ret); GE_CHK_RT(rtStreamDestroy(stream)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtStreamDestroy(stream); if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "rtStreamDestroy failed."); - return FAILED; + GELOGE(RT_FAILED, "rtStreamDestroy failed. ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; } @@ -166,8 +168,8 @@ ge::Status ModelManager::DestroyAicpuSessionForInfer(uint32_t model_id) { std::lock_guard lock(map_mutex_); auto it = model_map_.find(model_id); if (it == model_map_.end()) { - GELOGE(PARAM_INVALID, "model id %u does not exists.", model_id); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_ID_INVALID, "model id %u does not exists.", model_id); + return GE_EXEC_MODEL_ID_INVALID; } uint64_t session_id = it->second->GetSessionId(); GELOGI("Destroy aicpu session for infer, session id is %u.", session_id); @@ -221,10 +223,11 @@ Status ModelManager::SetDevice(int32_t deviceId) const { return SUCCESS; } -ge::Status ModelManager::SetDynamicSize(uint32_t model_id, const std::vector &batch_num) { +ge::Status ModelManager::SetDynamicSize(uint32_t model_id, const std::vector &batch_num, + int32_t dynamic_type) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHECK_NOTNULL(davinci_model); - davinci_model->SetDynamicSize(batch_num); + davinci_model->SetDynamicSize(batch_num, dynamic_type); return SUCCESS; } @@ -272,6 +275,10 @@ Status ModelManager::LoadModelOnline(uint32_t &model_id, const shared_ptrSetId(model_id); davinci_model->SetDeviceId(GetContext().DeviceId()); + const DumpProperties &dump_properties = PropertiesManager::Instance().GetDumpProperties(GetContext().SessionId()); + davinci_model->SetDumpProperties(dump_properties); + dump_properties_ = dump_properties; + auto root_graph = ge_root_model->GetRootGraph(); GE_CHECK_NOTNULL(root_graph); string root_model_name = root_graph->GetName(); @@ -296,9 +303,6 @@ Status ModelManager::LoadModelOnline(uint32_t &model_id, const shared_ptrSetProfileTime(MODEL_LOAD_START, (timespec.tv_sec * 1000 * 1000 * 1000 + timespec.tv_nsec)); // 1000 ^ 3 converts second to nanosecond davinci_model->SetProfileTime(MODEL_LOAD_END); - if (davinci_model->SinkModelProfile() != SUCCESS) { - GELOGW("Sink model profile failed."); - } } } while (0); @@ -325,12 +329,18 @@ Status ModelManager::DeleteModel(uint32_t id) { auto it = model_map_.find(id); auto hybrid_model_it = hybrid_model_map_.find(id); if (it != model_map_.end()) { + uint64_t session_id = it->second->GetSessionId(); + std::string model_key = std::to_string(session_id) + "_" + std::to_string(id); + auto iter_aicpu_kernel = model_aicpu_kernel_.find(model_key); + if (iter_aicpu_kernel != model_aicpu_kernel_.end()) { + (void)model_aicpu_kernel_.erase(iter_aicpu_kernel); + } (void)model_map_.erase(it); } else if (hybrid_model_it != hybrid_model_map_.end()) { (void)hybrid_model_map_.erase(hybrid_model_it); } else { - GELOGE(PARAM_INVALID, "model id %u does not exists.", id); - return PARAM_INVALID; + GELOGE(GE_EXEC_MODEL_ID_INVALID, "model id %u does not exists.", id); + return GE_EXEC_MODEL_ID_INVALID; } return SUCCESS; @@ -383,7 +393,7 @@ Status ModelManager::DataInput(const InputData &input_data, OutputData &output_d std::shared_ptr model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(model != nullptr, PARAM_INVALID, "Invalid Model ID %u in InputData! ", model_id); + GE_CHK_BOOL_RET_STATUS(model != nullptr, PARAM_INVALID, "Invalid model id %u in InputData! ", model_id); GE_IF_BOOL_EXEC(model->GetDataInputTid() == 0, model->SetDataInputTid(mmGetTid())); @@ -419,7 +429,7 @@ Status ModelManager::DataInputTensor(uint32_t model_id, const std::vector(inputs[i].length); + data.length = inputs[i].length; input_data.blobs.push_back(data); } @@ -439,7 +449,7 @@ Status ModelManager::DataInputTensor(uint32_t model_id, const std::vectorGetDataInputer(); GE_CHECK_NOTNULL(inputer); @@ -469,7 +479,7 @@ Status ModelManager::Start(uint32_t model_id) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to start! ", model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid model id %u to start! ", model_id); Status status = davinci_model->ModelRunStart(); if (status == SUCCESS) { @@ -496,7 +506,7 @@ Status ModelManager::Stop(uint32_t model_id) { } std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to stop!", model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid model id %u to stop!", model_id); Status status = davinci_model->ModelRunStop(); if (status == SUCCESS) { @@ -611,10 +621,10 @@ Status ModelManager::HandleDumpCommand(const Command &command) { GELOGE(PARAM_INVALID, "parser dump model failed"); return FAILED; } - GELOGI("dump status = %s.", dump_model.c_str()); + GELOGI("dump model = %s.", dump_model.c_str()); if (dump_status == "off" || dump_status == "OFF") { - PropertiesManager::Instance().DeleteDumpPropertyValue(dump_model); + dump_properties_.DeletePropertyValue(dump_model); return SUCCESS; } @@ -631,9 +641,10 @@ Status ModelManager::HandleDumpCommand(const Command &command) { return FAILED; } if (!dump_path.empty() && dump_path[dump_path.size() - 1] != '/') { - dump_path = dump_path + "/" + CurrentTimeInStr() + "/"; + dump_path = dump_path + "/"; } - GELOGI("dump status = %s.", dump_path.c_str()); + dump_path = dump_path + CurrentTimeInStr() + "/"; + GELOGI("dump path = %s.", dump_path.c_str()); ret = ParserPara(command, DUMP_MODE, dump_mode); if (ret != SUCCESS) { @@ -642,20 +653,10 @@ Status ModelManager::HandleDumpCommand(const Command &command) { } GELOGI("dump mode = %s", dump_mode.c_str()); - auto iter_dump_mode = std::find(command.cmd_params.begin(), command.cmd_params.end(), DUMP_MODE); - if (iter_dump_mode != command.cmd_params.end()) { - ++iter_dump_mode; - if (iter_dump_mode == command.cmd_params.end()) { - GELOGE(PARAM_INVALID, "Invalid access."); - return PARAM_INVALID; - } - dump_mode = *iter_dump_mode; - GELOGI("dump mode = %s", dump_mode.c_str()); - } + dump_properties_.AddPropertyValue(dump_model, dump_layers); + dump_properties_.SetDumpPath(dump_path); + dump_properties_.SetDumpMode(dump_mode); - PropertiesManager::Instance().AddDumpPropertyValue(dump_model, dump_layers); - PropertiesManager::Instance().SetDumpOutputPath(dump_path); - PropertiesManager::Instance().SetDumpMode(dump_mode); return SUCCESS; } @@ -667,7 +668,7 @@ Status ModelManager::GetMaxUsedMemory(const uint32_t model_id, uint64_t &max_siz } std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetMaxUsedMemory Failed, Invalid Model ID %u !", + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetMaxUsedMemory Failed, Invalid model id %u!", model_id); max_size = davinci_model->TotalMemSize(); @@ -677,8 +678,8 @@ Status ModelManager::GetMaxUsedMemory(const uint32_t model_id, uint64_t &max_siz Status ModelManager::GetInputOutputDescInfo(const uint32_t model_id, vector &input_desc, vector &output_desc) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, - "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetInputOutputDescInfo Failed, Invalid model id %u!", + model_id); return davinci_model->GetInputOutputDescInfo(input_desc, output_desc); } @@ -688,8 +689,8 @@ Status ModelManager::GetInputOutputDescInfo(const uint32_t model_id, vector &inputFormats, std::vector &outputFormats, bool new_model_desc) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, - "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, GE_EXEC_MODEL_ID_INVALID, + "GetInputOutputDescInfo Failed, Invalid model id %u!", model_id); davinci_model->SetModelDescVersion(new_model_desc); @@ -703,18 +704,35 @@ Status ModelManager::GetInputOutputDescInfo(const uint32_t model_id, vector> &batch_info) { +Status ModelManager::GetDynamicBatchInfo(const uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type) { + std::shared_ptr davinci_model = GetModel(model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, GE_EXEC_MODEL_ID_INVALID, + "GetDynamicBatchInfo failed, Invalid model id %u!", model_id); + + return davinci_model->GetDynamicBatchInfo(batch_info, dynamic_type); +} + +/// +/// @ingroup ge +/// @brief Get combined dynamic dims info +/// @param [in] model_id +/// @param [out] batch_info +/// @return execute result +/// +Status ModelManager::GetCombinedDynamicDims(const uint32_t model_id, vector> &batch_info) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetDynamicBatchInfo Failed, Invalid Model ID %u !", + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetCombinedDynamicDims Failed, Invalid Model ID %u!", model_id); - return davinci_model->GetDynamicBatchInfo(batch_info); + davinci_model->GetCombinedDynamicDims(batch_info); + return SUCCESS; } -Status ModelManager::GetCurShape(const uint32_t model_id, std::vector &batch_info) { +Status ModelManager::GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type) { std::shared_ptr davinci_model = GetModel(model_id); GE_CHECK_NOTNULL(davinci_model); - davinci_model->GetCurShape(batch_info); + davinci_model->GetCurShape(batch_info, dynamic_type); return SUCCESS; } @@ -730,8 +748,8 @@ Status ModelManager::GetInputOutputDescInfoForZeroCopy(const uint32_t model_id, std::vector &inputFormats, std::vector &outputFormats) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, - "GetInputOutputDescInfo Failed, Invalid Model ID %u !", model_id); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "GetInputOutputDescInfo Failed, Invalid model id %u!", + model_id); return davinci_model->GetInputOutputDescInfoForZeroCopy(input_desc, output_desc, inputFormats, outputFormats); } @@ -771,21 +789,10 @@ Status ModelManager::GenSessionId(uint64_t &session_id) { return SUCCESS; } -Status ModelManager::UpdateSessionId(std::shared_ptr &davinci_model, uint64_t session_id) { - GeModelPtr ge_model_current = davinci_model->GetGeModel(); - GE_CHECK_NOTNULL(ge_model_current); - if (!ge::AttrUtils::SetInt(ge_model_current, ge::MODEL_ATTR_SESSION_ID, static_cast(session_id))) { - GELOGW("Set attr[%s] failed in updating session_id.", MODEL_ATTR_SESSION_ID.c_str()); - } - - GELOGD("Update session id: %lu.", session_id); - return SUCCESS; -} - Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model, shared_ptr listener, void *dev_ptr, size_t mem_size, void *weight_ptr, size_t weight_size) { - GE_CHK_BOOL_RET_STATUS(model.key.empty() || access(model.key.c_str(), F_OK) == 0, PARAM_INVALID, - "input key file path is not valid, %s", strerror(errno)); + GE_CHK_BOOL_RET_STATUS(model.key.empty() || access(model.key.c_str(), F_OK) == 0, GE_EXEC_MODEL_KEY_PATH_INVALID, + "input key file path %s is invalid, %s", model.key.c_str(), strerror(errno)); GenModelId(&model_id); shared_ptr davinci_model = nullptr; @@ -803,11 +810,11 @@ Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model try { davinci_model = std::make_shared(model.priority, listener); } catch (std::bad_alloc &) { - GELOGE(FAILED, "Make shared failed"); - return FAILED; + GELOGE(MEMALLOC_FAILED, "Make shared failed"); + return MEMALLOC_FAILED; } catch (...) { - GELOGE(FAILED, "Make shared failed since other exception raise"); - return FAILED; + GELOGE(INTERNAL_ERROR, "Make shared failed since other exception raise"); + return INTERNAL_ERROR; } ret = davinci_model->Assign(ge_model); if (ret != SUCCESS) { @@ -820,10 +827,11 @@ Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model rtError_t rt_ret = rtGetDevice(&device_id); if (rt_ret != RT_ERROR_NONE || device_id < 0) { GELOGE(RT_FAILED, "Call rtGetDevice failed, ret = 0x%X, device_id = %d.", rt_ret, device_id); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } davinci_model->SetDeviceId(device_id); davinci_model->SetOmName(model.om_name); + davinci_model->SetDumpProperties(dump_properties_); /// In multi-threaded inference, using the same session_id among multiple threads may cause some threads to fail. /// These session_ids come from the same model, so the values of session_id are the same. @@ -831,7 +839,7 @@ Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model uint64_t new_session_id; ret = GenSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, break, "Generate session_id for infer failed."); - ret = UpdateSessionId(davinci_model, new_session_id); + ret = davinci_model->UpdateSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, break, "Update session_id for infer failed."); ret = davinci_model->Init(dev_ptr, mem_size, weight_ptr, weight_size); @@ -846,9 +854,6 @@ Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model davinci_model->SetProfileTime(MODEL_LOAD_START, (timespec.tv_sec * 1000 * 1000 * 1000 + timespec.tv_nsec)); // 1000 ^ 3 converts second to nanosecond davinci_model->SetProfileTime(MODEL_LOAD_END); - if (davinci_model->SinkModelProfile() != SUCCESS) { - GELOGW("Sink model profile failed."); - } } GE_IF_BOOL_EXEC(ret == SUCCESS, device_count++); @@ -870,8 +875,9 @@ Status ModelManager::LoadModelOffline(uint32_t &model_id, const ModelData &model Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_data, const std::vector &input_queue_ids, const std::vector &output_queue_ids) { - GE_CHK_BOOL_RET_STATUS(model_data.key.empty() || access(model_data.key.c_str(), F_OK) == 0, PARAM_INVALID, - "input key file path is not valid, %s", strerror(errno)); + GE_CHK_BOOL_RET_STATUS(model_data.key.empty() || access(model_data.key.c_str(), F_OK) == 0, + GE_EXEC_MODEL_KEY_PATH_INVALID, "input key file path %s is not valid, %s", + model_data.key.c_str(), strerror(errno)); ModelHelper model_helper; Status ret = model_helper.LoadModel(model_data); @@ -882,8 +888,8 @@ Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_d shared_ptr davinci_model = MakeShared(model_data.priority, nullptr); if (davinci_model == nullptr) { - GELOGE(FAILED, "create model failed."); - return FAILED; + GELOGE(MEMALLOC_FAILED, "create model failed."); + return MEMALLOC_FAILED; } ret = davinci_model->Assign(model_helper.GetGeModel()); @@ -898,7 +904,7 @@ Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_d uint64_t new_session_id; ret = GenSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Generate session_id for infer failed."); - ret = UpdateSessionId(davinci_model, new_session_id); + ret = davinci_model->UpdateSessionId(new_session_id); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Update session_id for infer failed."); GenModelId(&model_id); @@ -909,6 +915,8 @@ Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_d return ret; } + davinci_model->SetDumpProperties(dump_properties_); + ret = davinci_model->Init(); if (ret != SUCCESS) { GELOGE(ret, "init model failed."); @@ -933,14 +941,10 @@ Status ModelManager::LoadModelWithQ(uint32_t &model_id, const ModelData &model_d Status ModelManager::ExecuteModel(uint32_t model_id, rtStream_t stream, bool async_mode, const InputData &input_data, OutputData &output_data) { std::shared_ptr davinci_model = GetModel(model_id); - GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid Model ID %u to start! ", model_id); - - GeModelPtr ge_model_current = davinci_model->GetGeModel(); - bool need_destroy_aicpu_kernel = false; - bool result = ge::AttrUtils::GetBool(ge_model_current, kNeedDestroySpecifiedAicpuKernel, need_destroy_aicpu_kernel); - if (result && need_destroy_aicpu_kernel) { - GELOGI("Get attr %s successfully, start to destroy specified aicpu kernel.", kNeedDestroySpecifiedAicpuKernel); + GE_CHK_BOOL_RET_STATUS(davinci_model != nullptr, PARAM_INVALID, "Invalid model id %u.", model_id); + if (davinci_model->NeedDestroyAicpuKernel()) { + GELOGI("Start to destroy specified aicpu kernel."); // Zero copy is enabled by default, no need to judge. uint64_t session_id_davinci = davinci_model->GetSessionId(); uint32_t model_id_davinci = davinci_model->GetModelId(); @@ -994,29 +998,30 @@ Status ModelManager::GetModelMemAndWeightSize(const ModelData &model, size_t &me auto partition_table = reinterpret_cast(model_data); if (partition_table->num == 1) { - GELOGE(FAILED, "om model is error,please use executable om model"); - return FAILED; + GELOGE(GE_EXEC_MODEL_PARTITION_NUM_INVALID, "om model is error,please use executable om model"); + return GE_EXEC_MODEL_PARTITION_NUM_INVALID; } ModelPartition task_partition; if (om_file_helper.GetModelPartition(ModelPartitionType::TASK_INFO, task_partition) != SUCCESS) { - GELOGE(FAILED, "get task model partition failed."); - return FAILED; + GELOGE(GE_EXEC_LOAD_TASK_PARTITION_FAILED, "get task model partition failed."); + return GE_EXEC_LOAD_TASK_PARTITION_FAILED; } std::shared_ptr model_task_def = MakeShared(); if (model_task_def == nullptr) { - return FAILED; + return MEMALLOC_FAILED; } if (task_partition.size != 0) { if (!ReadProtoFromArray(task_partition.data, static_cast(task_partition.size), model_task_def.get())) { - GELOGE(FAILED, "ReadProtoFromArray failed."); - return FAILED; + GELOGE(GE_EXEC_LOAD_TASK_PARTITION_FAILED, "ReadProtoFromArray failed."); + return GE_EXEC_LOAD_TASK_PARTITION_FAILED; } } ModelPartition partition_weight; ret = om_file_helper.GetModelPartition(ModelPartitionType::WEIGHTS_DATA, partition_weight); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return ret, "Get weight partition failed. ret = %u", ret); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ret != SUCCESS, return GE_EXEC_LOAD_WEIGHT_PARTITION_FAILED, + "Get weight partition failed. ret = %u", ret); mem_size = model_task_def->memory_size(); weight_size = partition_weight.size; @@ -1050,4 +1055,19 @@ Status ModelManager::GetAllAippInputOutputDims(uint32_t model_id, uint32_t index return davinci_model->GetAllAippInputOutputDims(index, input_dims, output_dims); } +bool ModelManager::IsDynamicShape(uint32_t model_id) { + auto model = GetHybridModel(model_id); + return model != nullptr; +} + +ge::Status ModelManager::SyncExecuteModel(uint32_t model_id, const vector &inputs, + vector &outputs) { + auto model = GetHybridModel(model_id); + if (model == nullptr) { + GELOGE(FAILED, "Hybrid model not found. model id = %u.", model_id); + return FAILED; + } + + return model->Execute(inputs, outputs); +} } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/model_manager.h b/src/ge/graph/load/new_model_manager/model_manager.h index 8e2424bf..153d324d 100644 --- a/src/ge/graph/load/new_model_manager/model_manager.h +++ b/src/ge/graph/load/new_model_manager/model_manager.h @@ -31,6 +31,7 @@ #include "common/ge_types.h" #include "common/helper/model_helper.h" #include "common/helper/om_file_helper.h" +#include "common/properties_manager.h" #include "common/types.h" #include "ge/ge_api_types.h" #include "graph/ge_context.h" @@ -141,6 +142,8 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { ge::Status ExecuteModel(uint32_t model_id, rtStream_t stream, bool async_mode, const InputData &input_data, OutputData &output_data); + ge::Status SyncExecuteModel(uint32_t model_id, const std::vector &inputs, std::vector &outputs); + /// /// @ingroup domi_ome /// @brief model stop @@ -184,9 +187,19 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { /// @brief Get dynamic batch_info /// @param [in] model_id /// @param [out] batch_info + /// @param [out] dynamic_type /// @return execute result /// - ge::Status GetDynamicBatchInfo(const uint32_t model_id, std::vector> &batch_info); + ge::Status GetDynamicBatchInfo(const uint32_t model_id, std::vector> &batch_info, + int32_t &dynamic_type); + /// + /// @ingroup ge + /// @brief Get combined dynamic dims info + /// @param [in] model_id + /// @param [out] batch_info + /// @return execute result + /// + ge::Status GetCombinedDynamicDims(const uint32_t model_id, std::vector> &batch_info); /// /// @ingroup ge @@ -212,13 +225,13 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { std::vector &inputFormats, std::vector &outputFormats); - ge::Status GetCurShape(const uint32_t model_id, std::vector &batch_info); + ge::Status GetCurShape(const uint32_t model_id, std::vector &batch_info, int32_t &dynamic_type); ge::Status GetModelAttr(uint32_t model_id, std::vector &dynamic_output_shape_info); ge::Status SetDevice(int32_t deviceId) const; - ge::Status SetDynamicSize(uint32_t model_id, const std::vector &batch_num); + ge::Status SetDynamicSize(uint32_t model_id, const std::vector &batch_num, int32_t dynamic_type); /// /// @ingroup domi_ome @@ -249,6 +262,8 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { ge::Status GetAllAippInputOutputDims(uint32_t model_id, uint32_t index, std::vector &input_dims, std::vector &output_dims); + bool IsDynamicShape(uint32_t model_id); + private: /// /// @ingroup domi_ome @@ -276,7 +291,6 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { ge::Status DeleteModel(uint32_t id); void GenModelId(uint32_t *id); - ge::Status UpdateSessionId(std::shared_ptr &davinci_model, uint64_t session_id); std::map> model_map_; std::map> hybrid_model_map_; @@ -287,6 +301,8 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY ModelManager { std::mutex session_id_create_mutex_; uint64_t session_id_bias_; std::set sess_ids_; + + static DumpProperties dump_properties_; }; } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/model_utils.cc b/src/ge/graph/load/new_model_manager/model_utils.cc index a807f2a3..8a92e1e6 100644 --- a/src/ge/graph/load/new_model_manager/model_utils.cc +++ b/src/ge/graph/load/new_model_manager/model_utils.cc @@ -31,9 +31,9 @@ namespace ge { /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get input size. -/// @return vector +/// @return vector /// vector ModelUtils::GetInputSize(ConstOpDescPtr op_desc) { vector v_input_size; @@ -43,22 +43,29 @@ vector ModelUtils::GetInputSize(ConstOpDescPtr op_desc) { const vector v_is_input_const = op_desc->GetIsInputConst(); for (size_t i = 0; i < inputs_size; ++i) { + const GeTensorDescPtr tensor_desc = op_desc->MutableInputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + + int64_t tensor_size = 0; if ((i < v_is_input_const.size()) && v_is_input_const[i] && (op_type != NETOUTPUT)) { // TBE: add weights size to input - GeTensorDesc tensor_desc = op_desc->GetInputDesc(i); - int64_t tensor_size = 0; - GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + GE_CHK_STATUS(TensorUtils::GetSize(*tensor_desc, tensor_size)); if (tensor_size) { v_input_size.push_back(tensor_size); } + GELOGI("[IMAS]GetInputSize op: %s, index: %lu, size:%ld", op_desc->GetName().c_str(), i, tensor_size); continue; } - int64_t tensor_size = 0; GE_IF_BOOL_EXEC( - TensorUtils::GetSize(op_desc->GetInputDesc(i), tensor_size) != GRAPH_SUCCESS, + TensorUtils::GetSize(*tensor_desc, tensor_size) != GRAPH_SUCCESS, GELOGI("Get size from TensorDesc failed, op : %s, input index : %zu", op_desc->GetName().c_str(), i); - continue;); + continue); + + GELOGI("[IMAS]GetInputSize op: %s, index: %lu, size:%ld", op_desc->GetName().c_str(), i, tensor_size); v_input_size.push_back(tensor_size); } @@ -67,9 +74,9 @@ vector ModelUtils::GetInputSize(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get output size. -/// @return vector +/// @return vector /// vector ModelUtils::GetOutputSize(ConstOpDescPtr op_desc) { vector v_output_size; @@ -82,11 +89,17 @@ vector ModelUtils::GetOutputSize(ConstOpDescPtr op_desc) { return v_output_size;); for (size_t i = 0; i < outputs_size; ++i) { + const GeTensorDescPtr tensor_desc = op_desc->MutableOutputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + int64_t tensor_size = 0; GE_IF_BOOL_EXEC( - TensorUtils::GetSize(op_desc->GetOutputDesc(i), tensor_size) != GRAPH_SUCCESS, + TensorUtils::GetSize(*tensor_desc, tensor_size) != GRAPH_SUCCESS, GELOGI("Get size from TensorDesc failed, op : %s, output index : %zu", op_desc->GetName().c_str(), i); - continue;); + continue); v_output_size.push_back(tensor_size); } @@ -95,9 +108,9 @@ vector ModelUtils::GetOutputSize(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get workspace size. -/// @return vector +/// @return vector /// vector ModelUtils::GetWorkspaceSize(ConstOpDescPtr op_desc) { vector v_workspace_size; @@ -118,9 +131,9 @@ vector ModelUtils::GetWorkspaceSize(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get weight size. -/// @return vector +/// @return vector /// vector ModelUtils::GetWeightSize(ConstOpDescPtr op_desc) { vector v_weight_size; @@ -142,8 +155,14 @@ vector ModelUtils::GetWeightSize(ConstOpDescPtr op_desc) { const vector v_is_input_const = op_desc->GetIsInputConst(); for (size_t i = 0; i < inputs_size; ++i) { if ((i < v_is_input_const.size()) && v_is_input_const[i]) { + const GeTensorDescPtr tensor_desc = op_desc->MutableInputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + int64_t tensor_size = 0; - (void)TensorUtils::GetSize(op_desc->GetInputDesc(i), tensor_size); + (void)TensorUtils::GetSize(*tensor_desc, tensor_size); v_weight_size.push_back(tensor_size); } } @@ -152,7 +171,7 @@ vector ModelUtils::GetWeightSize(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get weights. /// @return vector /// @@ -176,9 +195,14 @@ vector ModelUtils::GetWeights(ConstOpDescPtr op_desc) { const vector v_is_input_const = op_desc->GetIsInputConst(); for (size_t i = 0; i < inputs_size; ++i) { if ((i < v_is_input_const.size()) && v_is_input_const[i]) { + const GeTensorDescPtr tensor_desc = op_desc->MutableInputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + ConstGeTensorPtr weight = nullptr; - GeTensorDesc tensor_desc = op_desc->GetInputDesc(i); - if (AttrUtils::GetTensor(tensor_desc, ATTR_NAME_WEIGHTS, weight)) { + if (AttrUtils::GetTensor(*tensor_desc, ATTR_NAME_WEIGHTS, weight)) { v_weights.push_back(weight); } } @@ -188,7 +212,7 @@ vector ModelUtils::GetWeights(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get AiCpuOp Input descriptor. /// @return vector<::tagCcAICPUTensor> /// @@ -205,20 +229,25 @@ vector<::tagCcAICPUTensor> ModelUtils::GetInputDescs(ConstOpDescPtr op_desc) { continue; } + const GeTensorDescPtr tensor_desc = op_desc->MutableInputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + uint32_t dim_cnt = 0; - const auto &descriptor = op_desc->GetInputDesc(i); - GE_CHK_BOOL_EXEC_WARN(TensorUtils::GetRealDimCnt(descriptor, dim_cnt) == GRAPH_SUCCESS, continue, + GE_CHK_BOOL_EXEC_WARN(TensorUtils::GetRealDimCnt(*tensor_desc, dim_cnt) == GRAPH_SUCCESS, continue, "Get dim_cnt failed"); opTensor_t tmp; - uint32_t tmp_fmt = descriptor.GetFormat(); + uint32_t tmp_fmt = tensor_desc->GetFormat(); tmp.format = tagOpTensorFormat(tmp_fmt); tmp.dim_cnt = static_cast(dim_cnt); - uint32_t tmp_type = descriptor.GetDataType(); + uint32_t tmp_type = tensor_desc->GetDataType(); tmp.data_type = tagOpDataType(tmp_type); for (int32_t j = 0; j < 4; j++) { // 4 dims - tmp.dim[j] = (j < tmp.dim_cnt ? descriptor.GetShape().GetDim(j) : 1); + tmp.dim[j] = (j < tmp.dim_cnt ? tensor_desc->GetShape().GetDim(j) : 1); } v_input_descs.push_back(tmp); @@ -228,7 +257,7 @@ vector<::tagCcAICPUTensor> ModelUtils::GetInputDescs(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get AiCpuOp Output descriptor. /// @return vector<::tagCcAICPUTensor> /// @@ -240,20 +269,25 @@ vector<::tagCcAICPUTensor> ModelUtils::GetOutputDescs(ConstOpDescPtr op_desc) { // init op output opTensor_t struct const size_t output_num = op_desc->GetOutputsSize(); for (size_t i = 0; i < output_num; ++i) { + const GeTensorDescPtr tensor_desc = op_desc->MutableOutputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + uint32_t dim_cnt = 0; - const auto &descriptor = op_desc->GetOutputDesc(i); - GE_CHK_BOOL_EXEC_WARN(TensorUtils::GetRealDimCnt(descriptor, dim_cnt) == GRAPH_SUCCESS, continue, + GE_CHK_BOOL_EXEC_WARN(TensorUtils::GetRealDimCnt(*tensor_desc, dim_cnt) == GRAPH_SUCCESS, continue, "Get dim_cnt failed"); opTensor_t tmp; - uint32_t tmp_fmt = descriptor.GetFormat(); + uint32_t tmp_fmt = tensor_desc->GetFormat(); tmp.format = tagOpTensorFormat(tmp_fmt); tmp.dim_cnt = static_cast(dim_cnt); - uint32_t tmp_type = descriptor.GetDataType(); + uint32_t tmp_type = tensor_desc->GetDataType(); tmp.data_type = tagOpDataType(tmp_type); for (int32_t j = 0; j < 4; j++) { // 4 dims - tmp.dim[j] = (j < tmp.dim_cnt ? descriptor.GetShape().GetDim(j) : 1); + tmp.dim[j] = (j < tmp.dim_cnt ? tensor_desc->GetShape().GetDim(j) : 1); } v_output_descs.push_back(tmp); @@ -263,44 +297,14 @@ vector<::tagCcAICPUTensor> ModelUtils::GetOutputDescs(ConstOpDescPtr op_desc) { } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get input data address. /// @return vector /// -vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert) { +vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc) { vector v_input_data_addr; // init as:buf_base + op_def_->input(i)); GE_CHECK_NOTNULL_EXEC(op_desc, return v_input_data_addr); uint64_t session_id = model_param.session_id; - uint8_t *mem_base = model_param.mem_base; - uint8_t *var_base = model_param.var_base; - uint8_t *weight_base = model_param.weight_base; - const uint64_t logic_mem_base = 0; - uint64_t logic_weight_base = 0; - uint64_t logic_var_base = model_param.logic_var_base; - uint64_t mem_size = model_param.mem_size; - uint64_t weight_size = model_param.weight_size; - uint64_t var_size = model_param.var_size; - - if (need_convert) { - Status status = ConvertVirtualAddressToPhysical(mem_base, mem_size, mem_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for mem_base failed."); - return v_input_data_addr; - } - - status = ConvertVirtualAddressToPhysical(weight_base, weight_size, weight_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for weight_base failed."); - return v_input_data_addr; - } - - status = ConvertVirtualAddressToPhysical(var_base, var_size, var_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for var_base failed."); - return v_input_data_addr; - } - } const size_t inputs_size = op_desc->GetInputsSize(); const vector v_input_offset = op_desc->GetInputOffset(); @@ -319,13 +323,18 @@ vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, Co for (size_t i = 0; i < inputs_size; ++i) { if ((i < v_is_input_const.size()) && v_is_input_const[i] && (op_type != NETOUTPUT)) { // TBE: add weights address to input - GeTensorDesc tensor_desc = op_desc->GetInputDesc(i); + const GeTensorDescPtr tensor_desc = op_desc->MutableInputDesc(i); + if (tensor_desc == nullptr) { + GELOGW("Op: %s, Index: %zu, Tensor Desc is null", op_desc->GetName().c_str(), i); + continue; + } + int64_t tensor_size = 0; - GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + GE_CHK_STATUS(TensorUtils::GetSize(*tensor_desc, tensor_size)); if (tensor_size) { int64_t data_offset = 0; - GE_CHK_STATUS(TensorUtils::GetDataOffset(tensor_desc, data_offset)); - uint8_t *weight_addr = static_cast(weight_base + data_offset - logic_weight_base); + GE_CHK_STATUS(TensorUtils::GetDataOffset(*tensor_desc, data_offset)); + uint8_t *weight_addr = model_param.weight_base + data_offset; v_input_data_addr.push_back(weight_addr); GELOGI("[IMAS]GetInputDataAddrs graph_%u type[C] name[%s] input[%zu] memaddr[%p]", model_param.graph_id, op_desc->GetName().c_str(), i, weight_addr); @@ -340,17 +349,13 @@ vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, Co int64_t input_offset = v_input_offset[non_const_index]; non_const_index++; - GE_IF_BOOL_EXEC(var_size != 0 && ge::VarManager::Instance(session_id)->IsVarAddr(input_offset), - uint8_t *variable_addr = var_base + input_offset - logic_var_base; + GE_IF_BOOL_EXEC(model_param.var_size != 0 && ge::VarManager::Instance(session_id)->IsVarAddr(input_offset), + uint8_t *variable_addr = model_param.var_base + input_offset - model_param.logic_var_base; v_input_data_addr.push_back(variable_addr); GELOGI("[IMAS]GetInputDataAddrs graph_%u type[V] name[%s] input[%lu] memaddr[%p]", model_param.graph_id, op_desc->GetName().c_str(), i, variable_addr); - continue;); + continue); - bool input_tensor = false; - GE_IF_BOOL_EXEC(TensorUtils::GetInputTensor(op_desc->GetOutputDesc(i), input_tensor) != GRAPH_SUCCESS, - GELOGW("get size from TensorDesc failed, op: %s, input index: %zu", op_desc->GetName().c_str(), i); - continue;); // feature maps uint8_t *mem_addr = nullptr; // fusion @@ -358,7 +363,7 @@ vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, Co mem_addr = reinterpret_cast(reinterpret_cast(input_offset)); v_input_data_addr.push_back(mem_addr); } else { - mem_addr = static_cast(mem_base + input_offset - logic_mem_base); + mem_addr = model_param.mem_base + input_offset; v_input_data_addr.push_back(mem_addr); } GELOGI("[IMAS]GetInputDataAddrs graph_%u type[F] name[%s] input[%zu] memaddr[%p]", model_param.graph_id, @@ -369,41 +374,20 @@ vector ModelUtils::GetInputDataAddrs(const RuntimeParam &model_param, Co } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get output data address. /// @return vector /// -vector ModelUtils::GetOutputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert) { +vector ModelUtils::GetOutputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc) { vector v_output_data_addr; // init as:buf_base + op_def_->output(i) GE_CHECK_NOTNULL_EXEC(op_desc, return v_output_data_addr); uint64_t session_id = model_param.session_id; - uint8_t *mem_base = model_param.mem_base; - uint8_t *var_base = model_param.var_base; - const uint64_t logic_mem_base = 0; - uint64_t logic_var_base = model_param.logic_var_base; - uint64_t mem_size = model_param.mem_size; - uint64_t var_size = model_param.var_size; - - if (need_convert) { - Status status = ConvertVirtualAddressToPhysical(mem_base, mem_size, mem_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for mem_base failed."); - return v_output_data_addr; - } - - status = ConvertVirtualAddressToPhysical(var_base, var_size, var_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for var_base failed."); - return v_output_data_addr; - } - } const size_t outputs_size = op_desc->GetOutputsSize(); const vector v_output_offset = op_desc->GetOutputOffset(); GE_IF_BOOL_EXEC(v_output_offset.size() != outputs_size, GELOGW("Output param invalid: output_offset=%zu, outputs=%zu.", v_output_offset.size(), outputs_size); - return v_output_data_addr;); + return v_output_data_addr); vector v_memory_type; bool has_mem_type_attr = ge::AttrUtils::GetListInt(op_desc, ATTR_NAME_OUTPUT_MEM_TYPE_LIST, v_memory_type); if (has_mem_type_attr && (v_memory_type.size() != outputs_size)) { @@ -413,12 +397,12 @@ vector ModelUtils::GetOutputDataAddrs(const RuntimeParam &model_param, C return v_output_data_addr; } for (size_t i = 0; i < outputs_size; ++i) { - GE_IF_BOOL_EXEC(var_size != 0 && ge::VarManager::Instance(session_id)->IsVarAddr(v_output_offset[i]), - uint8_t *variable_addr = static_cast(var_base + v_output_offset[i] - logic_var_base); + GE_IF_BOOL_EXEC(model_param.var_size != 0 && ge::VarManager::Instance(session_id)->IsVarAddr(v_output_offset[i]), + uint8_t *variable_addr = model_param.var_base + v_output_offset[i] - model_param.logic_var_base; v_output_data_addr.push_back(variable_addr); GELOGI("[IMAS]GetOutputDataAddrs graph_%u type[V] name[%s] output[%zu] memaddr[%p]", model_param.graph_id, op_desc->GetName().c_str(), i, variable_addr); - continue;); + continue); // feature maps uint8_t *mem_addr = nullptr; // fusion @@ -426,7 +410,7 @@ vector ModelUtils::GetOutputDataAddrs(const RuntimeParam &model_param, C mem_addr = reinterpret_cast(reinterpret_cast(v_output_offset[i])); v_output_data_addr.push_back(mem_addr); } else { - mem_addr = static_cast(mem_base + v_output_offset[i] - logic_mem_base); + mem_addr = static_cast(model_param.mem_base + v_output_offset[i]); v_output_data_addr.push_back(mem_addr); } GELOGI("[IMAS]GetOutputDataAddrs graph_%u type[F] name[%s] output[%zu] memaddr[%p]", model_param.graph_id, @@ -436,24 +420,13 @@ vector ModelUtils::GetOutputDataAddrs(const RuntimeParam &model_param, C } /// -/// @ingroup domi_ome +/// @ingroup ge /// @brief Get workspace data address. /// @return vector /// -vector ModelUtils::GetWorkspaceDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert) { +vector ModelUtils::GetWorkspaceDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc) { vector v_workspace_data_addr; GE_CHECK_NOTNULL_EXEC(op_desc, return v_workspace_data_addr); - uint8_t *mem_base = model_param.mem_base; - uint64_t mem_size = model_param.mem_size; - - if (need_convert) { - Status status = ConvertVirtualAddressToPhysical(mem_base, mem_size, mem_base); - if (status != SUCCESS) { - GELOGE(RT_FAILED, "Convert virtual address to physical for mem_base failed."); - return v_workspace_data_addr; - } - } const vector v_workspace_offset = op_desc->GetWorkspace(); const vector v_workspace_bytes = op_desc->GetWorkspaceBytes(); @@ -466,13 +439,13 @@ vector ModelUtils::GetWorkspaceDataAddrs(const RuntimeParam &model_param bool has_mem_type_attr = ge::AttrUtils::GetListInt(op_desc, TVM_ATTR_NAME_WORKSPACE_TYPE, v_memory_type); for (size_t i = 0; i < v_workspace_bytes.size(); ++i) { if (has_mem_type_attr && v_memory_type[i] == RT_MEMORY_L1) { - v_workspace_data_addr.push_back(reinterpret_cast(v_workspace_offset[i])); + v_workspace_data_addr.push_back(reinterpret_cast(reinterpret_cast(v_workspace_offset[i]))); GELOGI("Fusion: op: %s, GetWorkspaceDataAddrs mem_addr[workspace index %zu]:%p", op_desc->GetName().c_str(), i, reinterpret_cast(reinterpret_cast(v_workspace_offset[i]))); } else { int64_t workspace_offset = v_workspace_offset[i]; int64_t workspace_bytes = v_workspace_bytes[i]; - uint8_t *mem_addr = workspace_bytes == 0 ? nullptr : mem_base + workspace_offset; + uint8_t *mem_addr = workspace_bytes == 0 ? nullptr : model_param.mem_base + workspace_offset; v_workspace_data_addr.push_back(mem_addr); GELOGI("[IMAS]GetWorkspaceDataAddrs graph_%u type[F] name[%s] workspace[%zu] offset[%ld] bytes[%ld] memaddr[%p]", model_param.graph_id, op_desc->GetName().c_str(), i, workspace_offset, workspace_bytes, mem_addr); @@ -482,21 +455,32 @@ vector ModelUtils::GetWorkspaceDataAddrs(const RuntimeParam &model_param return v_workspace_data_addr; } -Status ModelUtils::ConvertVirtualAddressToPhysical(uint8_t *virtual_address, uint64_t size, - uint8_t *&physical_address) { - // Indicates whether use physical address. - const char *use_physical_address = std::getenv("GE_USE_PHYSICAL_ADDRESS"); - if (use_physical_address == nullptr || virtual_address == 0 || size == 0) { - return SUCCESS; - } - - rtError_t ret = rtKernelConfigTransArg(virtual_address, size, 0, reinterpret_cast(&physical_address)); - if (ret != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "Call rtKernelConfigTransArg failed, ret: 0x%X", ret); - return RT_FAILED; +/// +/// @ingroup ge +/// @brief Get runtime memory address. +/// @return Status +/// +Status ModelUtils::GetRtAddress(const RuntimeParam ¶m, uintptr_t logic_addr, uint8_t *&mem_addr) { + uint8_t *runtime_base_addr = nullptr; + if ((param.logic_mem_base <= logic_addr) && (logic_addr < param.logic_mem_base + param.mem_size)) { + runtime_base_addr = param.mem_base - param.logic_mem_base; + GELOGI("The logic addr:0x%lx is data address, base:0x%lx, size:%lu", logic_addr, param.logic_mem_base, + param.mem_size); + } else if ((param.logic_weight_base <= logic_addr) && (logic_addr < param.logic_weight_base + param.weight_size)) { + runtime_base_addr = param.weight_base - param.logic_weight_base; + GELOGI("The logic addr:0x%lx is weight address, base:0x%lx, size:%lu", logic_addr, param.logic_weight_base, + param.weight_size); + } else if ((param.logic_var_base <= logic_addr) && (logic_addr < param.logic_var_base + param.var_size)) { + runtime_base_addr = param.var_base - param.logic_var_base; + GELOGI("The logic addr:0x%lx is variable address, base:0x%lx, size:%lu", logic_addr, param.logic_var_base, + param.var_size); + } else if (logic_addr != 0) { + mem_addr = nullptr; + GELOGE(PARAM_INVALID, "The logic addr:0x%lx is abnormal", logic_addr); + return PARAM_INVALID; } - GELOGD("virtual_address=%p, physical_address=%p", virtual_address, physical_address); + mem_addr = runtime_base_addr + logic_addr; return SUCCESS; } } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/model_utils.h b/src/ge/graph/load/new_model_manager/model_utils.h index d6afd5c8..8474a987 100644 --- a/src/ge/graph/load/new_model_manager/model_utils.h +++ b/src/ge/graph/load/new_model_manager/model_utils.h @@ -34,78 +34,79 @@ class ModelUtils { ~ModelUtils() = default; /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get input size. /// @return vector /// static vector GetInputSize(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get output size. /// @return vector /// static vector GetOutputSize(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get workspace size. /// @return vector /// static vector GetWorkspaceSize(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get weight size. /// @return vector /// static vector GetWeightSize(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get weights. /// @return vector /// static vector GetWeights(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get AiCpuOp Input descriptor. /// @return vector<::tagCcAICPUTensor> /// static vector<::tagCcAICPUTensor> GetInputDescs(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get AiCpuOp Output descriptor. /// @return vector<::tagCcAICPUTensor> /// static vector<::tagCcAICPUTensor> GetOutputDescs(ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get input data address. /// @return vector /// - static vector GetInputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert = true); + static vector GetInputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get output data address. /// @return vector /// - static vector GetOutputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert = true); + static vector GetOutputDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc); /// - /// @ingroup domi_ome + /// @ingroup ge /// @brief Get workspace data address. /// @return vector /// - static vector GetWorkspaceDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc, - bool need_convert = true); + static vector GetWorkspaceDataAddrs(const RuntimeParam &model_param, ConstOpDescPtr op_desc); - static ge::Status ConvertVirtualAddressToPhysical(uint8_t *virtual_address, uint64_t size, - uint8_t *&physical_address); + /// + /// @ingroup ge + /// @brief Get memory runtime base. + /// @return Status + /// + static Status GetRtAddress(const RuntimeParam &model_param, uintptr_t logic_addr, uint8_t *&mem_addr); }; } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.cc index 077ae827..39f0591d 100644 --- a/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.cc @@ -34,7 +34,7 @@ Status EndGraphTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin Status ret = SetStream(task_def.stream_id(), davinci_model->GetStreamList()); if (ret != SUCCESS) { GELOGE(ret, "SetStream fail, stream_id:%u", task_def.stream_id()); - return FAILED; + return ret; } model_ = davinci_model->GetRtModelHandle(); @@ -45,7 +45,7 @@ Status EndGraphTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin Status EndGraphTaskInfo::Distribute() { GELOGI("EndGraphTaskInfo Distribute Start."); GE_CHECK_NOTNULL(davinci_model_); - auto all_dump_model = PropertiesManager::Instance().GetAllDumpModel(); + auto all_dump_model = davinci_model_->GetDumpProperties().GetAllDumpModel(); if (all_dump_model.find(ge::DUMP_ALL_MODEL) != all_dump_model.end() || all_dump_model.find(davinci_model_->Name()) != all_dump_model.end() || all_dump_model.find(davinci_model_->OmName()) != all_dump_model.end()) { @@ -53,14 +53,14 @@ Status EndGraphTaskInfo::Distribute() { rtError_t rt_ret = rtEndGraphEx(model_, stream_, kDumpFlag); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtEndGraphEx failed, ret: 0x%x", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } else { GELOGI("Start to call rtEndGraph"); rtError_t rt_ret = rtEndGraph(model_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rtEndGraph failed, ret: 0x%x", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } @@ -69,7 +69,7 @@ Status EndGraphTaskInfo::Distribute() { rtError_t rt_ret = rtModelGetTaskId(davinci_model_->GetRtModelHandle(), &task_id, &stream_id); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } task_id_ = task_id; stream_id_ = stream_id; @@ -80,5 +80,4 @@ Status EndGraphTaskInfo::Distribute() { } REGISTER_TASK_INFO(RT_MODEL_TASK_MODEL_END_GRAPH, EndGraphTaskInfo); - } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.h b/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.h index 49bef082..82e228e6 100644 --- a/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/end_graph_task_info.h @@ -22,7 +22,7 @@ namespace ge { class EndGraphTaskInfo : public TaskInfo { public: - EndGraphTaskInfo() : model_(0) {} + EndGraphTaskInfo() {} ~EndGraphTaskInfo() override { model_ = nullptr; } @@ -35,10 +35,10 @@ class EndGraphTaskInfo : public TaskInfo { uint32_t GetStreamId() override { return stream_id_; } private: - rtModel_t model_; - DavinciModel *davinci_model_; - uint32_t task_id_; - uint32_t stream_id_; + rtModel_t model_{nullptr}; + DavinciModel *davinci_model_{nullptr}; + uint32_t task_id_{0}; + uint32_t stream_id_{0}; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_END_GRAPH_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/event_record_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/event_record_task_info.cc index edfd8d17..f742118c 100644 --- a/src/ge/graph/load/new_model_manager/task_info/event_record_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/event_record_task_info.cc @@ -49,7 +49,7 @@ Status EventRecordTaskInfo::Distribute() { rtError_t rt_ret = rtEventRecord(event_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; diff --git a/src/ge/graph/load/new_model_manager/task_info/event_wait_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/event_wait_task_info.cc index a8db158d..e8f96b35 100644 --- a/src/ge/graph/load/new_model_manager/task_info/event_wait_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/event_wait_task_info.cc @@ -51,13 +51,13 @@ Status EventWaitTaskInfo::Distribute() { rtError_t rt_ret = rtStreamWaitEvent(stream_, event_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtEventReset(event_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; diff --git a/src/ge/graph/load/new_model_manager/task_info/fusion_start_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/fusion_start_task_info.cc index f3fa7959..9b1ea04a 100644 --- a/src/ge/graph/load/new_model_manager/task_info/fusion_start_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/fusion_start_task_info.cc @@ -40,7 +40,7 @@ Status FusionStartTaskInfo::Distribute() { rtError_t rt_ret = rtKernelFusionStart(stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("FusionStartTaskInfo Distribute Success."); diff --git a/src/ge/graph/load/new_model_manager/task_info/fusion_stop_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/fusion_stop_task_info.cc index 128fb325..7acbb5b3 100644 --- a/src/ge/graph/load/new_model_manager/task_info/fusion_stop_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/fusion_stop_task_info.cc @@ -40,7 +40,7 @@ Status FusionStopTaskInfo::Distribute() { rtError_t rt_ret = rtKernelFusionEnd(stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("FusionStopTaskInfo Distribute Success."); diff --git a/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.cc index 0ee9727a..cb8cfed6 100644 --- a/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.cc @@ -42,6 +42,7 @@ HcclTaskInfo::~HcclTaskInfo() { davinci_model_ = nullptr; ops_kernel_store_ = nullptr; max_node_of_hccl_stream_ = 0; + args_ = nullptr; } Status HcclTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) { GELOGI("HcclTaskInfo Init Start."); @@ -60,52 +61,59 @@ Status HcclTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_m GELOGI("HcclTaskInfo Init, op_index is: %u", op_index); // Get HCCL op - OpDescPtr op_desc = davinci_model->GetOpByIndex(op_index); - GE_CHECK_NOTNULL(op_desc); + op_desc_ = davinci_model->GetOpByIndex(op_index); + GE_CHECK_NOTNULL(op_desc_); // Create the kernel hccl infos - CreateKernelHcclInfo(op_desc); + CreateKernelHcclInfo(op_desc_); // Initialize the hccl_type of all kernel hccl info HcomOmeUtil::GetHcclType(task_def, kernel_hccl_infos_); // Only in Horovod scenario should get the inputName and GeShape - ret = HcomOmeUtil::GetHorovodInputs(op_desc, kernel_hccl_infos_); + ret = HcomOmeUtil::GetHorovodInputs(op_desc_, kernel_hccl_infos_); if (ret != SUCCESS) { - GELOGE(FAILED, "davinci_model: GetHorovodInputs fail! domi error: %u", ret); - return FAILED; + GELOGE(ret, "davinci_model: GetHorovodInputs fail! domi error: %u", ret); + return ret; } - Status dmrt = HcomOmeUtil::GetHcclDataType(op_desc, kernel_hccl_infos_); + Status dmrt = HcomOmeUtil::GetHcclDataType(op_desc_, kernel_hccl_infos_); if (dmrt != SUCCESS) { - GELOGE(FAILED, "davinci_model: GetHcomDataType fail! domi error: %u", dmrt); - return FAILED; + GELOGE(dmrt, "davinci_model: GetHcomDataType fail! domi error: %u", dmrt); + return dmrt; } - dmrt = HcomOmeUtil::GetHcclCount(op_desc, kernel_hccl_infos_); + dmrt = HcomOmeUtil::GetHcclCount(op_desc_, kernel_hccl_infos_); if (dmrt != SUCCESS) { - GELOGE(FAILED, "davinci_model: GetHcomCount fail! domi error: %u", dmrt); - return FAILED; + GELOGE(dmrt, "davinci_model: GetHcomCount fail! domi error: %u", dmrt); + return dmrt; } // Only HCOMBROADCAST and HVDCALLBACKBROADCAST need to get the rootId - dmrt = HcomOmeUtil::GetAllRootId(op_desc, kernel_hccl_infos_); + dmrt = HcomOmeUtil::GetAllRootId(op_desc_, kernel_hccl_infos_); if (dmrt != SUCCESS) { - GELOGE(FAILED, "davinci_model: Get rootId fail! domi error: %u", dmrt); - return FAILED; + GELOGE(dmrt, "davinci_model: Get rootId fail! domi error: %u", dmrt); + return dmrt; } - ret = SetAddrs(op_desc, kernel_hccl_infos_); + + // GE's new process: hccl declares the number of streams required, creates a stream by GE, and sends it to hccl + ret = SetFollowStream(op_desc_, davinci_model); if (ret != SUCCESS) { - GELOGE(ret, "Setaddrs Fail."); + GELOGE(ret, "SetStream Fail."); return ret; } - // GE's new process: hccl declares the need for Workspace size, and GE allocates Workspace - ret = SetWorkspace(op_desc, kernel_hccl_infos_); + + if (davinci_model_->IsKnownNode()) { + args_ = davinci_model_->GetCurrentArgsAddr(args_offset_); + GELOGI("Known node %s args addr %p, offset %u.", op_desc_->GetName().c_str(), args_, args_offset_); + } + + ret = SetAddrs(op_desc_, kernel_hccl_infos_); if (ret != SUCCESS) { - GELOGE(ret, "SetWorkspace Fail."); + GELOGE(ret, "Setaddrs Fail."); return ret; } - // GE's new process: hccl declares the number of streams required, creates a stream by GE, and sends it to hccl - ret = SetFollowStream(op_desc, davinci_model); + // GE's new process: hccl declares the need for Workspace size, and GE allocates Workspace + ret = SetWorkspace(op_desc_, kernel_hccl_infos_); if (ret != SUCCESS) { - GELOGE(ret, "SetStream Fail."); + GELOGE(ret, "SetWorkspace Fail."); return ret; } @@ -130,8 +138,8 @@ Status HcclTaskInfo::SetFollowStream(const ge::ConstOpDescPtr &op_desc, DavinciM uint32_t max_task_count; ret = rtGetMaxStreamAndTask(RT_NORMAL_STREAM, &max_stream_count, &max_task_count); if (ret != RT_ERROR_NONE) { - GELOGE(FAILED, "Get max stream and task count by rts failed."); - return FAILED; + GELOGE(RT_FAILED, "Get max stream and task count by rts failed."); + return RT_ERROR_TO_GE_STATUS(ret); } max_node_of_hccl_stream_ = max_task_count / kMaxTaskOfStream; } @@ -145,8 +153,8 @@ Status HcclTaskInfo::SetFollowStream(const ge::ConstOpDescPtr &op_desc, DavinciM ReuseStream(created_stream_num, davinci_model); ret = CreateStream(hccl_stream_num - created_stream_num, davinci_model); if (ret != SUCCESS) { - GELOGE(FAILED, "Create hccl stream failed."); - return FAILED; + GELOGE(RT_FAILED, "Create hccl stream failed."); + return RT_ERROR_TO_GE_STATUS(ret); } } GELOGI("Initialize hccl slave stream success, hcclStreamNum =%ld", hccl_stream_num); @@ -171,14 +179,14 @@ Status HcclTaskInfo::CreateStream(int64_t stream_num, DavinciModel *davinci_mode rtStreamCreateWithFlags(&stream, davinci_model->Priority(), RT_STREAM_PERSISTENT | RT_STREAM_FORCE_COPY); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // Create slave stream, inactive by default, activated by hccl rt_ret = rtModelBindStream(davinci_model->GetRtModelHandle(), stream, RT_MODEL_WAIT_ACTIVE_STREAM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); (void)rtStreamDestroy(stream); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGD("hccl_stream addr is=%p", stream); int64_t remain_cap = max_node_of_hccl_stream_ - 1; @@ -209,40 +217,82 @@ Status HcclTaskInfo::Distribute() { GELOGI("HcclTaskInfo Distribute Success."); return SUCCESS; } + +Status HcclTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) { + GE_CHECK_NOTNULL(davinci_model); + auto hccl_def = task_def.kernel_hccl(); + uint32_t op_index = hccl_def.op_index(); + GELOGI("HcclTaskInfo Init, op_index is: %u", op_index); + // Get HCCL op + auto op_desc = davinci_model->GetOpByIndex(op_index); + GE_CHECK_NOTNULL(op_desc); + GELOGI("Calc opType[%s] args size. Node name is [%s]", op_desc->GetType().c_str(), op_desc->GetName().c_str()); + // Only need the number of addr to allocate args memory + auto input_size = op_desc->GetInputsSize(); + auto output_size = op_desc->GetOutputsSize(); + auto workspace_size = op_desc->GetWorkspaceBytes().size(); + uint32_t args_size = sizeof(void *) * (input_size + output_size + workspace_size); + args_offset_ = davinci_model->GetTotalArgsSize(); + davinci_model->SetTotalArgsSize(args_size); + GELOGI("Calculate hccl task args , args_size %u, args_offset %u", args_size, args_offset_); + return SUCCESS; +} + +Status HcclTaskInfo::UpdateArgs() { + GELOGI("HcclTaskInfo::UpdateArgs in."); + const RuntimeParam &rts_param = davinci_model_->GetRuntimeParam(); + input_data_addrs_ = ModelUtils::GetInputDataAddrs(rts_param, op_desc_); + output_data_addrs_ = ModelUtils::GetOutputDataAddrs(rts_param, op_desc_); + workspace_data_addrs_ = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc_); + + vector io_addrs; + io_addrs.insert(io_addrs.end(), input_data_addrs_.begin(), input_data_addrs_.end()); + io_addrs.insert(io_addrs.end(), output_data_addrs_.begin(), output_data_addrs_.end()); + io_addrs.insert(io_addrs.end(), workspace_data_addrs_.begin(), workspace_data_addrs_.end()); + + davinci_model_->SetTotalIOAddrs(io_addrs); + + GELOGI("HcclTaskInfo::UpdateArgs success."); + return SUCCESS; +} + Status HcclTaskInfo::SetAddrs(const std::shared_ptr &op_desc, std::vector &kernel_hccl_infos) { GE_CHECK_NOTNULL(op_desc); - if (HcomOmeUtil::CheckKernelHcclInfo(op_desc, kernel_hccl_infos) != SUCCESS) { - GELOGE(PARAM_INVALID, "HcomOmeUtil:: the number of GETaskKernelHcclInfo is invalid."); - return PARAM_INVALID; - } + GE_CHK_STATUS_RET(HcomOmeUtil::CheckKernelHcclInfo(op_desc, kernel_hccl_infos), + "HcomOmeUtil:: the number of GETaskKernelHcclInfo is invalid."); GELOGI("Set hccl task input output address, node[%s}, type[%s] kernel_hccl_infos.size[%zu].", op_desc->GetName().c_str(), op_desc->GetType().c_str(), kernel_hccl_infos.size()); if (op_desc->GetType() == HVDWAIT) { return SUCCESS; } - domi::Status dmrt; + hcclRedOp_t op_type = HCCL_REP_OP_SUM; GE_CHECK_NOTNULL(davinci_model_); GELOGI("Calc opType[%s] input address before. Node name[%s]", op_desc->GetType().c_str(), op_desc->GetName().c_str()); - auto input_data_addr_list = ModelUtils::GetInputDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); - - auto output_data_addr_list = ModelUtils::GetOutputDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); + if (!davinci_model_->IsKnownNode()) { + input_data_addrs_ = ModelUtils::GetInputDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); + output_data_addrs_ = ModelUtils::GetOutputDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); + } + void *input_data_addr = nullptr; + void *output_data_addr = nullptr; // initialize every kernel_hccl_info inputDataAddr for (size_t i = 0; i < kernel_hccl_infos.size(); i++) { std::string hccl_type = kernel_hccl_infos[i].hccl_type; - void *input_data_addr = input_data_addr_list.empty() ? nullptr : input_data_addr_list[i]; + if (davinci_model_->IsKnownNode()) { + input_data_addr = reinterpret_cast(reinterpret_cast(args_) + i); + output_data_addr = reinterpret_cast(reinterpret_cast(args_) + op_desc->GetInputsSize() + i); + GELOGI("Hccl task info known input addr %p, output addr %p.", input_data_addr, output_data_addr); + } else { + input_data_addr = input_data_addrs_.empty() ? nullptr : input_data_addrs_[i]; + output_data_addr = output_data_addrs_.empty() ? nullptr : output_data_addrs_[i]; + } kernel_hccl_infos[i].inputDataAddr = input_data_addr; - - void *output_data_addr = output_data_addr_list.empty() ? nullptr : output_data_addr_list[i]; if (hccl_type == HCOMALLGATHER || hccl_type == HCOMRECEIVE || hccl_type == HVDCALLBACKALLGATHER) { kernel_hccl_infos[i].outputDataAddr = output_data_addr; } else if (hccl_type == HCOMALLREDUCE || hccl_type == HCOMREDUCESCATTER || hccl_type == HVDCALLBACKALLREDUCE) { - dmrt = HcomOmeUtil::GetHcclOperationType(op_desc, op_type); - if (dmrt != SUCCESS) { - GELOGE(FAILED, "davinci_model: GetHcomOperationType fail! domi error: %u", dmrt); - return FAILED; - } + GE_CHK_STATUS_RET(HcomOmeUtil::GetHcclOperationType(op_desc, op_type), + "davinci_model: GetHcomOperationType fail!"); kernel_hccl_infos[i].outputDataAddr = output_data_addr; kernel_hccl_infos[i].opType = op_type; } @@ -310,6 +360,7 @@ void HcclTaskInfo::CreateKernelHcclInfo(const ge::ConstOpDescPtr &op_desc) { Status HcclTaskInfo::SetWorkspace(const std::shared_ptr &op_desc, std::vector &kernel_hccl_infos) { GE_CHECK_NOTNULL(op_desc); + GE_CHECK_NOTNULL(davinci_model_); GELOGI("SetWorkspace Node[%s] opType[%s] set workspace.", op_desc->GetName().c_str(), op_desc->GetType().c_str()); uint64_t workspace_mem_size = 0; void *workspace_addr = nullptr; @@ -319,11 +370,12 @@ Status HcclTaskInfo::SetWorkspace(const std::shared_ptr &op_desc, GELOGI("hccl need workSpaceMemSize=%lu", workspace_mem_size_tmp); if (workspace_mem_size_tmp != 0) { workspace_mem_size = workspace_mem_size_tmp; - vector workspace_data_addrs = - ModelUtils::GetWorkspaceDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); - if (!workspace_data_addrs.empty()) { - GELOGI("Get workSpaceAddr"); - workspace_addr = workspace_data_addrs[0]; + if (davinci_model_->IsKnownNode()) { + workspace_addr = reinterpret_cast(reinterpret_cast(args_) + op_desc->GetInputsSize() + + op_desc->GetOutputsSize()); + } else { + workspace_data_addrs_ = ModelUtils::GetWorkspaceDataAddrs(davinci_model_->GetRuntimeParam(), op_desc); + workspace_addr = workspace_data_addrs_.empty() ? nullptr : workspace_data_addrs_[0]; } } } diff --git a/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.h b/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.h index bb0a88de..cc3109f4 100644 --- a/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/hccl_task_info.h @@ -34,7 +34,10 @@ class HcclTaskInfo : public TaskInfo { hccl_stream_list_(), ops_kernel_store_(nullptr), private_def_(nullptr), - private_def_len_(0) {} + private_def_len_(0), + op_desc_(nullptr), + args_(nullptr), + args_offset_(0) {} ~HcclTaskInfo() override; @@ -44,6 +47,10 @@ class HcclTaskInfo : public TaskInfo { uint32_t GetTaskID() override { return id_; } + Status CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; + + Status UpdateArgs() override; + private: ge::Status SetAddrs(const std::string &hccl_type, const std::shared_ptr &op); @@ -72,6 +79,12 @@ class HcclTaskInfo : public TaskInfo { static std::mutex hccl_follow_stream_mutex_; static uint32_t max_node_of_hccl_stream_; vector kernel_hccl_infos_; + vector input_data_addrs_; + vector output_data_addrs_; + vector workspace_data_addrs_; + OpDescPtr op_desc_; + void *args_; + uint32_t args_offset_; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_HCCL_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.cc index 79971529..4f72ec36 100644 --- a/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.cc @@ -72,13 +72,16 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin auto rt_ret = rtMalloc(&ext_info_addr_, ext_info.size(), RT_MEMORY_HBM); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc ext_info error: 0x%X, size=%zu", rt_ret, ext_info.size()); - return FAILED;) + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy(ext_info_addr_, ext_info.size(), ext_info.c_str(), ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy ext_info error: 0x%X, size=%zu", rt_ret, ext_info.size()); - return FAILED;) + return RT_ERROR_TO_GE_STATUS(rt_ret);) } + GELOGI("Node[%s] type[%s] kernel_ext_info size=%zu, ext_info_addr_=%p", op_desc_->GetName().c_str(), + op_desc_->GetType().c_str(), ext_info.size(), ext_info_addr_); + // 2.1 get loop cond variable for tensor array write uint64_t step_id_addr = 0; OpDescPtr step_id_node = davinci_model_->GetVariableOp(NODE_NAME_GLOBAL_STEP); @@ -97,6 +100,11 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin GE_IF_BOOL_EXEC(ModelManager::GetInstance()->CreateAicpuKernel(session_id, davinci_model->Id(), kernel_id) != SUCCESS, GELOGE(FAILED, "CreateAicpuKernel error."); return FAILED;) + // 2.3 Create session + GE_CHECK_NOTNULL(ModelManager::GetInstance()); + GE_IF_BOOL_EXEC(ModelManager::GetInstance()->CreateAicpuSession(session_id) != SUCCESS, + GELOGE(FAILED, "CreateAicpuSession error. session id: %lu", session_id); + return FAILED;) kernel_buf_size_ = sizeof(STR_FWK_OP_KERNEL); if (davinci_model_->IsKnownNode()) { @@ -105,7 +113,8 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin static_cast(reinterpret_cast(input_output_addr)); void *workspace_base_addr = nullptr; rtError_t rt_ret = rtMalloc(&workspace_base_addr, kernel_ex_def.task_info_size(), RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc error, ret: Ox%X", rt_ret); return FAILED;); + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error, ret: Ox%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);); rt_ret = rtMemcpy(workspace_base_addr, kernel_ex_def.task_info_size(), kernel_ex_def.task_info().data(), kernel_ex_def.task_info_size(), RT_MEMCPY_HOST_TO_DEVICE); fwk_op_kernel.fwkKernelBase.fwk_kernel.workspaceBaseAddr = @@ -115,20 +124,23 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast(ext_info_addr_); rt_ret = rtMalloc(&kernel_buf_, kernel_buf_size_, RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc error: 0x%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy(kernel_buf_, kernel_buf_size_, static_cast(&fwk_op_kernel), kernel_buf_size_, RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy error, ret: Ox%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy error, ret: Ox%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) GELOGI("KernelExTaskInfo knonw node Init Success."); return SUCCESS; } // 3. Set workspaceaddr, inputOutputDataAddr - if (CopyTaskInfo(kernel_ex_def, rts_param, op_desc) != SUCCESS) { - GELOGE(FAILED, "copy task info to workspace failed."); - return FAILED; + Status ge_ret = CopyTaskInfo(kernel_ex_def, rts_param, op_desc); + if (ge_ret != SUCCESS) { + GELOGE(ge_ret, "copy task info to workspace failed."); + return ge_ret; } const vector workspace_data_addrs = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc); @@ -147,14 +159,15 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin auto addrs_size = sizeof(uint64_t) * (io_addrs.size()); if (addrs_size > 0) { rtError_t rt_ret = rtMalloc(&input_output_addr_, addrs_size, RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); return RT_FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error, ret: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy(input_output_addr_, addrs_size, io_addrs.data(), addrs_size, RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy to input_output_addr_ error: 0x%X", rt_ret); - return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy to input_output_addr_ error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) - if (PropertiesManager::Instance().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), - op_desc->GetName())) { + if (davinci_model_->GetDumpProperties().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), + op_desc->GetName())) { dump_flag_ = RT_KERNEL_DUMPFLAG; dump_args_ = input_output_addr_; } @@ -167,25 +180,17 @@ Status KernelExTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davin fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoLen = ext_info.size(); fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast(ext_info_addr_); - // 4. Create session - GE_CHECK_NOTNULL(ModelManager::GetInstance()); - GE_IF_BOOL_EXEC(ModelManager::GetInstance()->CreateAicpuSession(session_id) != SUCCESS, - GELOGE(FAILED, "CreateAicpuSession error. session id: %lu", session_id); - return FAILED;) - // 5. Return result + // 4. Return result rtError_t rt_ret = rtMalloc(&kernel_buf_, sizeof(STR_FWK_OP_KERNEL), RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc error: 0x%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy(kernel_buf_, sizeof(STR_FWK_OP_KERNEL), static_cast(&fwk_op_kernel), sizeof(STR_FWK_OP_KERNEL), RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy error, ret: Ox%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy error, ret: Ox%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) - vector virtual_io_addrs; // use virtual address for zero copy key. - const vector virtual_in_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc, false); - const vector virtual_out_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc, false); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_in_addrs.begin(), virtual_in_addrs.end()); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_out_addrs.begin(), virtual_out_addrs.end()); - davinci_model_->SetZeroCopyAddr(op_desc, virtual_io_addrs, io_addrs.data(), input_output_addr_, addrs_size, 0); + davinci_model_->SetZeroCopyAddr(op_desc, io_addrs, io_addrs.data(), input_output_addr_, addrs_size, 0); GELOGI("KernelExTaskInfo Init Success. session id: %lu", session_id); return SUCCESS; @@ -207,22 +212,56 @@ Status KernelExTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciMod uint32_t mem_size = sizeof(uint64_t) * mem_length; davinci_model->SetTotalArgsSize(mem_size); GELOGI("kernel task name %s, args_size %u, args_offset %u", op_desc->GetName().c_str(), mem_size, args_offset_); + + // alloc fixed addr + string peer_input_name; + if (AttrUtils::GetStr(op_desc, ATTR_DYNAMIC_SHAPE_FIXED_ADDR, peer_input_name) && !peer_input_name.empty()) { + uint32_t output_index = davinci_model->GetFixedAddrOutputIndex(peer_input_name); + if (output_index > outputs_size) { + GELOGE(FAILED, "The output size[%zu] and output index[%u] are inconsistent.", outputs_size, output_index); + return FAILED; + } + fixed_addr_offset_ = davinci_model->GetFixedAddrsSize(peer_input_name); + auto tensor_desc = op_desc->GetOutputDesc(output_index); + int64_t tensor_size = 0; + GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + davinci_model->SetTotalFixedAddrsSize(peer_input_name, tensor_size); + GELOGI("Calculate stream switch task args , tensor size is %ld, fixed addr offset %ld", tensor_size, + fixed_addr_offset_); + } return SUCCESS; } Status KernelExTaskInfo::UpdateArgs() { GELOGI("KernelExTaskInfo::UpdateArgs in."); const RuntimeParam &rts_param = davinci_model_->GetRuntimeParam(); - vector io_addrs; vector input_data_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc_); vector output_data_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc_); - - io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); - io_addrs.insert(io_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); - - GE_CHK_STATUS_RET(davinci_model_->UpdateKnownZeroCopyAddr(io_addrs, args_offset_), - "update known node %s zero copy addr failed.", op_desc_->GetName().c_str()); - + vector io_addrs; + if (!op_desc_->HasAttr(ATTR_DYNAMIC_SHAPE_FIXED_ADDR)) { + io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + io_addrs.insert(io_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); + } else { + string peer_input_name; + if (AttrUtils::GetStr(op_desc_, ATTR_DYNAMIC_SHAPE_FIXED_ADDR, peer_input_name)) { + uint32_t output_index = davinci_model_->GetFixedAddrOutputIndex(peer_input_name); + if (output_index > output_data_addrs.size()) { + GELOGE(FAILED, "The output data addr size[%zu] and output index[%u] are inconsistent.", + output_data_addrs.size(), output_index); + return FAILED; + } + io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + for (size_t i = 0; i < output_data_addrs.size(); ++i) { + if (i == output_index) { + void *fixed_addr = davinci_model_->GetCurrentFixedAddr(fixed_addr_offset_); + io_addrs.emplace_back(fixed_addr); + continue; + } + io_addrs.emplace_back(output_data_addrs[i]); + } + } + } + davinci_model_->SetTotalIOAddrs(io_addrs); GELOGI("KernelExTaskInfo::UpdateArgs success."); return SUCCESS; } @@ -231,7 +270,7 @@ Status KernelExTaskInfo::CopyTaskInfo(const domi::KernelExDef &kernel_def, const const OpDescPtr &op_desc) { // Userspace copy need virtual address. const vector workspace_data_sizes = ModelUtils::GetWorkspaceSize(op_desc); - const vector workspace_data_addrs = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc, false); + const vector workspace_data_addrs = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc); if (workspace_data_addrs.empty() || workspace_data_sizes.empty()) { GELOGE(FAILED, "Node:%s invalid workspace, addrs is %zu, size is %zu.", op_desc->GetName().c_str(), workspace_data_addrs.size(), workspace_data_sizes.size()); @@ -252,8 +291,8 @@ Status KernelExTaskInfo::CopyTaskInfo(const domi::KernelExDef &kernel_def, const rtError_t rt_ret = rtMemcpy(workspace_data_addrs[0], kernel_def.task_info_size(), kernel_def.task_info().data(), kernel_def.task_info_size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { - GELOGE(FAILED, "rtMemcpy error: 0x%X", rt_ret); - return FAILED; + GELOGE(RT_FAILED, "rtMemcpy error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; @@ -264,7 +303,7 @@ Status KernelExTaskInfo::Distribute() { rtError_t rt_ret = rtKernelLaunchEx(kernel_buf_, kernel_buf_size_, dump_flag_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } if (davinci_model_ == nullptr) { @@ -277,7 +316,7 @@ Status KernelExTaskInfo::Distribute() { rt_ret = rtModelGetTaskId(davinci_model_->GetRtModelHandle(), &task_id, &stream_id); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } task_id_ = task_id; stream_id_ = stream_id; @@ -292,7 +331,7 @@ Status KernelExTaskInfo::Release() { rtError_t rt_ret = rtFree(kernel_buf_); if (rt_ret != RT_ERROR_NONE) { GELOGW("rtFree error, ret: 0x%X", rt_ret); - ret = FAILED; + ret = RT_ERROR_TO_GE_STATUS(rt_ret); } else { kernel_buf_ = nullptr; } @@ -301,7 +340,7 @@ Status KernelExTaskInfo::Release() { rtError_t rt_ret = rtFree(input_output_addr_); if (rt_ret != RT_ERROR_NONE) { GELOGW("rtFree error, ret: 0x%X", rt_ret); - ret = FAILED; + ret = RT_ERROR_TO_GE_STATUS(rt_ret); } else { input_output_addr_ = nullptr; } @@ -310,7 +349,7 @@ Status KernelExTaskInfo::Release() { rtError_t rt_ret = rtFree(ext_info_addr_); if (rt_ret != RT_ERROR_NONE) { GELOGW("rtFree ext_info_addr[%p] error, ret: 0x%X", ext_info_addr_, rt_ret); - ret = FAILED; + ret = RT_ERROR_TO_GE_STATUS(rt_ret); } else { ext_info_addr_ = nullptr; } diff --git a/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.h b/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.h index ff8f3119..b26a95ac 100644 --- a/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/kernel_ex_task_info.h @@ -54,6 +54,7 @@ class KernelExTaskInfo : public TaskInfo { auto ret = reinterpret_cast(dump_args_); return ret; } + bool CallSaveDumpInfo() override { return true; }; private: Status CopyTaskInfo(const domi::KernelExDef &kernel_def, const RuntimeParam &rts_param, const OpDescPtr &op_desc); @@ -69,6 +70,7 @@ class KernelExTaskInfo : public TaskInfo { void *dump_args_; OpDescPtr op_desc_ = nullptr; uint32_t args_offset_ = 0; + int64_t fixed_addr_offset_ = 0; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_KERNEL_EX_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.cc index 7ef65555..da6d05ca 100644 --- a/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.cc @@ -47,16 +47,16 @@ const uint32_t kAddrLen = sizeof(void *); namespace ge { KernelTaskInfo::SuperKernelTaskInfo KernelTaskInfo::skt_info_ = { - 0, 0, 0, 0, nullptr, nullptr, {}, {}, RT_KERNEL_DEFAULT, kInvalidGroupKey, 0, nullptr}; + 0, 0, 0, 0, nullptr, nullptr, {}, {}, {}, {}, {}, RT_KERNEL_DEFAULT, kInvalidGroupKey, 0, nullptr}; Status KernelTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) { if (davinci_model == nullptr) { - GELOGE(PARAM_INVALID, "davinci_model is null!"); + GELOGE(PARAM_INVALID, "davinci model is null!"); return PARAM_INVALID; } davinci_model_ = davinci_model; is_l1_fusion_enable_ = davinci_model_->GetL1FusionEnableOption(); - GELOGD("KernelTaskInfo Init Start, ge.enableL1Fusion in davinci model is %d.", is_l1_fusion_enable_); + GELOGD("KernelTaskInfo init start, ge.enableL1Fusion in davinci model is %d.", is_l1_fusion_enable_); Status ret = SetStream(task_def.stream_id(), davinci_model_->GetStreamList()); if (ret != SUCCESS) { @@ -73,7 +73,7 @@ Status KernelTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci // get opdesc op_desc_ = davinci_model_->GetOpByIndex(context.op_index()); if (op_desc_ == nullptr) { - GELOGE(INTERNAL_ERROR, "Get op_desc failed, index is out of range!"); + GELOGE(INTERNAL_ERROR, "Get op desc failed, index is out of range!"); return INTERNAL_ERROR; } (void)AttrUtils::GetBool(*op_desc_, ATTR_N_BATCH_SPILT, is_n_batch_spilt_); @@ -99,13 +99,13 @@ Status KernelTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci rt_ret = rtGetFunctionByName(const_cast(kernel_def.stub_func().c_str()), &stub_func_); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "execute rtGetFunctionByName failed. stub_func: %s", kernel_def.stub_func().c_str()); - return RT_FAILED;); + return RT_ERROR_TO_GE_STATUS(rt_ret);); } else if (kernel_type_ != cce::ccKernelType::AI_CPU) { rtError_t rt_ret; rt_ret = rtGetFunctionByName(bin_file_key, &stub_func_); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "execute rtGetFunctionByName failed. bin_file_key: %s", bin_file_key); - return RT_FAILED;); + return RT_ERROR_TO_GE_STATUS(rt_ret);); } if (context.origin_op_index_size() > CC_FUSION_OP_MAX) { @@ -138,14 +138,21 @@ Status KernelTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci ret = InitCceTask(kernel_def); } - GELOGD("KernelTaskInfo Init finish, result=%u.", ret); + GELOGD("KernelTaskInfo init finish, result=%u.", ret); return ret; } Status KernelTaskInfo::SaveSKTDumpInfo() { GE_CHECK_NOTNULL(davinci_model_); - davinci_model_->SaveDumpTask(skt_info_.last_task_id, skt_info_.last_stream_id, skt_info_.last_op, - skt_info_.last_dump_args); + if (skt_dump_flag_ == RT_KERNEL_DEFAULT) { + GELOGD("no need save skt dump info"); + return SUCCESS; + } + // all op in super kernel share one taskid and streamid + for (size_t i = 0; i < skt_info_.op_desc_list.size(); i++) { + davinci_model_->SaveDumpTask(skt_info_.last_task_id, skt_info_.last_stream_id, skt_info_.op_desc_list[i], + skt_info_.dump_args_list[i]); + } return SUCCESS; } @@ -187,6 +194,9 @@ Status KernelTaskInfo::SKTFinalize() { GELOGI("SuperKernel Distribute [skt_id:%u]", skt_id_); skt_info_.kernel_list.clear(); skt_info_.arg_list.clear(); + skt_info_.dump_flag_list.clear(); + skt_info_.op_desc_list.clear(); + skt_info_.dump_args_list.clear(); skt_info_.last_stream = nullptr; skt_info_.last_block_dim = 0; skt_info_.last_sm_desc = sm_desc_; @@ -197,6 +207,15 @@ Status KernelTaskInfo::SKTFinalize() { return SUCCESS; } +uint32_t KernelTaskInfo::GetDumpFlag() { + for (auto flag : skt_info_.dump_flag_list) { + if (flag == RT_KERNEL_DUMPFLAG) { + return RT_KERNEL_DUMPFLAG; + } + } + return RT_KERNEL_DEFAULT; +} + Status KernelTaskInfo::SuperKernelLaunch() { if (skt_info_.kernel_list.empty()) { GELOGI("SuperKernelLaunch: Skt_kernel_list has no task, just return"); @@ -206,38 +225,46 @@ Status KernelTaskInfo::SuperKernelLaunch() { auto &skt_kernel_list = skt_info_.kernel_list; auto &skt_arg_list = skt_info_.arg_list; GELOGI("SuperKernelLaunch: Skt_kernel_list size[%d] skt_arg_list[%d]", skt_kernel_list.size(), skt_arg_list.size()); - if (skt_kernel_list.size() == kSKTSingleSize) { + if (skt_kernel_list.size() == kSKTSingleSize && skt_arg_list.size() == kSKTSingleSize) { rt_ret = rtKernelLaunchWithFlag(skt_info_.kernel_list[0], static_cast(skt_info_.last_block_dim), skt_info_.arg_list[0], skt_info_.last_args_size, static_cast(skt_info_.last_sm_desc), skt_info_.last_stream, skt_info_.last_dump_flag); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "SuperKernelLaunch: Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } + call_save_dump_ = true; GE_CHK_STATUS_RET(SKTFinalize(), "Skt finalize failed"); return SUCCESS; } // Create super kernel factory skt::SuperKernelFactory *factory = &skt::SuperKernelFactory::GetInstance(); // Init super kernel factory - if (factory->Init() != SUCCESS) { - GELOGE(RT_FAILED, "SuperKernelLaunch: SuperKernelFactory init failed"); - return RT_FAILED; + Status ge_ret = factory->Init(); + if (ge_ret != SUCCESS) { + GELOGE(ge_ret, "SuperKernelLaunch: SuperKernelFactory init failed"); + return ge_ret; } // Call the fuse API - skt::SuperKernel *superKernel = nullptr; - if (factory->FuseKernels(skt_kernel_list, skt_arg_list, skt_info_.last_block_dim, superKernel) != SUCCESS) { - GELOGE(RT_FAILED, "SuperKernelLaunch: fuse call failed"); - return RT_FAILED; + std::unique_ptr superKernel = nullptr; + ge_ret = factory->FuseKernels(skt_kernel_list, skt_arg_list, skt_info_.last_block_dim, superKernel); + if (ge_ret != SUCCESS) { + GELOGE(ge_ret, "SuperKernelLaunch: fuse call failed"); + return ge_ret; } // Launch a super kernel - if (superKernel->Launch(skt_info_.last_stream, RT_KERNEL_DUMPFLAG) != SUCCESS) { - GELOGE(RT_FAILED, "SuperKernelLaunch: launch failed"); - return RT_FAILED; + skt_dump_flag_ = GetDumpFlag(); + ge_ret = superKernel->Launch(skt_info_.last_stream, skt_dump_flag_); + if (ge_ret != SUCCESS) { + GELOGE(ge_ret, "SuperKernelLaunch: launch failed"); + return ge_ret; } GELOGI("SuperKernelLaunch: success[skt_kernel_list size[%zu] skt_arg_list[%zu]]", skt_kernel_list.size(), skt_arg_list.size()); + // record skt addr for release + superkernel_dev_nav_table_ = superKernel->GetNavTablePtr(); + superkernel_device_args_addr_ = superKernel->GetDeviceArgsPtr(); GE_CHK_STATUS_RET(SKTFinalize(), "Skt finalize failed"); return SUCCESS; } @@ -250,8 +277,11 @@ Status KernelTaskInfo::SaveSuperKernelInfo() { skt_info_.last_args_size = args_size_; skt_info_.last_sm_desc = sm_desc_; skt_info_.last_dump_flag = dump_flag_; + skt_info_.dump_flag_list.push_back(dump_flag_); + skt_info_.op_desc_list.push_back(op_desc_); + skt_info_.dump_args_list.push_back(reinterpret_cast(skt_dump_args_)); skt_info_.last_group_key = group_key_; - skt_info_.last_dump_args = reinterpret_cast(dump_args_); + skt_info_.last_dump_args = reinterpret_cast(skt_dump_args_); skt_info_.last_op = op_desc_; // last node in a stream, just launch if (IsMarkedLastNode()) { @@ -318,23 +348,24 @@ Status KernelTaskInfo::SuperKernelDistribute() { // 1.launch before ret = SuperKernelLaunch(); if (ret != SUCCESS) { - GELOGE(FAILED, "Call SuperKernelLaunch failed!"); - return FAILED; + GELOGE(ret, "Call SuperKernelLaunch failed!"); + return ret; } // 2.launch current rtError_t rt_ret = rtKernelLaunchWithFlag(stub_func_, block_dim_, args_, args_size_, static_cast(sm_desc_), stream_, dump_flag_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return FAILED; + return rt_ret; } + call_save_dump_ = true; UpdateTaskId(); GELOGI("Current Common Task Distribute [taskid:%u]", task_id_); } else { ret = SaveSuperKernelInfo(); if (ret != SUCCESS) { - GELOGE(FAILED, "Call SuperKernelLaunch failed!"); - return FAILED; + GELOGE(ret, "Call SuperKernelLaunch failed!"); + return ret; } GELOGI("Save Current task [block_dim:%u, size:%zu].", block_dim_, skt_info_.kernel_list.size()); } @@ -356,6 +387,7 @@ Status KernelTaskInfo::Distribute() { rt_ret = rtCpuKernelLaunchWithFlag(reinterpret_cast(so_name_.c_str()), reinterpret_cast(kernel_name_.c_str()), 1, args_, args_size_, nullptr, stream_, dump_flag_); + call_save_dump_ = true; } else { /* default: not skt launch */ GELOGI( @@ -369,11 +401,12 @@ Status KernelTaskInfo::Distribute() { // call rtKernelLaunch for current task rt_ret = rtKernelLaunchWithFlag(stub_func_, block_dim_, args_, args_size_, static_cast(sm_desc_), stream_, dump_flag_); + call_save_dump_ = true; } } if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // set for task_id_ UpdateTaskId(); @@ -392,13 +425,33 @@ Status KernelTaskInfo::UpdateArgs() { vector workspace_data_addrs = ModelUtils::GetWorkspaceDataAddrs(rts_param, op_desc_); vector io_addrs; - io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); - io_addrs.insert(io_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); - io_addrs.insert(io_addrs.end(), workspace_data_addrs.begin(), workspace_data_addrs.end()); - - GE_CHK_STATUS_RET(davinci_model_->UpdateKnownZeroCopyAddr(io_addrs, args_offset_), - "update known node %s zero copy addr failed.", op_desc_->GetName().c_str()); + if (!op_desc_->HasAttr(ATTR_DYNAMIC_SHAPE_FIXED_ADDR)) { + io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + io_addrs.insert(io_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); + io_addrs.insert(io_addrs.end(), workspace_data_addrs.begin(), workspace_data_addrs.end()); + } else { + string peer_input_name; + if (AttrUtils::GetStr(op_desc_, ATTR_DYNAMIC_SHAPE_FIXED_ADDR, peer_input_name)) { + uint32_t output_index = davinci_model_->GetFixedAddrOutputIndex(peer_input_name); + if (output_index > output_data_addrs.size()) { + GELOGE(FAILED, "The output data addr size[%zu] and output index[%u] are inconsistent.", + output_data_addrs.size(), output_index); + return FAILED; + } + io_addrs.insert(io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + for (size_t i = 0; i < output_data_addrs.size(); ++i) { + if (i == output_index) { + void *fixed_addr = davinci_model_->GetCurrentFixedAddr(fixed_addr_offset_); + io_addrs.emplace_back(fixed_addr); + continue; + } + io_addrs.emplace_back(output_data_addrs[i]); + } + io_addrs.insert(io_addrs.end(), workspace_data_addrs.begin(), workspace_data_addrs.end()); + } + } + davinci_model_->SetTotalIOAddrs(io_addrs); GELOGI("KernelTaskInfo::UpdateArgs success."); return SUCCESS; } @@ -407,24 +460,31 @@ Status KernelTaskInfo::Release() { if (davinci_model_ != nullptr && davinci_model_->IsKnownNode()) { return SUCCESS; } - FreeRtMem(&args_); - FreeRtMem(&flowtable_); - FreeRtMem(&custom_info_.input_descs); - FreeRtMem(&custom_info_.input_addrs); - FreeRtMem(&custom_info_.output_descs); - FreeRtMem(&custom_info_.output_addrs); - FreeRtMem(&custom_info_.attr_handle); - FreeRtMem(&aicpu_ext_info_addr_); + rtContext_t ctx = nullptr; + rtError_t ret = rtCtxGetCurrent(&ctx); + + if (ret == RT_ERROR_NONE) { + FreeRtMem(&args_); + FreeRtMem(&superkernel_device_args_addr_); + FreeRtMem(&superkernel_dev_nav_table_); + FreeRtMem(&flowtable_); + FreeRtMem(&custom_info_.input_descs); + FreeRtMem(&custom_info_.input_addrs); + FreeRtMem(&custom_info_.output_descs); + FreeRtMem(&custom_info_.output_addrs); + FreeRtMem(&custom_info_.attr_handle); + FreeRtMem(&aicpu_ext_info_addr_); + } if (ctx_.argsOffset != nullptr) { delete[] ctx_.argsOffset; ctx_.argsOffset = nullptr; } - rtError_t ret = (sm_desc_ != nullptr) ? rtMemFreeManaged(sm_desc_) : RT_ERROR_NONE; + ret = (sm_desc_ != nullptr) ? rtMemFreeManaged(sm_desc_) : RT_ERROR_NONE; if (ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", static_cast(ret)); - return FAILED; + return RT_ERROR_TO_GE_STATUS(ret); } sm_desc_ = nullptr; @@ -454,13 +514,13 @@ Status KernelTaskInfo::UpdateL2Data(const domi::KernelDef &kernel_def) { rtError_t rt_ret = rtMemAllocManaged(&sm_desc_, sm_desc.size(), RT_MEMORY_SPM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(sm_desc_, sm_desc.size(), sm_desc.data(), sm_desc.size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; @@ -472,6 +532,29 @@ Status KernelTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel args_offset_ = davinci_model->GetTotalArgsSize(); davinci_model->SetTotalArgsSize(args_size); GELOGI("kernel task name , args_size %u, args_offset %u", args_size, args_offset_); + + // get opcontext stored in model + const domi::KernelContext &context = kernel_def.context(); + // get opdesc + op_desc_ = davinci_model->GetOpByIndex(context.op_index()); + GE_CHECK_NOTNULL(op_desc_); + // alloc fixed addr + string peer_input_name; + if (AttrUtils::GetStr(op_desc_, ATTR_DYNAMIC_SHAPE_FIXED_ADDR, peer_input_name) && !peer_input_name.empty()) { + uint32_t output_index = davinci_model->GetFixedAddrOutputIndex(peer_input_name); + if (output_index > op_desc_->GetOutputsSize()) { + GELOGE(FAILED, "The output size[%zu] and output index[%u] are inconsistent.", op_desc_->GetOutputsSize(), + output_index); + return FAILED; + } + fixed_addr_offset_ = davinci_model->GetFixedAddrsSize(peer_input_name); + auto tensor_desc = op_desc_->GetOutputDesc(output_index); + int64_t tensor_size = 0; + GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + davinci_model->SetTotalFixedAddrsSize(peer_input_name, tensor_size); + GELOGI("Calculate stream switch task args , tensor size is %ld, fixed addr offset %ld", tensor_size, + fixed_addr_offset_); + } return SUCCESS; } @@ -514,14 +597,14 @@ Status KernelTaskInfo::InitTVMTask(uint16_t offset, const domi::KernelDef &kerne rt_ret = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // copy orign args rt_ret = rtMemcpy(args_, args_size_, kernel_def.args().data(), args_size_, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } vector args_info(args_size_); errno_t sec_ret = memcpy_s(args_info.data(), args_size_, kernel_def.args().data(), args_size_); @@ -540,7 +623,7 @@ Status KernelTaskInfo::InitTVMTask(uint16_t offset, const domi::KernelDef &kerne kAddrLen * tensor_device_addrs.size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } sec_ret = memcpy_s(args_info.data() + offset, args_size_ - offset, tensor_device_addrs.data(), kAddrLen * tensor_device_addrs.size()); @@ -548,23 +631,22 @@ Status KernelTaskInfo::InitTVMTask(uint16_t offset, const domi::KernelDef &kerne GELOGE(FAILED, "memcpy failed, ret: %d", sec_ret); return FAILED; } - - if (PropertiesManager::Instance().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), - op_desc->GetName())) { + skt_dump_args_ = static_cast(args_) + offset; + if (davinci_model_->GetDumpProperties().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), + op_desc->GetName())) { dump_flag_ = RT_KERNEL_DUMPFLAG; dump_args_ = static_cast(args_) + offset; } + Status ge_ret = UpdateL2Data(kernel_def); // update origin l2 data - if (UpdateL2Data(kernel_def) != SUCCESS) { - return RT_FAILED; + if (ge_ret != SUCCESS) { + return ge_ret; } vector virtual_io_addrs; // use virtual address for zero copy key. - const vector virtual_in_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc, false); - const vector virtual_out_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc, false); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_in_addrs.begin(), virtual_in_addrs.end()); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_out_addrs.begin(), virtual_out_addrs.end()); + virtual_io_addrs.insert(virtual_io_addrs.end(), input_data_addrs.begin(), input_data_addrs.end()); + virtual_io_addrs.insert(virtual_io_addrs.end(), output_data_addrs.begin(), output_data_addrs.end()); davinci_model_->SetZeroCopyAddr(op_desc, virtual_io_addrs, args_info.data(), args_, args_size_, offset); GELOGD("Do InitTVMTask end"); @@ -602,7 +684,6 @@ Status KernelTaskInfo::InitAICPUCustomTask(uint32_t op_index, const domi::Kernel const std::vector output_data_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc); Status ret = StoreInputOutputTensor(input_data_addrs, output_data_addrs, ModelUtils::GetInputDescs(op_desc), ModelUtils::GetOutputDescs(op_desc)); - if (ret != SUCCESS) { GELOGE(ret, "StoreInputOutputTensor Failed"); return ret; @@ -624,13 +705,13 @@ Status KernelTaskInfo::InitAICPUCustomTask(uint32_t op_index, const domi::Kernel rtError_t rt_ret = rtMalloc(&custom_info_.attr_handle, op_attr_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(custom_info_.attr_handle, op_attr_size, buffer.GetData(), op_attr_size, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // args @@ -657,21 +738,19 @@ Status KernelTaskInfo::InitAICPUCustomTask(uint32_t op_index, const domi::Kernel rt_ret = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(args_, kernel_def.args_size(), kernel_def.args().data(), kernel_def.args_size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } - const vector virtual_in_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc, false); - const vector virtual_out_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc, false); - davinci_model_->SetZeroCopyAddr(op_desc, virtual_in_addrs, input_data_addrs.data(), custom_info_.input_addrs, - virtual_in_addrs.size() * kAddrLen, 0); - davinci_model_->SetZeroCopyAddr(op_desc, virtual_out_addrs, output_data_addrs.data(), custom_info_.output_addrs, + davinci_model_->SetZeroCopyAddr(op_desc, input_data_addrs, input_data_addrs.data(), custom_info_.input_addrs, + input_data_addrs.size() * kAddrLen, 0); + davinci_model_->SetZeroCopyAddr(op_desc, output_data_addrs, output_data_addrs.data(), custom_info_.output_addrs, output_data_addrs.size() * kAddrLen, 0); return SUCCESS; } @@ -712,7 +791,8 @@ Status KernelTaskInfo::InitCceTask(const domi::KernelDef &kernel_def) { ctx_.genVariableBaseSize = davinci_model_->TotalVarMemSize(); ctx_.l2ctrlSize = sm_contrl_size; - if (UpdateCceArgs(sm_desc, flowtable, kernel_def) != SUCCESS) { + ret = UpdateCceArgs(sm_desc, flowtable, kernel_def); + if (ret != SUCCESS) { GELOGE(ret, "update cce args fail"); return ret; } @@ -728,7 +808,7 @@ Status KernelTaskInfo::InitCceTask(const domi::KernelDef &kernel_def) { rtError_t rt_ret = rtMalloc(&args_, kernel_def.args_size(), RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "cce task physical memory.", kernel_def.args_size()) @@ -736,7 +816,7 @@ Status KernelTaskInfo::InitCceTask(const domi::KernelDef &kernel_def) { rtMemcpy(args_, kernel_def.args_size(), kernel_def.args().data(), kernel_def.args_size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // L2 @@ -744,13 +824,13 @@ Status KernelTaskInfo::InitCceTask(const domi::KernelDef &kernel_def) { rt_ret = rtMemAllocManaged(&sm_desc_, sm_desc.size(), RT_MEMORY_SPM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(sm_desc_, sm_desc.size(), sm_desc.data(), sm_desc.size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } return SUCCESS; @@ -801,6 +881,9 @@ Status KernelTaskInfo::InitAicpuTask(uint32_t op_index, const domi::KernelDef &k GELOGE(init_ret, "Init aicpu task ext info failed, ext_info size=%zu", ext_info.size()); return init_ret; } + GELOGI("Node[%s] type[%s] kernel_ext_info size=%zu, aicpu_ext_info_addr_=%p", op_desc_->GetName().c_str(), + op_desc_->GetType().c_str(), ext_info.size(), aicpu_ext_info_addr_); + aicpu_param_head->extInfoAddr = reinterpret_cast(aicpu_ext_info_addr_); aicpu_param_head->extInfoLength = reinterpret_cast(ext_info.size()); @@ -808,7 +891,7 @@ Status KernelTaskInfo::InitAicpuTask(uint32_t op_index, const domi::KernelDef &k rtError_t rt_ret = rtMalloc(static_cast(&args_), args_size_, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api(rtMalloc) failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "cce task physical memory.", args_size_) @@ -816,22 +899,16 @@ Status KernelTaskInfo::InitAicpuTask(uint32_t op_index, const domi::KernelDef &k rt_ret = rtMemcpy(args_, args_size_, args_addr.get(), args_size_, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api(rtMemcpy) failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } - if (PropertiesManager::Instance().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), - op_desc->GetName())) { + if (davinci_model_->GetDumpProperties().IsLayerNeedDump(davinci_model_->Name(), davinci_model_->OmName(), + op_desc->GetName())) { dump_flag_ = RT_KERNEL_DUMPFLAG; dump_args_ = static_cast(args_) + sizeof(aicpu::AicpuParamHead); } - vector virtual_io_addrs; // use virtual address for zero copy key. - const vector virtual_in_addrs = ModelUtils::GetInputDataAddrs(rts_param, op_desc, false); - const vector virtual_out_addrs = ModelUtils::GetOutputDataAddrs(rts_param, op_desc, false); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_in_addrs.begin(), virtual_in_addrs.end()); - virtual_io_addrs.insert(virtual_io_addrs.end(), virtual_out_addrs.begin(), virtual_out_addrs.end()); - davinci_model_->SetZeroCopyAddr(op_desc, virtual_io_addrs, args_addr.get(), args_, args_size_, - sizeof(aicpu::AicpuParamHead)); + davinci_model_->SetZeroCopyAddr(op_desc, io_addrs, args_addr.get(), args_, args_size_, sizeof(aicpu::AicpuParamHead)); return SUCCESS; } @@ -843,12 +920,12 @@ Status KernelTaskInfo::InitAicpuTaskExtInfo(const std::string &ext_info) { auto rt_ret = rtMalloc(&aicpu_ext_info_addr_, ext_info.size(), RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "rtMalloc ext_info error: 0x%X, size=%zu", rt_ret, ext_info.size()); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtMemcpy(aicpu_ext_info_addr_, ext_info.size(), ext_info.c_str(), ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "rtMemcpy ext_info error: 0x%X, size=%zu", rt_ret, ext_info.size()); - return FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; @@ -865,7 +942,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d rtError_t rt_ret = rtMalloc(&custom_info_.input_descs, sizeof(opTensor_t) * input_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } for (std::size_t i = 0; i < input_size; ++i) { @@ -873,7 +950,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d const_cast(&input_descs[i]), sizeof(opTensor_t), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } @@ -881,7 +958,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d rt_ret = rtMalloc(&custom_info_.input_addrs, sizeof(opTensor_t) * input_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } if (!input_data_addrs.empty()) { @@ -889,7 +966,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } @@ -897,14 +974,14 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d rt_ret = rtMalloc(&custom_info_.output_descs, sizeof(opTensor_t) * output_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } for (std::size_t i = 0; i < output_size; ++i) { rt_ret = rtMemcpy(static_cast(custom_info_.output_descs) + i, sizeof(opTensor_t), const_cast(&input_descs[i]), sizeof(opTensor_t), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } @@ -912,7 +989,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d rt_ret = rtMalloc(&custom_info_.output_addrs, sizeof(opTensor_t) * output_size, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } if (!output_data_addrs.empty()) { @@ -920,7 +997,7 @@ Status KernelTaskInfo::StoreInputOutputTensor(const std::vector &input_d RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } } @@ -982,8 +1059,8 @@ Status KernelTaskInfo::UpdateCceArgs(std::string &sm_desc, std::string &flowtabl Status status = CceUpdateKernelArgs(context, data_base_addr, weight_base_addr, var_base_addr, sm_desc, flowtable, kernel_def); if (status != SUCCESS) { - GELOGE(FAILED, "Call cce api failed"); - return FAILED; + GELOGE(status, "Call cce api failed"); + return status; } return SUCCESS; } @@ -1049,14 +1126,14 @@ Status KernelTaskInfo::SetFlowtable(std::string &flowtable, const domi::KernelDe rtError_t rt_ret = rtMalloc(&flowtable_, flowtable.size(), RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GE_PRINT_DYNAMIC_MEMORY(rtMalloc, "flowtable refresh of cce scence.", flowtable.size()) rt_ret = rtMemcpy(flowtable_, flowtable.size(), flowtable.data(), flowtable.size(), RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } // modify flowtable addr in args diff --git a/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.h b/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.h index 41ed5728..cc8edc07 100644 --- a/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/kernel_task_info.h @@ -61,6 +61,8 @@ class KernelTaskInfo : public TaskInfo { sm_desc_ = nullptr; flowtable_ = nullptr; args_ = nullptr; + superkernel_device_args_addr_ = nullptr; + superkernel_dev_nav_table_ = nullptr; } Status Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; @@ -88,6 +90,8 @@ class KernelTaskInfo : public TaskInfo { uint32_t GetSktTaskID() override { return skt_id_; } + bool CallSaveDumpInfo() override { return call_save_dump_; }; + cce::ccOpContext ctx_; FusionOpInfo fusion_op_info_; @@ -130,6 +134,7 @@ class KernelTaskInfo : public TaskInfo { void UpdateSKTTaskId(); Status SKTFinalize(); Status SuperKernelLaunch(); + uint32_t GetDumpFlag(); Status SaveSuperKernelInfo(); bool IsMarkedLastNode(); bool IsMarkedFirstNode(); @@ -153,17 +158,23 @@ class KernelTaskInfo : public TaskInfo { OpDescPtr op_desc_; DavinciModel *davinci_model_; uint32_t args_offset_ = 0; + int64_t fixed_addr_offset_ = 0; + bool call_save_dump_ = false; // aicpu ext_info device mem void *aicpu_ext_info_addr_ = nullptr; // For super kernel + void *skt_dump_args_ = nullptr; uint32_t skt_id_; std::string stub_func_name_; bool is_l1_fusion_enable_; bool is_n_batch_spilt_; int64_t group_key_; bool has_group_key_; + uint32_t skt_dump_flag_ = RT_KERNEL_DEFAULT; + void *superkernel_device_args_addr_ = nullptr; + void *superkernel_dev_nav_table_ = nullptr; struct AICPUCustomInfo { void *input_descs = nullptr; @@ -183,6 +194,9 @@ class KernelTaskInfo : public TaskInfo { void *last_sm_desc; std::vector kernel_list; std::vector arg_list; + std::vector dump_flag_list; + std::vector op_desc_list; + std::vector dump_args_list; uint32_t last_dump_flag; int64_t last_group_key; uintptr_t last_dump_args; diff --git a/src/ge/graph/load/new_model_manager/task_info/label_goto_ex_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/label_goto_ex_task_info.cc index c157b1df..75f6c121 100644 --- a/src/ge/graph/load/new_model_manager/task_info/label_goto_ex_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/label_goto_ex_task_info.cc @@ -59,7 +59,7 @@ Status LabelGotoExTaskInfo::Distribute() { rtError_t rt_ret = rtLabelGotoEx(label_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("LabelGotoExTaskInfo Distribute Success."); diff --git a/src/ge/graph/load/new_model_manager/task_info/label_set_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/label_set_task_info.cc index e8888eef..de6a1d65 100644 --- a/src/ge/graph/load/new_model_manager/task_info/label_set_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/label_set_task_info.cc @@ -59,7 +59,7 @@ Status LabelSetTaskInfo::Distribute() { rtError_t rt_ret = rtLabelSet(label_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("LabelSetTaskInfo Distribute Success."); diff --git a/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.cc index 818307eb..efefd3e2 100644 --- a/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.cc @@ -16,8 +16,8 @@ #include "graph/load/new_model_manager/task_info/label_switch_by_index_task_info.h" -#include "graph/load/new_model_manager/davinci_model.h" #include "graph/debug/ge_attr_define.h" +#include "graph/load/new_model_manager/davinci_model.h" namespace ge { constexpr uint8_t kLabelSwitchIndexNum = 1; @@ -59,7 +59,13 @@ Status LabelSwitchByIndexTaskInfo::Init(const domi::TaskDef &task_def, DavinciMo op_desc->GetName().c_str(), input_data_addr.size(), kLabelSwitchIndexNum); return INTERNAL_ERROR; } - index_value_ = input_data_addr[0]; + + if (davinci_model->IsKnownNode()) { + index_value_ = davinci_model->GetCurrentFixedAddr(fixed_addr_offset_); + } else { + index_value_ = input_data_addr[0]; + } + davinci_model->DisableZeroCopy(index_value_); std::vector label_idx_list; @@ -92,13 +98,13 @@ Status LabelSwitchByIndexTaskInfo::Init(const domi::TaskDef &task_def, DavinciMo rtError_t rt_ret = rtMalloc(&args_, args_size_, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } rt_ret = rtLabelListCpy(label_list_.data(), label_list_.size(), args_, args_size_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("LabelSwitchByIndexTaskInfo Init success, branch max: %u.", branch_max_); @@ -124,5 +130,28 @@ Status LabelSwitchByIndexTaskInfo::Distribute() { return SUCCESS; } +Status LabelSwitchByIndexTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) { + GE_CHECK_NOTNULL(davinci_model); + auto label_switch = task_def.label_switch_by_index(); + uint32_t op_index = label_switch.op_index(); + GELOGI("Begin to calculate args, op_index is: %u", op_index); + auto op_desc = davinci_model->GetOpByIndex(op_index); + GE_CHECK_NOTNULL(op_desc); + GELOGI("Calc opType[%s] args size. Node name is [%s]", op_desc->GetType().c_str(), op_desc->GetName().c_str()); + if (op_desc->GetInputsSize() != kLabelSwitchIndexNum) { + GELOGE(FAILED, "Label switch op only have one data input. Now input size is %zu", op_desc->GetInputsSize()); + return FAILED; + } + string input_tensor_name = op_desc->GetInputNameByIndex(0); + fixed_addr_offset_ = davinci_model->GetFixedAddrsSize(input_tensor_name); + auto tensor_desc = op_desc->GetInputDesc(0); + int64_t tensor_size = 0; + GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + davinci_model->SetTotalFixedAddrsSize(input_tensor_name, tensor_size); + GELOGI("Calculate stream switchn task args , tensor_size %ld, fixed_addr_offset %ld", tensor_size, + fixed_addr_offset_); + return SUCCESS; +} + REGISTER_TASK_INFO(RT_MODEL_TASK_STREAM_LABEL_SWITCH_BY_INDEX, LabelSwitchByIndexTaskInfo); } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.h b/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.h index 1a644736..4cb39c95 100644 --- a/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/label_switch_by_index_task_info.h @@ -22,7 +22,8 @@ namespace ge { class LabelSwitchByIndexTaskInfo : public TaskInfo { public: - LabelSwitchByIndexTaskInfo() : index_value_(nullptr), branch_max_(0), args_(nullptr), args_size_(0) {} + LabelSwitchByIndexTaskInfo() + : index_value_(nullptr), branch_max_(0), args_(nullptr), args_size_(0), fixed_addr_offset_(0) {} ~LabelSwitchByIndexTaskInfo() override; @@ -30,13 +31,15 @@ class LabelSwitchByIndexTaskInfo : public TaskInfo { Status Distribute() override; + Status CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; + private: void *index_value_; // switch index input. uint32_t branch_max_; // max branch count. void *args_; // label info memory. uint32_t args_size_; // label info length. - std::vector label_list_; + int64_t fixed_addr_offset_; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_LABEL_SWITCH_BY_INDEX_TASK_INFO_H_ \ No newline at end of file diff --git a/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.cc index e9d99189..8cac9f82 100644 --- a/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.cc @@ -19,11 +19,15 @@ #include "framework/common/debug/ge_log.h" #include "graph/load/new_model_manager/davinci_model.h" +namespace { +const uint32_t kAlignBytes = 64; +} + namespace ge { Status MemcpyAddrAsyncTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) { - GELOGI("MemcpyAddrAsyncTaskInfo Init Start."); + GELOGI("MemcpyAddrAsyncTaskInfo Init Start"); if (davinci_model == nullptr) { - GELOGE(PARAM_INVALID, "davinci_model is null!"); + GELOGE(PARAM_INVALID, "davinci_model is null"); return PARAM_INVALID; } @@ -32,120 +36,67 @@ Status MemcpyAddrAsyncTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel return ret; } - auto memcpy_async_def = task_def.memcpy_async(); - uint32_t op_index = memcpy_async_def.op_index(); - OpDescPtr op_desc = davinci_model->GetOpByIndex(op_index); + const auto &memcpy_async = task_def.memcpy_async(); + OpDescPtr op_desc = davinci_model->GetOpByIndex(memcpy_async.op_index()); if (op_desc == nullptr) { - GELOGE(INTERNAL_ERROR, "Init MemcpyAddrAsyncTaskInfo error, index is out of range!"); + GELOGE(INTERNAL_ERROR, "Task op index:%u out of range", memcpy_async.op_index()); return INTERNAL_ERROR; } - uint64_t logic_dst = memcpy_async_def.dst(); - uint64_t logic_src = memcpy_async_def.src(); - - dst_max_ = memcpy_async_def.dst_max(); - - uint64_t update_base_addr = 0; - ret = GetUpdateBaseAddr(davinci_model, logic_src, update_base_addr); + ret = ModelUtils::GetRtAddress(davinci_model->GetRuntimeParam(), memcpy_async.src(), src_); if (ret != SUCCESS) { return ret; } - src_ = reinterpret_cast(update_base_addr + logic_src); - if (src_ == nullptr) { - GELOGE(PARAM_INVALID, "src_ is null!"); - return PARAM_INVALID; - } - uint64_t mem_base = reinterpret_cast(davinci_model->MemBase()); - uint64_t logic_mem_base = davinci_model->GetRtBaseAddr(); - dst_ = reinterpret_cast(reinterpret_cast(mem_base + (logic_dst - logic_mem_base))); - if (dst_ == nullptr) { - GELOGE(PARAM_INVALID, "dst_ is null!"); - return PARAM_INVALID; + ret = ModelUtils::GetRtAddress(davinci_model->GetRuntimeParam(), memcpy_async.dst(), dst_); + if (ret != SUCCESS) { + return ret; } vector io_addrs; io_addrs.emplace_back(src_); io_addrs.emplace_back(dst_); - count_ = memcpy_async_def.count(); - kind_ = memcpy_async_def.kind(); - // malloc args memory size_t args_size = sizeof(void *) * io_addrs.size(); - rtError_t rt_ret = rtMalloc(&args_, args_size, RT_MEMORY_HBM); + rtError_t rt_ret = rtMalloc(&args_, args_size + kAlignBytes, RT_MEMORY_HBM); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } + args_align_ = reinterpret_cast((reinterpret_cast(args_) / kAlignBytes + 1) * kAlignBytes); // copy orign src/dst - GELOGI("src_args:%p, destMax:%zu, src_:%p, dst_args:%p, dst_:%p, count=%zu", args_, args_size, src_, - static_cast(args_) + args_size, dst_, io_addrs.size()); - rt_ret = rtMemcpy(args_, args_size, io_addrs.data(), args_size, RT_MEMCPY_HOST_TO_DEVICE); + GELOGI("src_args:%p, destMax:%zu, src_:%p, dst_args:%p, dst_:%p, count=%zu", args_align_, args_size, src_, + static_cast(args_align_) + args_size, dst_, io_addrs.size()); + rt_ret = rtMemcpy(args_align_, args_size, io_addrs.data(), args_size, RT_MEMCPY_HOST_TO_DEVICE); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api for src failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } - // Just dest addr need zero copy. - davinci_model->SetZeroCopyAddr(op_desc, {dst_}, io_addrs.data(), args_, args_size, sizeof(void *)); - - GELOGI("InitMemcpyAddrAsyncTaskInfo, logic_src:%p, logic_dst:%p, src:%p, dst:%p, src_args:%p, dst_args:%p", - reinterpret_cast(reinterpret_cast(logic_src)), - reinterpret_cast(reinterpret_cast(logic_dst)), src_, dst_, args_, - reinterpret_cast(reinterpret_cast(args_) + args_size)); + count_ = memcpy_async.count(); + kind_ = memcpy_async.kind(); + dst_max_ = memcpy_async.dst_max(); + GELOGI("InitMemcpyAddrAsyncTaskInfo, logic[0x%lx, 0x%lx], src:%p, dst:%p, max:%lu, count:%lu, args:%p, size:%zu", + memcpy_async.src(), memcpy_async.dst(), src_, dst_, dst_max_, count_, args_align_, args_size); + davinci_model->SetZeroCopyAddr(op_desc, io_addrs, io_addrs.data(), args_align_, args_size, 0); return SUCCESS; } Status MemcpyAddrAsyncTaskInfo::Distribute() { - GELOGI("MemcpyAddrAsyncTaskInfo Distribute Start."); - GELOGI("Distribute MemcpyAddrAsync, dst_max:%lu, count:%lu, kind:%u.", dst_max_, count_, kind_); + GELOGI("MemcpyAddrAsyncTaskInfo Distribute Start, dst_max:%lu, count:%lu, kind:%u", dst_max_, count_, kind_); - rtError_t rt_ret = rtMemcpyAsync(reinterpret_cast(reinterpret_cast(args_) + sizeof(void *)), - dst_max_, args_, count_, static_cast(kind_), stream_); + rtError_t rt_ret = rtMemcpyAsync(reinterpret_cast(reinterpret_cast(args_align_) + sizeof(void *)), + dst_max_, args_align_, count_, static_cast(kind_), stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } return SUCCESS; } -Status MemcpyAddrAsyncTaskInfo::GetUpdateBaseAddr(DavinciModel *davinci_model, uint64_t update_addr, - uint64_t &base_addr) { - GE_CHECK_NOTNULL(davinci_model); - uint64_t data_base_addr = - static_cast(reinterpret_cast(davinci_model->MemBase())) - davinci_model->GetRtBaseAddr(); - uint64_t weight_base_addr = static_cast(reinterpret_cast(davinci_model->WeightsMemBase())) - - davinci_model->GetRtWeightAddr(); - uint64_t var_base_addr = - static_cast(reinterpret_cast(davinci_model->VarMemBase())) - davinci_model->GetRtVarAddr(); - - uint64_t data_base_addr_start = davinci_model->GetRtBaseAddr(); - uint64_t data_base_addr_end = davinci_model->GetRtBaseAddr() + davinci_model->TotalMemSize(); - uint64_t wight_base_addr_start = davinci_model->GetRtWeightAddr(); - uint64_t wight_base_addr_end = davinci_model->GetRtWeightAddr() + davinci_model->TotalWeightsMemSize(); - uint64_t varible_base_addr_start = davinci_model->GetRtVarAddr(); - uint64_t varible_base_addr_end = davinci_model->GetRtVarAddr() + davinci_model->TotalVarMemSize(); - - if ((data_base_addr_start <= update_addr) && (update_addr <= data_base_addr_end)) { - base_addr = data_base_addr; - GELOGI("The update_addr is data address."); - } else if ((wight_base_addr_start <= update_addr) && (update_addr <= wight_base_addr_end)) { - base_addr = weight_base_addr; - GELOGI("The update_addr is weight address."); - } else if ((varible_base_addr_start <= update_addr) && (update_addr <= varible_base_addr_end)) { - base_addr = var_base_addr; - GELOGI("The update_addr is variable address."); - } else if (update_addr != 0) { - base_addr = 0; - GELOGE(PARAM_INVALID, "The update_addr is abnormal."); - return PARAM_INVALID; - } - return SUCCESS; -} - REGISTER_TASK_INFO(RT_MODEL_TASK_MEMCPY_ADDR_ASYNC, MemcpyAddrAsyncTaskInfo); } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.h b/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.h index 9252e43a..90aad9b7 100644 --- a/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/memcpy_addr_async_task_info.h @@ -16,12 +16,14 @@ #ifndef GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_MEMCPY_ADDR_ASYNC_TASK_INFO_H_ #define GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_MEMCPY_ADDR_ASYNC_TASK_INFO_H_ + #include "graph/load/new_model_manager/task_info/task_info.h" namespace ge { class MemcpyAddrAsyncTaskInfo : public TaskInfo { public: - MemcpyAddrAsyncTaskInfo() : dst_(nullptr), dst_max_(0), src_(nullptr), args_(nullptr), count_(0), kind_(0) {} + MemcpyAddrAsyncTaskInfo() + : dst_(nullptr), dst_max_(0), src_(nullptr), args_(nullptr), args_align_(nullptr), count_(0), kind_(0) {} ~MemcpyAddrAsyncTaskInfo() override { src_ = nullptr; @@ -32,9 +34,8 @@ class MemcpyAddrAsyncTaskInfo : public TaskInfo { if (ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", ret); } + args_ = nullptr; } - - args_ = nullptr; } Status Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; @@ -42,12 +43,11 @@ class MemcpyAddrAsyncTaskInfo : public TaskInfo { Status Distribute() override; private: - Status GetUpdateBaseAddr(DavinciModel *davinci_model, uint64_t update_addr, uint64_t &base_addr); - - void *dst_; + uint8_t *dst_; uint64_t dst_max_; - void *src_; + uint8_t *src_; void *args_; + void *args_align_; uint64_t count_; uint32_t kind_; }; diff --git a/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.cc index 82eabe69..1cc18a85 100644 --- a/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.cc @@ -21,9 +21,9 @@ namespace ge { Status MemcpyAsyncTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) { - GELOGI("MemcpyAsyncTaskInfo Init Start."); + GELOGI("MemcpyAsyncTaskInfo Init Start"); if (davinci_model == nullptr) { - GELOGE(PARAM_INVALID, "davinci_model is null!"); + GELOGE(PARAM_INVALID, "davinci_model is null"); return PARAM_INVALID; } @@ -32,76 +32,79 @@ Status MemcpyAsyncTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *da return ret; } - auto memcpy_async_def = task_def.memcpy_async(); - uint64_t logic_dst = memcpy_async_def.dst(); - uint64_t logic_src = memcpy_async_def.src(); - - dst_max_ = memcpy_async_def.dst_max(); - - uint64_t update_base_addr = 0; - ret = GetUpdateBaseAddr(davinci_model, logic_src, update_base_addr); + memcpy_async = task_def.memcpy_async(); + count_ = memcpy_async.count(); + kind_ = memcpy_async.kind(); + dst_max_ = memcpy_async.dst_max(); + if (davinci_model->IsKnownNode()) { + src_ = reinterpret_cast(davinci_model_->GetCurrentArgsAddr(args_offset_)); + dst_ = reinterpret_cast(reinterpret_cast(src_) + sizeof(void *)); + // for zero copy + kind_ = RT_MEMCPY_ADDR_DEVICE_TO_DEVICE; + GELOGI("MemcpyAsyncTaskInfo src_ %p, dst_ %p, args_offset %u.", src_, dst_, args_offset_); + return SUCCESS; + } + ret = ModelUtils::GetRtAddress(davinci_model->GetRuntimeParam(), memcpy_async.src(), src_); if (ret != SUCCESS) { return ret; } - src_ = reinterpret_cast(update_base_addr + logic_src); - davinci_model->DisableZeroCopy(src_); - uint64_t mem_base = reinterpret_cast(davinci_model->MemBase()); - uint64_t logic_mem_base = davinci_model->GetRtBaseAddr(); - dst_ = reinterpret_cast(mem_base + (logic_dst - logic_mem_base)); + ret = ModelUtils::GetRtAddress(davinci_model->GetRuntimeParam(), memcpy_async.dst(), dst_); + if (ret != SUCCESS) { + return ret; + } - count_ = memcpy_async_def.count(); - kind_ = memcpy_async_def.kind(); - GELOGI("MemcpyAsyncTaskInfo Init Success, logic_src:%p, logic_dst:%p, src:%p, dst:%p", - reinterpret_cast(reinterpret_cast(logic_src)), - reinterpret_cast(reinterpret_cast(logic_dst)), src_, dst_); + GELOGI("MemcpyAsyncTaskInfo Init Success, logic[0x%lx, 0x%lx], src:%p, dst:%p, max:%lu, count:%lu", + memcpy_async.src(), memcpy_async.dst(), src_, dst_, dst_max_, count_); + davinci_model->DisableZeroCopy(src_); + davinci_model->DisableZeroCopy(dst_); return SUCCESS; } Status MemcpyAsyncTaskInfo::Distribute() { - GELOGI("MemcpyAsyncTaskInfo Distribute Start. dst_max:%lu, count:%lu, kind:%u.", dst_max_, count_, kind_); + GELOGI("MemcpyAsyncTaskInfo Distribute Start. dst_max:%lu, count:%lu, kind:%u", dst_max_, count_, kind_); rtError_t rt_ret = rtMemcpyAsync(dst_, dst_max_, src_, count_, static_cast(kind_), stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } - GELOGI("MemcpyAsyncTaskInfo Distribute Success."); + GELOGI("MemcpyAsyncTaskInfo Distribute Success"); return SUCCESS; } -Status MemcpyAsyncTaskInfo::GetUpdateBaseAddr(DavinciModel *davinci_model, uint64_t update_addr, uint64_t &base_addr) { - GE_CHECK_NOTNULL(davinci_model); - uint64_t data_base_addr = - reinterpret_cast(reinterpret_cast(davinci_model->MemBase())) - davinci_model->GetRtBaseAddr(); - uint64_t weight_base_addr = reinterpret_cast(reinterpret_cast(davinci_model->WeightsMemBase())) - - davinci_model->GetRtWeightAddr(); - uint64_t var_base_addr = reinterpret_cast(reinterpret_cast(davinci_model->VarMemBase())) - - davinci_model->GetRtVarAddr(); - - uint64_t data_base_addr_start = davinci_model->GetRtBaseAddr(); - uint64_t data_base_addr_end = davinci_model->GetRtBaseAddr() + davinci_model->TotalMemSize(); - uint64_t wight_base_addr_start = davinci_model->GetRtWeightAddr(); - uint64_t wight_base_addr_end = davinci_model->GetRtWeightAddr() + davinci_model->TotalWeightsMemSize(); - uint64_t varible_base_addr_start = davinci_model->GetRtVarAddr(); - uint64_t varible_base_addr_end = davinci_model->GetRtVarAddr() + davinci_model->TotalVarMemSize(); - - if ((data_base_addr_start <= update_addr) && (update_addr <= data_base_addr_end)) { - base_addr = data_base_addr; - GELOGI("The update_addr is data address."); - } else if ((wight_base_addr_start <= update_addr) && (update_addr <= wight_base_addr_end)) { - base_addr = weight_base_addr; - GELOGI("The update_addr is weight address."); - } else if ((varible_base_addr_start <= update_addr) && (update_addr <= varible_base_addr_end)) { - base_addr = var_base_addr; - GELOGI("The update_addr is variable address."); - } else if (update_addr != 0) { - base_addr = 0; - GELOGE(PARAM_INVALID, "The update_addr is abnormal."); - return PARAM_INVALID; +Status MemcpyAsyncTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) { + // the num of src and dst size is 2 + uint32_t args_size = sizeof(void *) * 2; + args_offset_ = davinci_model->GetTotalArgsSize(); + davinci_model->SetTotalArgsSize(args_size); + davinci_model_ = davinci_model; + GELOGI("MemcpyAsyncTaskInfo kernel args_size %u, args_offset %u", args_size, args_offset_); + return SUCCESS; +} + +Status MemcpyAsyncTaskInfo::UpdateArgs() { + GELOGI("MemcpyAsyncTaskInfo::UpdateArgs in."); + GE_CHECK_NOTNULL(davinci_model_); + Status ret = ModelUtils::GetRtAddress(davinci_model_->GetRuntimeParam(), memcpy_async.src(), src_); + if (ret != SUCCESS) { + return ret; + } + + ret = ModelUtils::GetRtAddress(davinci_model_->GetRuntimeParam(), memcpy_async.dst(), dst_); + if (ret != SUCCESS) { + return ret; } + + vector io_addrs; + io_addrs.emplace_back(reinterpret_cast(src_)); + io_addrs.emplace_back(reinterpret_cast(dst_)); + + davinci_model_->SetTotalIOAddrs(io_addrs); + + GELOGI("MemcpyAsyncTaskInfo::UpdateArgs success."); return SUCCESS; } diff --git a/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.h b/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.h index 02872f34..c3daa862 100644 --- a/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/memcpy_async_task_info.h @@ -16,6 +16,7 @@ #ifndef GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_MEMCPY_ASYNC_TASK_INFO_H_ #define GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_MEMCPY_ASYNC_TASK_INFO_H_ + #include "graph/load/new_model_manager/task_info/task_info.h" namespace ge { @@ -32,14 +33,19 @@ class MemcpyAsyncTaskInfo : public TaskInfo { Status Distribute() override; - private: - Status GetUpdateBaseAddr(DavinciModel *davinci_model, uint64_t update_addr, uint64_t &base_addr); + Status UpdateArgs() override; - void *dst_; + Status CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; + + private: + uint8_t *dst_; uint64_t dst_max_; - void *src_; + uint8_t *src_; uint64_t count_; uint32_t kind_; + DavinciModel *davinci_model_ = nullptr; + uint32_t args_offset_ = 0; + domi::MemcpyAsyncDef memcpy_async; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_MEMCPY_ASYNC_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/profiler_trace_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/profiler_trace_task_info.cc index 1232ddb2..fd5f4f4c 100644 --- a/src/ge/graph/load/new_model_manager/task_info/profiler_trace_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/profiler_trace_task_info.cc @@ -47,7 +47,7 @@ Status ProfilerTraceTaskInfo::Distribute() { rtError_t rt_ret = rtProfilerTrace(log_id_, notify_, flat_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("ProfilerTraceTaskInfo Distribute Success."); diff --git a/src/ge/graph/load/new_model_manager/task_info/stream_active_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/stream_active_task_info.cc index c30cad09..f48f64e3 100644 --- a/src/ge/graph/load/new_model_manager/task_info/stream_active_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/stream_active_task_info.cc @@ -74,7 +74,7 @@ Status StreamActiveTaskInfo::Distribute() { rtError_t rt_ret = rtStreamActive(active_stream_, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("StreamActiveTaskInfo Distribute Success. activeStreamID:%p.", active_stream_); diff --git a/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.cc index a1d2f143..45db2be5 100644 --- a/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.cc @@ -42,16 +42,11 @@ Status StreamSwitchTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *d auto stream_switch_def = task_def.stream_switch(); uint32_t op_index = stream_switch_def.op_index(); - // get StreamSwitch op OpDescPtr op_desc = davinci_model->GetOpByIndex(op_index); GE_CHECK_NOTNULL(op_desc); auto input_data_addr = ModelUtils::GetInputDataAddrs(davinci_model->GetRuntimeParam(), op_desc); - if (!input_data_addr.empty() && input_data_addr.size() >= STREAM_SWITCH_INPUT_NUM) { - input_ptr_ = input_data_addr[0]; - value_ptr_ = input_data_addr[1]; - } - + SetInputAndValuePtr(davinci_model, input_data_addr); uint32_t cond = 0; if (!AttrUtils::GetInt(op_desc, ATTR_NAME_STREAM_SWITCH_COND, cond)) { GELOGE(INTERNAL_ERROR, "StreamSwitchOp get attr STREAM_SWITCH_COND fail."); @@ -109,12 +104,48 @@ Status StreamSwitchTaskInfo::Distribute() { rtError_t rt_ret = rtStreamSwitchEx(input_ptr_, cond_, value_ptr_, true_stream_, stream_, data_type_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("StreamSwitchTaskInfo Distribute Success. cond:%d, stream:%p, datatype:%d.", cond_, true_stream_, data_type_); return SUCCESS; } +Status StreamSwitchTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) { + GE_CHECK_NOTNULL(davinci_model); + auto stream_switch_def = task_def.stream_switch(); + uint32_t op_index = stream_switch_def.op_index(); + GELOGI("Begin to calculate args, op_index is: %u", op_index); + auto op_desc = davinci_model->GetOpByIndex(op_index); + GE_CHECK_NOTNULL(op_desc); + GELOGI("Calc opType[%s] args size. Node name is [%s]", op_desc->GetType().c_str(), op_desc->GetName().c_str()); + if (op_desc->GetInputsSize() != STREAM_SWITCH_INPUT_NUM) { + GELOGE(FAILED, "Stream switch op only have one data input. Now input size is %zu", op_desc->GetInputsSize()); + return FAILED; + } + for (uint32_t i = 0; i < STREAM_SWITCH_INPUT_NUM; ++i) { + string input_tensor_name = op_desc->GetInputNameByIndex(i); + int64_t fixed_addr_offset = davinci_model->GetFixedAddrsSize(input_tensor_name); + fixed_addr_offset_.emplace_back(fixed_addr_offset); + auto tensor_desc = op_desc->GetInputDesc(i); + int64_t tensor_size = 0; + GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + davinci_model->SetTotalFixedAddrsSize(input_tensor_name, tensor_size); + GELOGI("Calculate stream switch task args , tensor size is %ld, fixed addr[%u] offset %ld", tensor_size, i, + fixed_addr_offset); + } + return SUCCESS; +} +void StreamSwitchTaskInfo::SetInputAndValuePtr(DavinciModel *davinci_model, const vector &input_data_addrs) { + if (davinci_model->IsKnownNode() && fixed_addr_offset_.size() == STREAM_SWITCH_INPUT_NUM) { + input_ptr_ = davinci_model->GetCurrentFixedAddr(fixed_addr_offset_[0]); + value_ptr_ = davinci_model->GetCurrentFixedAddr(fixed_addr_offset_[1]); + } else { + if (!input_data_addrs.empty() && input_data_addrs.size() >= STREAM_SWITCH_INPUT_NUM) { + input_ptr_ = input_data_addrs[0]; + value_ptr_ = input_data_addrs[1]; + } + } +} REGISTER_TASK_INFO(RT_MODEL_TASK_STREAM_SWITCH, StreamSwitchTaskInfo); } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.h b/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.h index 07509c7c..e6e8339a 100644 --- a/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/stream_switch_task_info.h @@ -39,13 +39,18 @@ class StreamSwitchTaskInfo : public TaskInfo { Status Distribute() override; + Status CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; + private: + void SetInputAndValuePtr(DavinciModel *davinci_model, const vector &input_data_addrs); void *input_ptr_; rtCondition_t cond_; void *value_ptr_; rtStream_t true_stream_; uint32_t true_stream_id_; rtSwitchDataType_t data_type_; + static const uint32_t kInputNum = 2; + vector fixed_addr_offset_; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_STREAM_SWITCH_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.cc b/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.cc index 29b107bd..d134dfdd 100644 --- a/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.cc +++ b/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.cc @@ -22,20 +22,15 @@ #include "graph/load/new_model_manager/model_utils.h" namespace { -const uint32_t kDynamicBtachParamNum = 1; -const uint32_t kDynamicResolutionParamNum = 2; -} // namespace +const uint8_t kStreamSwitchnInputNum = 1; +} namespace ge { Status StreamSwitchNTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel *davinci_model) { GELOGI("StreamSwitchNTaskInfo Init Start."); - if (davinci_model == nullptr) { - GELOGE(PARAM_INVALID, "davinci_model is null!"); - return PARAM_INVALID; - } + GE_CHECK_NOTNULL(davinci_model); - Status ret = SetStream(task_def.stream_id(), davinci_model->GetStreamList()); - if (ret != SUCCESS) { + if (SetStream(task_def.stream_id(), davinci_model->GetStreamList()) != SUCCESS) { return FAILED; } @@ -48,10 +43,6 @@ Status StreamSwitchNTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel * // set size_ input_size_ = stream_switchn_def.size(); - if (input_size_ != kDynamicBtachParamNum && input_size_ != kDynamicResolutionParamNum) { - GELOGE(FAILED, "The size of dynamic batch or imagesize input is 1 or 2, now it is %u.", input_size_); - return FAILED; - } // set value_ptr_ auto value = stream_switchn_def.target_value(); @@ -75,14 +66,16 @@ Status StreamSwitchNTaskInfo::Init(const domi::TaskDef &task_def, DavinciModel * GELOGE(FAILED, "Get true stream ptr of switchN op failed."); return FAILED; } - - // set input_ptr_ - auto input_data_addr = ModelUtils::GetInputDataAddrs(davinci_model->GetRuntimeParam(), op_desc); - if (input_data_addr.empty()) { - GELOGE(FAILED, "Input data addr is nullptr."); - return FAILED; + if (davinci_model->IsKnownNode()) { + input_ptr_ = davinci_model->GetCurrentFixedAddr(args_offset_); + } else { + auto input_data_addr = ModelUtils::GetInputDataAddrs(davinci_model->GetRuntimeParam(), op_desc); + if (input_data_addr.empty()) { + GELOGE(FAILED, "Input data addr is nullptr."); + return FAILED; + } + input_ptr_ = input_data_addr[0]; } - input_ptr_ = input_data_addr[0]; davinci_model->DisableZeroCopy(input_ptr_); GELOGI("StreamSwitchNTaskInfo Init Success, inputSize:%u, elementSize:%d, trueStreamID:%ld.", input_size_, element_size_, op_desc->GetStreamId()); @@ -96,7 +89,7 @@ Status StreamSwitchNTaskInfo::Distribute() { rtStreamSwitchN(input_ptr_, input_size_, value_ptr_, true_stream_ptr_, element_size_, stream_, data_type_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Call rt api failed, ret: 0x%X", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } GELOGI("StreamSwitchNTaskInfo Distribute Success. inputSize:%u, elementSize:%d, datatype:%d.", input_size_, @@ -140,5 +133,26 @@ Status StreamSwitchNTaskInfo::GetTrueStreamPtr(const OpDescPtr &op_desc, Davinci return SUCCESS; } +Status StreamSwitchNTaskInfo::CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) { + GE_CHECK_NOTNULL(davinci_model); + auto stream_switchn_def = task_def.stream_switch_n(); + uint32_t op_index = stream_switchn_def.op_index(); + GELOGI("Begin to calculate args, op_index is: %u", op_index); + auto op_desc = davinci_model->GetOpByIndex(op_index); + GE_CHECK_NOTNULL(op_desc); + GELOGI("Calc opType[%s] args size. Node name is [%s]", op_desc->GetType().c_str(), op_desc->GetName().c_str()); + if (op_desc->GetInputsSize() != kStreamSwitchnInputNum) { + GELOGE(FAILED, "Stream switchn op only have one data input. Now input size is %zu", op_desc->GetInputsSize()); + return FAILED; + } + string input_tensor_name = op_desc->GetInputNameByIndex(0); + args_offset_ = davinci_model->GetFixedAddrsSize(input_tensor_name); + auto tensor_desc = op_desc->GetInputDesc(0); + int64_t tensor_size = 0; + GE_CHK_STATUS(TensorUtils::GetSize(tensor_desc, tensor_size)); + davinci_model->SetTotalFixedAddrsSize(input_tensor_name, tensor_size); + GELOGI("Calculate stream switchn task args , tensor_size %ld, args_offset %ld", tensor_size, args_offset_); + return SUCCESS; +} REGISTER_TASK_INFO(RT_MODEL_TASK_STREAM_SWITCH_N, StreamSwitchNTaskInfo); } // namespace ge \ No newline at end of file diff --git a/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.h b/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.h index d1002da7..1a96243a 100644 --- a/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/stream_switchn_task_info.h @@ -29,7 +29,8 @@ class StreamSwitchNTaskInfo : public TaskInfo { value_ptr_(nullptr), true_stream_ptr_(nullptr), element_size_(0), - data_type_(RT_SWITCH_INT64) {} + data_type_(RT_SWITCH_INT64), + args_offset_(0) {} ~StreamSwitchNTaskInfo() override {} @@ -37,6 +38,8 @@ class StreamSwitchNTaskInfo : public TaskInfo { Status Distribute() override; + Status CalculateArgs(const domi::TaskDef &task_def, DavinciModel *davinci_model) override; + private: Status GetTrueStreamPtr(const OpDescPtr &op_desc, DavinciModel *davinci_model); void *input_ptr_; @@ -47,6 +50,7 @@ class StreamSwitchNTaskInfo : public TaskInfo { rtSwitchDataType_t data_type_; vector true_stream_list_; vector value_list_; + int64_t args_offset_; }; } // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_STREAM_SWITCHN_TASK_INFO_H_ diff --git a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc index b8fc77ac..100a4fea 100644 --- a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc +++ b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.cc @@ -26,13 +26,15 @@ Status SuperKernel::Launch(rtStream_t stream, uint32_t dump_flag) { reinterpret_cast(reinterpret_cast(this->GetNavTableSize()))}; rtError_t rt_ret = rtMalloc((void **)&(device_args_addr_), sizeof(args), RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc failied. error: 0x%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc failied. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtMemcpy((void *)device_args_addr_, sizeof(args), (void *)args, sizeof(args), RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy failied. error: 0x%X", rt_ret); return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy failied. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtKernelLaunchWithFlag((void *const)func_stub_, block_dim_, device_args_addr_, sizeof(args), NULL, stream, dump_flag); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtKernelLaunchWithFlag failied. error: 0x%X", rt_ret); - return FAILED;) + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtKernelLaunchWithFlag failied. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) return SUCCESS; } } // namespace skt diff --git a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.h b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.h index 1c31acd1..b7e76af0 100644 --- a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.h +++ b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel.h @@ -34,22 +34,13 @@ class SuperKernel { public: SuperKernel(const void *stub, void *ptr, uint64_t sz, uint32_t dim) : func_stub_(stub), dev_nav_table_(ptr), nav_table_size_(sz), block_dim_(dim) {} - ~SuperKernel() { - // free memory when all releasing - if (device_args_addr_ != nullptr) { - GE_CHK_RT(rtFree(device_args_addr_)); - GELOGI("SKT: super_kernel args addr free."); - } - if (dev_nav_table_ != nullptr) { - GE_CHK_RT(rtFree(dev_nav_table_)); - GELOGI("SKT: super_kernel args addr free."); - } - } + ~SuperKernel() = default; Status Launch(rtStream_t stream, uint32_t dump_flag); const void *GetFuncStub() const { return func_stub_; } - const void *GetNavTablePtr() const { return dev_nav_table_; } uint64_t GetNavTableSize() const { return nav_table_size_; } uint32_t GetBlockDim() const { return block_dim_; } + void *GetNavTablePtr() const { return dev_nav_table_; } + void *GetDeviceArgsPtr() const { return device_args_addr_; } }; } // namespace skt } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc index d2ad474a..ca42b4e2 100644 --- a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc +++ b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.cc @@ -33,30 +33,19 @@ Status SuperKernelFactory::Init() { } rtError_t rt_ret; rt_ret = rtGetFunctionByName(this->sk_stub_name_.c_str(), &this->func_stub_); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtGetFunctionByName " "failed. stub_func: %s, please export LD_LIBRARY_PATH for " "libcce_aicore.so", this->sk_stub_name_.c_str()); - return FAILED;) + return RT_ERROR_TO_GE_STATUS(rt_ret);) rt_ret = rtGetAddrByFun(this->func_stub_, &this->func_ptr_); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtGetAddrByFun failed. error: 0x%X", rt_ret); - return FAILED;) - if (this->use_physical_address_ != nullptr) { - void *skt_func = nullptr; - rt_ret = rtKernelConfigTransArg(this->func_ptr_, sizeof(uint64_t), 0, &skt_func); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtKernelConfigTransArg failed. error: 0x%X", rt_ret); - return FAILED;) - GELOGD( - "SKT: fuseKernels super_kernel_template subFunc %p, device func " - "address %p, device physic PC %p", - this->func_stub_, this->func_ptr_, skt_func); - } else { - GELOGD( - "SKT: fuseKernels super_kernel_template subFunc %p, device func " - "address %p", - this->func_stub_, this->func_ptr_); - } + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtGetAddrByFun failed. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) + GELOGD( + "SKT: fuseKernels super_kernel_template subFunc %p, device func " + "address %p", + this->func_stub_, this->func_ptr_); } is_init_ = true; @@ -71,7 +60,8 @@ Status SuperKernelFactory::Uninitialize() { } Status SuperKernelFactory::FuseKernels(const std::vector &stub_func_list, - const std::vector &args_addr_list, uint32_t block_dim, SuperKernel *&h) { + const std::vector &args_addr_list, uint32_t block_dim, + std::unique_ptr &h) { // Iterate through the ops to be fused // Each subkernel to be fused contains 2 fields: fn address offset, args // address. @@ -101,70 +91,29 @@ Status SuperKernelFactory::FuseKernels(const std::vector &stub_func_list rtError_t rt_ret; void *hbm_nav_table_addr = nullptr; - if (this->use_physical_address_ != nullptr) { - for (unsigned i = 0; i < stub_func_list.size(); i++) { - void *sub_device_func = nullptr; - rt_ret = rtGetAddrByFun(stub_func_list[i], &sub_device_func); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtGetAddrByFun failed. error: 0x%X", rt_ret); - return FAILED;) - void *sub_device_func_pys = nullptr; - void *args_addr_pys = nullptr; - rt_ret = rtKernelConfigTransArg(sub_device_func, sizeof(uint64_t), 0, &sub_device_func_pys); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtKernelConfigTransArg failed. error: 0x%X", rt_ret); - return FAILED;) - rt_ret = rtKernelConfigTransArg(args_addr_list[i], sizeof(uint64_t), 0, &args_addr_pys); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtKernelConfigTransArg failed. error: 0x%X", rt_ret); - return FAILED;) - GELOGD( - "SKT: fuseKernels subFunc %p, device func address %p, device " - "physic func address %p", - stub_func_list[i], sub_device_func, sub_device_func_pys); - // store two uint64_t address - // address divided by 4 because of 32bits encoding, call offset will *4 when calculating - nav_table[i * 2] = reinterpret_cast(reinterpret_cast(sub_device_func_pys)) / 4; - GELOGD("SKT: CALL offset %lu", nav_table[i * 2]); - nav_table[i * 2 + 1] = reinterpret_cast(reinterpret_cast(args_addr_pys)); - - GELOGD("SKT: fuseKernels args base address %lu", nav_table[i * 2 + 1]); - } - - void *hbm_nav_table_addr_pys = nullptr; - rt_ret = rtMalloc((void **)&hbm_nav_table_addr, nav_table_size, RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc failed. error: 0x%X", rt_ret); return FAILED;) - rt_ret = - rtMemcpy((void *)hbm_nav_table_addr, nav_table_size, (void *)nav_table, nav_table_size, RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy failed. error: 0x%X", rt_ret); - GE_CHK_RT(rtFree(hbm_nav_table_addr)); return FAILED;) - rt_ret = rtKernelConfigTransArg(hbm_nav_table_addr, sizeof(uint64_t), 0, &hbm_nav_table_addr_pys); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtKernelConfigTransArg failed. error: 0x%X", rt_ret); - GE_CHK_RT(rtFree(hbm_nav_table_addr)); return FAILED;) - - GELOGD("SKT: hbm_nav_table_addr %p, hbm_nav_table_addr_pys %p", hbm_nav_table_addr, hbm_nav_table_addr_pys); - // Create the necessary metadata for the super kernel - h = new SuperKernel(this->func_stub_, hbm_nav_table_addr_pys, nav_table_size, block_dim); - } else { - for (unsigned i = 0; i < stub_func_list.size(); i++) { - void *sub_device_func = nullptr; - rt_ret = rtGetAddrByFun(stub_func_list[i], &sub_device_func); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtGetAddrByFun failed. error: 0x%X", rt_ret); - return FAILED;) - GELOGD("SKT: fuseKernels subFunc %p, device func address %p", stub_func_list[i], sub_device_func); - // store two uint64_t address - // address divided by 4 because of 32bits encoding, call offset will *4 when calculating - nav_table[i * 2] = reinterpret_cast(reinterpret_cast(sub_device_func)) / 4; - GELOGD("SKT: CALL offet %lu", nav_table[i * 2]); - nav_table[i * 2 + 1] = reinterpret_cast(reinterpret_cast(args_addr_list[i])); - GELOGD("SKT: fuseKernels args base address %lu", nav_table[i * 2 + 1]); - } - rt_ret = rtMalloc((void **)&hbm_nav_table_addr, nav_table_size, RT_MEMORY_HBM); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMalloc failed. error: 0x%X", rt_ret); return FAILED;) - rt_ret = - rtMemcpy((void *)hbm_nav_table_addr, nav_table_size, (void *)nav_table, nav_table_size, RT_MEMCPY_HOST_TO_DEVICE); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtMemcpy failed. error: 0x%X", rt_ret); - GE_CHK_RT(rtFree(hbm_nav_table_addr)); return FAILED;) - // Create the necessary metadata for the super kernel - h = new SuperKernel(this->func_stub_, hbm_nav_table_addr, nav_table_size, block_dim); + for (unsigned i = 0; i < stub_func_list.size(); i++) { + void *sub_device_func = nullptr; + rt_ret = rtGetAddrByFun(stub_func_list[i], &sub_device_func); + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtGetAddrByFun failed. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) + GELOGD("SKT: fuseKernels subFunc %p, device func address %p", stub_func_list[i], sub_device_func); + // store two uint64_t address + // address divided by 4 because of 32bits encoding, call offset will *4 when calculating + nav_table[i * 2] = reinterpret_cast(reinterpret_cast(sub_device_func)) / 4; + GELOGD("SKT: CALL offet %lu", nav_table[i * 2]); + nav_table[i * 2 + 1] = reinterpret_cast(reinterpret_cast(args_addr_list[i])); + GELOGD("SKT: fuseKernels args base address %lu", nav_table[i * 2 + 1]); } + rt_ret = rtMalloc((void **)&hbm_nav_table_addr, nav_table_size, RT_MEMORY_HBM); + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMalloc failed. error: 0x%X", rt_ret); + return RT_ERROR_TO_GE_STATUS(rt_ret);) + rt_ret = + rtMemcpy((void *)hbm_nav_table_addr, nav_table_size, (void *)nav_table, nav_table_size, RT_MEMCPY_HOST_TO_DEVICE); + GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(RT_FAILED, "rtMemcpy failed. error: 0x%X", rt_ret); + GE_CHK_RT(rtFree(hbm_nav_table_addr)); return RT_ERROR_TO_GE_STATUS(rt_ret);) + // Create the necessary metadata for the super kernel + h = + std::unique_ptr(new SuperKernel(this->func_stub_, hbm_nav_table_addr, nav_table_size, block_dim)); return SUCCESS; } } // namespace skt diff --git a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.h b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.h index d8b7ff26..7db44eec 100644 --- a/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.h +++ b/src/ge/graph/load/new_model_manager/task_info/super_kernel/super_kernel_factory.h @@ -29,7 +29,6 @@ class SuperKernelFactory { void *func_ptr_ = nullptr; void *handle_ = nullptr; std::string sk_stub_name_ = "_Z21super_kernel_templatePmm"; - const char *use_physical_address_ = getenv("GE_USE_PHYSICAL_ADDRESS"); bool is_init_ = false; SuperKernelFactory(){}; ~SuperKernelFactory() { @@ -48,7 +47,7 @@ class SuperKernelFactory { Status Init(); Status Uninitialize(); Status FuseKernels(const std::vector &stub_func_list, const std::vector &args_addr_list, - uint32_t block_dim, SuperKernel *&h); + uint32_t block_dim, std::unique_ptr &h); }; } // namespace skt } // namespace ge diff --git a/src/ge/graph/load/new_model_manager/task_info/task_info.h b/src/ge/graph/load/new_model_manager/task_info/task_info.h index 5d2c89eb..f69511e6 100644 --- a/src/ge/graph/load/new_model_manager/task_info/task_info.h +++ b/src/ge/graph/load/new_model_manager/task_info/task_info.h @@ -72,6 +72,8 @@ class TaskInfo { virtual uint32_t GetTaskID() { return 0xFFFFFFFF; } + virtual bool CallSaveDumpInfo() { return false; } + virtual uint32_t GetStreamId() { return 0xFFFFFFFF; } virtual uintptr_t GetDumpArgs() { return 0; } diff --git a/src/ge/graph/load/new_model_manager/task_info/task_info_factory.h b/src/ge/graph/load/new_model_manager/task_info/task_info_factory.h index b6954016..5b220960 100644 --- a/src/ge/graph/load/new_model_manager/task_info/task_info_factory.h +++ b/src/ge/graph/load/new_model_manager/task_info/task_info_factory.h @@ -86,5 +86,5 @@ class TaskInfoFactory { return ptr; \ } \ TaskInfoFactory::Registerar g_##type##_Task_Info_Creator(type, Creator_##type##_Task_Info); -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_TASK_INFO_TASK_INFO_FACTORY_H_ diff --git a/src/ge/graph/load/new_model_manager/zero_copy_offset.cc b/src/ge/graph/load/new_model_manager/zero_copy_offset.cc new file mode 100644 index 00000000..18b958ef --- /dev/null +++ b/src/ge/graph/load/new_model_manager/zero_copy_offset.cc @@ -0,0 +1,220 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/load/new_model_manager/zero_copy_offset.h" + +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "graph/load/new_model_manager/model_utils.h" +#include "graph/load/new_model_manager/zero_copy_task.h" + +namespace ge { +namespace { +const uint32_t kDataIndex = 0; +} // namespace + +ZeroCopyOffset::ZeroCopyOffset() {} + +ZeroCopyOffset::~ZeroCopyOffset() {} + +Status ZeroCopyOffset::InitInputDataInfo(const vector &output_size_list, + const vector &virtual_addr_list, const OpDescPtr &op_desc, + bool &fusion_flag) { + GELOGI("[ZCPY] Start to InitInputDataInfo of %s, total_data_size is %ld, virtual_addr is %p", + op_desc->GetName().c_str(), output_size_list[kDataIndex], virtual_addr_list[kDataIndex]); + if (output_size_list.empty() || virtual_addr_list.empty() || (output_size_list.size() != virtual_addr_list.size())) { + GELOGE(PARAM_INVALID, "Data[%s] init failed: Output size is %zu, Output addr is %zu", op_desc->GetName().c_str(), + output_size_list.size(), virtual_addr_list.size()); + return PARAM_INVALID; + } + + basic_addr_ = virtual_addr_list[kDataIndex]; + (void)ge::AttrUtils::GetListInt(op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset_); + (void)ge::AttrUtils::GetListInt(op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset_); + GE_CHK_BOOL_EXEC(zero_copy_basic_offset_.size() == zero_copy_relative_offset_.size(), return PARAM_INVALID, + "basic_offset_size should be equal to relative_offset_size"); + GELOGI("[ZCPY] zero_copy_basic_offset size is %zu", zero_copy_basic_offset_.size()); + + int64_t virtual_addr_offset = op_desc->GetOutputOffset().at(kDataIndex); + GELOGI("virtual_addr_offset is %ld.", virtual_addr_offset); + IsL2Fusion(zero_copy_basic_offset_, virtual_addr_offset, fusion_flag); + + uint32_t out_count = 0; + data_size_ = output_size_list[kDataIndex]; + if (!fusion_flag) { + GELOGI("[ZCPY] %s not set l2_fusion.", op_desc->GetName().c_str()); + out_count++; + data_info_.emplace_back(output_size_list[kDataIndex], virtual_addr_list[kDataIndex]); + relative_offset_.emplace_back(0); + GELOGI("[ZCPY] %s size is %ld, virtual_addr is %p.", op_desc->GetName().c_str(), output_size_list[kDataIndex], + virtual_addr_list[kDataIndex]); + } else { + GELOGI("[ZCPY] set l2_fusion for %s.", op_desc->GetName().c_str()); + for (size_t index = 0; index < zero_copy_basic_offset_.size(); ++index) { + if (zero_copy_basic_offset_.at(index) == virtual_addr_offset) { + out_count++; + uint64_t out_offset = + reinterpret_cast(virtual_addr_list[kDataIndex]) + zero_copy_relative_offset_.at(index); + int64_t real_data_size = ModelUtils::GetOutputSize(op_desc).at(kDataIndex); + data_info_.emplace_back(real_data_size, reinterpret_cast(reinterpret_cast(out_offset))); + relative_offset_.emplace_back(zero_copy_relative_offset_.at(index)); + GELOGI("[ZCPY] virtual_addr: %p has been l2-fusion to %lu, need copy data_size is %ld.", basic_addr_, + out_offset, real_data_size); + } + } + } + data_count_ = out_count; + return SUCCESS; +} + +Status ZeroCopyOffset::InitOutputDataInfo(const vector &input_size_list, + const vector &virtual_addr_list, const OpDescPtr &op_desc, + const size_t &idx, bool &fusion_flag) { + GELOGI("[ZCPY] Start to InitOutputDataInfo of %s.", op_desc->GetName().c_str()); + int64_t size = input_size_list[idx]; + auto tensor_desc = op_desc->GetInputDescPtr(idx); + GE_CHECK_NOTNULL(tensor_desc); + if (TensorUtils::GetTensorSizeInBytes(*tensor_desc, size) != GRAPH_SUCCESS) { + GELOGE(FAILED, "GetTensorSizeInBytes failed!"); + return FAILED; + } + + GELOGI("Tensor data size: GetSize=%ld, GetTensorSizeInBytes=%ld", input_size_list[idx], size); + + basic_addr_ = virtual_addr_list[idx]; + (void)ge::AttrUtils::GetListInt(op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset_); + (void)ge::AttrUtils::GetListInt(op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset_); + GE_CHK_BOOL_EXEC(zero_copy_basic_offset_.size() == zero_copy_relative_offset_.size(), return PARAM_INVALID, + "basic_offset_size should be equal to relative_offset_size"); + int64_t virtual_addr_offset = op_desc->GetInputOffset().at(idx); + GELOGI("virtual_addr_offset is %ld.", virtual_addr_offset); + IsL2Fusion(zero_copy_basic_offset_, virtual_addr_offset, fusion_flag); + + uint32_t in_count = 0; + data_size_ = size; + if (!fusion_flag) { + GELOGI("[ZCPY] %s not set l2-fusion.", op_desc->GetName().c_str()); + in_count++; + data_info_.emplace_back(size, virtual_addr_list[idx]); + // op_desc not set l2fusion when fusion_flag is false + relative_offset_.emplace_back(0); + GELOGI("[ZCPY] %s size is %ld, virtual_addr is %p.", op_desc->GetName().c_str(), size, virtual_addr_list[idx]); + } else { + GELOGI("[ZCPY] set l2-fusion for %s.", op_desc->GetName().c_str()); + for (size_t index = 0; index < zero_copy_basic_offset_.size(); ++index) { + if (zero_copy_basic_offset_.at(index) == virtual_addr_offset) { + in_count++; + uint64_t in_offset = reinterpret_cast(virtual_addr_list[idx]) + zero_copy_relative_offset_.at(index); + int64_t real_data_size = ModelUtils::GetInputSize(op_desc).at(idx); + data_info_.emplace_back(real_data_size, reinterpret_cast(reinterpret_cast(in_offset))); + relative_offset_.emplace_back(zero_copy_relative_offset_.at(index)); + GELOGI("[ZCPY] virtual_addr: %p has been l2-fusion from %lu, need copy data_size is %ld.", basic_addr_, + in_offset, real_data_size); + } + } + } + data_count_ = in_count; + return SUCCESS; +} + +void ZeroCopyOffset::IsL2Fusion(const vector &fusion_basic_addrs, const int64_t &tensor_offset, + bool &fusion_flag) { + for (size_t fusion_count = 0; fusion_count < fusion_basic_addrs.size(); ++fusion_count) { + if (fusion_basic_addrs.at(fusion_count) == tensor_offset) { + fusion_flag = true; + break; + } + } +} + +void ZeroCopyOffset::SetInputOutsideAddrs(const vector &output_offset_list, void *addr, const size_t &index, + bool fusion_flag, std::vector &real_virtual_addrs) { + GELOGI("[ZCPY] Start to SetInputOutsideAddrs for virtual_addr %p.", addr); + uint32_t out_count = 0; + if (!fusion_flag) { + GELOGI("[ZCPY] not set l2-fusion for virtual_adr %p.", addr); + out_count++; + std::map> addr_mapping; + addr_mapping[addr] = {}; + outside_addrs_.emplace_back(addr_mapping); + real_virtual_addrs.emplace_back(addr); + } else { + GELOGI("[ZCPY] set l2-fusion for virtual_addr %p.", addr); + int64_t output_offset = output_offset_list.at(index); + for (size_t i = 0; i < zero_copy_basic_offset_.size(); ++i) { + if (zero_copy_basic_offset_.at(i) == output_offset) { + out_count++; + void *virtual_addr = + reinterpret_cast(reinterpret_cast(addr) + zero_copy_relative_offset_.at(i)); + std::map> addr_mapping; + addr_mapping[virtual_addr] = {}; + outside_addrs_.emplace_back(addr_mapping); + real_virtual_addrs.emplace_back(virtual_addr); + GELOGI("[ZCPY] virtual_addr %p has been fusion to virtual_addr %p.", addr, virtual_addr); + } + } + } + addr_count_ = out_count; +} + +void ZeroCopyOffset::SetOutputOutsideAddrs(const int64_t &input_offset, const bool &fusion_flag, void *addr, + std::vector &tensor_addrs) { + GELOGI("[ZCPY] Start to SetOutputOutsideAddrs for virtual_addr %p.", addr); + uint32_t out_count = 0; + if (!fusion_flag) { + GELOGI("[ZCPY] not set l2-fusion for virtual_addr %p.", addr); + out_count++; + std::map> addr_mapping; + addr_mapping[addr] = {}; + outside_addrs_.emplace_back(addr_mapping); + tensor_addrs.emplace_back(addr); + } else { + GELOGI("[ZCPY] set l2-fusion for virtual_addr %p.", addr); + for (size_t i = 0; i < zero_copy_basic_offset_.size(); ++i) { + if (zero_copy_basic_offset_.at(i) == input_offset) { + out_count++; + void *virtual_addr = + reinterpret_cast(reinterpret_cast(addr) + zero_copy_relative_offset_.at(i)); + std::map> addr_mapping; + addr_mapping[virtual_addr] = {}; + outside_addrs_.emplace_back(addr_mapping); + tensor_addrs.emplace_back(virtual_addr); + GELOGI("[ZCPY] virtual_addr %p has been fusion to virtual_addr %p.", addr, virtual_addr); + } + } + } + addr_count_ = out_count; +} + +bool ZeroCopyOffset::SetOutsideAddrsValue(ZeroCopyTask &zero_copy_task, void *outside_addr, void *args, size_t offset) { + const auto addr_val = reinterpret_cast(outside_addr); + bool set_batch_label_flag = false; + for (uint32_t out_count = 0; out_count < GetAddrCount(); ++out_count) { + auto &addrs_mapping_list = GetOutsideAddrs(); + auto args_addrs = addrs_mapping_list[out_count].find(outside_addr); + if (args_addrs != addrs_mapping_list[out_count].end()) { + GE_CHK_STATUS(zero_copy_task.SetTaskArgsOffset(addr_val, offset), "Input args invalid."); + void *args_val = static_cast(args) + offset; + args_addrs->second.push_back(args_val); + GELOGI("[ZCPY] set copy input: virtual_addr: 0x%lx, task_addr: %p, args: %p, offset: %zu.", addr_val, args_val, + args, offset); + set_batch_label_flag = true; + } + } + return set_batch_label_flag; +} + +} // namespace ge diff --git a/src/ge/graph/load/new_model_manager/zero_copy_offset.h b/src/ge/graph/load/new_model_manager/zero_copy_offset.h new file mode 100644 index 00000000..eb2cdb4d --- /dev/null +++ b/src/ge/graph/load/new_model_manager/zero_copy_offset.h @@ -0,0 +1,84 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_LOAD_NEW_MODEL_MANAGER_ZERO_COPY_OFFSET_H_ +#define GE_GRAPH_LOAD_NEW_MODEL_MANAGER_ZERO_COPY_OFFSET_H_ + +#include +#include +#include +#include + +#include "external/ge/ge_api_error_codes.h" +#include "framework/common/ge_types.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/load/new_model_manager/zero_copy_task.h" +#include "graph/utils/attr_utils.h" +#include "graph/utils/tensor_utils.h" +#include "runtime/mem.h" +#include "task_info/task_info.h" + +using std::map; +using std::set; +using std::string; +using std::vector; + +namespace ge { +class ZeroCopyOffset { + public: + ZeroCopyOffset(); + ~ZeroCopyOffset(); + + Status InitInputDataInfo(const vector &output_size_list, const vector &virtual_addr_list, + const OpDescPtr &op_desc, bool &fusion_flag); + void SetInputOutsideAddrs(const vector &output_offset_list, void *addr, const size_t &index, + bool fusion_flag, std::vector &real_virtual_addrs); + + void IsL2Fusion(const vector &fusion_basic_addrs, const int64_t &tensor_addr, bool &fusion_flag); + Status InitOutputDataInfo(const vector &input_size_list, const vector &virtual_addr_list, + const OpDescPtr &op_desc, const size_t &idx, bool &fusion_flag); + void SetOutputOutsideAddrs(const int64_t &input_offset, const bool &fusion_flag, void *addr, + std::vector &tensor_addrs); + bool SetOutsideAddrsValue(ZeroCopyTask &zero_copy_task, void *outside_addr, void *args, size_t offset); + + // basic_addr of l2-fusion + void *GetBasicAddr() const { return basic_addr_; } + // total num of out_of_data/in_of_phonyconcat + uint32_t GetDataCount() const { return data_count_; } + uint32_t GetAddrCount() const { return addr_count_; } + // value of *data_info_ from davinci_model + std::vector> GetDataInfo() const { return data_info_; } + // relative_offset from zero_copy_relative_offset_ + std::vector GetRelativeOffset() const { return relative_offset_; } + // data_size of Data/Netoutput + int64_t GetDataSize() const { return data_size_; } + // value of *outside_addrs_ from davinci_model + std::vector>> &GetOutsideAddrs() { return outside_addrs_; } + + private: + void *basic_addr_ = nullptr; + uint32_t data_count_ = 0; + std::vector> data_info_; + vector relative_offset_; + int64_t data_size_ = 0; + uint32_t addr_count_ = 0; + std::vector>> outside_addrs_; + + std::vector zero_copy_basic_offset_; + std::vector zero_copy_relative_offset_; +}; +} // namespace ge +#endif // GE_GRAPH_LOAD_NEW_MODEL_MANAGER_ZERO_COPY_OFFSET_H_ \ No newline at end of file diff --git a/src/ge/graph/load/new_model_manager/zero_copy_task.cc b/src/ge/graph/load/new_model_manager/zero_copy_task.cc index 42734a87..5b595d76 100644 --- a/src/ge/graph/load/new_model_manager/zero_copy_task.cc +++ b/src/ge/graph/load/new_model_manager/zero_copy_task.cc @@ -16,9 +16,9 @@ #include "graph/load/new_model_manager/zero_copy_task.h" -#include "graph/load/new_model_manager/model_utils.h" #include "framework/common/debug/ge_log.h" #include "framework/common/util.h" +#include "graph/load/new_model_manager/model_utils.h" namespace ge { const char *const kDefaultBatchLable = "Batch_default"; @@ -48,8 +48,8 @@ Status ZeroCopyTask::SetTaskArgsOffset(uintptr_t addr, size_t offset) { it->second.push_back(offset); } - GELOGI("[ZCPY] %s set task, addr: 0x%lx, args: %p, size: %zu, offset: %zu", name_.c_str(), addr, args_addr_, - args_size_, offset); + GELOGI("[ZCPY] %s set task, virtual_addr: 0x%lx, args_addr: %p, size: %zu, offset: %zu", name_.c_str(), addr, + args_addr_, args_size_, offset); return SUCCESS; } @@ -65,7 +65,8 @@ void ZeroCopyTask::SetOriginalArgs(const void *info, size_t size) { const uint8_t *data = static_cast(info); args_info_.assign(data, data + size); - GELOGI("[ZCPY] %s set info, args: %p, args size: %zu, info size: %zu", name_.c_str(), args_addr_, args_size_, size); + GELOGI("[ZCPY] %s set info from virtual_addr: %p, args_addr: %p, args size: %zu, info size: %zu", name_.c_str(), info, + args_addr_, args_size_, size); } /** @@ -110,13 +111,13 @@ bool ZeroCopyTask::CheckDynamicBatch(const map> &batch_ad * @ingroup ge * @brief Set user data addr to Task param. * @param [in] addr: virtual address value from Op. - * @param [in] data: data buffer from user. + * @param [in] buffer_addr: real_data_buffer_addr from user. * @param [in] batch_addrs: dynamic batch addr info. * @param [in] batch_label: batch label. * @return: void */ -Status ZeroCopyTask::UpdateTaskParam(uintptr_t addr, const DataBuffer &data, - const map> &batch_addrs, const string &batch_label) { +Status ZeroCopyTask::UpdateTaskParam(uintptr_t addr, void *buffer_addr, const map> &batch_addrs, + const string &batch_label) { for (auto pair : task_addr_offset_) { if (pair.first != addr) { continue; @@ -128,15 +129,9 @@ Status ZeroCopyTask::UpdateTaskParam(uintptr_t addr, const DataBuffer &data, continue; } - auto dst_addr = static_cast(data.data); - auto dst_size = static_cast(data.length); - if (ModelUtils::ConvertVirtualAddressToPhysical(dst_addr, dst_size, dst_addr) != SUCCESS) { - GELOGE(FAILED, "[ZCPY] Convert virtual address to physical for dst_addr failed."); - return FAILED; - } - - GELOGI("[ZCPY] %s update task, args: %p, size: %zu, offset: %zu, addr: 0x%lx, length: %u", name_.c_str(), - args_addr_, args_size_, offset, addr, data.length); + auto dst_addr = static_cast(buffer_addr); + GELOGI("[ZCPY] %s update task, args_addr: %p, size: %zu, offset: %zu, virtual_addr: 0x%lx", name_.c_str(), + args_addr_, args_size_, offset, addr); *(uintptr_t *)(args_info + offset) = reinterpret_cast(dst_addr); is_updated_ = true; } @@ -168,11 +163,11 @@ Status ZeroCopyTask::DistributeParam(rtStream_t stream) { } if (rt_err != RT_ERROR_NONE) { - GELOGE(FAILED, "[ZCPY] %s distribute task param failed, error=0x%x", name_.c_str(), rt_err); - return FAILED; + GELOGE(RT_FAILED, "[ZCPY] %s distribute task param failed, error=0x%x", name_.c_str(), rt_err); + return RT_ERROR_TO_GE_STATUS(rt_err); } - GELOGI("[ZCPY] %s refresh task args success, args: %p, size: %zu, args_info_: %p, length: %zu", name_.c_str(), + GELOGI("[ZCPY] %s refresh task args success, args_addr: %p, size: %zu, args_info_: %p, length: %zu", name_.c_str(), args_addr_, args_size_, args_info_.data(), args_info_.size()); return SUCCESS; } diff --git a/src/ge/graph/load/new_model_manager/zero_copy_task.h b/src/ge/graph/load/new_model_manager/zero_copy_task.h index 9d3f5b03..d2a91ce7 100644 --- a/src/ge/graph/load/new_model_manager/zero_copy_task.h +++ b/src/ge/graph/load/new_model_manager/zero_copy_task.h @@ -66,12 +66,12 @@ class ZeroCopyTask { * @ingroup ge * @brief Set user data addr to Task param. * @param [in] addr: virtual address value from Op. - * @param [in] data: data buffer from user. + * @param [in] buffer_addr: data buffer_addr from user. * @param [in] batch_addrs: dynamic batch addr info. * @param [in] batch_label: batch label. * @return: 0 SUCCESS / others FAILED */ - ge::Status UpdateTaskParam(uintptr_t addr, const DataBuffer &data, const map> &batch_addrs, + ge::Status UpdateTaskParam(uintptr_t addr, void *buffer_addr, const map> &batch_addrs, const string &batch_label); /** diff --git a/src/ge/graph/load/output/output.cc b/src/ge/graph/load/output/output.cc deleted file mode 100644 index d922ce7c..00000000 --- a/src/ge/graph/load/output/output.cc +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright 2019-2020 Huawei Technologies 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. - */ - -#include "graph/load/output/output.h" - -#include - -#include "common/properties_manager.h" -#include "graph/load/new_model_manager/davinci_model.h" -#include "graph/manager/graph_var_manager.h" -#include "graph/utils/op_desc_utils.h" -#include "graph/utils/tensor_utils.h" - -namespace ge { -Output::Output(const OpDescPtr &op_desc, DavinciModel *model) - : base_(nullptr), - var_base_(nullptr), - logic_base_(0), - logic_var_base_(0), - model_(model), - op_desc_(op_desc), - input_num_(0) {} - -Output::~Output() { - var_base_ = nullptr; - base_ = nullptr; - model_ = nullptr; -} - -/// -/// @ingroup domi -/// @brief Initialize input/output params -/// @return Status -/// -Status Output::Init() { - if (op_desc_ == nullptr || model_ == nullptr) { - GELOGE(INTERNAL_ERROR, "The op_desc_ or model_ is nullptr."); - return INTERNAL_ERROR; - } - - base_ = model_->MemBase(); - var_base_ = model_->VarMemBase(); - logic_base_ = model_->GetRtBaseAddr(); - logic_var_base_ = model_->GetRtVarAddr(); - - input_num_ = op_desc_->GetInputsSize(); - v_input_size_.clear(); - v_input_data_addr_.clear(); - - auto input_vector = op_desc_->GetInputOffset(); - if (input_num_ != input_vector.size()) { - GELOGE(INTERNAL_ERROR, "input desc size: %zu != input offset size: %zu.", input_num_, input_vector.size()); - return INTERNAL_ERROR; - } - - for (size_t i = 0; i < input_num_; i++) { - int64_t tensor_size = 0; - auto input_desc = op_desc_->GetInputDescPtr(i); - GE_CHECK_NOTNULL(input_desc); - Status ret = TensorUtils::GetSize(*input_desc, tensor_size); - if (ret != GRAPH_SUCCESS) { - GELOGE(ret, "Get size from TensorDesc failed, op : %s, input index : %zu", op_desc_->GetName().c_str(), i); - return ret; - } - v_input_size_.push_back(tensor_size); - - if (VarManager::Instance(model_->SessionId())->IsVarAddr(input_vector[i])) { - v_input_data_addr_.push_back(static_cast(var_base_ + input_vector[i] - logic_var_base_)); - } else { - v_input_data_addr_.push_back(static_cast(base_ + input_vector[i])); - } - } - - GELOGI("Init output:%lu, %lu, %lu", input_num_, v_input_size_.size(), v_input_data_addr_.size()); - - return SUCCESS; -} - -/// -/// @ingroup domi -/// @brief Copy Op Output to user space. -/// @brief when model running, Add one DataOp as input node, Add one Output Op as output node. -/// @return Status -/// -Status Output::CopyResult(OutputData &rslt, uint32_t data_begin, uint32_t &data_index, bool support_mem_share) { - uint32_t data_count = 0; - if (input_num_ > rslt.blobs.size() - data_begin) { - GELOGE(FAILED, "Tensor num %zu, data_buf num: %zu.", input_num_, rslt.blobs.size() - data_begin); - return FAILED; - } else if (input_num_ < rslt.blobs.size() - data_begin) { - GELOGW("Tensor num %zu, data_buf num: %zu.", input_num_, rslt.blobs.size() - data_begin); - } - - for (size_t i = 0; i < input_num_; i++) { - DataBuffer data_buf = rslt.blobs[data_begin + data_count]; - Status ret = SetDataBuf(data_buf, data_count, i, support_mem_share); - if (ret != SUCCESS) { - GELOGE(ret, "Copy data to host error. index: %zu", i); - return ret; - } - data_index = data_begin + data_count; - } - - return SUCCESS; -} - -Status Output::SetDataBuf(DataBuffer &data_buf, uint32_t &data_count, size_t i, bool support_mem_share) { - if (data_buf.length == 0) { - ++data_count; - GELOGD("Length of data_buffer is zero, No need to copy. output op : %s, output tensor index : %zu!", - op_desc_->GetName().c_str(), i); - return SUCCESS; - } - - auto tensor_desc = op_desc_->GetInputDescPtr(static_cast(i)); - if (tensor_desc == nullptr) { - GELOGE(FAILED, "tensor_desc is null"); - return FAILED; - } - - if (data_buf.isDataSupportMemShare && support_mem_share) { - GELOGI("No need to copy input data, user's output data buffer can be shared."); - } else { - // Copy result to Databuf - int64_t size = v_input_size_[i]; - GELOGI("Tensor data size before: %ld", size); - - graphStatus graph_status = TensorUtils::GetTensorSizeInBytes(*tensor_desc, size); - if (graph_status != ge::GRAPH_SUCCESS) { - GELOGE(graph_status, "GetTensorSizeInBytes failed!"); - return FAILED; - } - - if (data_buf.length < size) { - GELOGE(FAILED, "Tensor data size: %ld data_buf length: %ld", size, data_buf.length); - return FAILED; - } else if (data_buf.length > size) { - GELOGW("Tensor data size: %ld data_buf length: %ld", size, data_buf.length); - } - - rtError_t rt_ret = rtMemcpy(data_buf.data, size, v_input_data_addr_[i], size, RT_MEMCPY_DEVICE_TO_HOST); - if (rt_ret != RT_ERROR_NONE) { - GELOGE(rt_ret, "rtmemcpy error"); - return FAILED; - } - GELOGI("Tensor data size: %ld data_buf length: %ld", size, data_buf.length); - } - - ++data_count; - GELOGD("Successfully copy the output tensor memory to buffer, output op : %s, output tensor index : %zu!", - op_desc_->GetName().c_str(), i); - - return SUCCESS; -} - -void Output::GetOutputData(vector &v_data_addr, vector &v_data_size) { - for (size_t i = 0; i < input_num_; ++i) { - v_data_addr.push_back(v_input_data_addr_[i]); - v_data_size.push_back(v_input_size_[i]); - } -} -} // namespace ge diff --git a/src/ge/graph/load/output/output.h b/src/ge/graph/load/output/output.h deleted file mode 100644 index d93b8de9..00000000 --- a/src/ge/graph/load/output/output.h +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright 2019-2020 Huawei Technologies 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. - */ - -#ifndef GE_GRAPH_LOAD_OUTPUT_OUTPUT_H_ -#define GE_GRAPH_LOAD_OUTPUT_OUTPUT_H_ - -#include -#include - -#include "common/debug/log.h" -#include "common/op/attr_value_util.h" -#include "common/op/ge_op_utils.h" -#include "common/types.h" -#include "common/util.h" -#include "common/ge_types.h" -#include "graph/load/new_model_manager/davinci_model.h" -#include "graph/op_desc.h" -#include "graph/debug/ge_attr_define.h" - -namespace ge { -using std::string; -using std::vector; - -// The base class for all op -class Output { - public: - Output(const OpDescPtr &op_desc, DavinciModel *model); - virtual ~Output(); - - /// - /// @ingroup domi - /// @brief Initialize input/output params - /// @return Status - /// - virtual Status Init(); - - /// - /// @ingroup domi - /// @brief Copy Op Output to user space. - /// @brief when model running, Add one DataOp as input node, Add one Output Op as output node. - /// @return Status - /// - virtual Status CopyResult(OutputData &rslt, uint32_t data_begin, uint32_t &data_index, bool support_mem_share); - - /// - /// @ingroup domi - /// @brief Trans Output data to fp16 - /// @return Status - /// - Status SetDataBuf(DataBuffer &data_buf, uint32_t &data_count, size_t i, bool support_mem_share); - - /// - /// @ingroup domi - /// @brief Get Output data and size. - /// @return void - /// - void GetOutputData(vector &v_data_addr, vector &v_data_size); - - // Copy assignment operator and copy constructor are deleted - Output &operator=(const Output &output) = delete; - Output(const Output &output) = delete; - - protected: - // Model's base address - uint8_t *base_; - uint8_t *var_base_; - uint64_t logic_base_; - uint64_t logic_var_base_; - // The DavinciModel which ops belong to - DavinciModel *model_; - - ConstOpDescPtr op_desc_; - - // Input descriptions - size_t input_num_; - vector v_input_data_addr_; // init as:buf_base + op_def_->input(i)); - vector v_input_size_; -}; -} // namespace ge - -#endif // GE_GRAPH_LOAD_OUTPUT_OUTPUT_H_ diff --git a/src/ge/graph/manager/block_memory.h b/src/ge/graph/manager/block_memory.h new file mode 100644 index 00000000..e2bf74b2 --- /dev/null +++ b/src/ge/graph/manager/block_memory.h @@ -0,0 +1,43 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_MANAGER_BLOCK_MEMORY_H_ +#define GE_GRAPH_MANAGER_BLOCK_MEMORY_H_ +namespace ge { +struct Block; +typedef bool (*Comparison)(const Block *, const Block *); +using BlockBin = std::set; + +struct Block { + uint32_t device_id; // npu device id + size_t size; // block size in bytes + BlockBin *bin; // owning block bin + uint8_t *ptr; // memory address + bool allocated; // in-use flag + Block *prev; // prev block if split from a larger allocation + Block *next; // next block if split from a larger allocation + + Block(uint32_t device, size_t size, BlockBin *bin, uint8_t *ptr) + : device_id(device), size(size), bin(bin), ptr(ptr), allocated(false), prev(nullptr), next(nullptr) {} + + // constructor for search key + Block(uint32_t device, size_t size, uint8_t *ptr) + : device_id(device), size(size), bin(nullptr), ptr(ptr), allocated(false), prev(nullptr), next(nullptr) {} + + bool IsSplit() const { return (prev != nullptr) || (next != nullptr); } +}; +} // namespace ge +#endif // GE_GRAPH_MANAGER_BLOCK_MEMORY_H_ diff --git a/src/ge/graph/manager/graph_caching_allocator.cc b/src/ge/graph/manager/graph_caching_allocator.cc index 5df6769b..4ba39ca8 100644 --- a/src/ge/graph/manager/graph_caching_allocator.cc +++ b/src/ge/graph/manager/graph_caching_allocator.cc @@ -34,9 +34,6 @@ const size_t bin_ranges[kNumBins] = {kRoundBlockSize * kKByteSize, 26 * kGByteSize}; static bool BlockComparator(const Block *left, const Block *right) { - if (left->device_id != right->device_id) { - return left->device_id < right->device_id; - } if (left->size != right->size) { return left->size < right->size; } @@ -137,11 +134,6 @@ uint8_t *CachingAllocator::Malloc(size_t size, uint8_t *org_ptr, uint32_t device } if (ptr == nullptr) { GELOGE(FAILED, "Malloc failed device id = %u, size= %zu", device_id, size); - } else { - std::lock_guard lock(mutex_); - block->allocated = true; - allocated_blocks_[block->ptr] = block; - GELOGI("Malloc device id = %u, size= %zu", device_id, size); } return ptr; } @@ -225,9 +217,16 @@ Block *CachingAllocator::FindFreeBlock(size_t size, uint8_t *org_ptr, uint32_t d if (block != nullptr) { GELOGI("Find block size = %zu", block->size); if (ShouldSplit(block, size)) { - return SplitBlock(block, size, *bin, device_id); + block = SplitBlock(block, size, *bin, device_id); + } + + if (block->ptr != nullptr) { + block->allocated = true; + allocated_blocks_[block->ptr] = block; + GELOGI("Malloc device id = %u, size= %zu", device_id, size); } } + return block; } return nullptr; @@ -267,20 +266,20 @@ Status CachingAllocator::TryExtendCache(size_t size, uint32_t device_id) { return ge::FAILED; } } - if (AddToBlockBin(memory_addr, memory_size) != ge::SUCCESS) { + if (AddToBlockBin(memory_addr, memory_size, device_id) != ge::SUCCESS) { (void)memory_allocator_->FreeMemory(memory_addr); return ge::FAILED; } return ge::SUCCESS; } -Status CachingAllocator::AddToBlockBin(uint8_t *ptr, size_t size) { +Status CachingAllocator::AddToBlockBin(uint8_t *ptr, size_t size, uint32_t device_id) { BlockBin *bin = GetBlockBin(size); if (bin == nullptr) { GELOGE(ge::FAILED, "Get block bin failed size = %zu", size); return ge::FAILED; } - Block *block = new (std::nothrow) Block(0, size, bin, nullptr); + Block *block = new (std::nothrow) Block(device_id, size, bin, nullptr); if (block == nullptr) { GELOGE(ge::FAILED, "Alloc block failed size = %zu", size); return ge::FAILED; @@ -339,5 +338,4 @@ void CachingAllocator::FreeBlockBins() { } } } - } // namespace ge diff --git a/src/ge/graph/manager/graph_caching_allocator.h b/src/ge/graph/manager/graph_caching_allocator.h index 75864ce7..94a5066a 100644 --- a/src/ge/graph/manager/graph_caching_allocator.h +++ b/src/ge/graph/manager/graph_caching_allocator.h @@ -32,7 +32,6 @@ #include "runtime/mem.h" namespace ge { - constexpr size_t kRoundBlockSize = 512; // all block sizes are rounded to at least 512 bytes constexpr double kSplitThreshold = 0.75; // split when malloc size <= small block size * kSpliThreshold constexpr size_t kKByteSize = 1024; @@ -69,6 +68,10 @@ class CachingAllocator { public: explicit CachingAllocator(rtMemType_t memory_type); + CachingAllocator(const CachingAllocator &) = delete; + + CachingAllocator &operator=(const CachingAllocator &) = delete; + virtual ~CachingAllocator() = default; /// @@ -137,9 +140,10 @@ class CachingAllocator { /// @brief add memory to right bin based on size /// @param [in] memory ptr /// @param [in] memory size + /// @param [in] device_id device id /// @return Status result of function /// - Status AddToBlockBin(uint8_t *ptr, size_t size); + Status AddToBlockBin(uint8_t *ptr, size_t size, uint32_t device_id); /// /// @ingroup ge_graph @@ -206,7 +210,5 @@ class CachingAllocator { // block bins by different block size BlockBin *free_block_bins_[kNumBins]; }; - -}; // namespace ge - +} // namespace ge #endif // GE_GRAPH_MANAGER_GRAPH_CACHING_ALLOCATOR_H_ diff --git a/src/ge/graph/manager/graph_manager.cc b/src/ge/graph/manager/graph_manager.cc index dd4855b6..bdf2143c 100644 --- a/src/ge/graph/manager/graph_manager.cc +++ b/src/ge/graph/manager/graph_manager.cc @@ -43,7 +43,9 @@ #include "graph/manager/util/rt_context_util.h" #include "graph/partition/dynamic_shape_partition.h" #include "graph/passes/addn_pass.h" +#include "graph/passes/bitcast_pass.h" #include "graph/passes/atomic_addr_clean_pass.h" +#include "graph/passes/attach_stream_label_pass.h" #include "graph/passes/cast_remove_pass.h" #include "graph/passes/common_subexpression_elimination_pass.h" #include "graph/passes/compile_nodes_pass.h" @@ -57,15 +59,18 @@ #include "graph/passes/flow_ctrl_pass.h" #include "graph/passes/hccl_group_pass.h" #include "graph/passes/hccl_memcpy_pass.h" -#include "graph/passes/identify_reference_pass.h" #include "graph/passes/identity_pass.h" +#include "graph/passes/input_output_connection_identify_pass.h" #include "graph/passes/iterator_op_pass.h" #include "graph/passes/link_gen_mask_nodes_pass.h" +#include "graph/passes/mark_graph_unknown_status_pass.h" #include "graph/passes/merge_pass.h" +#include "graph/passes/merge_to_stream_merge_pass.h" #include "graph/passes/multi_batch_pass.h" #include "graph/passes/next_iteration_pass.h" #include "graph/passes/permute_pass.h" #include "graph/passes/prune_pass.h" +#include "graph/passes/ref_identity_delete_op_pass.h" #include "graph/passes/replace_with_empty_const_pass.h" #include "graph/passes/reshape_recovery_pass.h" #include "graph/passes/reshape_remove_pass.h" @@ -74,7 +79,7 @@ #include "graph/passes/switch_data_edges_bypass.h" #include "graph/passes/switch_dead_branch_elimination.h" #include "graph/passes/switch_logic_remove_pass.h" -#include "graph/passes/switch_op_pass.h" +#include "graph/passes/switch_to_stream_switch_pass.h" #include "graph/passes/transop_breadth_fusion_pass.h" #include "graph/passes/transop_depth_fusion_pass.h" #include "graph/passes/transop_nearby_allreduce_fusion_pass.h" @@ -85,6 +90,7 @@ #include "graph/passes/variable_prepare_op_pass.h" #include "graph/passes/variable_ref_delete_op_pass.h" #include "graph/passes/variable_ref_useless_control_out_delete_pass.h" +#include "graph/passes/end_of_sequence_add_control_pass.h" #include "graph/utils/tensor_adapter.h" #include "inc/pass_manager.h" #include "init/gelib.h" @@ -347,12 +353,13 @@ Status GraphManager::SetSubgraph(uint64_t session_id, ComputeGraphPtr compute_gr return SUCCESS; } -#define GM_RUN_AND_DUMP(name, func, ...) \ +#define GM_RUN_AND_DUMP_PERF(name, func, ...) \ do { \ - GE_RUN(GraphManager, func, __VA_ARGS__); \ + GE_RUN_PERF(GraphManager, func, __VA_ARGS__); \ GE_DUMP(compute_graph, "PreRunAfter" name); \ GELOGI("Run %s on graph %s(%u) success.", name, compute_graph->GetName().c_str(), graph_node->GetGraphId()); \ } while (0) + Status GraphManager::PreRun(const GraphNodePtr &graph_node, const std::vector &inputs, GeRootModelPtr &ge_root_model, uint64_t session_id) { GE_CHECK_NOTNULL(graph_node); @@ -365,30 +372,30 @@ Status GraphManager::PreRun(const GraphNodePtr &graph_node, const std::vectorGetName().c_str()); GE_DUMP(compute_graph, "PreRunBegin"); - GM_RUN_AND_DUMP("OptimizeGraphPrepare", graph_optimize_.OptimizeOriginalGraphForQuantize, compute_graph); - GM_RUN_AND_DUMP("HandleSummaryOp", graph_optimize_.HandleSummaryOp, compute_graph); - GM_RUN_AND_DUMP("Prepare", graph_preparer_.PrepareDynShape, graph_node->GetGraph(), inputs, compute_graph, - session_id); - GM_RUN_AND_DUMP("OptimizeOriginalGraph", graph_optimize_.OptimizeOriginalGraph, compute_graph); + GM_RUN_AND_DUMP_PERF("OptimizeGraphPrepare", graph_optimize_.OptimizeOriginalGraphForQuantize, compute_graph); + GM_RUN_AND_DUMP_PERF("HandleSummaryOp", graph_optimize_.HandleSummaryOp, compute_graph); + GM_RUN_AND_DUMP_PERF("Prepare", graph_preparer_.PrepareDynShape, graph_node->GetGraph(), inputs, compute_graph, + session_id); + GM_RUN_AND_DUMP_PERF("OptimizeOriginalGraph", graph_optimize_.OptimizeOriginalGraph, compute_graph); - GM_RUN_AND_DUMP("PrepareRunningFormatRefiner", graph_preparer_.PrepareRunningFormatRefiner); - GM_RUN_AND_DUMP("RefineRunningFormat", graph_optimize_.OptimizeOriginalGraphJudgeInsert, compute_graph); + GM_RUN_AND_DUMP_PERF("PrepareRunningFormatRefiner", graph_preparer_.PrepareRunningFormatRefiner); + GM_RUN_AND_DUMP_PERF("RefineRunningFormat", graph_optimize_.OptimizeOriginalGraphJudgeInsert, compute_graph); GE_RUN(GraphManager, graph_preparer_.RecordAIPPInfo, compute_graph); if (IsTailingOptimization()) { - GM_RUN_AND_DUMP("OptimizeSwitchOp", graph_preparer_.SwitchOpOptimize, compute_graph); + GM_RUN_AND_DUMP_PERF("OptimizeSwitchOp", graph_preparer_.SwitchOpOptimize, compute_graph); } - GM_RUN_AND_DUMP("Optimize1", OptimizeStage1, compute_graph); - GM_RUN_AND_DUMP("InferShape2", compute_graph->InferShapeInNeed); + GM_RUN_AND_DUMP_PERF("Optimize1", OptimizeStage1, compute_graph); + GM_RUN_AND_DUMP_PERF("InferShape2", compute_graph->InferShapeInNeed); const char *unknown_shape_skip = std::getenv("EXPERIMENTAL_DYNAMIC_PARTITION"); if (unknown_shape_skip != nullptr) { PassManager graph_pass; GE_CHK_STATUS_RET(graph_pass.AddPass("PreRun::CtrlEdgeTransferPass", new (std::nothrow) CtrlEdgeTransferPass)) GE_CHK_STATUS_RET(graph_pass.Run(compute_graph)); } - - GM_RUN_AND_DUMP("OptimizeSubgraph", OptimizeSubgraph, graph_node, compute_graph, session_id); - GM_RUN_AND_DUMP("Optimize2", OptimizeStage2, compute_graph); - GM_RUN_AND_DUMP("Build", Build, graph_node, compute_graph, ge_root_model, session_id); + GE_CHK_STATUS_RET(graph_optimize_.IdentifyReference(compute_graph), "Identify reference failed."); + GM_RUN_AND_DUMP_PERF("OptimizeSubgraph", OptimizeSubgraph, graph_node, compute_graph, session_id); + GM_RUN_AND_DUMP_PERF("Optimize2", OptimizeStage2, compute_graph); + GM_RUN_AND_DUMP_PERF("Build", Build, graph_node, compute_graph, ge_root_model, session_id); // when set incre build, save om model and var manager GeModelPtr ge_model = nullptr; @@ -397,7 +404,7 @@ Status GraphManager::PreRun(const GraphNodePtr &graph_node, const std::vectorSetRunFlag(false); @@ -634,7 +641,7 @@ Status GraphManager::RunGraph(const GraphId &graph_id, const std::vector &inputs, + GeRootModelPtr &ge_root_model, uint64_t session_id) { + // find graph + GraphNodePtr graph_node = nullptr; + Status ret = GetGraphNode(graph_id, graph_node); + if (ret != SUCCESS) { + GELOGE(ret, "[BuildGraph] graph not exist, graph_id = %u.", graph_id); + return ret; + } + + if (graph_node == nullptr) { + GELOGE(GE_GRAPH_GRAPH_NODE_NULL, "[BuildGraph] graph node is NULL, graphId = %u.", graph_id); + return GE_GRAPH_GRAPH_NODE_NULL; + } + auto compute_graph = GraphUtils::GetComputeGraph(*graph_node->GetGraph()); + GE_CHECK_NOTNULL(compute_graph); + + GM_RUN_AND_DUMP_PERF("Prepare", graph_preparer_.PrepareDynShape, graph_node->GetGraph(), inputs, compute_graph, + session_id); + + for (auto &node : compute_graph->GetAllNodes()) { + OpDescPtr op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (op_desc->HasAttr(ATTR_NAME_UNREGST_OPPATH)) { + vector node_vec = {node}; + + auto instance_ptr = ge::GELib::GetInstance(); + if (instance_ptr == nullptr || !instance_ptr->InitFlag()) { + GELOGE(GE_CLI_GE_NOT_INITIALIZED, "GE is not initialized"); + return GE_CLI_GE_NOT_INITIALIZED; + } + + OpsKernelInfoStorePtr kernel_info = + instance_ptr->OpsKernelManagerObj().GetOpsKernelInfoStore(op_desc->GetOpKernelLibName()); + if (kernel_info == nullptr) { + GELOGE(FAILED, "Get op kernel info store failed"); + return FAILED; + } + + ret = kernel_info->CompileOp(node_vec); + if (ret != SUCCESS) { + GELOGE(ret, "Compile op failed, op = %s, graph_id = %u.", op_desc->GetName().c_str(), graph_id); + return ret; + } + } + } + + GM_RUN_AND_DUMP_PERF("Build", Build, graph_node, compute_graph, ge_root_model, session_id); + + return SUCCESS; +} + Status GraphManager::BuildGraph(const GraphId &graph_id, const std::vector &inputs, GeRootModelPtr &ge_root_model, uint64_t session_id, bool async) { GELOGI("[BuildGraph] start to build graph, graph_id=%u.", graph_id); @@ -1613,7 +1672,6 @@ Status GraphManager::OptimizeStage1(ge::ComputeGraphPtr &compute_graph) { SwitchDeadBranchElimination switch_dead_branch_elimination; SwitchLogicRemovePass switch_logic_remove_pass; MergePass merge_pass; - IdentifyReferencePass identify_reference_pass; CastRemovePass cast_remove_pass; TransposeTransDataPass transpose_transdata_pass; TransOpSymmetryEliminationPass symmetry_elimination_pass; @@ -1622,7 +1680,6 @@ Status GraphManager::OptimizeStage1(ge::ComputeGraphPtr &compute_graph) { names_to_passes.emplace_back("SwitchDeadBranchElimination", &switch_dead_branch_elimination); names_to_passes.emplace_back("SwitchLogicRemovePass", &switch_logic_remove_pass); names_to_passes.emplace_back("MergePass", &merge_pass); - names_to_passes.emplace_back("IdentifyReferencePass", &identify_reference_pass); names_to_passes.emplace_back("CastRemovePass", &cast_remove_pass); names_to_passes.emplace_back("TransposeTransDataPass", &transpose_transdata_pass); names_to_passes.emplace_back("TransOpSymmetryEliminationPass", &symmetry_elimination_pass); @@ -1638,14 +1695,32 @@ Status GraphManager::OptimizeStage1(ge::ComputeGraphPtr &compute_graph) { GELOGE(ret, "Run passes when OptimizeStage1_2 failed, ret:%u.", ret); return ret; } + // Calculate Op/Fe constantfolding cost + uint64_t op_constant_folding_cost = 0; + for (auto &it : constant_folding_pass.GetOpConstantFoldingPerfStatistic()) { + op_constant_folding_cost += it.second.second; + GELOGI("The time cost of %s constant folding is [%lu] micro second, calls is %lu.", it.first.c_str(), + it.second.second, it.second.first); + } + GEEVENT("[GEPERFTRACE] The time cost of extern constant folding is [%lu] micro second.", op_constant_folding_cost); + for (auto &it : constant_folding_pass.GetGeConstantFoldingPerfStatistic()) { + op_constant_folding_cost += it.second.second; + GELOGI("The time cost of %s constant folding is [%lu] micro second, calls is %lu.", it.first.c_str(), + it.second.second, it.second.first); + } GraphUtils::DumpGEGraphToOnnx(*compute_graph, "OptimizeStage1_2"); PassManager graph_pass; - // the prune pass should between SwtichPass and SwitchOpPass + // the prune pass should between SwitchPass and SwitchToStreamSwitchPass GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::PrunePass", new (std::nothrow) PrunePass)) GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::NextIterationPass", new (std::nothrow) NextIterationPass)) GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::ControlTriggerPass", new (std::nothrow) ControlTriggerPass)) - GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::SwitchOpPass", new (std::nothrow) SwitchOpPass)) + GE_CHK_STATUS_RET( + graph_pass.AddPass("OptimizeStage1_3::MergeToStreamMergePass", new (std::nothrow) MergeToStreamMergePass)) + GE_CHK_STATUS_RET( + graph_pass.AddPass("OptimizeStage1_3::SwitchToStreamSwitchPass", new (std::nothrow) SwitchToStreamSwitchPass)) + GE_CHK_STATUS_RET( + graph_pass.AddPass("OptimizeStage1_3::AttachStreamLabelPass", new (std::nothrow) AttachStreamLabelPass)) GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::IteratorOpPass", new (std::nothrow) IteratorOpPass)) GE_CHK_STATUS_RET(graph_pass.AddPass("OptimizeStage1_3::VariableRefUselessControlOutDeletePass", new (std::nothrow) VariableRefUselessControlOutDeletePass)) @@ -1657,10 +1732,9 @@ Status GraphManager::OptimizeStage1(ge::ComputeGraphPtr &compute_graph) { GELOGE(ret, "Run passes when OptimizeStage1_3 failed, ret:%u.", ret); return ret; } - NamesToPass identity_remove_pass; GE_TIMESTAMP_START(identity_remove_pass); - IdentityPass identity_force_pass(true); // after SwitchOpPass + IdentityPass identity_force_pass(false); // after SwitchToStreamSwitchPass identity_remove_pass.emplace_back("IdentityPass", &identity_force_pass); ret = GEPass(compute_graph).Run(identity_remove_pass); GE_TIMESTAMP_END(identity_remove_pass, "GraphPrepare::IdentityRemovePass"); @@ -1692,9 +1766,11 @@ Status GraphManager::OptimizeStage2(ge::ComputeGraphPtr &compute_graph) { ConstantFoldingPass constant_folding_pass; ReshapeRemovePass reshape_remove_pass; CondRemovePass condition_remove_pass; + BitcastPass bitcast_pass; names_to_passes.emplace_back("ConstantFoldingPass", &constant_folding_pass); names_to_passes.emplace_back("ReshapeRemovePass", &reshape_remove_pass); names_to_passes.emplace_back("CondRemovePass", &condition_remove_pass); + names_to_passes.emplace_back("BitcastPass", &bitcast_pass); GE_TIMESTAMP_START(names_to_passes); ret = GEPass(compute_graph).Run(names_to_passes); GE_TIMESTAMP_END(names_to_passes, "OptimizeStage2::MergedGraphNameToPasses"); @@ -1720,6 +1796,8 @@ Status GraphManager::OptimizeStage2(ge::ComputeGraphPtr &compute_graph) { GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::ControlAttrOptimize::MultiBatchPass", new (std::nothrow) MultiBatchPass)) + GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::AfterMergePasses::RefIdentityDeleteOpPass", + new (std::nothrow) RefIdentityDeleteOpPass)) // the value of the attr is the original variable name the ref-variable ref from. // The attr will be used when allocating memory, // the node marked attr will be output to a variable instead of new-allocated memory. @@ -1729,19 +1807,31 @@ Status GraphManager::OptimizeStage2(ge::ComputeGraphPtr &compute_graph) { new (std::nothrow) VariableRefDeleteOpPass)) GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::ControlAttrOptimize::CompileNodesPass", new (std::nothrow) CompileNodesPass)) + GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass( + "OptimizeStage2::AfterMergePasses::MarkGraphUnknownStatusPass", new (std::nothrow) MarkGraphUnknownStatusPass)) + GE_CHK_STATUS_RET( + pass_for_control_attr_optimize.AddPass("OptimizeStage2::AfterMergePasses::InputOutputConnectionIdentifyPass", + new (std::nothrow) InputOutputConnectionIdentifyPass)) // When the input node to be cleared is after a `Data` node, the atomic-clean-node should not be inserted. // So The ComputeGraph should not delete nodes after `AtomicAddrCleanPass` // to prevent unexpected deletion of nodes after a `Data` node GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::AfterMergePasses::AtomicAddrCleanPass", new (std::nothrow) AtomicAddrCleanPass)) + GE_CHK_STATUS_RET( + pass_for_control_attr_optimize.AddPass("OptimizeStage2::AfterMergePasses::" + "EndOfSequenceAddControlPass", + new (std::nothrow) EndOfSequenceAddControlPass)) const char *unknown_shape_skip = std::getenv("EXPERIMENTAL_DYNAMIC_PARTITION"); if (unknown_shape_skip == nullptr) { // SubgraphPass solves memory_assign_conflicts by insert MemcpyAsync node, which depends on multi attrs and // graph-structure. So try not to add new pass after SubgraphPass. GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::ControlAttrOptimize::SubgraphPass", - new (std::nothrow) SubgraphPass)); + new (std::nothrow) SubgraphPass)) } + // AttachStreamLabelPass modifies attr without changing structure of compute_graph + GE_CHK_STATUS_RET(pass_for_control_attr_optimize.AddPass("OptimizeStage2::ControlAttrOptimize::AttachStreamLabelPass", + new (std::nothrow) AttachStreamLabelPass)) GE_TIMESTAMP_START(pass_for_control_attr_optimize); ret = pass_for_control_attr_optimize.Run(compute_graph); @@ -1751,6 +1841,14 @@ Status GraphManager::OptimizeStage2(ge::ComputeGraphPtr &compute_graph) { return ret; } + // After while sub graph handle, mark all node rw type + auto result = graph_optimize_.HandleMemoryRWConflict(compute_graph); + if (result != SUCCESS) { + GELOGW( + "Mark node rw type failed. It will take some effect on memory_assign_conflicts handling." + "Please pay attention to it."); + } + ChangeConstTypeWhenTraining(compute_graph); ret = compute_graph->TopologicalSorting(); @@ -1777,8 +1875,6 @@ Status GraphManager::OptimizeAfterMergeSubGraph(ge::ComputeGraphPtr &compute_gra GEPass ge_passes_for_shape(compute_graph); NamesToPass names_to_passes_for_shape; - IdentifyReferencePass identify_reference_pass; - names_to_passes_for_shape.emplace_back("IdentifyReferencePass", &identify_reference_pass); CastRemovePass cast_remove_pass; names_to_passes_for_shape.emplace_back("CastRemovePass", &cast_remove_pass); TransposeTransDataPass transpose_transdata_pass; @@ -1821,6 +1917,8 @@ Status GraphManager::OptimizeAfterMergeSubGraph(ge::ComputeGraphPtr &compute_gra after_merge_fusion_passes.AddPass("VariableRefDeleteOpPass", new (std::nothrow) VariableRefDeleteOpPass)); GE_CHK_STATUS_RET(after_merge_fusion_passes.AddPass("SameTransdataBreadthFusionPass", new (std::nothrow) SameTransdataBreadthFusionPass)); + GE_CHK_STATUS_RET( + after_merge_fusion_passes.AddPass("MarkGraphUnknownStatusPass", new (std::nothrow) MarkGraphUnknownStatusPass)); GE_CHK_STATUS_RET(after_merge_fusion_passes.AddPass("AtomicAddrCleanPass", new (std::nothrow) AtomicAddrCleanPass)); GE_CHK_STATUS_RET(after_merge_fusion_passes.AddPass( "LinkGenMaskNodesPass", new (std::nothrow) LinkGenMaskNodesPass(options_.stream_max_parallel_num))); @@ -1866,7 +1964,10 @@ Status GraphManager::OptimizeAfterMergeSubGraph(ge::ComputeGraphPtr &compute_gra GE_CHK_STATUS_RET(ret, "Remove isolated Constant failed, ret:%d.", ret); PassManager pass_for_optimize; - GE_CHK_STATUS_RET(pass_for_optimize.AddPass("SubgraphPass", new (std::nothrow) SubgraphPass)); + const char *unknown_shape_skip = std::getenv("EXPERIMENTAL_DYNAMIC_PARTITION"); + if (unknown_shape_skip == nullptr) { + GE_CHK_STATUS_RET(pass_for_optimize.AddPass("SubgraphPass", new (std::nothrow) SubgraphPass)); + } GE_CHK_STATUS_RET(pass_for_optimize.AddPass("MultiBatchPass", new (std::nothrow) MultiBatchPass)); GE_CHK_STATUS_RET(pass_for_optimize.AddPass("CompileNodesPass", new (std::nothrow) CompileNodesPass)); GE_TIMESTAMP_START(pass_for_optimize); @@ -1906,7 +2007,7 @@ Status GraphManager::LoadGraphAsync(const GeRootModelPtr &ge_root_model, const G GE_CHECK_NOTNULL(graph_node->graph_run_async_listener_); Status ret = GraphLoader::LoadModelOnline(model_id_info.model_id, ge_root_model, graph_node->graph_run_async_listener_); - GE_TIMESTAMP_END(LoadGraph, "GraphManager::LoadGraphAsync"); + GE_TIMESTAMP_EVENT_END(LoadGraph, "GraphManager::LoadGraphAsync"); if (ret != SUCCESS) { GELOGE(ret, "[LoadGraphAsync] LoadGraphAsync Failed"); graph_node->SetRunFlag(false); @@ -2309,21 +2410,21 @@ Status GraphManager::OptimizeSubgraph(const GraphNodePtr &graph_node, ComputeGra GELOGE(FAILED, "failed get dynamic shape partitioned flag on partitioned graph."); return FAILED; } - GE_TIMESTAMP_END(GraphPartitionDynamicShape, "OptimizeSubgraph::GraphPartitionDynamicShape"); + GE_TIMESTAMP_EVENT_END(GraphPartitionDynamicShape, "OptimizeSubgraph::GraphPartitionDynamicShape"); GE_TIMESTAMP_START(GraphPartition); ret = graph_partitioner_.Partition(compute_graph, GraphPartitioner::kPartitioning); if (ret != SUCCESS) { GELOGE(ret, "Graph partition Failed"); return ret; } - GE_TIMESTAMP_END(GraphPartition, "OptimizeSubgraph::Partition1"); + GE_TIMESTAMP_EVENT_END(GraphPartition, "OptimizeSubgraph::Partition1"); GE_TIMESTAMP_START(SetSubgraph); ret = SetSubgraph(session_id, compute_graph); if (ret != SUCCESS) { GELOGE(ret, "Graph set subgraph Failed"); return ret; } - GE_TIMESTAMP_END(SetSubgraph, "OptimizeSubgraph::SetSubGraph"); + GE_TIMESTAMP_EVENT_END(SetSubgraph, "OptimizeSubgraph::SetSubGraph"); ComputeGraphPtr merged_compute_graph = nullptr; std::vector merged_sub_graph_list; @@ -2342,7 +2443,7 @@ Status GraphManager::OptimizeSubgraph(const GraphNodePtr &graph_node, ComputeGra sub_graph->SetSessionID(session_id); sub_graph->SetGraphID(graph_node->GetGraphId()); } - GE_TIMESTAMP_END(MergeSubgraph, "OptimizeSubgraph::MergeSubGraph"); + GE_TIMESTAMP_EVENT_END(MergeSubgraph, "OptimizeSubgraph::MergeSubGraph"); GE_DUMP(merged_compute_graph, "mergedComputeGraph"); compute_graph = merged_compute_graph; if (!AttrUtils::SetBool(*compute_graph, ATTR_NAME_DYNAMIC_SHAPE_PARTITIONED, dynamic_shape_partitioned)) { @@ -2368,8 +2469,7 @@ Status GraphManager::Build(const GraphNodePtr &graph_node, ComputeGraphPtr &comp } bool is_always_dump = false; - PropertiesManager &properties_manager = PropertiesManager::Instance(); - if (!properties_manager.GetDumpOutputPath().empty()) { + if (!PropertiesManager::Instance().GetDumpProperties(session_id).GetDumpPath().empty()) { is_always_dump = true; } diff --git a/src/ge/graph/manager/graph_manager.h b/src/ge/graph/manager/graph_manager.h index 8ab28316..681efac8 100644 --- a/src/ge/graph/manager/graph_manager.h +++ b/src/ge/graph/manager/graph_manager.h @@ -102,6 +102,9 @@ class GraphManager { ge::Status BuildGraph(const GraphId &graph_id, const std::vector &inputs, GeRootModelPtr &models, uint64_t session_id = 0, bool async = false); + Status BuildGraphForUnregisteredOp(const GraphId &graph_id, const std::vector &inputs, + GeRootModelPtr &ge_root_model, uint64_t session_id); + /// /// @ingroup ge_graph /// @brief Save extra attribute to Model @@ -327,6 +330,6 @@ class GraphManager { std::mutex run_mutex_; }; -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_MANAGER_GRAPH_MANAGER_H_ diff --git a/src/ge/graph/manager/graph_mem_allocator.h b/src/ge/graph/manager/graph_mem_allocator.h index 7bf82897..e4eeded3 100644 --- a/src/ge/graph/manager/graph_mem_allocator.h +++ b/src/ge/graph/manager/graph_mem_allocator.h @@ -190,6 +190,6 @@ class MemManager { std::map caching_allocator_map_; std::recursive_mutex allocator_mutex_; }; -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_MANAGER_GRAPH_MEM_ALLOCATOR_H_ diff --git a/src/ge/graph/manager/graph_var_manager.cc b/src/ge/graph/manager/graph_var_manager.cc index 2982eb89..7ca0224b 100644 --- a/src/ge/graph/manager/graph_var_manager.cc +++ b/src/ge/graph/manager/graph_var_manager.cc @@ -91,7 +91,7 @@ ge::Status VarResource::SaveVarAddr(const std::string &var_name, const ge::GeTen std::string var_key = VarKey(var_name, tensor_desc); GELOGD("VarResource::SaveVarAddr, var_key = %s", var_key.c_str()); if (var_addr_mgr_map_.count(var_key) == 0) { - uint64_t logic_address = VarManager::Instance(0)->GetVarMemLogicBase() + + uint64_t logic_address = VarManager::Instance(session_id_)->GetVarMemLogicBase() + reinterpret_cast(reinterpret_cast(address)); GELOGI("SaveVarAddr node_name %s, tensor_desc format %s, type %s.", var_name.c_str(), TypeUtils::FormatToSerialString(tensor_desc.GetFormat()).c_str(), @@ -274,7 +274,7 @@ MemResource::MemResource() : total_size_(0), var_mem_size_(0) {} Status MemResource::AssignVarMem(const std::string &var_name, uint64_t size, uint64_t session_id, size_t &mem_offset) { size = (size + kSessionMemAlignSize - 1) / kSessionMemAlignSize * kSessionMemAlignSize; uint64_t real_size = size; - total_size_ = VarManager::Instance(0)->GetVarMemMaxSize(); + total_size_ = VarManager::Instance(session_id)->GetVarMemMaxSize(); if (total_size_ < var_mem_size_) { GELOGE(PARAM_INVALID, "total_size_: %lu is smaller than var_mem_size_: %lu", total_size_, var_mem_size_); return PARAM_INVALID; @@ -684,7 +684,8 @@ uint8_t *VarManager::GetVarMemoryAddr(uint8_t *logic_addr, rtMemType_t memory_ty if (mem_base == nullptr) { return nullptr; } - uint8_t *mem_addr = logic_addr + reinterpret_cast(mem_base) - VarManager::Instance(0)->GetVarMemLogicBase(); + uint8_t *mem_addr = + logic_addr + reinterpret_cast(mem_base) - VarManager::Instance(session_id_)->GetVarMemLogicBase(); return mem_addr; } diff --git a/src/ge/graph/manager/graph_var_manager.h b/src/ge/graph/manager/graph_var_manager.h index be839eee..2142d906 100644 --- a/src/ge/graph/manager/graph_var_manager.h +++ b/src/ge/graph/manager/graph_var_manager.h @@ -309,5 +309,5 @@ class VarManagerPool { std::mutex var_manager_mutex_; map var_manager_map_; }; -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_MANAGER_GRAPH_VAR_MANAGER_H_ diff --git a/src/ge/graph/manager/host_mem_manager.cc b/src/ge/graph/manager/host_mem_manager.cc new file mode 100644 index 00000000..1d35f7af --- /dev/null +++ b/src/ge/graph/manager/host_mem_manager.cc @@ -0,0 +1,86 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/manager/host_mem_manager.h" + +#include + +#include "graph/utils/tensor_utils.h" + +namespace ge { +Status HostMemoryAllocator::Allocate(std::size_t memory_size, uint8_t *memory_addr) { + GELOGI("HostMemoryAllocator::MallocMemory size= %zu.", memory_size); + return SUCCESS; +} + +Status HostMemoryAllocator::DeAllocate(uint8_t *memory_addr) { + if (rtFreeHost(memory_addr) != RT_ERROR_NONE) { + GELOGE(GE_GRAPH_FREE_FAILED, "MemoryAllocator::Free memory failed."); + return GE_GRAPH_FREE_FAILED; + } + memory_addr = nullptr; + return ge::SUCCESS; +} + +HostMemManager &HostMemManager::Instance() { + static HostMemManager mem_manager; + return mem_manager; +} + +Status HostMemManager::Initialize() { + std::lock_guard lock(mutex_); + allocator_ = std::unique_ptr(new (std::nothrow) HostMemoryAllocator()); + if (allocator_ == nullptr) { + GELOGE(GE_GRAPH_MALLOC_FAILED, "Host mem allocator init failed!"); + return GE_GRAPH_MALLOC_FAILED; + } + return SUCCESS; +} + +void HostMemManager::Finalize() noexcept { + std::lock_guard lock(mutex_); + + for (const auto &it : var_memory_base_map_) { + if (allocator_->DeAllocate(it.second.address) != SUCCESS) { + GELOGW("Host %s mem deAllocator failed!", it.first.c_str()); + } + } + var_memory_base_map_.clear(); +} + +Status HostMemManager::MallocMemoryForHostVar(const string &op_name, uint64_t tensor_size, uint8_t *&var_addr) { + std::lock_guard lock(mutex_); + if (var_memory_base_map_.find(op_name) != var_memory_base_map_.end()) { + GELOGI("Host mem for variable %s has been malloced", op_name.c_str()); + return SUCCESS; + } + GE_CHECK_NOTNULL(allocator_); + GE_CHK_STATUS(allocator_->Allocate(tensor_size, var_addr)); + HostMemInfo info(var_addr, tensor_size); + var_memory_base_map_[op_name] = info; + return SUCCESS; +} + +Status HostMemManager::QueryVarMemInfo(const string &op_name, uint64_t &base_addr, uint64_t &data_size) { + if (var_memory_base_map_.find(op_name) == var_memory_base_map_.end()) { + GELOGE(INTERNAL_ERROR, "Find host base base_addr failed,node name:%s!", op_name.c_str()); + return INTERNAL_ERROR; + } + base_addr = reinterpret_cast(reinterpret_cast(var_memory_base_map_[op_name].address)); + data_size = var_memory_base_map_[op_name].data_size; + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/manager/host_mem_manager.h b/src/ge/graph/manager/host_mem_manager.h new file mode 100644 index 00000000..3a5a0602 --- /dev/null +++ b/src/ge/graph/manager/host_mem_manager.h @@ -0,0 +1,73 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_MANAGER_HOST_VAR_MANAGER_H_ +#define GE_GRAPH_MANAGER_HOST_VAR_MANAGER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "framework/common/ge_inner_error_codes.h" +#include "framework/common/ge_types.h" +#include "framework/common/l2_cache_optimize.h" +#include "graph/ge_tensor.h" +#include "graph/op_desc.h" +#include "graph/tensor.h" +#include "runtime/mem.h" + +namespace ge { +class HostMemoryAllocator { + public: + ~HostMemoryAllocator() = default; + + Status Allocate(std::size_t size, uint8_t *memory_addr); + Status DeAllocate(uint8_t *memory_addr); +}; + +struct HostMemInfo { + uint8_t *address; + uint64_t data_size; + HostMemInfo() : address(nullptr), data_size(0) {} + HostMemInfo(uint8_t *addr, uint64_t size) : address(addr), data_size(size) {} +}; + +class HostMemManager { + public: + HostMemManager() = default; + ~HostMemManager() { Finalize(); } + HostMemManager(const HostMemManager &) = delete; + HostMemManager &operator=(const HostMemManager &) = delete; + + static HostMemManager &Instance(); + Status Initialize(); + void Finalize() noexcept; + Status MallocMemoryForHostVar(const string &op_name, uint64_t tensor_size, uint8_t *&var_addr); + Status QueryVarMemInfo(const string &op_name, uint64_t &base_addr, uint64_t &data_size); + + private: + std::unordered_map var_memory_base_map_; + std::unique_ptr allocator_; + mutable std::recursive_mutex mutex_; +}; +} // namespace ge + +#endif // GE_GRAPH_MANAGER_HOST_VAR_MANAGER_H_ diff --git a/src/ge/graph/manager/memory_api.cc b/src/ge/graph/manager/memory_api.cc new file mode 100644 index 00000000..0a98e983 --- /dev/null +++ b/src/ge/graph/manager/memory_api.cc @@ -0,0 +1,45 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "framework/memory/memory_api.h" + +#include + +#include "graph/manager/graph_mem_allocator.h" +#include "graph/manager/host_mem_manager.h" +#include "graph/manager/rdma_pool_allocator.h" +#include "hccl/base.h" +#include "hccl/hcom.h" + +namespace ge { +Status InitRdmaPool(size_t size, rtMemType_t mem_type) { + GELOGD("InitRdmaPool in"); + return MemManager::Instance().RdmaPoolInstance(mem_type).InitMemory(size); +} + +Status RdmaRemoteRegister(const std::vector &var_info, rtMemType_t mem_type) { + GELOGD("Start to register rdma memory with host var size %zu", var_info.size()); + uint64_t device_base = 0; + uint64_t device_size = 0; + GE_CHK_STATUS_RET(MemManager::Instance().RdmaPoolInstance(mem_type).GetBaseAddr(device_base, device_size)); + return SUCCESS; +} + +Status GetVarBaseAddrAndSize(const string &var_name, uint64_t &base_addr, uint64_t &var_size) { + GELOGD("GetVarBaseAddrAndSize in"); + return HostMemManager::Instance().QueryVarMemInfo(var_name, base_addr, var_size); +} +} // namespace ge \ No newline at end of file diff --git a/src/ge/graph/manager/model_manager/event_manager.h b/src/ge/graph/manager/model_manager/event_manager.h index bdf0633a..a20afead 100644 --- a/src/ge/graph/manager/model_manager/event_manager.h +++ b/src/ge/graph/manager/model_manager/event_manager.h @@ -92,6 +92,6 @@ class EventManager { std::vector event_list_; bool inited_; uint32_t current_idx_; -}; // EventManager -}; // namespace ge +}; // EventManager +} // namespace ge #endif // GE_GRAPH_MANAGER_MODEL_MANAGER_EVENT_MANAGER_H_ diff --git a/src/ge/graph/manager/rdma_pool_allocator.cc b/src/ge/graph/manager/rdma_pool_allocator.cc new file mode 100644 index 00000000..1daeafb8 --- /dev/null +++ b/src/ge/graph/manager/rdma_pool_allocator.cc @@ -0,0 +1,179 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/manager/rdma_pool_allocator.h" +#include "framework/common/debug/ge_log.h" +#include "graph/manager/graph_mem_allocator.h" + +namespace { +const size_t kAlignedSize = 512; +const float kSplitThreshold = 0.5; + +inline size_t GetAlignedBlockSize(size_t size) { + if (size == 0) { + return kAlignedSize; + } + return kAlignedSize * ((size + kAlignedSize - 1) / kAlignedSize); +} + +inline bool ShouldSplit(const ge::Block *block, size_t size) { + return static_cast(size) <= (static_cast(block->size) * kSplitThreshold); +} + +inline bool CanMerge(ge::Block *block) { return block != nullptr && !block->allocated; } +} // namespace + +namespace ge { +RdmaPoolAllocator::RdmaPoolAllocator(rtMemType_t memory_type) + : memory_type_(memory_type), block_bin_(BlockBin([](const Block *left, const Block *right) { + if (left->size != right->size) { + return left->size < right->size; + } + return reinterpret_cast(left->ptr) < reinterpret_cast(right->ptr); + })) {} + +Status RdmaPoolAllocator::Initialize() { + memory_allocator_ = MemManager::Instance(memory_type_); + if (memory_allocator_ == nullptr) { + return ge::FAILED; + } + return ge::SUCCESS; +} +void RdmaPoolAllocator::Finalize() { + for (auto it = allocated_blocks_.begin(); it != allocated_blocks_.end();) { + auto block = it->second; + allocated_blocks_.erase(it); + delete block; + } + for (auto it = block_bin_.begin(); it != block_bin_.end();) { + auto block = *it; + block_bin_.erase(it); + delete block; + } + + if (rdma_base_addr_ != nullptr) { + if (memory_allocator_->FreeMemory(rdma_base_addr_) != SUCCESS) { + GELOGW("Free rdma pool memory failed"); + } + } +} + +Status RdmaPoolAllocator::InitMemory(size_t mem_size, uint32_t device_id) { + if (rdma_base_addr_ != nullptr) { + GELOGE(GE_MULTI_INIT, "Rdma pool has been malloced"); + return GE_MULTI_INIT; + } + const std::string purpose = "Memory for rdma pool."; + std::lock_guard lock(mutex_); + rdma_base_addr_ = memory_allocator_->MallocMemory(purpose, mem_size, device_id); + if (rdma_base_addr_ == nullptr) { + GELOGE(GE_GRAPH_MALLOC_FAILED, "Rdma pool memory malloc failed"); + return GE_GRAPH_MALLOC_FAILED; + } + rdma_mem_size_ = mem_size; + // Init with a base block. + auto *base_block = new (std::nothrow) Block(device_id, mem_size, rdma_base_addr_); + if (base_block == nullptr) { + GELOGE(GE_GRAPH_MALLOC_FAILED, "Block malloc failed"); + return GE_GRAPH_MALLOC_FAILED; + } + block_bin_.insert(base_block); + return SUCCESS; +} + +uint8_t *RdmaPoolAllocator::Malloc(size_t size, uint32_t device_id) { + auto aligned_size = GetAlignedBlockSize(size); + Block key(device_id, aligned_size, nullptr); + std::lock_guard lock(mutex_); + auto it = block_bin_.lower_bound(&key); + if (it != block_bin_.end()) { + Block *block = *it; + block_bin_.erase(it); + block->allocated = true; + if (block->ptr == nullptr) { + GELOGE(INTERNAL_ERROR, "Rdmapool memory address is nullptr."); + return nullptr; + } + allocated_blocks_.emplace(block->ptr, block); + GELOGI("Find block size = %zu", block->size); + + if (ShouldSplit(block, aligned_size)) { + auto *new_block = + new (std::nothrow) Block(device_id, block->size - aligned_size, nullptr, block->ptr + aligned_size); + if (new_block == nullptr) { + GELOGW("Block split failed"); + return block->ptr; + } + new_block->next = block->next; + if (block->next != nullptr) { + block->next->prev = new_block; + } + new_block->prev = block; + block->next = new_block; + block->size = aligned_size; + block_bin_.insert(new_block); + } + return block->ptr; + } + return nullptr; +} + +Status RdmaPoolAllocator::Free(uint8_t *memory_addr, uint32_t device_id) { + GELOGI("Free device id = %u", device_id); + if (memory_addr == nullptr) { + GELOGE(GE_GRAPH_FREE_FAILED, "Invalid memory pointer"); + return GE_GRAPH_FREE_FAILED; + } + + std::lock_guard lock(mutex_); + auto it = allocated_blocks_.find(memory_addr); + if (it == allocated_blocks_.end()) { + GELOGE(PARAM_INVALID, "Invalid memory pointer"); + return PARAM_INVALID; + } + Block *block = it->second; + block->allocated = false; + allocated_blocks_.erase(it); + block_bin_.insert(block); + // Each time merge with its pre and next. + MergeBlockNearby(block, block->next); + MergeBlockNearby(block->prev, block); + return SUCCESS; +} + +void RdmaPoolAllocator::MergeBlockNearby(Block *pre_block, Block *block) { + if (!(CanMerge(pre_block) && CanMerge(block))) { + return; + } + pre_block->size += block->size; + pre_block->next = block->next; + if (block->next != nullptr) { + block->next->prev = pre_block; + } + block_bin_.erase(block); + delete block; +} + +Status RdmaPoolAllocator::GetBaseAddr(uint64_t &base_addr, uint64_t &mem_size) { + if (rdma_base_addr_ == nullptr) { + GELOGE(INTERNAL_ERROR, "Rdma base addr is nullptr."); + return INTERNAL_ERROR; + } + base_addr = reinterpret_cast(reinterpret_cast(rdma_base_addr_)); + mem_size = rdma_mem_size_; + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/manager/rdma_pool_allocator.h b/src/ge/graph/manager/rdma_pool_allocator.h new file mode 100644 index 00000000..59d33916 --- /dev/null +++ b/src/ge/graph/manager/rdma_pool_allocator.h @@ -0,0 +1,71 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_MANAGER_RDMA_POOL_ALLOCATOR_H_ +#define GE_GRAPH_MANAGER_RDMA_POOL_ALLOCATOR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "framework/common/ge_inner_error_codes.h" +#include "graph/manager/block_memory.h" +#include "graph/node.h" +#include "runtime/mem.h" + +namespace ge { +class MemoryAllocator; + +class RdmaPoolAllocator { + public: + explicit RdmaPoolAllocator(rtMemType_t memory_type); + + RdmaPoolAllocator(const RdmaPoolAllocator &) = delete; + + RdmaPoolAllocator &operator=(const RdmaPoolAllocator &) = delete; + + ~RdmaPoolAllocator() { Finalize(); } + + Status Initialize(); + void Finalize(); + + Status InitMemory(size_t mem_size, uint32_t device_id = 0); + + uint8_t *Malloc(size_t size, uint32_t device_id = 0); + + Status Free(uint8_t *memory_addr, uint32_t device_id = 0); + + Status GetBaseAddr(uint64_t &base_addr, uint64_t &mem_size); + + private: + void MergeBlockNearby(Block *pre_block, Block *block); + + rtMemType_t memory_type_; + size_t rdma_mem_size_ = 0; // Total rdma memory size to be allocated. + uint8_t *rdma_base_addr_ = nullptr; + MemoryAllocator *memory_allocator_ = nullptr; + BlockBin block_bin_; // Save all rdma blocks. + std::unordered_map allocated_blocks_; + // lock around all operations + mutable std::recursive_mutex mutex_; +}; +} // namespace ge + +#endif // GE_GRAPH_MANAGER_RDMA_POOL_ALLOCATOR_H_ diff --git a/src/ge/graph/manager/trans_var_data_utils.cc b/src/ge/graph/manager/trans_var_data_utils.cc index e8444c53..60a0d0db 100644 --- a/src/ge/graph/manager/trans_var_data_utils.cc +++ b/src/ge/graph/manager/trans_var_data_utils.cc @@ -397,10 +397,11 @@ Status TransVarDataUtils::SyncTensorToHost(const string &var_name, const ge::GeT uint8_t *src_addr = nullptr; GE_CHK_STATUS_RET(VarManager::Instance(session_id)->GetVarAddr(var_name, src_tensor_desc, &src_addr)); - uint8_t *mem_addr = src_addr - - static_cast(reinterpret_cast(VarManager::Instance(0)->GetVarMemLogicBase())) + - static_cast( - reinterpret_cast(VarManager::Instance(session_id)->GetVarMemoryBase(RT_MEMORY_HBM))); + uint8_t *mem_addr = + src_addr - + static_cast(reinterpret_cast(VarManager::Instance(session_id)->GetVarMemLogicBase())) + + static_cast( + reinterpret_cast(VarManager::Instance(session_id)->GetVarMemoryBase(RT_MEMORY_HBM))); GE_CHK_RT_RET(rtMallocHost(reinterpret_cast(host_addr), src_tensor_size)); GE_CHK_RT_RET(rtMemcpy(*host_addr, src_tensor_size, mem_addr, src_tensor_size, RT_MEMCPY_DEVICE_TO_HOST)); @@ -413,10 +414,11 @@ Status TransVarDataUtils::SyncTensorToDevice(const string &var_name, const uint8 const ge::GeTensorDesc &dst_tensor_desc, uint64_t session_id) { uint8_t *dst_addr = nullptr; GE_CHK_STATUS_RET(VarManager::Instance(session_id)->GetVarAddr(var_name, dst_tensor_desc, &dst_addr)); - uint8_t *mem_addr = dst_addr - - static_cast(reinterpret_cast(VarManager::Instance(0)->GetVarMemLogicBase())) + - static_cast( - reinterpret_cast(VarManager::Instance(session_id)->GetVarMemoryBase(RT_MEMORY_HBM))); + uint8_t *mem_addr = + dst_addr - + static_cast(reinterpret_cast(VarManager::Instance(session_id)->GetVarMemLogicBase())) + + static_cast( + reinterpret_cast(VarManager::Instance(session_id)->GetVarMemoryBase(RT_MEMORY_HBM))); GE_CHK_RT_RET(rtMemcpy(mem_addr, addr_size, host_addr, addr_size, RT_MEMCPY_HOST_TO_DEVICE)); GELOGI("SyncTensorToDevice var_name %s, addr_size %u", var_name.c_str(), addr_size); @@ -442,7 +444,7 @@ Status TransVarDataUtils::TransAllVarData(const vector &variable_nodes, rtError_t rt_ret = rtCtxSetCurrent(ctx); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Failed to set context, error_code is: 0x%X.", rt_ret); - return RT_FAILED; + return RT_ERROR_TO_GE_STATUS(rt_ret); } uint32_t allocated_graph_id = 0; Status ret = VarManager::Instance(session_id)->GetAllocatedGraphId(node->GetName(), allocated_graph_id); diff --git a/src/ge/graph/manager/util/hcom_util.cc b/src/ge/graph/manager/util/hcom_util.cc index 4f6fe591..5f31c982 100644 --- a/src/ge/graph/manager/util/hcom_util.cc +++ b/src/ge/graph/manager/util/hcom_util.cc @@ -24,7 +24,6 @@ #include "graph/utils/type_utils.h" namespace ge { - Status HcomOmeUtil::GetHcclDataType(const ge::ConstOpDescPtr &op_desc, std::vector &kernel_hccl_infos) { GE_CHECK_NOTNULL(op_desc); @@ -101,6 +100,12 @@ Status HcomOmeUtil::GetHcomCount(const ge::ConstOpDescPtr &op_desc, hcclDataType GE_CHECK_NOTNULL(op_desc->GetInputDescPtr(i)); GE_CHK_STATUS_RET(ge::TensorUtils::GetSize(*op_desc->GetInputDescPtr(i), input_size), "get size from TensorDesc failed, op : %s, input index : %zu", op_desc->GetName().c_str(), i); + // dynamic shape hccl op get size from output tensor desc + if (op_desc->HasAttr(ATTR_NAME_IS_UNKNOWN_SHAPE)) { + GE_CHECK_NOTNULL(op_desc->GetOutputDescPtr(i)); + GE_CHK_STATUS_RET(ge::TensorUtils::GetSize(*op_desc->GetOutputDescPtr(i), input_size), + "get size from TensorDesc failed, op : %s, input index : %zu", op_desc->GetName().c_str(), i); + } GE_IF_BOOL_EXEC( op_desc->GetType() == HCOMREDUCESCATTER, int32_t rank_size = 0; @@ -114,6 +119,8 @@ Status HcomOmeUtil::GetHcomCount(const ge::ConstOpDescPtr &op_desc, hcclDataType total_size = total_size + block_size; continue;); int64_t shape_size = op_desc->GetInputDescPtr(i)->GetShape().GetShapeSize(); + GELOGD("hcom util node %s inputsize %ld, shapesize %ld, datasize %d.", op_desc->GetName().c_str(), input_size, + shape_size, size); GE_CHK_STATUS_RET(ge::CheckInt64Int32MulOverflow(shape_size, size), "Product of shape size and size beyond INT64_MAX"); GE_IF_BOOL_EXEC(is_allgather, block_size = shape_size * size;); diff --git a/src/ge/graph/manager/util/hcom_util.h b/src/ge/graph/manager/util/hcom_util.h index 40aac3e5..e31e3ef0 100644 --- a/src/ge/graph/manager/util/hcom_util.h +++ b/src/ge/graph/manager/util/hcom_util.h @@ -144,8 +144,6 @@ class HcomOmeUtil { /// static Status GetHorovodInputs(const ge::ConstOpDescPtr &op_desc, std::vector &kernel_hccl_infos); - - private: /// /// @ingroup domi_ome /// @brief GetHcomCount @@ -154,6 +152,8 @@ class HcomOmeUtil { /// static Status GetHcomCount(const ge::ConstOpDescPtr &op_desc, hcclDataType_t data_type, bool is_allgather, int &count); + + private: /// /// @ingroup domi_ome /// @brief GetHorovodCount diff --git a/src/ge/graph/manager/util/rt_context_util.cc b/src/ge/graph/manager/util/rt_context_util.cc index 05120f6a..e6344539 100644 --- a/src/ge/graph/manager/util/rt_context_util.cc +++ b/src/ge/graph/manager/util/rt_context_util.cc @@ -19,13 +19,30 @@ #include "framework/common/debug/ge_log.h" namespace ge { -void RtContextUtil::AddrtContext(rtContext_t context) { rtContexts_.emplace_back(context); } +void RtContextUtil::AddRtContext(uint64_t session_id, rtContext_t context) { + std::lock_guard lock(ctx_mutex_); + rt_contexts_[session_id].emplace_back(context); +} + +void RtContextUtil::DestroyRtContexts(uint64_t session_id) { + std::lock_guard lock(ctx_mutex_); + auto &contexts = rt_contexts_[session_id]; + DestroyRtContexts(session_id, contexts); +} + +void RtContextUtil::DestroyAllRtContexts() { + std::lock_guard lock(ctx_mutex_); + for (auto &ctx_pair : rt_contexts_) { + DestroyRtContexts(ctx_pair.first, ctx_pair.second); + } + rt_contexts_.clear(); +} -void RtContextUtil::DestroyrtContexts() { - GELOGI("The size of runtime context handle is %zu.", rtContexts_.size()); - for (auto &rtContext : rtContexts_) { +void RtContextUtil::DestroyRtContexts(uint64_t session_id, std::vector &contexts) { + GELOGI("Runtime context handle number of session %lu is %zu.", session_id, contexts.size()); + for (auto &rtContext : contexts) { (void)rtCtxDestroy(rtContext); } - rtContexts_.clear(); + contexts.clear(); } } // namespace ge diff --git a/src/ge/graph/manager/util/rt_context_util.h b/src/ge/graph/manager/util/rt_context_util.h index 93db9882..58cc0803 100644 --- a/src/ge/graph/manager/util/rt_context_util.h +++ b/src/ge/graph/manager/util/rt_context_util.h @@ -18,6 +18,8 @@ #define GE_GRAPH_MANAGER_UTIL_RT_CONTEXT_UTIL_H_ #include +#include +#include #include "runtime/context.h" @@ -29,13 +31,14 @@ class RtContextUtil { return instance; } - void AddrtContext(rtContext_t context); + void AddRtContext(uint64_t session_id, rtContext_t context); const rtContext_t GetNormalModeContext() const { return before_prerun_ctx_; } void SetNormalModeContext(rtContext_t context) { before_prerun_ctx_ = context; } - void DestroyrtContexts(); + void DestroyRtContexts(uint64_t session_id); + void DestroyAllRtContexts(); RtContextUtil &operator=(const RtContextUtil &) = delete; RtContextUtil(const RtContextUtil &RtContextUtil) = delete; @@ -44,8 +47,12 @@ class RtContextUtil { RtContextUtil() = default; ~RtContextUtil() {} - std::vector rtContexts_; + void DestroyRtContexts(uint64_t session_id, std::vector &contexts); + + std::map> rt_contexts_; rtContext_t before_prerun_ctx_ = nullptr; + + std::mutex ctx_mutex_; }; } // namespace ge diff --git a/src/ge/graph/optimize/graph_optimize.cc b/src/ge/graph/optimize/graph_optimize.cc index b42c2e01..09acae33 100644 --- a/src/ge/graph/optimize/graph_optimize.cc +++ b/src/ge/graph/optimize/graph_optimize.cc @@ -299,4 +299,36 @@ void GraphOptimize::TranFrameOp(ComputeGraphPtr &compute_graph) { } } } + +Status GraphOptimize::IdentifyReference(ComputeGraphPtr &compute_graph) { + for (auto &node : compute_graph->GetAllNodes()) { + GE_CHECK_NOTNULL(node); + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + auto input_name_index = op_desc->GetAllInputName(); + bool is_ref = false; + for (const auto &name_index : input_name_index) { + const int out_index = op_desc->GetOutputIndexByName(name_index.first); + if (out_index != -1) { + auto input_desc = op_desc->GetInputDesc(name_index.second); + input_desc.SetRefPortByIndex({name_index.second}); + op_desc->UpdateInputDesc(name_index.second, input_desc); + GELOGI("SetRefPort: set op[%s] input desc[%u-%s] ref.", op_desc->GetName().c_str(), name_index.second, + name_index.first.c_str()); + auto output_desc = op_desc->GetOutputDesc(static_cast(out_index)); + output_desc.SetRefPortByIndex({name_index.second}); + op_desc->UpdateOutputDesc(static_cast(out_index), output_desc); + GELOGI("SetRefPort: set op[%s] output desc[%u-%s] ref.", op_desc->GetName().c_str(), out_index, + name_index.first.c_str()); + is_ref = true; + } + } + if (is_ref) { + AttrUtils::SetBool(op_desc, ATTR_NAME_REFERENCE, is_ref); + GELOGI("param [node] %s is reference node, set attribute %s to be true.", node->GetName().c_str(), + ATTR_NAME_REFERENCE.c_str()); + } + } + return SUCCESS; +} } // namespace ge diff --git a/src/ge/graph/optimize/graph_optimize.h b/src/ge/graph/optimize/graph_optimize.h index 72709932..f3eb2009 100644 --- a/src/ge/graph/optimize/graph_optimize.h +++ b/src/ge/graph/optimize/graph_optimize.h @@ -60,13 +60,20 @@ class GraphOptimize { const std::map> &GetSummaryOutputIndexes() const { return summary_output_indexes_; - } + } // lint !e1073 void ClearSummaryOutputIndexes() { summary_output_indexes_.clear(); } // handle summary node before preRun graph Status HandleSummaryOp(ComputeGraphPtr &compute_graph); + // Identify reference node before optimize subgraph + Status IdentifyReference(ComputeGraphPtr &compute_graph); + + Status HandleMemoryRWConflict(ComputeGraphPtr &compute_graph); + + Status CheckRWConflict(ComputeGraphPtr &compute_graph, bool &has_conflict); + void TranFrameOp(ComputeGraphPtr &compute_graph); private: @@ -85,5 +92,5 @@ class GraphOptimize { std::map> summary_output_indexes_ = {}; std::string func_bin_path_; }; -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_OPTIMIZE_GRAPH_OPTIMIZE_H_ diff --git a/src/ge/graph/optimize/mem_rw_conflict_optimize.cc b/src/ge/graph/optimize/mem_rw_conflict_optimize.cc new file mode 100644 index 00000000..f75565ba --- /dev/null +++ b/src/ge/graph/optimize/mem_rw_conflict_optimize.cc @@ -0,0 +1,712 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include +#include + +#include "common/ge/ge_util.h" +#include "graph/common/omg_util.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/optimize/graph_optimize.h" +#include "graph/utils/graph_utils.h" +#include "graph/utils/node_utils.h" + +namespace { +using namespace ge; +const int kIdentityAnchorIndex = 0; +// rw type of input. +enum class InputRWType { + kReadOnly, // Normal op input only read + kWriteable, // Op like Assign/ApplyMomentum + kScopeWriteable, // Op like hcom_allreduce, it will modify input ,but not expect take effect on pre ouput + kInvalidRWType +}; +// rw type of output +enum class OutputRWType { + kReadOnly, // 1.const output 2.not ref output but has several peer output + kSoftRead, // not ref output but only has one output node + kWriteable, // ref output. Like Assign/ApplyMomentum + kInvalidRWType +}; +// input and output rw_type of one node. key is anchor_idx, value is rw_type +struct NodeInputOutputRWType { + map input_rw_type_map; + map output_rw_type_map; +}; +// input and output rw_type of node in current graph +map node_rwtype_map_; + +/// +/// @brief Convert input rw_type enum to string. For log print. +/// @param rw_type +/// @return rw_type_name +/// +static std::string InputRWTypeToSerialString(InputRWType rw_type) { + const static char *names[4] = {"ReadOnly", "Writeable", "ScopeWriteable", "InvalidRWType"}; + return names[static_cast(rw_type)]; +} + +/// +/// @brief Convert output rw_type enum to string. For log print. +/// @param rw_type +/// @return rw_type_name +/// +static std::string OutputRWTypeToSerialString(OutputRWType rw_type) { + const static char *names[4] = {"ReadOnly", "SoftRead", "Writeable", "InvalidRWType"}; + return names[static_cast(rw_type)]; +} + +OutputRWType GetSingleNodeOutputRWTypeByIndex(const Node &node, uint32_t index) { + auto op_desc = node.GetOpDesc(); + if (op_desc == nullptr) { + return OutputRWType::kInvalidRWType; + } + if (op_desc->GetType() == VARIABLE) { + return OutputRWType::kWriteable; + } + // check if it is ref output + auto input_names = op_desc->GetAllInputName(); + for (auto &input_name_2_idx : input_names) { + if (op_desc->GetOutputNameByIndex(index) == input_name_2_idx.first) { + return OutputRWType::kWriteable; + } + } + // check if it is ref switch + std::string type; + if ((node.GetType() == FRAMEWORK_OP_TYPE) && AttrUtils::GetStr(op_desc, ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type) && + (type == REFSWITCH)) { + return OutputRWType::kWriteable; + } + + if (op_desc->GetType() == CONSTANT || op_desc->GetType() == CONSTANTOP) { + return OutputRWType::kReadOnly; + } + auto out_data_anchor = node.GetOutDataAnchor(index); + if (out_data_anchor == nullptr) { + return OutputRWType::kInvalidRWType; + } + if (out_data_anchor->GetPeerInDataNodesSize() > 1) { + return OutputRWType::kReadOnly; + } else { + return OutputRWType::kSoftRead; + } +} + +/// +/// @brief Get input rw_type of one node with sub graph. It will return rw_type after solve conflict scene. +/// @param rw_type_set +/// @return +/// +InputRWType GetInputRwTypeInConflict(std::set rw_type_set) { + // for input rw type calc + int total_rw_type = 0; + for (auto rw : rw_type_set) { + total_rw_type += rw; + } + switch (total_rw_type) { + case 0: + return InputRWType::kReadOnly; + case 2: + return InputRWType::kScopeWriteable; + case 3: + return InputRWType::kWriteable; + case 5: + return InputRWType::kInvalidRWType; + default: + return InputRWType::kInvalidRWType; + } +} + +NodePtr CreateIdentityAfterSrcNode(const Node &src_node, int out_anchor_idx) { + if (src_node.GetOpDesc() == nullptr) { + return nullptr; + } + static std::atomic identity_num(0); + auto next_num = identity_num.fetch_add(1); + // 1. create new identity op desc + string identity_name = src_node.GetName() + "_" + IDENTITY + std::to_string(next_num); + auto identity_opdesc = MakeShared(identity_name, IDENTITY); + if (identity_opdesc == nullptr) { + GELOGE(OUT_OF_MEMORY, "Failed to insert identity node, name %s", identity_name.c_str()); + return nullptr; + } + auto data_desc = src_node.GetOpDesc()->GetOutputDesc(out_anchor_idx); + // 2. add input_desc & output_desc for new identity + Status ret = identity_opdesc->AddInputDesc(data_desc); + if (ret != SUCCESS) { + GELOGE(ret, "Add Input desc failed for new identity %s.", identity_name.c_str()); + return nullptr; + } + ret = identity_opdesc->AddOutputDesc(data_desc); + if (ret != SUCCESS) { + GELOGE(ret, "Add Output desc failed for new Identity %s.", identity_name.c_str()); + return nullptr; + } + GELOGI("Insert new Identity node %s.", identity_name.c_str()); + auto graph = src_node.GetOwnerComputeGraph(); + if (graph == nullptr) { + GELOGE(GRAPH_PARAM_INVALID, "Node %s owner compute graph is null.", src_node.GetName().c_str()); + return nullptr; + } + return graph->AddNode(identity_opdesc); +} + +OutputRWType GetOutputRWTypeByIndex(const Node &node, uint32_t index) { + auto op_desc = node.GetOpDesc(); + if (op_desc == nullptr) { + return OutputRWType::kInvalidRWType; + } + if (op_desc->GetType() == WHILE) { + return OutputRWType::kSoftRead; + } + vector subgraph_names = op_desc->GetSubgraphInstanceNames(); + if (subgraph_names.empty()) { + // single node without sub graph + return GetSingleNodeOutputRWTypeByIndex(node, index); + } else { + // node with sub graph + auto output_node_vec = NodeUtils::GetSubgraphOutputNodes(node); + auto output_rw_type = OutputRWType::kInvalidRWType; + if (output_node_vec.size() == 1) { + // find rw type from map. + auto iter = node_rwtype_map_.find(output_node_vec.at(0)->GetName()); + if (iter == node_rwtype_map_.end()) { + GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.", + output_node_vec.at(0)->GetName().c_str()); + return OutputRWType::kInvalidRWType; + } + auto index_2_output_rw_type = iter->second.output_rw_type_map.find(index); + if (index_2_output_rw_type == iter->second.output_rw_type_map.end()) { + GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.", + output_node_vec.at(0)->GetName().c_str()); + return OutputRWType::kInvalidRWType; + } + output_rw_type = index_2_output_rw_type->second; + } else { + output_rw_type = OutputRWType::kSoftRead; + } + // check peer input + auto out_data_anchor = node.GetOutDataAnchor(index); + if (out_data_anchor == nullptr) { + return OutputRWType::kInvalidRWType; + } + if (out_data_anchor->GetPeerInDataNodesSize() > 1) { + return OutputRWType::kReadOnly; + } else { + return output_rw_type; + } + } +} + +InputRWType GetSingleNodeInputRWTypeByIndex(const Node &node, uint32_t index) { + auto op_desc = node.GetOpDesc(); + if (op_desc == nullptr) { + return InputRWType::kInvalidRWType; + } + if (op_desc->GetType() == HCOMALLREDUCE || op_desc->GetType() == HCOMALLGATHER || + op_desc->GetType() == HCOMREDUCESCATTER) { + return InputRWType::kScopeWriteable; + } + // check if it is ref input + auto output_names = op_desc->GetAllOutputName(); + for (auto &output_name_2_idx : output_names) { + if (op_desc->GetInputNameByIndex(index) == output_name_2_idx.first) { + return InputRWType::kWriteable; + } + } + // check if it is ref switch todo + std::string type; + if ((node.GetType() == FRAMEWORK_OP_TYPE) && (AttrUtils::GetStr(op_desc, ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type)) && + (type == REFSWITCH) && (index == 0)) { + return InputRWType::kWriteable; + } + + return InputRWType::kReadOnly; +} + +InputRWType GetInputRWTypeByIndex(const Node &node, uint32_t index) { + auto op_desc = node.GetOpDesc(); + if (op_desc == nullptr) { + return InputRWType::kInvalidRWType; + } + if (op_desc->GetType() == WHILE) { + return InputRWType::kScopeWriteable; + } + vector subgraph_names = op_desc->GetSubgraphInstanceNames(); + if (subgraph_names.empty()) { + // single node without sub graph + return GetSingleNodeInputRWTypeByIndex(node, index); + } else { + // node with sub graph + std::set node_rw_type_set; + auto data_node_vec = NodeUtils::GetSubgraphDataNodesByIndex(node, index); + // get all input data node in subgraph + std::set anchor_rw_type_set; + for (const auto &data_node : data_node_vec) { + // Data only has 1 out data anchor. Here just take first out data anchor. And index 0 is valid. + auto out_data_anchor = data_node->GetOutDataAnchor(0); + if (out_data_anchor == nullptr) { + continue; + } + auto data_op_desc = data_node->GetOpDesc(); + if (data_op_desc == nullptr) { + continue; + } + // find rw type from map. + auto iter = node_rwtype_map_.find(data_op_desc->GetName()); + if (iter == node_rwtype_map_.end()) { + GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.", + data_op_desc->GetName().c_str()); + return InputRWType::kInvalidRWType; + } + auto input_rw_type = iter->second.input_rw_type_map.find(out_data_anchor->GetIdx()); + if (input_rw_type == iter->second.input_rw_type_map.end()) { + GELOGW("Can not find rw type of node %s from map.It could take some effect on following preprocess.", + data_op_desc->GetName().c_str()); + return InputRWType::kInvalidRWType; + } + anchor_rw_type_set.emplace(static_cast(input_rw_type->second)); + } + return GetInputRwTypeInConflict(anchor_rw_type_set); + } +} + +/// +/// @brief Reverse traversal all subgraph and mark rw_type for Data/Netoutput. +/// @param sub_graph_vecgs +/// +Status MarkRWTypeForSubgraph(vector> sub_graph_vec) { + for (auto iter = sub_graph_vec.rbegin(); iter != sub_graph_vec.rend(); ++iter) { + auto parent_node = (*iter)->GetParentNode(); + if (parent_node == nullptr) { + GELOGD("Current sub graph has no parent node. Ignore it."); + continue; + } + if (parent_node->GetType() == WHILE) { + continue; + } + for (const auto &node : (*iter)->GetDirectNode()) { + GE_CHECK_NOTNULL(node); + GE_CHECK_NOTNULL(node->GetOpDesc()); + if (node->GetType() == DATA) { + // calc all input_rw_type of peer output , as input_rw_type of DATA. Index 0 is valid. + auto out_data_anchor = node->GetOutDataAnchor(0); + GE_CHECK_NOTNULL(out_data_anchor); + std::set anchor_rw_type_set; + for (const auto peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { + GE_CHECK_NOTNULL(peer_in_anchor); + auto peer_in_node = peer_in_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_in_node); + auto input_rw_type = GetInputRWTypeByIndex(*peer_in_node, peer_in_anchor->GetIdx()); + GELOGD("Input rw type of Node %s %dth input anchor is %s", peer_in_node->GetName().c_str(), + peer_in_anchor->GetIdx(), InputRWTypeToSerialString(input_rw_type).c_str()); + anchor_rw_type_set.emplace(static_cast(input_rw_type)); + } + auto anchor_rw_type = GetInputRwTypeInConflict(anchor_rw_type_set); + GELOGD("Input rw type of Node %s is %s", node->GetName().c_str(), + InputRWTypeToSerialString(anchor_rw_type).c_str()); + map input_rw_type_map{std::make_pair(0, anchor_rw_type)}; + NodeInputOutputRWType data_rw_type{input_rw_type_map}; + node_rwtype_map_.emplace(std::make_pair(node->GetName(), data_rw_type)); + } + + if (node->GetType() == NETOUTPUT) { + // calc all output_rw_type of peer input , as output_rw_type of DATA + map output_rw_type_map; + for (const auto &in_data_anchor : node->GetAllInDataAnchors()) { + GE_CHECK_NOTNULL(in_data_anchor); + auto pre_out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(pre_out_anchor); + auto pre_node = pre_out_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(pre_node); + + auto pre_output_rw_type = GetOutputRWTypeByIndex(*pre_node, pre_out_anchor->GetIdx()); + GELOGD("Output rw type of Node %s %dth output anchor is %s", pre_node->GetName().c_str(), + pre_out_anchor->GetIdx(), OutputRWTypeToSerialString(pre_output_rw_type).c_str()); + if (pre_output_rw_type == OutputRWType::kWriteable) { + // insert identity + auto identity_node = CreateIdentityAfterSrcNode(*pre_node, pre_out_anchor->GetIdx()); + GE_CHECK_NOTNULL(identity_node); + auto ret = GraphUtils::InsertNodeBetweenDataAnchors(pre_out_anchor, in_data_anchor, identity_node); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to insert identity"); + return ret; + } + GELOGI("InsertNode %s between %s and %s successfully.", identity_node->GetName().c_str(), + pre_node->GetName().c_str(), node->GetName().c_str()); + } + output_rw_type_map.emplace(std::make_pair(in_data_anchor->GetIdx(), OutputRWType::kSoftRead)); + } + NodeInputOutputRWType output_rw_type{{}, output_rw_type_map}; + node_rwtype_map_.emplace(std::make_pair(node->GetName(), output_rw_type)); + } + } + } + return SUCCESS; +} + +/// +/// @brief Check identity is near subgraph. +/// Eg. As output of Data node in subgraph +/// or as input of Netoutput of subgraph +/// or as input of one node with subgraph +/// or as output of one node with subgraph +/// @param node +/// @return is_near_subgraph +/// +bool CheckIdentityIsNearSubgraph(const NodePtr &node) { + for (const auto &in_node : node->GetInDataNodes()) { + auto in_node_opdesc = in_node->GetOpDesc(); + if (in_node_opdesc == nullptr) { + continue; + } + // near entrance of subgraph + if (in_node->GetType() == DATA && NodeUtils::IsSubgraphInput(in_node)) { + return true; + } + // near subgraph + if (!in_node_opdesc->GetSubgraphInstanceNames().empty()) { + return true; + } + } + + for (const auto &out_node : node->GetOutDataNodes()) { + auto out_node_opdesc = out_node->GetOpDesc(); + if (out_node_opdesc == nullptr) { + continue; + } + // near output of subgraph + if (out_node->GetType() == NETOUTPUT && NodeUtils::IsSubgraphOutput(out_node)) { + return true; + } + // near subgraph + if (!out_node_opdesc->GetSubgraphInstanceNames().empty()) { + return true; + } + } + return false; +} +enum ConflictResult { DO_NOTHING, WRONG_GRAPH, INSERT_IDENTITY }; +vector> output_2_input_rwtype = {{DO_NOTHING, WRONG_GRAPH, INSERT_IDENTITY}, + {DO_NOTHING, WRONG_GRAPH, DO_NOTHING}, + {DO_NOTHING, DO_NOTHING, INSERT_IDENTITY}}; +ConflictResult GetConflictResultBetweenNode(const OutputRWType output_rw_type, const InputRWType input_rw_type) { + if (output_rw_type == OutputRWType::kInvalidRWType || input_rw_type == InputRWType::kInvalidRWType) { + return WRONG_GRAPH; + } + auto n = static_cast(output_rw_type); + auto m = static_cast(input_rw_type); + // no need to check index or container, because container and index is all defined. + return output_2_input_rwtype[n][m]; +} + +/// +/// @brief Keep identity_node which near subgraph or has multi output +/// @param node +/// @return +/// +Status RemoveNoUseIdentity(const NodePtr &node) { + if (node->GetInDataNodes().empty()) { + return SUCCESS; + } + if (node->GetOutDataNodesSize() > 1) { + return SUCCESS; + } + if (node->GetOutDataNodesSize() == 1 && node->GetOutDataNodes().at(0)->GetType() == STREAMMERGE) { + return SUCCESS; + } + if (CheckIdentityIsNearSubgraph(node)) { + return SUCCESS; + } + auto out_data_anchor = node->GetOutDataAnchor(kIdentityAnchorIndex); + GE_CHECK_NOTNULL(out_data_anchor); + GE_CHECK_NOTNULL(node->GetInDataAnchor(kIdentityAnchorIndex)); + auto pre_out_anchor = node->GetInDataAnchor(kIdentityAnchorIndex)->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(pre_out_anchor); + auto pre_node = pre_out_anchor->GetOwnerNode(); + auto pre_output_rw_type = GetOutputRWTypeByIndex(*pre_node, pre_out_anchor->GetIdx()); + + ConflictResult conflict_result = WRONG_GRAPH; + if (!out_data_anchor->GetPeerInDataAnchors().empty()) { + auto peer_in_data_anchor = out_data_anchor->GetPeerInDataAnchors().at(0); + GE_CHECK_NOTNULL(peer_in_data_anchor); + auto peer_node = peer_in_data_anchor->GetOwnerNode(); + auto peer_input_rw_type = GetInputRWTypeByIndex(*peer_node, peer_in_data_anchor->GetIdx()); + + GELOGD("Pre Node %s %dth output rw type is %s, peer node %s %dth input rw type is %s.", pre_node->GetName().c_str(), + pre_out_anchor->GetIdx(), OutputRWTypeToSerialString(pre_output_rw_type).c_str(), + peer_node->GetName().c_str(), peer_in_data_anchor->GetIdx(), + InputRWTypeToSerialString(peer_input_rw_type).c_str()); + conflict_result = GetConflictResultBetweenNode(pre_output_rw_type, peer_input_rw_type); + } else { + // identity node has no out data node, it can be removed + conflict_result = DO_NOTHING; + } + + switch (conflict_result) { + case DO_NOTHING: { + GELOGI("No need insert Identity. Node %s need to remove.", node->GetName().c_str()); + auto ret = GraphUtils::IsolateNode(node, {0}); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to isolate node %s.", node->GetName().c_str()); + return ret; + } + ret = GraphUtils::RemoveNodeWithoutRelink(node->GetOwnerComputeGraph(), node); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to isolate node %s.", node->GetName().c_str()); + return ret; + } + GELOGI("Pre node is %s and %dth output rw type is %s. Isolate and remove Identity node %s.", + pre_node->GetName().c_str(), pre_out_anchor->GetIdx(), + OutputRWTypeToSerialString(pre_output_rw_type).c_str(), node->GetName().c_str()); + return SUCCESS; + } + default: + return SUCCESS; + } + return SUCCESS; +} + +Status SplitIdentity(const NodePtr &node) { + GE_CHECK_NOTNULL(node); + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (op_desc->GetType() != IDENTITY) { + return SUCCESS; + } + auto out_data_anchor = node->GetOutDataAnchor(kIdentityAnchorIndex); + GE_CHECK_NOTNULL(out_data_anchor); + if (out_data_anchor->GetPeerInDataNodesSize() <= 1) { + return SUCCESS; + } + // get pre node and next node of identity + GE_CHECK_NOTNULL(node->GetInDataAnchor(kIdentityAnchorIndex)); + auto pre_out_data_anchor = node->GetInDataAnchor(kIdentityAnchorIndex)->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(pre_out_data_anchor); + auto pre_node = pre_out_data_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(pre_node); + for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) { + // 1.check peer in node RW type. + GE_CHECK_NOTNULL(peer_in_data_anchor); + auto peer_in_data_node = peer_in_data_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_in_data_node); + auto input_rw_type = GetInputRWTypeByIndex(*peer_in_data_node, peer_in_data_anchor->GetIdx()); + auto ret = out_data_anchor->Unlink(peer_in_data_anchor); + if (ret != SUCCESS) { + GELOGE(ret, "Failed to unlink from %s %dth out to %s.", node->GetName().c_str(), out_data_anchor->GetIdx(), + peer_in_data_anchor->GetOwnerNode()->GetName().c_str()); + return ret; + } + if (input_rw_type == InputRWType::kScopeWriteable || input_rw_type == InputRWType::kWriteable) { + auto identity_node = CreateIdentityAfterSrcNode(*pre_node, pre_out_data_anchor->GetIdx()); + GE_CHECK_NOTNULL(identity_node); + ret = GraphUtils::AddEdge(pre_out_data_anchor, identity_node->GetInDataAnchor(kIdentityAnchorIndex)); + if (ret != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Failed to insert Identity between node %s and %s", + pre_out_data_anchor->GetOwnerNode()->GetName().c_str(), + peer_in_data_anchor->GetOwnerNode()->GetName().c_str()); + return INTERNAL_ERROR; + } + ret = GraphUtils::AddEdge(identity_node->GetOutDataAnchor(kIdentityAnchorIndex), peer_in_data_anchor); + if (ret != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Failed to insert Identity between node %s and %s", + pre_out_data_anchor->GetOwnerNode()->GetName().c_str(), + peer_in_data_anchor->GetOwnerNode()->GetName().c_str()); + return INTERNAL_ERROR; + } + // 2. copy in-control-edge from dst to Identity + GraphUtils::CopyInCtrlEdges(peer_in_data_node, identity_node); + GELOGI("Node %s intput rw type is %s. Insert Identity between %s and %s.", peer_in_data_node->GetName().c_str(), + InputRWTypeToSerialString(input_rw_type).c_str(), pre_out_data_anchor->GetOwnerNode()->GetName().c_str(), + peer_in_data_anchor->GetOwnerNode()->GetName().c_str()); + } else { + // link identity pre node to next node directly + // todo control edge + if (GraphUtils::AddEdge(pre_out_data_anchor, peer_in_data_anchor) != SUCCESS) { + GELOGW("Fail to link data edge from node %s to %s.", pre_out_data_anchor->GetOwnerNode()->GetName().c_str(), + peer_in_data_anchor->GetOwnerNode()->GetName().c_str()); + return FAILED; + } + GELOGI("Node %s intput rw type is %s, link data edge from Identity input node %s to out node %s directly.", + peer_in_data_node->GetName().c_str(), InputRWTypeToSerialString(input_rw_type).c_str(), + pre_node->GetName().c_str(), peer_in_data_node->GetName().c_str()); + } + } + // 2.isolate Identity node with no data output + if (node->GetOutDataNodesSize() == 0) { + auto ret = GraphUtils::IsolateNode(node, {}); + if (ret != SUCCESS) { + GELOGE(FAILED, "IsolateAndDelete identity node %s.", node->GetName().c_str()); + return FAILED; + } + ret = GraphUtils::RemoveNodeWithoutRelink(node->GetOwnerComputeGraph(), node); + if (ret != SUCCESS) { + GELOGE(FAILED, "IsolateAndDelete identity node %s.", node->GetName().c_str()); + return FAILED; + } + GELOGI("IsolateAndDelete identity node %s.", node->GetName().c_str()); + } + return SUCCESS; +} + +Status InsertIdentityAsNeeded(const NodePtr &node) { + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (node->GetOutDataNodesSize() == 0 || node->GetInDataNodes().empty()) { + return SUCCESS; + } + for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) { + GE_CHECK_NOTNULL(out_data_anchor); + auto output_rw_type = GetOutputRWTypeByIndex(*node, out_data_anchor->GetIdx()); + for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) { + GE_CHECK_NOTNULL(peer_in_data_anchor); + auto peer_in_node = peer_in_data_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_in_node); + auto input_rw_type = GetInputRWTypeByIndex(*peer_in_node, peer_in_data_anchor->GetIdx()); + GELOGD("Node %s output rw type is %s, Node %s input rw type is %s", node->GetName().c_str(), + OutputRWTypeToSerialString(output_rw_type).c_str(), peer_in_node->GetName().c_str(), + InputRWTypeToSerialString(input_rw_type).c_str()); + auto conflict_result = GetConflictResultBetweenNode(output_rw_type, input_rw_type); + switch (conflict_result) { + case DO_NOTHING: + case WRONG_GRAPH: + GELOGD("No need insert Identity."); + continue; + case INSERT_IDENTITY: + auto identity_node = CreateIdentityAfterSrcNode(*node, out_data_anchor->GetIdx()); + if (identity_node == nullptr) { + GELOGE(FAILED, "Create identity node failed."); + return FAILED; + } + auto ret = GraphUtils::InsertNodeBetweenDataAnchors(out_data_anchor, peer_in_data_anchor, identity_node); + if (ret != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Failed to insert reshape between node %s and %s", node->GetName().c_str(), + peer_in_node->GetName().c_str()); + return INTERNAL_ERROR; + } + GELOGI("Insert Identity between %s and %s to handle memory conflict.", node->GetName().c_str(), + peer_in_node->GetName().c_str()); + continue; + } + } + } + return SUCCESS; +} +} // namespace + +namespace ge { +Status GraphOptimize::CheckRWConflict(ComputeGraphPtr &compute_graph, bool &has_conflict) { + node_rwtype_map_.clear(); + auto sub_graph_vec = compute_graph->GetAllSubgraphs(); + if (sub_graph_vec.empty()) { + GELOGD("No sub graph here. Ignore memory conflict handle."); + return SUCCESS; + } + // 1.loop all subgraph, mark rw type from inside to outside + Status ret = MarkRWTypeForSubgraph(sub_graph_vec); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to mark rw type for subgraph."); + return ret; + } + has_conflict = false; + for (const auto &node : compute_graph->GetAllNodes()) { + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (node->GetOutDataNodesSize() == 0) { + return SUCCESS; + } + if (node->GetType() == WHILE) { + return SUCCESS; + } + for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) { + GE_CHECK_NOTNULL(out_data_anchor); + auto output_rw_type = GetOutputRWTypeByIndex(*node, out_data_anchor->GetIdx()); + for (const auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) { + GE_CHECK_NOTNULL(peer_in_data_anchor); + auto peer_in_node = peer_in_data_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_in_node); + if (peer_in_node->GetType() == WHILE) { + return SUCCESS; + } + auto input_rw_type = GetInputRWTypeByIndex(*peer_in_node, peer_in_data_anchor->GetIdx()); + auto conflict_result = GetConflictResultBetweenNode(output_rw_type, input_rw_type); + switch (conflict_result) { + case DO_NOTHING: + GELOGD("No rw conflict."); + continue; + case WRONG_GRAPH: + has_conflict = true; + GELOGI("Node %s output rw type is %s, next node %s input_rw_type is %s.It is wrong graph.", + node->GetName().c_str(), OutputRWTypeToSerialString(output_rw_type).c_str(), + peer_in_node->GetName().c_str(), InputRWTypeToSerialString(input_rw_type).c_str()); + return SUCCESS; + case INSERT_IDENTITY: + GELOGD("There is rw conflict. It will handle later."); + continue; + } + } + } + } + return SUCCESS; +} +Status GraphOptimize::HandleMemoryRWConflict(ComputeGraphPtr &compute_graph) { + node_rwtype_map_.clear(); + auto sub_graph_vec = compute_graph->GetAllSubgraphs(); + if (sub_graph_vec.empty()) { + GELOGD("No sub graph here. Ignore memory conflict handle."); + return SUCCESS; + } + GE_DUMP(compute_graph, "BeforeHandleMemConflict"); + // 1.loop all subgraph, mark rw type from inside to outside + Status ret = MarkRWTypeForSubgraph(sub_graph_vec); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to mark rw type for subgraph."); + return ret; + } + // 2.loop all node, including node in subgraph and handle memory rw conflict + for (auto &node : compute_graph->GetAllNodes()) { + // ignore data / netoutput of subgraph + if (node->GetType() == DATA && AttrUtils::HasAttr(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX)) { + continue; + } + if (node->GetType() == NETOUTPUT && AttrUtils::HasAttr(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX)) { + continue; + } + if (node->GetType() == IDENTITY || node->GetType() == READVARIABLEOP) { + // split identity + ret = SplitIdentity(node); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to split identity node %s.", node->GetName().c_str()); + return ret; + } + // remove no use identity + ret = RemoveNoUseIdentity(node); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to remove useless identity node %s.", node->GetName().c_str()); + return ret; + } + } + // insert Identity + ret = InsertIdentityAsNeeded(node); + if (ret != SUCCESS) { + GELOGE(ret, "Fail to insert Identity node."); + return ret; + } + } + GE_DUMP(compute_graph, "AfterHandleMemConflict"); + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/optimize/summary_optimize.cc b/src/ge/graph/optimize/summary_optimize.cc index 8b38d602..a8325da3 100644 --- a/src/ge/graph/optimize/summary_optimize.cc +++ b/src/ge/graph/optimize/summary_optimize.cc @@ -80,7 +80,8 @@ Status GraphOptimize::HandleSummaryOp(ComputeGraphPtr &compute_graph) { del_nodes.emplace_back(node_ptr); } } - summary_output_indexes_.insert({compute_graph->GetGraphID(), summary_output_indexes}); + GE_IF_BOOL_EXEC(!summary_output_indexes.empty(), + summary_output_indexes_.insert({compute_graph->GetGraphID(), summary_output_indexes})); // add output nodes for summary std::vector> out_nodes_info; diff --git a/src/ge/graph/partition/dynamic_shape_partition.cc b/src/ge/graph/partition/dynamic_shape_partition.cc index 6a396eef..903159b9 100644 --- a/src/ge/graph/partition/dynamic_shape_partition.cc +++ b/src/ge/graph/partition/dynamic_shape_partition.cc @@ -62,15 +62,16 @@ Status DynamicShapePartitioner::Partition() { } GELOGD("Start dynamic shape partition graph %s.", root_graph_->GetName().c_str()); - REQUIRE_SUCCESS(MarkUnknownShapeNodes(), "Failed mark unknown shape nodes."); + REQUIRE_SUCCESS(MarkUnknownShapeNodes(), "Failed mark unknown shape nodes, root grah name:%s.", + root_graph_->GetName().c_str()); if (unknown_shape_nodes_.empty()) { GELOGD("Skip dynamic shape partition of graph %s as all nodes are known shape.", root_graph_->GetName().c_str()); REQUIRE(AttrUtils::SetBool(*root_graph_, ATTR_NAME_DYNAMIC_SHAPE_PARTITIONED, false), - "Failed set dynamic shape partitioned flag on root graph."); + "Failed set dynamic shape partitioned flag on root graph %s.", root_graph_->GetName().c_str()); return SUCCESS; } REQUIRE(AttrUtils::SetBool(*root_graph_, ATTR_NAME_DYNAMIC_SHAPE_PARTITIONED, true), - "Failed set dynamic shape partitioned flag on root graph."); + "Failed set dynamic shape partitioned flag on root graph %s.", root_graph_->GetName().c_str()); DumpGraph("_Before_DSP"); auto status = PartitionImpl(); @@ -102,26 +103,32 @@ void DynamicShapePartitioner::PruneUniqueClusters() { if (unique_clusters_.count(cluster) != 0) { continue; } - unique_clusters_.insert(cluster); + if (unique_clusters_.insert(cluster).second) { + sorted_unique_clusters_.emplace_back(cluster); + } } + auto comp_func = [](std::shared_ptr clu_a, std::shared_ptr clu_b) -> bool { + return clu_a->Id() < clu_b->Id(); + }; + std::sort(sorted_unique_clusters_.begin(), sorted_unique_clusters_.end(), comp_func); } Status DynamicShapePartitioner::BuildPartitionFrame() { - for (auto cluster : unique_clusters_) { + for (const auto &cluster : sorted_unique_clusters_) { REQUIRE_SUCCESS(cluster->BuildFrame(), "Failed build frame of cluster[%lu].", cluster->Id()); } return SUCCESS; } Status DynamicShapePartitioner::CombinePartitionFrame() { - for (auto cluster : unique_clusters_) { + for (const auto &cluster : sorted_unique_clusters_) { REQUIRE_SUCCESS(cluster->CombinePartitionFrame(), "Failed combine frame of cluster[%lu].", cluster->Id()); } return SUCCESS; } Status DynamicShapePartitioner::BuildPartitionSubgraph() { - for (auto cluster : unique_clusters_) { + for (const auto &cluster : sorted_unique_clusters_) { REQUIRE_SUCCESS(cluster->BuildPartitionSubgraph(), "Failed build subgraph of cluster[%lu].", cluster->Id()); } return SUCCESS; @@ -134,10 +141,10 @@ std::string DynamicShapePartitioner::DebugString() const { size_t netoutput = 0; std::stringstream ss; ss << "All unknown shape nodes:" << std::endl; - for (auto node : unknown_shape_nodes_) { + for (const auto &node : unknown_shape_nodes_) { ss << " [" << node->GetName() << "](" << node->GetType() << ")" << std::endl; } - for (auto cluster : unique_clusters_) { + for (const auto &cluster : unique_clusters_) { if (cluster->IsUnknownShape()) { unknown++; } else if (cluster->IsKnownShape()) { @@ -150,7 +157,7 @@ std::string DynamicShapePartitioner::DebugString() const { } ss << "All clusters:" << unique_clusters_.size() << ", data:" << data << ", known:" << known << ", unknown:" << unknown << ", netoutput:" << netoutput << std::endl; - for (auto cluster : unique_clusters_) { + for (const auto &cluster : unique_clusters_) { ss << " " << cluster->DebugString() << std::endl; } return ss.str(); @@ -158,25 +165,25 @@ std::string DynamicShapePartitioner::DebugString() const { void DynamicShapePartitioner::DumpGraph(const std::string &suffix) { GraphUtils::DumpGEGraphToOnnx(*root_graph_, root_graph_->GetName() + suffix); - for (auto sub_graph : root_graph_->GetAllSubgraphs()) { + for (const auto &sub_graph : root_graph_->GetAllSubgraphs()) { GraphUtils::DumpGEGraphToOnnx(*sub_graph, sub_graph->GetName() + suffix); } } void DynamicShapePartitioner::ClearResource() { - for (auto cluster : unique_clusters_) { + for (const auto &cluster : unique_clusters_) { cluster->Clear(); } node_2_cluster_.clear(); ordered_cluster_.clear(); unique_clusters_.clear(); + sorted_unique_clusters_.clear(); unknown_shape_nodes_.clear(); root_graph_.reset(); } Status DynamicShapePartitioner::MarkUnknownShapeNodes() { - auto graph = root_graph_; - for (auto &node : graph->GetDirectNode()) { + for (auto &node : root_graph_->GetDirectNode()) { REQUIRE_SUCCESS(CollectSpreadUnknownShapeNodes(node), "Failed collect spread unknown shape nodes %s.", node->GetName().c_str()); } @@ -186,7 +193,7 @@ Status DynamicShapePartitioner::MarkUnknownShapeNodes() { Status DynamicShapePartitioner::InitClusters() { auto graph = root_graph_; size_t rank = 0; - for (const auto node : graph->GetDirectNode()) { + for (const auto &node : graph->GetDirectNode()) { Cluster::Type type = Cluster::DATA; if (node->GetType() == DATA) { type = Cluster::DATA; @@ -208,7 +215,7 @@ Status DynamicShapePartitioner::InitClusters() { cluster->AddInput(node_2_cluster_[parent]); } } - for (const auto node : graph->GetDirectNode()) { + for (const auto &node : graph->GetDirectNode()) { GELOGD("Make cluster for node %s : %s.", node->GetName().c_str(), node_2_cluster_[node]->DebugString().c_str()); } return SUCCESS; @@ -220,8 +227,8 @@ Status DynamicShapePartitioner::TopologicalSortClusters() { std::queue ready_clusters; std::unordered_map cluster_pending_count; std::unordered_set seen_clusters; - for (auto iter = node_2_cluster_.begin(); iter != node_2_cluster_.end(); iter++) { - auto cluster = iter->second; + for (auto &node : root_graph_->GetDirectNode()) { + auto &cluster = node_2_cluster_[node]; if (seen_clusters.count(cluster) != 0) { continue; } @@ -242,7 +249,7 @@ Status DynamicShapePartitioner::TopologicalSortClusters() { if (cluster->IsKnownShape()) { ordered_cluster_.push_back(cluster); } - for (auto out_cluster : cluster->Outputs()) { + for (const auto &out_cluster : cluster->Outputs()) { if (cluster_pending_count[out_cluster] > 0 && --cluster_pending_count[out_cluster] == 0) { ready_clusters.push(out_cluster); } @@ -273,16 +280,16 @@ static std::string ToString(const std::vector &clusters) { Status DynamicShapePartitioner::MergeClusters() { // Merge unknown shape clusters - for (auto cluster : ordered_cluster_) { - for (auto in_cluster : cluster->Inputs()) { + for (const auto &cluster : ordered_cluster_) { + for (const auto &in_cluster : cluster->Inputs()) { if (!in_cluster->IsUnknownShape()) { continue; } auto merged_clusters = cluster->MergeAllPathFrom(in_cluster); GELOGD("Merge all path cluster from %lu to %lu %s.", in_cluster->Id(), cluster->Id(), ToString(merged_clusters).c_str()); - for (auto merged_cluster : merged_clusters) { - for (auto node : merged_cluster->Nodes()) { + for (const auto &merged_cluster : merged_clusters) { + for (const auto &node : merged_cluster->Nodes()) { node_2_cluster_[node] = cluster; } } @@ -291,7 +298,7 @@ Status DynamicShapePartitioner::MergeClusters() { REQUIRE_SUCCESS(TopologicalSortClusters(), "Failed topological sort clusters after merge unknown shape clusters."); // Merge known shape clusters - for (auto cluster : ordered_cluster_) { + for (const auto &cluster : ordered_cluster_) { if (cluster->IsRefVariable() && cluster->Inputs().size() == 1) { auto in_cluster = *(cluster->Inputs().begin()); in_cluster->Merge(cluster); @@ -299,13 +306,13 @@ Status DynamicShapePartitioner::MergeClusters() { continue; } - for (auto in_cluster : cluster->Inputs()) { + for (const auto &in_cluster : cluster->Inputs()) { if (!in_cluster->IsKnownShape()) { continue; } if (cluster->TryMerge(in_cluster)) { GELOGD("Success merge known shape cluster from %lu to %lu.", in_cluster->Id(), cluster->Id()); - for (auto node : in_cluster->Nodes()) { + for (const auto &node : in_cluster->Nodes()) { node_2_cluster_[node] = cluster; } } @@ -333,7 +340,7 @@ Status DynamicShapePartitioner::CollectSpreadUnknownShapeNodes(NodePtr node) { if (IsUnknownShapeTensor(out_tensor)) { GELOGD("Collect node %s as unknown as output %lu is unknown.", node->GetName().c_str(), anchor_index); is_unknown = true; - auto anchor = node->GetOutDataAnchor(anchor_index); + auto anchor = node->GetOutDataAnchor(static_cast(anchor_index)); for (const auto peer_anchor : anchor->GetPeerInDataAnchors()) { if (peer_anchor != nullptr) { GELOGD("Collect node %s as has unknown input from %s:%lu.", peer_anchor->GetOwnerNode()->GetName().c_str(), @@ -349,7 +356,7 @@ Status DynamicShapePartitioner::CollectSpreadUnknownShapeNodes(NodePtr node) { if (IsUnknownShapeTensor(in_tensor)) { GELOGD("Collect node %s as unknown as input %lu is unknown.", node->GetName().c_str(), anchor_index); is_unknown = true; - auto anchor = node->GetInDataAnchor(anchor_index); + auto anchor = node->GetInDataAnchor(static_cast(anchor_index)); const auto peer_anchor = anchor->GetPeerOutAnchor(); if (peer_anchor != nullptr) { GELOGD("Collect node %s as has unknown output to %s:%lu.", peer_anchor->GetOwnerNode()->GetName().c_str(), @@ -453,15 +460,15 @@ std::string Cluster::DebugString() const { } ss << "[" << id_ << "](size:" << nodes_.size() << ")"; ss << "(" << min_ << "," << max_ << ")("; - for (auto cluster : in_clusters_) { + for (const auto &cluster : in_clusters_) { ss << cluster->id_ << ","; } ss << ")->("; - for (auto cluster : out_clusters_) { + for (const auto &cluster : out_clusters_) { ss << cluster->id_ << ","; } ss << ")|"; - for (auto node : nodes_) { + for (const auto &node : nodes_) { ss << (node->GetName() + "|"); } return ss.str(); @@ -507,12 +514,12 @@ void Cluster::Merge(ClusterPtr other) { in_clusters_.erase(other); out_clusters_.erase(other); auto in_clusters = other->in_clusters_; - for (auto cluster : in_clusters) { + for (const auto &cluster : in_clusters) { cluster->RemoveOutput(other); cluster->AddOutput(shared_from_this()); } auto out_clusters = other->out_clusters_; - for (auto cluster : out_clusters) { + for (const auto &cluster : out_clusters) { cluster->RemoveInput(other); cluster->AddInput(shared_from_this()); } @@ -529,7 +536,7 @@ bool Cluster::TryMerge(ClusterPtr other) { while (!forward_reached.empty()) { auto current_cluster = forward_reached.front(); forward_reached.pop(); - for (auto cluster : current_cluster->out_clusters_) { + for (const auto &cluster : current_cluster->out_clusters_) { if (cluster->max_ == max_ && current_cluster != other) { return false; } else if (cluster->min_ < max_) { @@ -557,7 +564,7 @@ std::vector Cluster::MergeAllPathFrom(ClusterPtr other) { while (!forward_reached_queue.empty()) { auto current_cluster = forward_reached_queue.front(); forward_reached_queue.pop(); - for (auto cluster : current_cluster->out_clusters_) { + for (const auto &cluster : current_cluster->out_clusters_) { if (cluster->min_ < max_ && cluster->max_ != max_ && forward_reached_clusters.count(cluster) == 0) { forward_reached_clusters.insert(cluster); forward_reached_queue.push(cluster); @@ -567,7 +574,7 @@ std::vector Cluster::MergeAllPathFrom(ClusterPtr other) { while (!backward_reached_queue.empty()) { auto current_cluster = backward_reached_queue.front(); backward_reached_queue.pop(); - for (auto cluster : current_cluster->in_clusters_) { + for (const auto &cluster : current_cluster->in_clusters_) { if (cluster->max_ > other->min_ && cluster->max_ != other->max_ && backward_reached_clusters.count(cluster) == 0) { backward_reached_clusters.insert(cluster); @@ -578,7 +585,7 @@ std::vector Cluster::MergeAllPathFrom(ClusterPtr other) { } } } - for (auto cluster : path_clusters) { + for (const auto &cluster : path_clusters) { Merge(cluster); } return path_clusters; @@ -598,11 +605,11 @@ void Cluster::AddFrameOutput(OutDataAnchorPtr anchor) { }; InDataAnchorPtr Cluster::GetFrameInDataAnchor(InDataAnchorPtr anchor) { - return partition_node_->GetInDataAnchor(inputs_index_[anchor]); + return partition_node_->GetInDataAnchor(static_cast(inputs_index_[anchor])); }; OutDataAnchorPtr Cluster::GetFrameOutDataAnchor(OutDataAnchorPtr anchor) { - return partition_node_->GetOutDataAnchor(outputs_index_[anchor]); + return partition_node_->GetOutDataAnchor(static_cast(outputs_index_[anchor])); }; InControlAnchorPtr Cluster::GetFrameInControlAnchor() { return partition_node_->GetInControlAnchor(); }; @@ -616,22 +623,25 @@ Status Cluster::BuildFrame() { auto node = nodes_.front(); auto in_control_anchor = node->GetInControlAnchor(); if (in_control_anchor != nullptr) { - for (auto peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) { + for (const auto &peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) { auto src_cluster = partitioner_->node_2_cluster_[peer_out_control_anchor->GetOwnerNode()]; if (src_cluster->id_ != id_) { - auto src_cluster = partitioner_->node_2_cluster_[peer_out_control_anchor->GetOwnerNode()]; - GraphUtils::RemoveEdge(peer_out_control_anchor, in_control_anchor); + REQUIRE_GRAPH_SUCCESS( + GraphUtils::RemoveEdge(peer_out_control_anchor, in_control_anchor), + "Failed remove edge from node %s index %d to node %s index %d.", + peer_out_control_anchor->GetOwnerNode()->GetName().c_str(), AnchorUtils::GetIdx(peer_out_control_anchor), + in_control_anchor->GetOwnerNode()->GetName().c_str(), AnchorUtils::GetIdx(in_control_anchor)); control_inputs_.insert(src_cluster); src_cluster->control_outputs_.insert(peer_out_control_anchor); } } } if (IsData()) { - for (auto anchor : node->GetAllOutDataAnchors()) { + for (const auto &anchor : node->GetAllOutDataAnchors()) { AddFrameOutput(anchor); } } else { - for (auto anchor : node->GetAllInDataAnchors()) { + for (const auto &anchor : node->GetAllInDataAnchors()) { AddFrameInput(anchor); } } @@ -660,7 +670,7 @@ Status Cluster::BuildPartitionFrame() { "Failed set shape flag."); REQUIRE_GRAPH_SUCCESS(GraphUtils::RemoveJustNode(graph, node), "Failed remove root graph node."); REQUIRE_GRAPH_SUCCESS(node->SetOwnerComputeGraph(subgraph_), "Failed set owner graph."); - for (auto anchor : node->GetAllInDataAnchors()) { + for (const auto &anchor : node->GetAllInDataAnchors()) { auto peer_out_anchor = anchor->GetPeerOutAnchor(); if (peer_out_anchor == nullptr) { continue; // Skip overhang input. @@ -674,7 +684,7 @@ Status Cluster::BuildPartitionFrame() { } auto in_control_anchor = node->GetInControlAnchor(); if (in_control_anchor != nullptr) { - for (auto peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) { + for (const auto &peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) { if (peer_out_control_anchor == nullptr) { continue; } @@ -689,9 +699,9 @@ Status Cluster::BuildPartitionFrame() { } } } - for (auto anchor : node->GetAllOutDataAnchors()) { + for (const auto &anchor : node->GetAllOutDataAnchors()) { auto peer_in_anchors = anchor->GetPeerInDataAnchors(); - for (auto peer_in_anchor : peer_in_anchors) { + for (const auto &peer_in_anchor : peer_in_anchors) { auto src_cluster = partitioner_->node_2_cluster_[peer_in_anchor->GetOwnerNode()]; if (src_cluster->id_ != id_) { AddFrameOutput(anchor); @@ -717,7 +727,7 @@ Status Cluster::BuildPartitionFrame() { } Status Cluster::CombinePartitionFrame() { - for (auto anchor : inputs_) { + for (const auto &anchor : inputs_) { auto peer_out_anchor = anchor->GetPeerOutAnchor(); auto src_cluster = partitioner_->node_2_cluster_[peer_out_anchor->GetOwnerNode()]; auto src_anchor = src_cluster->GetFrameOutDataAnchor(peer_out_anchor); @@ -729,7 +739,7 @@ Status Cluster::CombinePartitionFrame() { src_anchor->GetOwnerNode()->GetName().c_str(), src_anchor->GetIdx(), dst_anchor->GetOwnerNode()->GetName().c_str(), dst_anchor->GetIdx()); } - for (auto src_cluster : control_inputs_) { + for (const auto &src_cluster : control_inputs_) { auto src_anchor = src_cluster->GetFrameOutControlAnchor(); auto dst_anchor = GetFrameInControlAnchor(); REQUIRE_GRAPH_SUCCESS(GraphUtils::AddEdge(src_anchor, dst_anchor), "Failed add edge from %s:%d to %s:%d.", @@ -753,6 +763,9 @@ Status Cluster::BuildPartitionSubgraph() { REQUIRE_GRAPH_SUCCESS(data_op->AddOutputDesc(input_desc), "Failed add output desc."); REQUIRE(AttrUtils::SetInt(data_op, ATTR_NAME_PARENT_NODE_INDEX, parent_node_index), "Failed set parent_node_index on subgraph data node."); + bool is_unknown_shape = IsUnknownShape(); + REQUIRE(AttrUtils::SetBool(data_op, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape), + "Failed set _is_unknown_shape flag on data op %s.", data_op->GetName().c_str()); auto data_node = subgraph_->AddNode(data_op); REQUIRE_NOT_NULL(data_node, "Failed add data node to subgraph."); REQUIRE_GRAPH_SUCCESS(data_node->SetOwnerComputeGraph(subgraph_), "Failed set owner graph of data node."); @@ -766,6 +779,9 @@ Status Cluster::BuildPartitionSubgraph() { } auto net_output_op = MakeShared(subgraph_->GetName() + "_" + NODE_NAME_NET_OUTPUT, ge::NETOUTPUT); REQUIRE_NOT_NULL(net_output_op, "Failed new memory for netoutput op."); + bool is_unknown_shape = IsUnknownShape(); + REQUIRE(AttrUtils::SetBool(net_output_op, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape), + "Failed set _is_unknown_shape flag on net_output_op %s.", net_output_op->GetName().c_str()); for (size_t i = 0; i < outputs_.size(); ++i) { GeTensorDesc input_desc; REQUIRE_GRAPH_SUCCESS(net_output_op->AddInputDesc(input_desc), "Failed add input desc."); @@ -774,8 +790,8 @@ Status Cluster::BuildPartitionSubgraph() { REQUIRE_NOT_NULL(net_output_node, "Failed add netoutput node to subgraph."); REQUIRE_GRAPH_SUCCESS(net_output_node->SetOwnerComputeGraph(subgraph_), "Failed set owner graph of netoutput node."); parent_node_index = 0; - for (auto anchor : outputs_) { - auto output_desc = anchor->GetOwnerNode()->GetOpDesc()->GetOutputDesc(anchor->GetIdx()); + for (const auto &anchor : outputs_) { + auto output_desc = anchor->GetOwnerNode()->GetOpDesc()->GetOutputDesc(static_cast(anchor->GetIdx())); REQUIRE(AttrUtils::SetInt(output_desc, ATTR_NAME_PARENT_NODE_INDEX, parent_node_index), "Failed set parent_node_index on subgraph netoutput's input."); REQUIRE_GRAPH_SUCCESS(net_output_op->UpdateInputDesc(parent_node_index, output_desc), @@ -786,7 +802,7 @@ Status Cluster::BuildPartitionSubgraph() { anchor->GetIdx()); parent_node_index++; } - for (auto anchor : control_outputs_) { + for (const auto &anchor : control_outputs_) { REQUIRE_GRAPH_SUCCESS(GraphUtils::AddEdge(anchor, net_output_node->GetInControlAnchor()), "Faile add control edge from %s:%d to netoutput node.", anchor->GetOwnerNode()->GetName().c_str(), anchor->GetIdx()); @@ -809,4 +825,4 @@ void Cluster::Clear() { } size_t Cluster::unique_id_ = 0; -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/graph/partition/dynamic_shape_partition.h b/src/ge/graph/partition/dynamic_shape_partition.h index 4cbd20b7..ba349b1c 100644 --- a/src/ge/graph/partition/dynamic_shape_partition.h +++ b/src/ge/graph/partition/dynamic_shape_partition.h @@ -150,6 +150,8 @@ class DynamicShapePartitioner { std::vector> ordered_cluster_; // Unique clusters left after merged clusters std::unordered_set> unique_clusters_; + // Unique clusters left after merged clusters sorted by rank + std::vector> sorted_unique_clusters_; // Nodes of root_graph_ that satisfy the unknowshape rules std::unordered_set unknown_shape_nodes_; }; diff --git a/src/ge/graph/partition/engine_place.cc b/src/ge/graph/partition/engine_place.cc index 74da0326..2d1a7f13 100644 --- a/src/ge/graph/partition/engine_place.cc +++ b/src/ge/graph/partition/engine_place.cc @@ -38,6 +38,7 @@ Status EnginePlacer::Run() { return FAILED; } // Assign engine for each node in the graph + instance_ptr->DNNEngineManagerObj().InitPerformanceStaistic(); for (const auto &node_ptr : compute_graph_->GetDirectNode()) { GE_CHECK_NOTNULL(node_ptr); GE_CHECK_NOTNULL(node_ptr->GetOpDesc()); @@ -60,12 +61,15 @@ Status EnginePlacer::Run() { return FAILED; } } + for (auto &it : instance_ptr->DNNEngineManagerObj().GetCheckSupportCost()) { + GEEVENT("The time cost of %s::CheckSupported is [%lu] micro second.", it.first.c_str(), it.second); + } GELOGI("Engine placer ends."); return SUCCESS; } Status EnginePlacer::AssignEngineAndLog(ge::ConstNodePtr node_ptr, const std::string &engine_name) { - if (node_ptr == nullptr || node_ptr->GetOpDesc() == nullptr) { + if ((node_ptr == nullptr) || (node_ptr->GetOpDesc() == nullptr)) { GELOGE(FAILED, "node_ptr is null."); return FAILED; } diff --git a/src/ge/graph/partition/graph_partition.cc b/src/ge/graph/partition/graph_partition.cc index 50cd7e81..15f298c0 100644 --- a/src/ge/graph/partition/graph_partition.cc +++ b/src/ge/graph/partition/graph_partition.cc @@ -25,6 +25,7 @@ #include "framework/common/types.h" #include "graph/debug/ge_attr_define.h" #include "graph/manager/graph_manager_utils.h" +#include "graph/common/ge_call_wrapper.h" #include "graph/utils/graph_utils.h" #include "graph/utils/op_desc_utils.h" #include "graph/utils/type_utils.h" @@ -231,33 +232,33 @@ Status ge::GraphPartitioner::MergeSubGraph(ge::ComputeGraphPtr &output_merged_co ComputeGraphPtr new_sub_graph = MakeShared(original_compute_graph->GetName()); GE_CHECK_NOTNULL(new_sub_graph); output_merged_compute_graph = new_sub_graph; - GE_TIMESTAMP_START(MergeGraphRemoveNode); + GE_TIMESTAMP_START(MergeSubGraphRemoveNode); if (RemoveNodeAndEdgeBetweenEndPld(output_merged_compute_graph, sub_graph_list) != ge::SUCCESS) { GELOGE(GE_GRAPH_PARAM_NULLPTR, "[GraphPartitioner]: merging sub-graphs failed"); return FAILED; } - GE_TIMESTAMP_END(MergeGraphRemoveNode, "GraphPartitioner::MergeGraphRemoveNodeAndEdge"); - GE_TIMESTAMP_START(MergeGraphTopologicalSorting); + GE_TIMESTAMP_END(MergeSubGraphRemoveNode, "GraphPartitioner::MergeGraphRemoveNodeAndEdge"); + GE_TIMESTAMP_START(MergeSubGraphTopologicalSorting); Status ret = output_merged_compute_graph->TopologicalSorting(); if (ret != SUCCESS) { GELOGE(GE_GRAPH_TOPO_SORT_FAILED, "[GraphPartitioner]: output_merged_compute_graph->TopologicalSorting failed"); return FAILED; } - GE_TIMESTAMP_END(MergeGraphTopologicalSorting, "GraphPartitioner::MergeGraphTopologicalSorting"); + GE_TIMESTAMP_END(MergeSubGraphTopologicalSorting, "GraphPartitioner::MergeGraphTopologicalSorting"); // flush all nodes' engine of merged graph - GE_TIMESTAMP_START(MergeGraphEnginePlacerRun); + GE_TIMESTAMP_START(MergeSubGraphEnginePlacerRun); graph_info_.engine_placer_.SetComputeGraph(output_merged_compute_graph); if (graph_info_.engine_placer_.Run() != SUCCESS) { GELOGE(GE_GRAPH_INIT_FAILED, "[GraphPartitioner]: engine_placer run failed"); return FAILED; } - GE_TIMESTAMP_END(MergeGraphEnginePlacerRun, "GraphPartitioner::MergeGraphEnginePlacerRun"); + GE_TIMESTAMP_END(MergeSubGraphEnginePlacerRun, "GraphPartitioner::MergeGraphEnginePlacerRun"); GELOGI("Graph merge ends."); return SUCCESS; } Status ge::GraphPartitioner::UpdatePldOpDesc(const NodePtr &dst_node, int input_index, OpDescPtr &pld_op_desc) { - if (dst_node == nullptr || pld_op_desc == nullptr || dst_node->GetOpDesc() == nullptr) { + if ((dst_node == nullptr) || (pld_op_desc == nullptr) || (dst_node->GetOpDesc() == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return FAILED; } @@ -275,7 +276,7 @@ Status ge::GraphPartitioner::UpdatePldOpDesc(const NodePtr &dst_node, int input_ } Status ge::GraphPartitioner::UpdateEndOpDesc(const NodePtr &src_node, int output_index, OpDescPtr &end_op_desc) { - if (src_node == nullptr || end_op_desc == nullptr || src_node->GetOpDesc() == nullptr) { + if ((src_node == nullptr) || (end_op_desc == nullptr) || (src_node->GetOpDesc() == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return FAILED; } @@ -296,9 +297,9 @@ graphStatus ge::GraphPartitioner::AddPlaceHolderEndInSrcDstGraph(const AnchorPtr const AnchorPtr &peer_in_anchor, const ge::ComputeGraphPtr &pld_graph, const ge::ComputeGraphPtr &end_graph) { - GE_CHECK_NOTNULL(out_anchor); GE_CHECK_NOTNULL(peer_in_anchor); GE_CHECK_NOTNULL(pld_graph); + GE_CHECK_NOTNULL(out_anchor); GE_CHECK_NOTNULL(end_graph); const auto &src_node = out_anchor->GetOwnerNode(); const auto &dst_node = peer_in_anchor->GetOwnerNode(); @@ -313,6 +314,12 @@ graphStatus ge::GraphPartitioner::AddPlaceHolderEndInSrcDstGraph(const AnchorPtr GELOGW("SetInt peerIndex failed");) GE_IF_BOOL_EXEC(!AttrUtils::SetStr(end_op_desc, "parentOpType", dst_node->GetType()), GELOGW("SetStr parentOpType failed");) + GE_IF_BOOL_EXEC(!end_op_desc->SetExtAttr("parentNode", dst_node), GELOGW("SetEndExtAttr parentNode failed");) + OpDescPtr dst_node_op_desc = dst_node->GetOpDesc(); + GE_CHECK_NOTNULL(dst_node_op_desc); + GE_IF_BOOL_EXEC( + !AttrUtils::SetStr(end_op_desc, ATTR_NAME_END_REAR_NODE_ENGINE_NAME, dst_node_op_desc->GetOpEngineName()), + GELOGW("SetStr rearNodeEngineName failed");) // replace input_desc of end with owner node's desc int output_index = ge::AnchorUtils::GetIdx(out_anchor); bool is_need_update_desc = (output_index >= 0) && (graph_info_.mode_ == kPartitioning); @@ -361,6 +368,12 @@ graphStatus ge::GraphPartitioner::AddPlaceHolderEndInSrcDstGraph(const AnchorPtr GELOGW("SetStr parentId failed");) GE_IF_BOOL_EXEC(!AttrUtils::SetInt(pld_op_desc, "anchorIndex", AnchorUtils::GetIdx(out_anchor)), GELOGW("SetInt anchorIndex failed");) + GE_IF_BOOL_EXEC(!pld_op_desc->SetExtAttr("parentNode", src_node), GELOGW("SetPldExtAttr parentNode failed");) + OpDescPtr src_node_op_desc = src_node->GetOpDesc(); + GE_CHECK_NOTNULL(src_node_op_desc); + GE_IF_BOOL_EXEC( + !AttrUtils::SetStr(pld_op_desc, ATTR_NAME_PLD_FRONT_NODE_ENGINE_NAME, src_node_op_desc->GetOpEngineName()), + GELOGW("SetStr frontNodeEngineName failed");) // do not care over flow graph_info_.num_of_pld_end_++; // replace output_desc of pld with input node's output desc @@ -395,14 +408,14 @@ graphStatus ge::GraphPartitioner::AddPlaceHolderEndInSrcDstGraph(const AnchorPtr return FAILED; } graph_info_.index_2_end_[graph_info_.num_of_pld_end_] = new_end_node; - graph_info_.end_2_pld_[new_end_node] = new_pld_node; graph_info_.pld_2_end_[new_pld_node] = new_end_node; + graph_info_.end_2_pld_[new_end_node] = new_pld_node; return SUCCESS; } Status ge::GraphPartitioner::LinkInput2EndRemoveOrginalLink(ge::NodePtr input_node, ge::ComputeGraphPtr src_graph, ge::ComputeGraphPtr dst_graph) { - if (input_node == nullptr || src_graph == nullptr || dst_graph == nullptr) { + if ((input_node == nullptr) || (src_graph == nullptr) || (dst_graph == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return FAILED; } @@ -442,7 +455,7 @@ Status ge::GraphPartitioner::LinkInput2EndRemoveOrginalLink(ge::NodePtr input_no Status ge::GraphPartitioner::PutInputNodesInSubGraph(const ge::ComputeGraphPtr &src_graph, const ge::ComputeGraphPtr &dst_graph) { - if (src_graph == nullptr || dst_graph == nullptr) { + if ((src_graph == nullptr) || (dst_graph == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return FAILED; } @@ -849,34 +862,34 @@ Status ge::GraphPartitioner::PartitionSubGraph(ge::ComputeGraphPtr compute_graph GELOGE(GE_GRAPH_TOPO_SORT_FAILED, "[GraphPartitioner]: subGraphPtr->TopologicalSorting failed"); return FAILED; } - GE_TIMESTAMP_START(GraphPartitionInitialize); + GE_TIMESTAMP_START(PartitionSubGraphInitialize); if (Initialize(compute_graph) != SUCCESS) { GELOGE(GE_GRAPH_INIT_FAILED, "[GraphPartitioner]: initialize failed"); return FAILED; } - GE_TIMESTAMP_END(GraphPartitionInitialize, "GraphPartitioner::PartitionInitialize"); - GE_TIMESTAMP_START(GraphPartitionMarkClusters); + GE_TIMESTAMP_END(PartitionSubGraphInitialize, "GraphPartitioner::PartitionInitialize"); + GE_TIMESTAMP_START(PartitionSubGraphMarkClusters); MarkClusters(); - GE_TIMESTAMP_END(GraphPartitionMarkClusters, "GraphPartitioner::PartitionMarkClusters"); - GE_TIMESTAMP_START(GraphPartitionSplitSubGraphs); + GE_TIMESTAMP_END(PartitionSubGraphMarkClusters, "GraphPartitioner::PartitionMarkClusters"); + GE_TIMESTAMP_START(PartitionSubGraphSplitSubGraphs); if (SplitSubGraphs(compute_graph) != SUCCESS) { GELOGE(FAILED, "[GraphPartitioner]: SplitSubGraphs failed"); return FAILED; } - GE_TIMESTAMP_END(GraphPartitionSplitSubGraphs, "GraphPartitioner::PartitionSplitSubGraphs"); - GE_TIMESTAMP_START(GraphPartitionSortSubGraphs); + GE_TIMESTAMP_END(PartitionSubGraphSplitSubGraphs, "GraphPartitioner::PartitionSplitSubGraphs"); + GE_TIMESTAMP_START(PartitionSubGraphSortSubGraphs); if (SortSubGraphs(compute_graph) != ge::SUCCESS) { GELOGE(GE_GRAPH_TOPO_SORT_FAILED, "Graph Partition SortSubGraphs failed."); return ge::FAILED; } - GE_TIMESTAMP_END(GraphPartitionSortSubGraphs, "GraphPartitioner::PartitionSortSubGraphs"); - GE_TIMESTAMP_START(GraphPartitionAddPartitionsToGraphNode); + GE_TIMESTAMP_END(PartitionSubGraphSortSubGraphs, "GraphPartitioner::PartitionSortSubGraphs"); + GE_TIMESTAMP_START(PartitionSubGraphAddPartitionsToGraphNode); vector output_subgraphs; if (AddPartitionsToGraphNode(output_subgraphs, compute_graph) != ge::SUCCESS) { GELOGE(GE_GRAPH_EMPTY_PARTITION, "Graph Partition AddPartitionsToGraphNode failed."); return ge::FAILED; } - GE_TIMESTAMP_END(GraphPartitionAddPartitionsToGraphNode, "GraphPartitioner::PartitionAddPartitionsToGraphNode"); + GE_TIMESTAMP_END(PartitionSubGraphAddPartitionsToGraphNode, "GraphPartitioner::PartitionAddPartitionsToGraphNode"); GELOGI("Graph Partition ends. Adding partitions to SubGraphInfo, got %zu sub graphs", output_subgraphs.size()); graph_info_.mode_ = kMerging; // do not care over flow @@ -923,7 +936,7 @@ Status ge::GraphPartitioner::AddPlaceHolderEnd(const AnchorPtr &out_anchor, cons Status ge::GraphPartitioner::SortSubGraphs(const ge::ComputeGraphPtr &compute_graph) { uint32_t rank = kRankOne; // rank 0 for data graph ComputeGraphPtr new_input_nodes_sub_graph = MakeShared("inputNodeGraph"); - if (new_input_nodes_sub_graph == nullptr || compute_graph == nullptr) { + if ((new_input_nodes_sub_graph == nullptr) || (compute_graph == nullptr)) { GELOGE(FAILED, "[GraphPartitioner]: new_input_nodes_sub_graph or compute_graph is null."); return FAILED; } @@ -965,7 +978,7 @@ Status ge::GraphPartitioner::SortSubGraphs(const ge::ComputeGraphPtr &compute_gr } AnchorPtr ge::GraphPartitioner::GetEndInAnchor(const AnchorPtr &src_anchor, const NodePtr &end_node) { - if (src_anchor == nullptr || end_node == nullptr) { + if ((src_anchor == nullptr) || (end_node == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return nullptr; } @@ -979,7 +992,7 @@ AnchorPtr ge::GraphPartitioner::GetEndInAnchor(const AnchorPtr &src_anchor, cons } AnchorPtr ge::GraphPartitioner::GetPldOutAnchor(const NodePtr &pld_node, const AnchorPtr &dst_anchor) { - if (pld_node == nullptr || dst_anchor == nullptr) { + if ((pld_node == nullptr) || (dst_anchor == nullptr)) { GELOGE(FAILED, "parameter ptr is null."); return nullptr; } @@ -992,16 +1005,16 @@ AnchorPtr ge::GraphPartitioner::GetPldOutAnchor(const NodePtr &pld_node, const A return pld_out_anchor; } -void ge::GraphPartitioner::AddEndPldInformationToSubGraphInfo(ge::SubGraphInfoPtr &sub_graph_info) { - if (sub_graph_info == nullptr) { +void ge::GraphPartitioner::AddEndPldInformationToSubGraphInfo(ge::SubGraphInfoPtr &subgraph_info) { + if (subgraph_info == nullptr) { GELOGE(FAILED, "parameter ptr is null."); return; } - auto sub_graph = sub_graph_info->GetSubGraph(); - GE_CHECK_NOTNULL_JUST_RETURN(sub_graph); + auto subgraph = subgraph_info->GetSubGraph(); + GE_CHECK_NOTNULL_JUST_RETURN(subgraph); NodetoNodeMap end_map; NodetoNodeMap pld_map; - for (const auto &node : sub_graph->GetDirectNode()) { + for (const auto &node : subgraph->GetDirectNode()) { if (node->GetType() == kEndType) { end_map[node] = graph_info_.end_2_pld_.at(node); } @@ -1009,8 +1022,8 @@ void ge::GraphPartitioner::AddEndPldInformationToSubGraphInfo(ge::SubGraphInfoPt pld_map[node] = graph_info_.pld_2_end_.at(node); } } - sub_graph_info->SetEnd2PldMap(end_map); - sub_graph_info->SetPld2EndMap(pld_map); + subgraph_info->SetEnd2PldMap(end_map); + subgraph_info->SetPld2EndMap(pld_map); } const Graph2SubGraphInfoList &ge::GraphPartitioner::GetSubGraphMap() { return graph_2_subgraph_list_; } diff --git a/src/ge/graph/passes/atomic_addr_clean_pass.cc b/src/ge/graph/passes/atomic_addr_clean_pass.cc index 7d9b8dec..2c7fb9bb 100644 --- a/src/ge/graph/passes/atomic_addr_clean_pass.cc +++ b/src/ge/graph/passes/atomic_addr_clean_pass.cc @@ -22,68 +22,44 @@ #include #include -#include "framework/common/debug/ge_log.h" #include "common/ge_inner_error_codes.h" #include "common/ge/ge_util.h" +#include "graph/common/ge_call_wrapper.h" #include "graph/debug/ge_attr_define.h" #include "graph/utils/node_utils.h" #include "init/gelib.h" -namespace { -bool is_loop_graph = false; -} namespace ge { -namespace { -bool GraphShouldBeSkip(const ge::ComputeGraphPtr &graph) { - // Internal function, guaranteeing graph non-null - if (graph->GetParentGraph() == nullptr) { - return false; - } - return GraphUtils::IsUnknownShapeGraph(graph); -} -} // namespace - Status AtomicAddrCleanPass::Run(ComputeGraphPtr graph) { - GE_TIMESTAMP_START(AtomicAddrCleanPass); - if (graph == nullptr) { - GELOGE(PARAM_INVALID, "param [graph] must not be null."); - return PARAM_INVALID; - } - if (GraphShouldBeSkip(graph)) { - return SUCCESS; - } + GE_CHECK_NOTNULL(graph); GELOGD("AtomicAddrCleanPass begin."); // 1.Recoginze atomic and loop mark vector atomic_node_vec; for (NodePtr &node : graph->GetDirectNode()) { if (IsAtomicOp(node)) { - bool is_unknown = false; - auto ret_status = NodeUtils::GetNodeUnknownShapeStatus(*node, is_unknown); - if (ret_status != GRAPH_SUCCESS) { - GELOGW("Get node unknown status failed, node name:%s, type:%s.", node->GetName().c_str(), - node->GetType().c_str()); - continue; - } - if (is_unknown) { - GELOGI("Current node %s, type %s is unknown shape which should be skip.", node->GetName().c_str(), - node->GetType().c_str()); - continue; - } atomic_node_vec.push_back(node); } - if (!is_loop_graph && node->GetType() == LOOPCOND) { + if (!is_loop_graph_ && node->GetType() == LOOPCOND) { // there is loop in this graph GELOGD("There is no loop node. It will insert clean node follow atomic node."); - is_loop_graph = true; + is_loop_graph_ = true; } } if (atomic_node_vec.empty()) { GELOGI("There is no atomic node. Ignore atomicAddrClean pass."); return SUCCESS; } + + bool is_known_graph = graph->GetGraphUnknownFlag(); + if (is_known_graph) { + GELOGD("Graph[%s] is unknown graph. It will call fe interface to compile op.", graph->GetName().c_str()); + GE_CHK_STATUS_RET(CompileUnknownGraphOp(atomic_node_vec)); + return SUCCESS; + } + // 2.Insert clean node and link to atomic node Status ret; - if (is_loop_graph) { + if (is_loop_graph_) { ret = HandleLoopGraph(graph, atomic_node_vec); if (ret != SUCCESS) { return ret; @@ -95,7 +71,6 @@ Status AtomicAddrCleanPass::Run(ComputeGraphPtr graph) { } } GELOGD("AtomicAddrCleanPass end."); - GE_TIMESTAMP_END(AtomicAddrCleanPass, "GraphManager::AtomicAddrCleanPass"); return SUCCESS; } @@ -129,15 +104,28 @@ Status AtomicAddrCleanPass::HandleLoopGraph(ComputeGraphPtr &graph, const vector } Status AtomicAddrCleanPass::HandleNormalGraph(ComputeGraphPtr &graph, const vector &atomic_node_vec) { - GELOGD("Not loop graph. It will insert only 1 clean node."); + GELOGD("Not loop graph and unknown graph. It will insert only 1 clean node."); + + vector common_atomic_nodes; + auto ret = HandleDispersedAtomicNodes(graph, atomic_node_vec, common_atomic_nodes); + if (ret != SUCCESS) { + GELOGE(ret, "Handle dispersed atomic nodes failed, graph name is %s.", graph->GetName().c_str()); + return ret; + } + + if (common_atomic_nodes.empty()) { + GELOGI("common_atomic_nodes is empty"); + return SUCCESS; + } + // not loop graph , insert only one clean node in graph NodePtr clean_addr_node = InsertAtomicAddrCleanNode(graph); if (clean_addr_node == nullptr) { GELOGE(FAILED, "Insert AtomicAddrClean node failed. Ignore atomicAddrClean pass."); return FAILED; } - for (const auto &node : atomic_node_vec) { - auto ret = LinkToAtomicNode(node, clean_addr_node); + for (const auto &node : common_atomic_nodes) { + ret = LinkToAtomicNode(node, clean_addr_node); if (ret != SUCCESS) { GELOGE(ret, "Link control anchor failed from atomic node to atomic_addr_clean node."); return ret; @@ -149,7 +137,7 @@ Status AtomicAddrCleanPass::HandleNormalGraph(ComputeGraphPtr &graph, const vect for (auto &in_anchor : node->GetAllInDataAnchors()) { GE_CHECK_NOTNULL(in_anchor->GetPeerOutAnchor()); NodePtr peer_in_node = in_anchor->GetPeerOutAnchor()->GetOwnerNode(); - Status ret = LinkToAtomicNode(peer_in_node, clean_addr_node); + ret = LinkToAtomicNode(peer_in_node, clean_addr_node); if (ret != SUCCESS) { GELOGE(ret, "Link failed, %s : %s", peer_in_node->GetName().c_str(), clean_addr_node->GetName().c_str()); return ret; @@ -159,6 +147,44 @@ Status AtomicAddrCleanPass::HandleNormalGraph(ComputeGraphPtr &graph, const vect return SUCCESS; } +Status AtomicAddrCleanPass::HandleDispersedAtomicNodes(ComputeGraphPtr &graph, + const std::vector &atomic_node_vec, + std::vector &common_atomic_nodes) { + int index = 0; + for (const auto &node : atomic_node_vec) { + vector node_anchors_connect_netoutput; + // If GetBool fail, attr is_connect_netoutput is an empty vector. + (void)ge::AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_NODE_CONNECT_OUTPUT, node_anchors_connect_netoutput); + if (!node_anchors_connect_netoutput.empty()) { + NodePtr dispersed_clean_addr_node = InsertAtomicAddrCleanNode(graph); + if (dispersed_clean_addr_node == nullptr) { + GELOGE(FAILED, "Insert AtomicAddrClean node failed. Ignore atomicAddrClean pass."); + return FAILED; + } + + auto dispersed_node_op_desc = dispersed_clean_addr_node->GetOpDesc(); + GE_CHECK_NOTNULL(dispersed_node_op_desc); + string node_name = dispersed_node_op_desc->GetName(); + std::ostringstream oss; + oss << node_name << "_" << index; + node_name = oss.str(); + dispersed_node_op_desc->SetName(node_name); + GELOGD("Inserted dispersed atomic clean node name is %s", node_name.c_str()); + ++index; + Status ret = LinkToAtomicNode(node, dispersed_clean_addr_node); + if (ret != SUCCESS) { + GELOGE(ret, "Link control anchor failed from atomic node: %s to atomic_addr_clean node: %s.", + node->GetName().c_str(), dispersed_clean_addr_node->GetName().c_str()); + return ret; + } + } else { + common_atomic_nodes.emplace_back(node); + } + } + + return SUCCESS; +} + NodePtr AtomicAddrCleanPass::InsertAtomicAddrCleanNode(ComputeGraphPtr &graph) { OpDescPtr op_desc = MakeShared(NODE_NAME_ATOMIC_ADDR_CLEAN, ATOMICADDRCLEAN); if (op_desc == nullptr) { @@ -172,12 +198,14 @@ NodePtr AtomicAddrCleanPass::InsertAtomicAddrCleanNode(ComputeGraphPtr &graph) { if (!session_graph_id.empty()) { (void)AttrUtils::SetStr(op_desc, ATTR_NAME_SESSION_GRAPH_ID, session_graph_id); } + string node_name = op_desc->GetName(); // Only flush subgraph name - string node_name = (graph->GetParentGraph() != nullptr) - ? (graph->GetName() + "_" + op_desc->GetName() + session_graph_id) - : (op_desc->GetName() + session_graph_id); + if (graph->GetParentGraph() != nullptr) { + node_name = graph->GetName() + "_" + node_name; + } - op_desc->SetName(node_name); + string name = node_name + session_graph_id; + op_desc->SetName(name); GELOGI("Create cleanAddr op:%s.", op_desc->GetName().c_str()); // To avoid same name between graphs, set session graph id to this node NodePtr clean_addr_node = graph->AddNodeFront(op_desc); @@ -203,7 +231,7 @@ Status AtomicAddrCleanPass::LinkToAtomicNode(const NodePtr &atomic_node, NodePtr } GELOGD("Graph add cleanAddrNode op out ctrl edge, dst node: %s.", atomic_node->GetName().c_str()); std::string stream_label; - if (is_loop_graph && AttrUtils::GetStr(atomic_node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, stream_label)) { + if (is_loop_graph_ && AttrUtils::GetStr(atomic_node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, stream_label)) { if (!AttrUtils::SetStr(atomic_clean_node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, stream_label)) { GELOGW("LinkToAtomicNode: SetStr failed"); return INTERNAL_ERROR; @@ -262,11 +290,56 @@ bool AtomicAddrCleanPass::IsAtomicOp(const NodePtr &node) { return true; } /// -/// @brief Clear Status, uesd for subgraph pass +/// @brief Clear Status, used for subgraph pass /// @return SUCCESS /// Status AtomicAddrCleanPass::ClearStatus() { hcom_node_vec_.clear(); return SUCCESS; } + +Status AtomicAddrCleanPass::CompileUnknownGraphOp(const vector &atomic_node_vec) { + GE_TIMESTAMP_CALLNUM_START(UnknownGraphCompileOp); + std::unordered_map> node_vector_map; + std::shared_ptr instance = ge::GELib::GetInstance(); + if ((instance == nullptr) || !instance->InitFlag()) { + GELOGE(ge::GE_CLI_GE_NOT_INITIALIZED, "CompileSingleOp failed."); + return ge::GE_CLI_GE_NOT_INITIALIZED; + } + + for (auto &atomic_node : atomic_node_vec) { + auto op_desc = atomic_node->GetOpDesc(); + if (op_desc == nullptr) { + GELOGW("op desc is nullptr."); + continue; + } + string kernel_lib_name = op_desc->GetOpKernelLibName(); + if (kernel_lib_name.empty()) { + GELOGE(ge::INTERNAL_ERROR, "Get atomic node:%s(%s) kernel lib failed.", atomic_node->GetName().c_str(), + atomic_node->GetType().c_str()); + return ge::INTERNAL_ERROR; + } + + OpsKernelInfoStorePtr kernel_info = instance->OpsKernelManagerObj().GetOpsKernelInfoStore(kernel_lib_name); + GE_CHECK_NOTNULL(kernel_info); + node_vector_map[kernel_lib_name].emplace_back(atomic_node); + } + + for (auto &it : node_vector_map) { + auto &kernel_lib_name = it.first; + auto &node_vector = it.second; + OpsKernelInfoStorePtr kernel_info = instance->OpsKernelManagerObj().GetOpsKernelInfoStore(kernel_lib_name); + GE_CHECK_NOTNULL(kernel_info); + GE_TIMESTAMP_RESTART(UnknownGraphCompileOp); + auto ret = kernel_info->CompileOp(node_vector); + GELOGI("The atomic node size of compile op of %s is %zu", kernel_lib_name.c_str(), node_vector.size()); + GE_TIMESTAMP_ADD(UnknownGraphCompileOp); + if (ret != ge::SUCCESS) { + GELOGE(ret, "Compile atomic op failed, kernel lib name is %s", kernel_lib_name.c_str()); + return ret; + } + } + GE_TIMESTAMP_CALLNUM_END(UnknownGraphCompileOp, "AtomicAddrCleanPass::CompileUnknownGraphOp"); + return SUCCESS; +} } // namespace ge diff --git a/src/ge/graph/passes/atomic_addr_clean_pass.h b/src/ge/graph/passes/atomic_addr_clean_pass.h index d2d8f2ce..e22c1792 100644 --- a/src/ge/graph/passes/atomic_addr_clean_pass.h +++ b/src/ge/graph/passes/atomic_addr_clean_pass.h @@ -74,7 +74,18 @@ class AtomicAddrCleanPass : public GraphPass { */ bool IsAtomicOp(const NodePtr &node); + /** + * Handle atomic node in unknown graph + * @param atomic_node_vec: atomic node vector in unknown graph + * @return + */ + Status CompileUnknownGraphOp(const vector &atomic_node_vec); + + Status HandleDispersedAtomicNodes(ComputeGraphPtr &graph, const std::vector &atomic_node_vec, + std::vector &common_atomic_nodes); + vector hcom_node_vec_; + bool is_loop_graph_ = false; }; } // namespace ge diff --git a/src/ge/graph/passes/attach_stream_label_pass.cc b/src/ge/graph/passes/attach_stream_label_pass.cc new file mode 100644 index 00000000..9962821b --- /dev/null +++ b/src/ge/graph/passes/attach_stream_label_pass.cc @@ -0,0 +1,291 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/attach_stream_label_pass.h" +#include "ge/ge_api_types.h" +#include "graph/common/omg_util.h" + +namespace ge { +Status AttachStreamLabelPass::Run(ComputeGraphPtr graph) { + GELOGD("AttachStreamLabelPass Enter."); + + FindNodes(graph); + for (const auto &node : need_label_nodes_) { + OpDescPtr op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (!op_desc->HasAttr(ATTR_NAME_STREAM_LABEL)) { + GE_CHK_STATUS_RET(UpdateCondBranch(node), "Update cond branch failed, start node:%s.", node->GetName().c_str()); + } + } + GE_CHK_STATUS_RET(UpdateEnterNode(), "UpdateEnterNode failed."); + + GELOGD("AttachStreamLabelPass Leave."); + return SUCCESS; +} + +/// +/// @brief Clear Status, used for subgraph pass +/// @return +/// +Status AttachStreamLabelPass::ClearStatus() { + stream_switch_nodes_.clear(); + need_label_nodes_.clear(); + enter_nodes_.clear(); + branch_head_nodes_.clear(); + return SUCCESS; +} + +/// +/// @brief Find StreamSwitch / StreamMerge / Enter node +/// @param [in] graph +/// @return void +/// +void AttachStreamLabelPass::FindNodes(const ComputeGraphPtr &graph) { + for (const NodePtr &node : graph->GetDirectNode()) { + const std::string &type = node->GetType(); + if (type == STREAMSWITCH) { + stream_switch_nodes_.emplace_back(node); + } else if (type == STREAMMERGE) { + if ((node->GetOpDesc() != nullptr) && !node->GetOpDesc()->HasAttr(ATTR_NAME_NEXT_ITERATION)) { + need_label_nodes_.emplace_back(node); + } + } else if ((type == ENTER) || (type == REFENTER)) { + enter_nodes_.emplace_back(node); + } + } + + for (const auto &node : stream_switch_nodes_) { + for (const auto &out_ctrl_node : node->GetOutControlNodes()) { + GELOGD("branch_head_node %s of stream_switch %s.", out_ctrl_node->GetName().c_str(), node->GetName().c_str()); + branch_head_nodes_[out_ctrl_node] = node; + } + need_label_nodes_.emplace_back(node); + } +} + +/// +/// @brief update cond branch +/// @param [in] node +/// @return Status +/// +Status AttachStreamLabelPass::UpdateCondBranch(const NodePtr &node) { + std::string stream_label; + std::unordered_set branch_nodes; + std::unordered_set visited; + std::stack nodes; + nodes.push(node); + + static const std::set end_type_set = {STREAMSWITCH, STREAMMERGE, MERGE}; + bool merge_flag = false; + bool exit_flag = false; + bool net_output_flag = false; + while (!nodes.empty()) { + NodePtr cur_node = nodes.top(); + nodes.pop(); + if (visited.count(cur_node) > 0) { + continue; + } + if (AttachFlag(cur_node, stream_label, merge_flag, exit_flag, net_output_flag) != SUCCESS) { + GELOGE(FAILED, "Attach flag for node %s failed.", cur_node->GetName().c_str()); + return FAILED; + } + + const std::string &type = cur_node->GetType(); + for (const auto &out_node : cur_node->GetOutAllNodes()) { + const std::string &out_type = out_node->GetType(); + bool stop_flag = (end_type_set.count(out_type) > 0) || + ((branch_head_nodes_.count(out_node) > 0) && (branch_head_nodes_[out_node] != node)) || + (((type == ENTER) || (type == REFENTER)) && (out_type != STREAMACTIVE)); + if (!stop_flag) { + nodes.push(out_node); + GELOGD("Insert branch node %s.", out_node->GetName().c_str()); + branch_nodes.insert(out_node); + } + } + visited.insert(cur_node); + } + + if (node->GetType() == STREAMSWITCH) { + GE_CHK_STATUS_RET(SetActiveLabelList(node, {stream_label}), "set active_label_list failed."); + } + + bool attach_flag = (merge_flag || exit_flag) && net_output_flag; + if (attach_flag) { + GELOGI("No need to keep on attaching label."); + return SUCCESS; + } + + for (const NodePtr &tmp_node : branch_nodes) { + GELOGD("Attach label %s to node: %s.", stream_label.c_str(), tmp_node->GetName().c_str()); + GE_CHK_STATUS_RET(SetStreamLabel(tmp_node, stream_label), "Set stream label failed."); + } + + return SUCCESS; +} + +/// +/// @brief attach flag +/// @param [in] node +/// @param [out] stream_label +/// @param [out] merge_flag +/// @param [out] exit_flag +/// @param [out] net_output_flag +/// @return Status +/// +Status AttachStreamLabelPass::AttachFlag(const NodePtr &node, std::string &stream_label, bool &merge_flag, + bool &exit_flag, bool &net_output_flag) { + const std::string &type = node->GetType(); + if (type == STREAMSWITCH) { + if (node->GetInDataNodes().empty()) { + GELOGE(INTERNAL_ERROR, "node %s has no input_data_node.", node->GetName().c_str()); + return INTERNAL_ERROR; + } + stream_label = node->GetInDataNodes().at(0)->GetName(); + GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "Set stream label failed."); + bool value = false; + OpDescPtr op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + GE_CHK_BOOL_EXEC(AttrUtils::GetBool(op_desc, ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG, value), return FAILED, + "StreamSwitch get attr TRUE_BRANCH_STREAM failed."); + stream_label += (value ? "_t" : "_f"); + } else if (type == STREAMMERGE) { + stream_label = node->GetName(); + GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "Set stream label failed."); + merge_flag = true; + } else if ((type == EXIT) || (type == REFEXIT)) { + GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "Set stream label failed."); + exit_flag = true; + } else if (type == NETOUTPUT) { + net_output_flag = true; + } + + return SUCCESS; +} + +/// +/// @brief Update stream_label start with enter nodes +/// @return Status +/// +Status AttachStreamLabelPass::UpdateEnterNode() { + std::unordered_map> enter_active_map; + for (const auto &enter_node : enter_nodes_) { + for (const auto &out_ctrl_node : enter_node->GetOutControlNodes()) { + if (out_ctrl_node->GetType() != STREAMACTIVE) { + continue; + } + auto iter = enter_active_map.find(out_ctrl_node); + if (iter == enter_active_map.end()) { + enter_active_map[out_ctrl_node] = {enter_node}; + } else { + iter->second.emplace_back(enter_node); + } + } + } + + for (const auto &pair : enter_active_map) { + if (SetEnterLabel(pair.second, pair.first) != SUCCESS) { + GELOGE(FAILED, "Set stream_label for enter_nodes failed."); + return FAILED; + } + + NodePtr active_node = pair.first; + GE_CHECK_NOTNULL(active_node); + std::vector active_label_list; + if (!AttrUtils::GetListStr(active_node->GetOpDesc(), ATTR_NAME_ACTIVE_LABEL_LIST, active_label_list) || + (active_label_list.size() != 1) || active_label_list[0].empty()) { + GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ACTIVE_LABEL_LIST failed, node: %s.", active_node->GetName().c_str()); + return INTERNAL_ERROR; + } + + std::stack enter_nodes; + for (const auto &enter_node : pair.second) { + enter_nodes.emplace(enter_node); + } + if (UpdateLoopBranch(enter_nodes, active_label_list[0]) != SUCCESS) { + GELOGE(FAILED, "Update stream_label for loop_branch failed."); + return FAILED; + } + } + + return SUCCESS; +} + +/// +/// @brief Set stream_label for enter_nodes +/// @param [in] enter_nodes +/// @param [in] active_node +/// @return Status +/// +Status AttachStreamLabelPass::SetEnterLabel(const std::vector &enter_nodes, const NodePtr &active_node) { + std::string stream_label; + GE_CHECK_NOTNULL(active_node); + (void)AttrUtils::GetStr(active_node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, stream_label); + + bool same_flag = true; + for (const auto &enter_node : enter_nodes) { + std::string tmp_label; + (void)AttrUtils::GetStr(enter_node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, tmp_label); + if (tmp_label.empty() || (stream_label == tmp_label)) { + continue; + } + same_flag = false; + break; + } + + if (stream_label.empty()) { + if (same_flag) { + stream_label = active_node->GetName(); + } else { + GELOGW("stream_label of enter_active is empty while stream_label of some enter_node is not."); + return SUCCESS; + } + } + + for (const auto &enter_node : enter_nodes) { + GE_CHK_STATUS_RET(SetStreamLabel(enter_node, stream_label), "Set stream label failed."); + } + GE_CHK_STATUS_RET(SetStreamLabel(active_node, stream_label), "Set stream label failed."); + return SUCCESS; +} + +/// +/// @brief Update stream_label for loop_branch +/// @param [in] enter_nodes +/// @param [in] stream_label +/// @return Status +/// +Status AttachStreamLabelPass::UpdateLoopBranch(const std::stack &enter_nodes, + const std::string &stream_label) { + std::stack nodes(enter_nodes); + NodePtr cur_node = nullptr; + while (!nodes.empty()) { + cur_node = nodes.top(); + nodes.pop(); + for (const NodePtr &out_node : cur_node->GetOutAllNodes()) { + OpDescPtr out_desc = out_node->GetOpDesc(); + GE_CHECK_NOTNULL(out_desc); + std::string out_type = out_desc->GetType(); + if (out_desc->HasAttr(ATTR_NAME_STREAM_LABEL) || (out_type == ENTER) || (out_type == REFENTER)) { + continue; + } + GELOGD("Attach label %s to node: %s.", stream_label.c_str(), out_node->GetName().c_str()); + GE_CHK_STATUS_RET(SetStreamLabel(out_node, stream_label), "Set stream label failed."); + nodes.push(out_node); + } + } + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/passes/attach_stream_label_pass.h b/src/ge/graph/passes/attach_stream_label_pass.h new file mode 100644 index 00000000..fc6abd30 --- /dev/null +++ b/src/ge/graph/passes/attach_stream_label_pass.h @@ -0,0 +1,89 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_ATTACH_STREAM_LABEL_PASS_H_ +#define GE_GRAPH_PASSES_ATTACH_STREAM_LABEL_PASS_H_ + +#include +#include "inc/graph_pass.h" + +namespace ge { +class AttachStreamLabelPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph); + + /// + /// @brief Clear Status, used for subgraph pass + /// @return + /// + Status ClearStatus() override; + + private: + /// + /// @brief Find StreamSwitch / StreamMerge / Enter node + /// @param [in] graph + /// @return void + /// + void FindNodes(const ComputeGraphPtr &graph); + + /// + /// @brief update cond branch + /// @param [in] node + /// @return Status + /// + Status UpdateCondBranch(const NodePtr &node); + + /// + /// @brief attach flag + /// @param [in] node + /// @param [out] stream_label + /// @param [out] merge_flag + /// @param [out] exit_flag + /// @param [out] net_output_flag + /// @return Status + /// + static Status AttachFlag(const NodePtr &node, std::string &stream_label, bool &merge_flag, bool &exit_flag, + bool &net_output_flag); + + /// + /// @brief Update stream_label for loop_branch + /// @param [in] enter_nodes + /// @param [in] stream_label + /// @return Status + /// + static Status UpdateLoopBranch(const std::stack &enter_nodes, const std::string &stream_label); + + /// + /// @brief Update stream_label start with enter nodes + /// @return Status + /// + Status UpdateEnterNode(); + + /// + /// @brief Set stream_label for enter_nodes + /// @param [in] enter_nodes + /// @param [in] active_node + /// @return Status + /// + static Status SetEnterLabel(const std::vector &enter_nodes, const NodePtr &active_node); + + std::vector stream_switch_nodes_; + std::vector need_label_nodes_; + std::vector enter_nodes_; + std::unordered_map branch_head_nodes_; +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_ATTACH_STREAM_LABEL_PASS_H_ diff --git a/src/ge/graph/passes/base_pass.cc b/src/ge/graph/passes/base_pass.cc index 629b08ba..4da51ab0 100644 --- a/src/ge/graph/passes/base_pass.cc +++ b/src/ge/graph/passes/base_pass.cc @@ -66,7 +66,7 @@ void AddNextIterNodes(const Node::Vistor &nodes, std::queue &n } Status RunPasses(NodePtr &node, const NamesToPass &names_to_passes, std::unordered_set &nodes_re_pass, - std::unordered_set &nodes_deleted, std::unordered_set &nodes_seen) { + std::unordered_set &nodes_deleted, std::unordered_set &nodes_seen) { if (node == nullptr) { GELOGE(FAILED, "parameter is null."); return FAILED; @@ -106,7 +106,7 @@ Status RunPasses(NodePtr &node, const NamesToPass &names_to_passes, std::unorder auto nodes_deleted_by_pass = name_to_pass.second->GetNodesDeleted(); nodes_deleted.insert(nodes_deleted_by_pass.begin(), nodes_deleted_by_pass.end()); - if (nodes_deleted_by_pass.count(node.get()) > 0) { + if (nodes_deleted_by_pass.count(node) > 0) { GELOGD("The node %s was deleted by pass %s, stop the remain passes", node->GetName().c_str(), name_to_pass.first.c_str()); break; @@ -153,7 +153,7 @@ Status BaseNodePass::IsolateAndDeleteNode(NodePtr &node, const std::vector return FAILED; } - AddNodeDeleted(node.get()); + AddNodeDeleted(node); return SUCCESS; } @@ -182,7 +182,7 @@ Status GEPass::RunPassesOneGraph(const NamesToPass &names_to_passes) { GELOGD("Begin to run pass on graph, passes count %zu", names_to_passes.size()); std::queue nodes; std::unordered_set nodes_seen; - std::unordered_set nodes_deleted; + std::unordered_set nodes_deleted; std::unordered_set nodes_re_pass; std::unordered_set nodes_last; GetAllNodesNoInputEdge(graph_, nodes, nodes_seen, nodes_last); @@ -202,7 +202,7 @@ Status GEPass::RunPassesOneGraph(const NamesToPass &names_to_passes) { (void)nodes_re_pass.erase(node); GE_IF_BOOL_EXEC(node == nullptr, GELOGW("node is null"); continue); - if (nodes_deleted.count(node.get()) > 0) { + if (nodes_deleted.count(node) > 0) { GELOGD("The node %s was deleted before, skip it.", node->GetName().c_str()); continue; } diff --git a/src/ge/graph/passes/base_pass.h b/src/ge/graph/passes/base_pass.h index dfba581e..6e7b292e 100644 --- a/src/ge/graph/passes/base_pass.h +++ b/src/ge/graph/passes/base_pass.h @@ -53,7 +53,7 @@ class BaseNodePass { std::unordered_set GetNodesNeedRePass() { return nodes_need_re_pass_; } - std::unordered_set GetNodesDeleted() { return nodes_deleted_; } + std::unordered_set GetNodesDeleted() { return nodes_deleted_; } void SetOption(NodePassOption option, const std::string &value) { options_[option] = value; } @@ -103,13 +103,13 @@ class BaseNodePass { /// next iterations. /// @param node /// - void AddNodeDeleted(Node *node) { nodes_deleted_.insert(node); } + void AddNodeDeleted(const NodePtr &node) { nodes_deleted_.insert(node); } bool OptionExists(NodePassOption option) { return options_.count(option) > 0; } private: std::unordered_set nodes_need_re_pass_; - std::unordered_set nodes_deleted_; + std::unordered_set nodes_deleted_; std::map options_; }; diff --git a/src/ge/graph/passes/bitcast_pass.cc b/src/ge/graph/passes/bitcast_pass.cc new file mode 100644 index 00000000..e8e1f84f --- /dev/null +++ b/src/ge/graph/passes/bitcast_pass.cc @@ -0,0 +1,148 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/bitcast_pass.h" + +#include +#include +#include "common/ge/ge_util.h" +#include "graph/utils/type_utils.h" +#include "framework/common/debug/log.h" +#include "framework/common/ge_inner_error_codes.h" + +namespace ge { +namespace { +const char *const kAttrNameType = "type"; +} // namespace + +Status BitcastPass::Run(NodePtr &node) { + GELOGD("Bitcast running"); + if (node == nullptr) { + GELOGE(PARAM_INVALID, "Param [node] must not be null."); + return PARAM_INVALID; + } + + if (node->GetType() != BITCAST) { + return SUCCESS; + } + + OpDescPtr op_desc = node->GetOpDesc(); + if (op_desc == nullptr) { + return PARAM_INVALID; + } + ge::DataType dst_data_type; + if (CheckDstDataType(op_desc, dst_data_type) != SUCCESS) { + return PARAM_INVALID; + } + + if (CheckOutputShape(op_desc, dst_data_type) != SUCCESS) { + return PARAM_INVALID; + } + + return IsolateAndDeleteNode(node, {0}); +} + +Status BitcastPass::CheckDstDataType(const OpDescPtr op_desc, ge::DataType &dst_data_type) { + if (!ge::AttrUtils::GetDataType(op_desc, kAttrNameType, dst_data_type)) { + GELOGE(PARAM_INVALID, "Node failed to get attribute type."); + return PARAM_INVALID; + } + if (dst_data_type >= ge::DT_UNDEFINED) { + GELOGE(PARAM_INVALID, "dst_data_type[%s] is not valid.", TypeUtils::DataTypeToSerialString(dst_data_type).c_str()); + return PARAM_INVALID; + } + + if (op_desc->GetOutputDescPtr(0) == nullptr) { + GELOGE(PARAM_INVALID, "Bitcast node outputDesc is null."); + return PARAM_INVALID; + } + if (op_desc->GetOutputDescPtr(0)->GetDataType() != dst_data_type) { + GELOGE(PARAM_INVALID, "dst_data_type[%s] is not equal to output_data_type[%s].", + TypeUtils::DataTypeToSerialString(dst_data_type).c_str(), + TypeUtils::DataTypeToSerialString(op_desc->GetOutputDescPtr(0)->GetDataType()).c_str()); + return PARAM_INVALID; + } + return SUCCESS; +} + +Status BitcastPass::CheckOutputShape(const OpDescPtr op_desc, const ge::DataType dst_data_type) { + const GeTensorDescPtr &input_tensor_desc = op_desc->MutableInputDesc(0); + const GeTensorDescPtr &output_tensor_desc = op_desc->MutableOutputDesc(0); + if (input_tensor_desc == nullptr) { + GELOGE(PARAM_INVALID, "input_tensor_desc must not be null."); + return PARAM_INVALID; + } + + // get origin data_type and shape + ge::DataType ori_data_type = input_tensor_desc->GetDataType(); + if (ori_data_type >= ge::DT_UNDEFINED) { + GELOGE(PARAM_INVALID, "ori_data_type[%s] is not valid.", TypeUtils::DataTypeToSerialString(ori_data_type).c_str()); + return PARAM_INVALID; + } + + if (ori_data_type == dst_data_type) { + GELOGW("Origin data type is equal to dest data type."); + return SUCCESS; + } + + BitcastPass::kVecInt64 dim_vec(input_tensor_desc->GetShape().GetDims()); + if (CalcAndUpdateShape(dim_vec, ori_data_type, dst_data_type) != SUCCESS) { + GELOGE(PARAM_INVALID, "CalcAndUpdateShape failed."); + return PARAM_INVALID; + } + + if (dim_vec != output_tensor_desc->GetShape().GetDims()) { + GELOGE(PARAM_INVALID, "out_put_shape is different from expectations."); + return PARAM_INVALID; + } + + return SUCCESS; +} + +Status BitcastPass::CalcAndUpdateShape(BitcastPass::kVecInt64 &dim_vec, ge::DataType ori_data_type, + ge::DataType dst_data_type) { + if (dim_vec.size() == 0) { + GELOGE(PARAM_INVALID, "Pre node shape size is zero."); + return PARAM_INVALID; + } + int64_t ori_data_size = GetSizeByDataType(ori_data_type); + int64_t dst_data_size = GetSizeByDataType(dst_data_type); + + if (ori_data_size == dst_data_size) { + return SUCCESS; + } else if (ori_data_size > dst_data_size) { + if (ori_data_size % dst_data_size != 0) { + GELOGE(PARAM_INVALID, "ori_data_size is not divisible by dst_data_size."); + return PARAM_INVALID; + } + dim_vec.push_back(ori_data_size / dst_data_size); + return SUCCESS; + } else { + if (dst_data_size % ori_data_size != 0) { + GELOGE(PARAM_INVALID, "dst_data_size is not divisible by ori_data_size."); + return PARAM_INVALID; + } + + if (dim_vec[dim_vec.size() - 1] != (dst_data_size / ori_data_size)) { + GELOGE(PARAM_INVALID, "The last dim is not equal to dst_data_size / ori_data_size."); + return PARAM_INVALID; + } + dim_vec.pop_back(); + } + return SUCCESS; +} + +} // namespace ge diff --git a/src/ge/graph/passes/bitcast_pass.h b/src/ge/graph/passes/bitcast_pass.h new file mode 100644 index 00000000..4a9e2e1b --- /dev/null +++ b/src/ge/graph/passes/bitcast_pass.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_BITCAST_PASS_H_ +#define GE_GRAPH_PASSES_BITCAST_PASS_H_ + +#include "common/ge_inner_error_codes.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/types.h" +#include "graph/graph.h" +#include "graph/op_desc.h" +#include "graph/passes/base_pass.h" +#include "graph/passes/pass_utils.h" + +namespace ge { +class BitcastPass : public BaseNodePass { + public: + Status Run(ge::NodePtr &node) override; + typedef std::vector kVecInt64; + + private: + Status CheckDstDataType(const OpDescPtr op_desc, ge::DataType &dst_data_type); + Status CheckOutputShape(const OpDescPtr op_desc, const ge::DataType dst_data_type); + Status CalcAndUpdateShape(BitcastPass::kVecInt64 &dim_vec, ge::DataType ori_data_type, ge::DataType dst_data_type); +}; +} // namespace ge + +#endif // GE_GRAPH_PASSES_BITCAST_PASS_H_ diff --git a/src/ge/graph/passes/cast_remove_pass.cc b/src/ge/graph/passes/cast_remove_pass.cc index d18c4b4e..f7ff941c 100644 --- a/src/ge/graph/passes/cast_remove_pass.cc +++ b/src/ge/graph/passes/cast_remove_pass.cc @@ -69,7 +69,6 @@ bool CastRemovePass::HasSameDataType(OpDescPtr &begin_op_desc, OpDescPtr &end_op auto begin_out_desc = begin_op_desc->MutableOutputDesc(0); DataType begin_out_datatype = begin_out_desc->GetDataType(); - if (begin_out_datatype == end_out_datatype && (begin_out_datatype == DT_FLOAT16 || begin_out_datatype == DT_FLOAT)) { type = begin_out_datatype; return true; diff --git a/src/ge/graph/passes/cast_translate_pass.cc b/src/ge/graph/passes/cast_translate_pass.cc index 2d67b0a8..ee67e93d 100644 --- a/src/ge/graph/passes/cast_translate_pass.cc +++ b/src/ge/graph/passes/cast_translate_pass.cc @@ -264,7 +264,7 @@ Status CastTranslatePass::FuseDstNTranslates(NodePtr &node) { GELOGE(FAILED, "[%s] RemoveNodeWithoutRelink failed.", out_data_node->GetName().c_str()); return FAILED; } - AddNodeDeleted(out_data_node.get()); + AddNodeDeleted(out_data_node); } return SUCCESS; diff --git a/src/ge/graph/passes/common_subexpression_elimination_pass.cc b/src/ge/graph/passes/common_subexpression_elimination_pass.cc index a52535c1..18f2e857 100644 --- a/src/ge/graph/passes/common_subexpression_elimination_pass.cc +++ b/src/ge/graph/passes/common_subexpression_elimination_pass.cc @@ -83,6 +83,7 @@ Status CommonSubexpressionEliminationPass::Run(ComputeGraphPtr graph) { continue; } auto key = GetCseKey(node); + GELOGD("The node %s cse key %s", node->GetName().c_str(), key.c_str()); auto iter = keys_to_node.find(key); if (iter == keys_to_node.end()) { keys_to_node[key] = node; diff --git a/src/ge/graph/passes/compile_nodes_pass.cc b/src/ge/graph/passes/compile_nodes_pass.cc index def7655e..330569a2 100644 --- a/src/ge/graph/passes/compile_nodes_pass.cc +++ b/src/ge/graph/passes/compile_nodes_pass.cc @@ -23,6 +23,7 @@ #include "common/ge_inner_error_codes.h" #include "framework/common/debug/ge_log.h" #include "graph/debug/ge_attr_define.h" +#include "graph/common/ge_call_wrapper.h" #include "graph/op_desc.h" using domi::ImplyType; @@ -78,7 +79,7 @@ graphStatus CompileNodesPass::Run(ComputeGraphPtr graph) { return result; } GELOGI("[CompileNodesPass]: Optimize success."); - GE_TIMESTAMP_END(CompileNodesPass, "GraphManager::CompileNodesPass"); + GE_TIMESTAMP_EVENT_END(CompileNodesPass, "OptimizeStage2::ControlAttrOptimize::CompileNodesPass"); return GRAPH_SUCCESS; } @@ -101,7 +102,6 @@ graphStatus CompileNodesPass::GetSupportedKernel(const NodePtr &node, const std: } } OpsKernelInfoStorePtr kernel_info = instance->OpsKernelManagerObj().GetOpsKernelInfoStore(kernel_lib_name); - if (kernel_info == nullptr) { GELOGE(ge::GE_GRAPH_PARAM_NULLPTR, "Get op %s ops kernel info store failed", node->GetName().c_str()); return ge::GE_GRAPH_PARAM_NULLPTR; diff --git a/src/ge/graph/passes/cond_pass.cc b/src/ge/graph/passes/cond_pass.cc index 651cf98b..2f3f9333 100644 --- a/src/ge/graph/passes/cond_pass.cc +++ b/src/ge/graph/passes/cond_pass.cc @@ -226,7 +226,7 @@ Status CondPass::HandleScalarCond(const ComputeGraphPtr &graph, const OutDataAnc return FAILED; } - if (GraphUtils::InsertNodeBefore(out_anchor, {in_anchor}, cast_node) != GRAPH_SUCCESS) { + if (GraphUtils::InsertNodeAfter(out_anchor, {in_anchor}, cast_node) != GRAPH_SUCCESS) { GELOGE(FAILED, "Insert Cast node %s between %s->%s failed.", cast_node->GetName().c_str(), out_anchor->GetOwnerNode()->GetName().c_str(), in_anchor->GetOwnerNode()->GetName().c_str()); return FAILED; @@ -271,7 +271,7 @@ Status CondPass::InsertNode(const ComputeGraphPtr &graph, const OutDataAnchorPtr } AddRePassNode(new_node); - if (GraphUtils::InsertNodeBefore(out_anchor, {in_anchor}, new_node) != GRAPH_SUCCESS) { + if (GraphUtils::InsertNodeAfter(out_anchor, {in_anchor}, new_node) != GRAPH_SUCCESS) { GELOGE(FAILED, "Insert %s node %s between %s->%s failed.", type.c_str(), new_node->GetName().c_str(), out_anchor->GetOwnerNode()->GetName().c_str(), in_anchor->GetOwnerNode()->GetName().c_str()); return FAILED; diff --git a/src/ge/graph/passes/cond_remove_pass.cc b/src/ge/graph/passes/cond_remove_pass.cc index 8bc34fbc..1650be92 100644 --- a/src/ge/graph/passes/cond_remove_pass.cc +++ b/src/ge/graph/passes/cond_remove_pass.cc @@ -225,41 +225,40 @@ bool CondRemovePass::CheckIfCondConstInput(const OutDataAnchorPtr &cond_out_anch Status CondRemovePass::ReplaceIfCaseNodeWithPartitioncall(const NodePtr &node, const ComputeGraphPtr &save_branch) { // Add compute graph to new node - const auto &input_anchors = node->GetAllInAnchors(); - const auto &output_anchors = node->GetAllOutAnchors(); + const auto &input_desc_size = node->GetOpDesc()->GetInputsSize(); + const auto &output_desc_size = node->GetOpDesc()->GetOutputsSize(); // Create subgraph opdesc & node auto partitioncall_opdesc = - CreateSubgraphOpDesc(save_branch->GetName(), input_anchors.size() - kConditionIndexNum, output_anchors.size()); + CreateSubgraphOpDesc(save_branch->GetName(), input_desc_size - kConditionIndexNum, output_desc_size); auto partitioncall_node = node->GetOwnerComputeGraph()->AddNode(partitioncall_opdesc); // Link node's peerout anchors to new node's inanchors - for (const auto &input_anchor : input_anchors) { + for (const auto &input_anchor : node->GetAllInAnchors()) { for (const auto &peerout_anchor : input_anchor->GetPeerAnchors()) { if (GraphUtils::AddEdge(peerout_anchor, partitioncall_node->GetInAnchor( input_anchor->GetIdx() - kConditionIndexNum)) != ge::GRAPH_SUCCESS) { GELOGE(FAILED, "Add edge failed, from node:%s idx:%d to node:%s idx:%d, input num:%d, output num:%d", peerout_anchor->GetOwnerNode()->GetName().c_str(), peerout_anchor->GetIdx(), - partitioncall_node->GetName().c_str(), input_anchor->GetIdx(), input_anchors.size(), - output_anchors.size()); + partitioncall_node->GetName().c_str(), input_anchor->GetIdx(), input_desc_size, output_desc_size); return FAILED; } } } // Remove If / Case anchor and peer in anchor // Link new node's out anchors to node's peer inanchors - for (const auto &output_anchor : output_anchors) { + for (const auto &output_anchor : node->GetAllOutAnchors()) { for (const auto &peerin_anchor : output_anchor->GetPeerAnchors()) { if (GraphUtils::RemoveEdge(node->GetOutAnchor(output_anchor->GetIdx()), peerin_anchor) != ge::GRAPH_SUCCESS) { GELOGE(FAILED, "Remove edge failed, from node:%s idx:%d to node:%s idx:%d, input num:%d, output num:%d", node->GetName().c_str(), output_anchor->GetIdx(), peerin_anchor->GetOwnerNode()->GetName().c_str(), - peerin_anchor->GetIdx(), input_anchors.size(), output_anchors.size()); + peerin_anchor->GetIdx(), input_desc_size, output_desc_size); return FAILED; } if (GraphUtils::AddEdge(partitioncall_node->GetOutAnchor(output_anchor->GetIdx()), peerin_anchor) != ge::GRAPH_SUCCESS) { GELOGE(FAILED, "Add edge failed, from node:%s idx:%d to node:%s idx:%d, input num:%d, output num:%d", partitioncall_node->GetName().c_str(), output_anchor->GetIdx(), - peerin_anchor->GetOwnerNode()->GetName().c_str(), peerin_anchor->GetIdx(), input_anchors.size(), - output_anchors.size()); + peerin_anchor->GetOwnerNode()->GetName().c_str(), peerin_anchor->GetIdx(), input_desc_size, + output_desc_size); return FAILED; } } diff --git a/src/ge/graph/passes/constant_folding_pass.cc b/src/ge/graph/passes/constant_folding_pass.cc index 3ac7feb6..80bf7867 100644 --- a/src/ge/graph/passes/constant_folding_pass.cc +++ b/src/ge/graph/passes/constant_folding_pass.cc @@ -29,6 +29,18 @@ #include "inc/kernel.h" namespace ge { +const int64_t kStartCallNum = 1; + +const std::unordered_map> + &ConstantFoldingPass::GetGeConstantFoldingPerfStatistic() const { + return statistic_of_ge_constant_folding_; +} + +const std::unordered_map> + &ConstantFoldingPass::GetOpConstantFoldingPerfStatistic() const { + return statistic_of_op_constant_folding_; +} + Status ConstantFoldingPass::Run(ge::NodePtr &node) { GE_CHECK_NOTNULL(node); GELOGD("Begin to run constant folding on node %s", node->GetName().c_str()); @@ -50,6 +62,8 @@ Status ConstantFoldingPass::Run(ge::NodePtr &node) { auto inputs = OpDescUtils::GetInputData(input_nodes); vector outputs; + // Statistic of ge constant folding kernel + uint64_t start_time = GetCurrentTimestap(); auto ret = RunOpKernel(node, inputs, outputs); if (ret != SUCCESS) { auto op_kernel = folding_pass::GetKernelByType(node); @@ -59,7 +73,18 @@ Status ConstantFoldingPass::Run(ge::NodePtr &node) { return SUCCESS; } + // Statistic of op and fe constant folding kernel + start_time = GetCurrentTimestap(); ret = op_kernel->Compute(node_desc, inputs, outputs); + uint64_t cost_time = GetCurrentTimestap() - start_time; + if (statistic_of_ge_constant_folding_.find(node->GetType()) != statistic_of_ge_constant_folding_.end()) { + uint64_t &cnt = statistic_of_ge_constant_folding_[node->GetType()].first; + uint64_t &cur_cost_time = statistic_of_ge_constant_folding_[node->GetType()].second; + cnt++; + cur_cost_time += cost_time; + } else { + statistic_of_ge_constant_folding_[node->GetType()] = std::pair(kStartCallNum, cost_time); + } if (ret != SUCCESS) { if (ret == NOT_CHANGED) { GELOGD("Node %s type %s, compute terminates and exits the constant folding.", node->GetName().c_str(), @@ -70,6 +95,16 @@ Status ConstantFoldingPass::Run(ge::NodePtr &node) { return ret; } GELOGI("Node %s type %s, constant folding compute success.", node->GetName().c_str(), node->GetType().c_str()); + } else { + if (statistic_of_op_constant_folding_.find(node->GetType()) != statistic_of_op_constant_folding_.end()) { + uint64_t &cnt = statistic_of_op_constant_folding_[node->GetType()].first; + uint64_t &cost_time = statistic_of_op_constant_folding_[node->GetType()].second; + cnt++; + cost_time += GetCurrentTimestap() - start_time; + } else { + statistic_of_op_constant_folding_[node->GetType()] = + std::pair(kStartCallNum, GetCurrentTimestap() - start_time); + } } if (outputs.empty()) { diff --git a/src/ge/graph/passes/constant_folding_pass.h b/src/ge/graph/passes/constant_folding_pass.h index 1dcbcdc3..683b66f1 100644 --- a/src/ge/graph/passes/constant_folding_pass.h +++ b/src/ge/graph/passes/constant_folding_pass.h @@ -26,6 +26,12 @@ namespace ge { class ConstantFoldingPass : public FoldingPass { public: Status Run(ge::NodePtr &node) override; + const std::unordered_map> &GetGeConstantFoldingPerfStatistic() const; + const std::unordered_map> &GetOpConstantFoldingPerfStatistic() const; + + private: + std::unordered_map> statistic_of_op_constant_folding_; + std::unordered_map> statistic_of_ge_constant_folding_; }; } // namespace ge diff --git a/src/ge/graph/passes/control_trigger_pass.cc b/src/ge/graph/passes/control_trigger_pass.cc index 77fcbd69..0c00d553 100644 --- a/src/ge/graph/passes/control_trigger_pass.cc +++ b/src/ge/graph/passes/control_trigger_pass.cc @@ -15,16 +15,9 @@ */ #include "graph/passes/control_trigger_pass.h" - #include - #include "common/ge/ge_util.h" -#include "framework/common/debug/ge_log.h" -#include "framework/common/debug/log.h" -#include "framework/common/ge_inner_error_codes.h" -#include "framework/common/types.h" #include "graph/common/omg_util.h" -#include "graph/debug/ge_attr_define.h" #include "graph/utils/type_utils.h" namespace ge { @@ -444,7 +437,7 @@ Status ControlTriggerPass::FindPredInput(const NodePtr &switch_node) { return SUCCESS; } /// -/// @brief Clear Status, uesd for subgraph pass +/// @brief Clear Status, used for subgraph pass /// @return SUCCESS /// Status ControlTriggerPass::ClearStatus() { diff --git a/src/ge/graph/passes/end_of_sequence_add_control_pass.cc b/src/ge/graph/passes/end_of_sequence_add_control_pass.cc new file mode 100644 index 00000000..a3928835 --- /dev/null +++ b/src/ge/graph/passes/end_of_sequence_add_control_pass.cc @@ -0,0 +1,139 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/end_of_sequence_add_control_pass.h" + +#include +#include + +#include "init/gelib.h" +#include "graph/node.h" + +namespace ge { + +Status EndOfSequenceAddControlPass::Run(ComputeGraphPtr graph) { + if (graph == nullptr) { + GELOGE(PARAM_INVALID, "param [graph] must not be null."); + return PARAM_INVALID; + } + if (graph->GetParentGraph() != nullptr) { + return SUCCESS; + } + NodePtr end_of_sequence = GetEndOfSequence(graph); + if (end_of_sequence == nullptr) { + return SUCCESS; + } + GELOGI("EndOfSequenceAddControlPass begin."); + + std::vector target_nodes; + for (NodePtr &node : graph->GetDirectNode()) { + if (node == nullptr) { + GELOGW("node is nullptr."); + continue; + } + string stream_label; + (void)AttrUtils::GetStr(node->GetOpDesc(), ATTR_NAME_STREAM_LABEL, stream_label); + if (!stream_label.empty() || IsDataLikeNode(node)) { + continue; + } + // Save the nodes whose pre-nodes are all data-like node + auto in_data_nodes = node->GetInDataNodes(); + bool flag = false; + for (auto in_node : in_data_nodes) { + if (!IsDataLikeNode(in_node)) { + flag = true; + break; + } + } + if (flag) { + continue; + } + target_nodes.push_back(node); + } + // Insert control edge + Status status = AddControlEdge(end_of_sequence, target_nodes); + if (status != SUCCESS) { + GELOGE(FAILED, "Graph add EndOfSequence op out ctrl edge fail."); + return FAILED; + } + GELOGI("EndOfSequenceAddControlPass end."); + return SUCCESS; +} + +Status EndOfSequenceAddControlPass::AddControlEdge(NodePtr &end_of_sequence, std::vector &target_nodes) { + auto out_ctrl_anchor = end_of_sequence->GetOutControlAnchor(); + for (NodePtr &node : target_nodes) { + auto in_ctrl_anchor = node->GetInControlAnchor(); + if (in_ctrl_anchor == nullptr) { + continue; + } + Status status = GraphUtils::AddEdge(out_ctrl_anchor, in_ctrl_anchor); + if (status != GRAPH_SUCCESS) { + GELOGE(FAILED, "Graph add EndOfSequence op out ctrl edge fail, dst node: %s.", node->GetName().c_str()); + return FAILED; + } + GELOGI("Graph add EndOfSequence op out ctrl edge, dst node: %s.", node->GetName().c_str()); + } + return SUCCESS; +} + +inline NodePtr EndOfSequenceAddControlPass::GetEndOfSequence(const ComputeGraphPtr &graph) const { + // Internal function, guaranteeing graph non-null + for (NodePtr &node : graph->GetDirectNode()) { + if (node->GetType() == ENDOFSEQUENCE) { + return node; + } + } + return nullptr; +} + +bool EndOfSequenceAddControlPass::IsDataLikeNode(const NodePtr &node) { + std::shared_ptr instance_ptr = GELib::GetInstance(); + if ((instance_ptr == nullptr) || (!instance_ptr->InitFlag())) { + GELOGW("GELib not initialized"); + return false; + } + OpDescPtr op_desc = node->GetOpDesc(); + if (op_desc == nullptr) { + return false; + } + string engine_name = op_desc->GetOpEngineName(); + if (engine_name.empty()) { + engine_name = instance_ptr->DNNEngineManagerObj().GetDNNEngineName(node->GetOpDesc()); + } + const map schedulers = instance_ptr->DNNEngineManagerObj().GetSchedulers(); + // Only one scheduler has been supported by now + for (auto schedulers_iter = schedulers.begin(); schedulers_iter != schedulers.end(); ++schedulers_iter) { + const map cal_engines = schedulers_iter->second.cal_engines; + auto cal_engines_iter = cal_engines.find(engine_name); + if (cal_engines_iter == cal_engines.end()) { + GELOGW("No cal_engines found within engine %s, node name %s", engine_name.c_str(), node->GetName().c_str()); + continue; + } + EngineConfPtr engine_conf_ptr = cal_engines_iter->second; + if (engine_conf_ptr == nullptr) { + GELOGW("engine_conf_ptr within engine %s, node name %s is null", engine_name.c_str(), node->GetName().c_str()); + continue; + } + bool skip_assign_stream = engine_conf_ptr->skip_assign_stream; + if (skip_assign_stream) { + return true; + } + return false; + } + return false; +} +} // namespace ge diff --git a/src/ge/graph/passes/end_of_sequence_add_control_pass.h b/src/ge/graph/passes/end_of_sequence_add_control_pass.h new file mode 100644 index 00000000..2540a988 --- /dev/null +++ b/src/ge/graph/passes/end_of_sequence_add_control_pass.h @@ -0,0 +1,56 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_END_OF_SEQUENCE_ADD_CONTROL_EDGE_PASS_H_ +#define GE_GRAPH_PASSES_END_OF_SEQUENCE_ADD_CONTROL_EDGE_PASS_H_ + +#include "graph/graph.h" +#include "inc/graph_pass.h" + +namespace ge { +class EndOfSequenceAddControlPass : public GraphPass { + public: + EndOfSequenceAddControlPass() {} + EndOfSequenceAddControlPass(const EndOfSequenceAddControlPass &eos_pass) = delete; + EndOfSequenceAddControlPass &operator=(const EndOfSequenceAddControlPass &eos_pass) = delete; + + ~EndOfSequenceAddControlPass() override {} + + Status Run(ComputeGraphPtr graph) override; + + private: + /** + * Get EndOfSequence node in graph, nullptr if not exist. + * @param graph + * @return EndOfSequence node + */ + inline NodePtr GetEndOfSequence(const ComputeGraphPtr &graph) const; + /** + * Check whether this node is a data-like node. + * @param node + * @return + */ + bool IsDataLikeNode(const NodePtr &node); + /** + * Check whether this node is a data-like node. + * @param node + * @return + */ + Status AddControlEdge(NodePtr &end_of_sequence, std::vector &target_nodes); +}; +} // namespace ge + +#endif // GE_GRAPH_PASSES_END_OF_SEQUENCE_ADD_CONTROL_EDGE_PASS_H_ diff --git a/src/ge/graph/passes/folding_pass.cc b/src/ge/graph/passes/folding_pass.cc index 4e51f1ca..44dbc182 100644 --- a/src/ge/graph/passes/folding_pass.cc +++ b/src/ge/graph/passes/folding_pass.cc @@ -291,7 +291,7 @@ Status FoldingPass::RemoveNodeKeepingCtrlEdges(NodePtr &node) { GELOGE(INTERNAL_ERROR, "Failed to remove node %s from graph", node->GetName().c_str()); return INTERNAL_ERROR; } - AddNodeDeleted(node.get()); + AddNodeDeleted(node); return SUCCESS; } diff --git a/src/ge/graph/passes/hccl_memcpy_pass.cc b/src/ge/graph/passes/hccl_memcpy_pass.cc index 5325f56e..a9b3484b 100644 --- a/src/ge/graph/passes/hccl_memcpy_pass.cc +++ b/src/ge/graph/passes/hccl_memcpy_pass.cc @@ -28,6 +28,7 @@ namespace { const int32_t kAnchorSize = 1; const int kAnchorNum = 0; +const char *const kInputMutable = "_input_mutable"; } // namespace namespace ge { Status HcclMemcpyPass::Run(ge::ComputeGraphPtr graph) { @@ -35,7 +36,16 @@ Status HcclMemcpyPass::Run(ge::ComputeGraphPtr graph) { for (const auto &node : graph->GetDirectNode()) { auto op_desc = node->GetOpDesc(); GE_IF_BOOL_EXEC(op_desc == nullptr, continue); - if (!NeedInsertMemcpyOp(op_desc)) { + + bool node_input_mutable = false; + if (!AttrUtils::HasAttr(op_desc, kInputMutable)) { + continue; + } + + GE_IF_BOOL_EXEC(!AttrUtils::GetBool(op_desc, kInputMutable, node_input_mutable), + GELOGE(INTERNAL_ERROR, "node:%s get attr:_input_mutable failed.", node->GetName().c_str()); + return FAILED); + if (!node_input_mutable) { continue; } @@ -53,7 +63,7 @@ Status HcclMemcpyPass::Run(ge::ComputeGraphPtr graph) { NodePtr src_node = src_out_anchor->GetOwnerNode(); std::string src_type = src_node->GetType(); bool check_src_type = (src_type == CONSTANTOP) || (src_type == DATA) || (src_type == CONSTANT); - if (check_src_type && node->GetType() == HCOMALLREDUCE) { + if (check_src_type) { Status ret = ModifyEdgeConnection(graph, src_out_anchor, hccl_in_anchor); if (ret != SUCCESS) { GELOGE(INTERNAL_ERROR, "Failed to modify the connection."); @@ -136,16 +146,6 @@ std::string HcclMemcpyPass::CheckDuplicateName(const std::string &node_name) { } /// -/// @brief Check hcom op -/// @param [in] ge::ConstOpDescPtr op_desc -/// @return bool -/// -bool HcclMemcpyPass::NeedInsertMemcpyOp(const ge::ConstOpDescPtr &op_desc) const { - return (op_desc->GetType() == HCOMALLGATHER || op_desc->GetType() == HCOMALLREDUCE || - op_desc->GetType() == HCOMREDUCESCATTER); -} - -/// /// @brief Modify edge connection /// @param [in] ComputeGraphPtr graph /// @param [in] OutDataAnchorPtr src_out_anchor @@ -182,7 +182,7 @@ Status HcclMemcpyPass::ModifyEdgeConnection(const ComputeGraphPtr &graph, const return SUCCESS; } /// -/// @brief Clear Status, uesd for subgraph pass +/// @brief Clear Status, used for subgraph pass /// @return SUCCESS /// Status HcclMemcpyPass::ClearStatus() { diff --git a/src/ge/graph/passes/hccl_memcpy_pass.h b/src/ge/graph/passes/hccl_memcpy_pass.h index 9de96fbf..13863bd6 100644 --- a/src/ge/graph/passes/hccl_memcpy_pass.h +++ b/src/ge/graph/passes/hccl_memcpy_pass.h @@ -34,8 +34,6 @@ class HcclMemcpyPass : public GraphPass { std::string CheckDuplicateName(const std::string &node_name); - bool NeedInsertMemcpyOp(const ge::ConstOpDescPtr &op_desc) const; - Status ModifyEdgeConnection(const ComputeGraphPtr &graph, const OutDataAnchorPtr &src_out_anchor, const InDataAnchorPtr &hccl_in_anchor); diff --git a/src/ge/graph/passes/identify_reference_pass.cc b/src/ge/graph/passes/identify_reference_pass.cc deleted file mode 100644 index 92f7e7b6..00000000 --- a/src/ge/graph/passes/identify_reference_pass.cc +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2019-2020 Huawei Technologies 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. - */ - -#include "graph/passes/identify_reference_pass.h" - -#include -#include "framework/common/debug/ge_log.h" -#include "graph/debug/ge_attr_define.h" - -namespace ge { -Status IdentifyReferencePass::Run(NodePtr &node) { - if (node == nullptr) { - GELOGE(PARAM_INVALID, "param [node] must not be null."); - return PARAM_INVALID; - } - auto op_desc = node->GetOpDesc(); - if (op_desc == nullptr) { - GELOGE(PARAM_INVALID, "OpDesc of param [node] must not be null."); - return PARAM_INVALID; - } - - auto input_names = op_desc->GetAllInputNames(); - auto outputs = op_desc->GetAllOutputName(); - for (auto &output : outputs) { - for (auto &input_name : input_names) { - if (input_name == output.first) { - bool is_ref = true; - if (AttrUtils::SetBool(op_desc, ATTR_NAME_REFERENCE, is_ref)) { - GELOGI("param [node] %s is reference node, set attribute %s to be true.", node->GetName().c_str(), - ATTR_NAME_REFERENCE.c_str()); - return SUCCESS; - } - } - } - } - - return SUCCESS; -} -} // namespace ge diff --git a/src/ge/graph/passes/identity_pass.cc b/src/ge/graph/passes/identity_pass.cc index 9b15f77a..1f4725bf 100644 --- a/src/ge/graph/passes/identity_pass.cc +++ b/src/ge/graph/passes/identity_pass.cc @@ -18,26 +18,35 @@ #include #include - #include "framework/common/debug/ge_log.h" -#include "framework/common/ge_inner_error_codes.h" #include "graph/common/omg_util.h" +#include "graph/utils/node_utils.h" namespace ge { namespace { /// -/// A `Identity` node may after a `Switch` node and has control-dependency-out nodes. +/// 1. A `Identity` node may after a `Switch` node and has control-dependency-out nodes. /// Or a `Identity` node may before a `Merge` node and has control-dependency-in nodes. /// The identity nodes are used to represent control dependencies in condition branch, and can not be deleted. -/// +/// 2. Check identity is near subgraph. +/// Eg. As output of Data node in subgraph +/// or as input of Netoutput of subgraph +/// or as input of one node with subgraph +/// or as output of one node with subgraph Status CheckIdentityUsable(const NodePtr &node, bool &usable) { std::string node_type; for (auto &in_node : node->GetInDataNodes()) { - auto ret = GetOriginalType(in_node, node_type); - if (ret != SUCCESS) { - GELOGE(ret, "Failed to get node type from node %s", node->GetName().c_str()); - return ret; + auto in_node_opdesc = in_node->GetOpDesc(); + GE_CHECK_NOTNULL(in_node_opdesc); + // near entrance of subgraph || near subgraph + if ((in_node->GetType() == DATA && NodeUtils::IsSubgraphInput(in_node)) || + !in_node_opdesc->GetSubgraphInstanceNames().empty()) { + usable = true; + return SUCCESS; } + + GE_CHK_STATUS_RET(GetOriginalType(in_node, node_type), "Failed to get node type from node %s", + node->GetName().c_str()); if ((node_type != SWITCH) && (node_type != REFSWITCH)) { GELOGD("skip identity %s connected to switch", node->GetName().c_str()); break; @@ -49,11 +58,15 @@ Status CheckIdentityUsable(const NodePtr &node, bool &usable) { } } for (auto &out_node : node->GetOutDataNodes()) { - auto ret = GetOriginalType(out_node, node_type); - if (ret != SUCCESS) { - GELOGE(ret, "Failed to get node type from node %s", node->GetName().c_str()); - return ret; + auto out_node_opdesc = out_node->GetOpDesc(); + GE_CHECK_NOTNULL(out_node_opdesc); + // near output of subgraph || near subgraph + if (NodeUtils::IsSubgraphOutput(out_node) || !out_node_opdesc->GetSubgraphInstanceNames().empty()) { + usable = true; + return SUCCESS; } + GE_CHK_STATUS_RET(GetOriginalType(out_node, node_type), "Failed to get node type from node %s", + node->GetName().c_str()); if ((node_type != MERGE) && (node_type != REFMERGE)) { GELOGD("skip identity %s connected to merge", node->GetName().c_str()); break; @@ -79,7 +92,7 @@ Status IdentityPass::Run(NodePtr &node) { GELOGE(status_ret, "Identity pass get original type fail."); return status_ret; } - if ((type != IDENTITY) && (type != IDENTITYN)) { + if ((type != IDENTITY) && (type != IDENTITYN) && (type != READVARIABLEOP)) { return SUCCESS; } diff --git a/src/ge/graph/passes/infershape_pass.cc b/src/ge/graph/passes/infershape_pass.cc index 18767cea..8b44d31b 100644 --- a/src/ge/graph/passes/infershape_pass.cc +++ b/src/ge/graph/passes/infershape_pass.cc @@ -15,7 +15,7 @@ */ #include "graph/passes/infershape_pass.h" - +#include "common/util/error_manager/error_manager.h" #include "framework/common/debug/ge_log.h" #include "framework/common/ge_inner_error_codes.h" #include "graph/shape_refiner.h" @@ -24,6 +24,8 @@ namespace ge { Status InferShapePass::Run(NodePtr &node) { auto ret = ShapeRefiner::InferShapeAndType(node, !OptionExists(kOptimizeAfterSubGraph)); if (ret != GRAPH_SUCCESS) { + ErrorManager::GetInstance().ATCReportErrMessage("E35003", {"opname", "err_msg"}, + {node->GetName(), "check your model!"}); GELOGE(GE_GRAPH_INFERSHAPE_FAILED, "infershape failed. node: %s", node->GetName().c_str()); return GE_GRAPH_INFERSHAPE_FAILED; } diff --git a/src/ge/graph/passes/input_output_connection_identify_pass.cc b/src/ge/graph/passes/input_output_connection_identify_pass.cc new file mode 100644 index 00000000..45560bf5 --- /dev/null +++ b/src/ge/graph/passes/input_output_connection_identify_pass.cc @@ -0,0 +1,193 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/input_output_connection_identify_pass.h" + +#include +#include +#include +#include +#include + +#include "common/ge/ge_util.h" +#include "common/ge_inner_error_codes.h" +#include "framework/common/debug/ge_log.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/utils/graph_utils.h" +#include "graph/utils/node_utils.h" + +using std::map; +using std::string; +using std::vector; + +namespace ge { +namespace { +inline bool IsDataOp(const std::string &node_type) { + return (node_type == DATA_TYPE) || (node_type == AIPP_DATA_TYPE) || (node_type == ANN_DATA_TYPE); +} +} // namespace + +Status InputOutputConnectionIdentifyPass::Run(ComputeGraphPtr graph) { + if (graph == nullptr) { + GELOGE(PARAM_INVALID, "Input param graph is null, skip identification of nodes that connect to input and output."); + return PARAM_INVALID; + } + + if (graph->GetParentGraph() != nullptr) { + GELOGD("Current graph %s is a subgraph, skip identification of nodes that connect to input and output.", + graph->GetName().c_str()); + return SUCCESS; + } + + GELOGD("Start to identify nodes that connect to input and output."); + if (graph->TopologicalSorting() != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Graph topological sort failed."); + return INTERNAL_ERROR; + } + + if (GraphUtils::GetRefMapping(graph, symbol_to_anchors_, anchor_to_symbol_) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Get ref-mapping for graph %s failed.", graph->GetName().c_str()); + return INTERNAL_ERROR; + } + + map> connect_input_node_idx_map; + map> connect_output_node_idx_map; + Status status = SUCCESS; + for (const NodePtr &node : graph->GetDirectNode()) { + // Not only node type Data is determined. + if (IsDataOp(node->GetType())) { + GELOGD("Find nodes that connect to root graph input node: %s.", node->GetName().c_str()); + status = ProcessInputNode(node, connect_input_node_idx_map, connect_output_node_idx_map); + if (status != SUCCESS) { + GELOGE(status, "Failed to process nodes that connect to input node: %s.", node->GetName().c_str()); + return status; + } + } + + if (node->GetType() == NETOUTPUT) { + GELOGD("Find nodes that connect to root graph output node: %s.", node->GetName().c_str()); + status = ProcessOutputNode(node, connect_input_node_idx_map, connect_output_node_idx_map); + if (status != SUCCESS) { + GELOGE(status, "Failed to process nodes that connect to output node: %s.", node->GetName().c_str()); + return status; + } + } + } + + status = SetNodeAttrOfConnectingInputOutput(connect_input_node_idx_map, connect_output_node_idx_map); + if (status != SUCCESS) { + GELOGE(status, "Failed to set attr for nodes that connect to input and output."); + return status; + } + + GELOGD("Success to identify nodes that connect to input and output."); + return SUCCESS; +} + +Status InputOutputConnectionIdentifyPass::ProcessInputNode(const NodePtr &node, + map> &connect_input_node_idx, + map> &connect_output_node_idx) { + GE_CHECK_NOTNULL(node); + for (const auto &out_data_anchor : node->GetAllOutDataAnchors()) { + // The return ptr of GetAllOutDataAnchors is always valid. + auto anchor_iter = anchor_to_symbol_.find(NodeIndexIO(node, out_data_anchor->GetIdx(), kOut).ToString()); + if (anchor_iter == anchor_to_symbol_.end()) { + GELOGW("Current node: %s out_data_anchor: %d is invalid, can not find related symbol.", node->GetName().c_str(), + out_data_anchor->GetIdx()); + continue; + } + + const string &symbol = anchor_iter->second; + auto status = UpdateNodeIdxMap(symbol, connect_input_node_idx, connect_output_node_idx); + if (status != SUCCESS) { + GELOGE(status, "Failed to update node anchor_index map."); + return status; + } + } + return SUCCESS; +} + +Status InputOutputConnectionIdentifyPass::UpdateNodeIdxMap(const string &symbol_string, + map> &connect_input_node_idx, + map> &connect_output_node_idx) { + auto symbol_iter = symbol_to_anchors_.find(symbol_string); + if (symbol_iter == symbol_to_anchors_.end()) { + GELOGE(PARAM_INVALID, "Input param symbol string: %s is invalid.", symbol_string.c_str()); + return PARAM_INVALID; + } + const auto &node_index_io_list = symbol_iter->second; + for (const auto &node_index_io : node_index_io_list) { + if (node_index_io.io_type_ == kOut) { + // find node that has shared output memory. + connect_output_node_idx[node_index_io.node_].emplace_back(node_index_io.index_); + } else { + // find node that has shared input memory. + connect_input_node_idx[node_index_io.node_].emplace_back(node_index_io.index_); + } + } + return SUCCESS; +} + +Status InputOutputConnectionIdentifyPass::ProcessOutputNode(const NodePtr &node, + map> &connect_input_node_idx, + map> &connect_output_node_idx) { + GE_CHECK_NOTNULL(node); + for (const auto &in_data_anchor : node->GetAllInDataAnchors()) { + // The return ptr of GetAllInDataAnchors is always valid. + auto anchor_iter = anchor_to_symbol_.find(NodeIndexIO(node, in_data_anchor->GetIdx(), kIn).ToString()); + if (anchor_iter == anchor_to_symbol_.end()) { + GELOGW("Current node: %s in_data_anchor: %d is invalid, can not find related symbol.", node->GetName().c_str(), + in_data_anchor->GetIdx()); + continue; + } + + const string &symbol = anchor_iter->second; + auto status = UpdateNodeIdxMap(symbol, connect_input_node_idx, connect_output_node_idx); + if (status != SUCCESS) { + GELOGE(status, "Failed to update node anchor_index map."); + return status; + } + } + return SUCCESS; +} + +Status InputOutputConnectionIdentifyPass::SetNodeAttrOfConnectingInputOutput( + const map> &connect_input_node_idx, + const map> &connect_output_node_idx) { + for (const auto &iter : connect_input_node_idx) { + GE_CHECK_NOTNULL(iter.first); + if (iter.first->GetOpDesc() != nullptr) { + if (!AttrUtils::SetListInt(iter.first->GetOpDesc(), ATTR_NAME_NODE_CONNECT_INPUT, iter.second)) { + GELOGE(INTERNAL_ERROR, "Failed to set attr %s for node %s.", ATTR_NAME_NODE_CONNECT_INPUT.c_str(), + iter.first->GetName().c_str()); + return INTERNAL_ERROR; + } + } + } + + for (const auto &iter : connect_output_node_idx) { + GE_CHECK_NOTNULL(iter.first); + if (iter.first->GetOpDesc() != nullptr) { + if (!AttrUtils::SetListInt(iter.first->GetOpDesc(), ATTR_NAME_NODE_CONNECT_OUTPUT, iter.second)) { + GELOGE(INTERNAL_ERROR, "Failed to set attr %s for node %s.", ATTR_NAME_NODE_CONNECT_OUTPUT.c_str(), + iter.first->GetName().c_str()); + return INTERNAL_ERROR; + } + } + } + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/passes/input_output_connection_identify_pass.h b/src/ge/graph/passes/input_output_connection_identify_pass.h new file mode 100644 index 00000000..0dd32102 --- /dev/null +++ b/src/ge/graph/passes/input_output_connection_identify_pass.h @@ -0,0 +1,75 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_INPUT_OUTPUT_CONNECTION_IDENTIFY_PASS_H_ +#define GE_GRAPH_PASSES_INPUT_OUTPUT_CONNECTION_IDENTIFY_PASS_H_ + +#include +#include +#include "graph/graph.h" +#include "inc/graph_pass.h" + +namespace ge { +class InputOutputConnectionIdentifyPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph) override; + + private: + /// + /// Find all nodes that connect to input node. + /// @param [in] input node + /// @param [out] map of nodes and anchor index that connect to input + /// @param [out] map of nodes and anchor index that connect to output + /// @return Status + /// + Status ProcessInputNode(const NodePtr &node, std::map> &connect_input_node_idx, + std::map> &connect_output_node_idx); + + /// + /// Find all nodes that connect to output node. + /// @param [in] output node + /// @param [out] map of nodes and anchor index that connect to input + /// @param [out] map of nodes and anchor index that connect to output + /// @return Status + /// + Status ProcessOutputNode(const NodePtr &node, std::map> &connect_input_node_idx, + std::map> &connect_output_node_idx); + + /// + /// Update all nodes that have shared memory. + /// @param [in] symbol string + /// @param [out] map of nodes and anchor index that connect to input + /// @param [out] map of nodes and anchor index that connect to output + /// @return Status + /// + Status UpdateNodeIdxMap(const string &symbol_string, std::map> &connect_input_node_idx, + std::map> &connect_output_node_idx); + + /// + /// Set attr for all nodes that connect to input and output. + /// @param [in] map of nodes and anchor index that connect to input + /// @param [in] map of nodes and anchor index that connect to output + /// @return Status + /// + Status SetNodeAttrOfConnectingInputOutput(const std::map> &connect_input_node_idx, + const std::map> &connect_output_node_idx); + + // Members for ref mapping + std::map> symbol_to_anchors_; + std::map anchor_to_symbol_; +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_INPUT_OUTPUT_CONNECTION_IDENTIFY_PASS_H_ \ No newline at end of file diff --git a/src/ge/graph/passes/iterator_op_pass.cc b/src/ge/graph/passes/iterator_op_pass.cc index e1d452b1..1d11004d 100644 --- a/src/ge/graph/passes/iterator_op_pass.cc +++ b/src/ge/graph/passes/iterator_op_pass.cc @@ -73,14 +73,14 @@ Status IteratorOpPass::Run(ge::ComputeGraphPtr graph) { GE_IF_BOOL_EXEC(status != SUCCESS, GELOGW("Fail to Get var_desc of NODE_NAME_FLOWCTRL_LOOP_PER_ITER failed."); continue); Status ret; - ret = SetRtContext(rtContext_t(), RT_CTX_NORMAL_MODE); + ret = SetRtContext(graph->GetSessionID(), rtContext_t(), RT_CTX_NORMAL_MODE); // EOS will not be considered if ret is not SUCCESS. - GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGW("Set rt context RT_CTX_GEN_MODE failed."); continue); + GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGW("Set rt context RT_CTX_NORMAL_MODE failed."); continue); status = GetVariableValue(graph->GetSessionID(), ge_tensor_desc, NODE_NAME_FLOWCTRL_LOOP_PER_ITER, &loop_per_iter); - ret = SetRtContext(rtContext_t(), RT_CTX_GEN_MODE); + ret = SetRtContext(graph->GetSessionID(), rtContext_t(), RT_CTX_GEN_MODE); // The following process will be affected if ret is not SUCCESS. GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGE(ret, "Set rt context RT_CTX_GEN_MODE failed."); return ret); @@ -108,7 +108,7 @@ Status IteratorOpPass::GetVariableValue(uint64_t session_id, const ge::GeTensorD // base_addr uint8_t *var_mem_base = VarManager::Instance(session_id)->GetVarMemoryBase(RT_MEMORY_HBM); GE_CHECK_NOTNULL(var_mem_base); - // offset + // offset + logic_base uint8_t *dev_ptr = nullptr; GE_CHK_STATUS_RET(VarManager::Instance(session_id)->GetVarAddr(var_name, tensor_desc, &dev_ptr), "Get variable %s address failed.", var_name.c_str()); @@ -279,11 +279,11 @@ ge::OpDescPtr IteratorOpPass::CreateMemcpyAsyncOp(const ge::NodePtr &pre_node) { return op_desc; } -Status IteratorOpPass::SetRtContext(rtContext_t rt_context, rtCtxMode_t mode) { +Status IteratorOpPass::SetRtContext(uint64_t session_id, rtContext_t rt_context, rtCtxMode_t mode) { GELOGI("set rt_context %d, device id:%u.", static_cast(mode), ge::GetContext().DeviceId()); GE_CHK_RT_RET(rtCtxCreate(&rt_context, mode, ge::GetContext().DeviceId())); GE_CHK_RT_RET(rtCtxSetCurrent(rt_context)); - RtContextUtil::GetInstance().AddrtContext(rt_context); + RtContextUtil::GetInstance().AddRtContext(session_id, rt_context); return SUCCESS; } } // namespace ge diff --git a/src/ge/graph/passes/iterator_op_pass.h b/src/ge/graph/passes/iterator_op_pass.h index e403020c..78b951e6 100644 --- a/src/ge/graph/passes/iterator_op_pass.h +++ b/src/ge/graph/passes/iterator_op_pass.h @@ -64,7 +64,7 @@ class IteratorOpPass : public GraphPass { /// ge::OpDescPtr CreateMemcpyAsyncOp(const ge::NodePtr &pre_node); - Status SetRtContext(rtContext_t rt_context, rtCtxMode_t mode); + Status SetRtContext(uint64_t session_id, rtContext_t rt_context, rtCtxMode_t mode); }; } // namespace ge #endif // GE_GRAPH_PASSES_ITERATOR_OP_PASS_H_ diff --git a/src/ge/graph/passes/link_gen_mask_nodes_pass.cc b/src/ge/graph/passes/link_gen_mask_nodes_pass.cc index ff150a54..63ca68a2 100644 --- a/src/ge/graph/passes/link_gen_mask_nodes_pass.cc +++ b/src/ge/graph/passes/link_gen_mask_nodes_pass.cc @@ -97,9 +97,16 @@ void LinkGenMaskNodesPass::GetAllGenMaskNodes(ComputeGraphPtr graph, vectorGetOpDesc() == nullptr) || (node->GetOpDesc()->HasAttr(ATTR_NAME_STREAM_LABEL))) { + continue; + } + auto in_data_nodes = node->GetInDataNodes(); if (in_data_nodes.size() > kGenMaskInputIndex) { NodePtr &gen_mask = in_data_nodes.at(kGenMaskInputIndex); + if ((gen_mask->GetOpDesc() == nullptr) || (gen_mask->GetOpDesc()->HasAttr(ATTR_NAME_STREAM_LABEL))) { + continue; + } if (AreAllInputsConst(gen_mask) && nodes_set.count(gen_mask) == 0) { gen_mask_nodes.emplace_back(gen_mask); nodes_set.emplace(gen_mask); diff --git a/src/ge/graph/passes/mark_graph_unknown_status_pass.cc b/src/ge/graph/passes/mark_graph_unknown_status_pass.cc new file mode 100644 index 00000000..7106e58c --- /dev/null +++ b/src/ge/graph/passes/mark_graph_unknown_status_pass.cc @@ -0,0 +1,35 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/mark_graph_unknown_status_pass.h" +#include "graph/utils/node_utils.h" + +namespace ge { +Status MarkGraphUnknownStatusPass::Run(ComputeGraphPtr graph) { + GE_CHECK_NOTNULL(graph); + bool is_unknown_shape = false; + for (const auto &node : graph->GetDirectNode()) { + GE_CHK_STATUS_RET(ge::NodeUtils::GetNodeUnknownShapeStatus(*node, is_unknown_shape), + "Get node[%s] shape status failed!", node->GetName().c_str()); + if (is_unknown_shape) { + break; + } + } + graph->SetGraphUnknownFlag(is_unknown_shape); + GELOGD("mark graph [%s] unknown status success! value is %d", graph->GetName().c_str(), is_unknown_shape); + return SUCCESS; +} +} // namespace ge \ No newline at end of file diff --git a/src/ge/graph/passes/identify_reference_pass.h b/src/ge/graph/passes/mark_graph_unknown_status_pass.h similarity index 67% rename from src/ge/graph/passes/identify_reference_pass.h rename to src/ge/graph/passes/mark_graph_unknown_status_pass.h index 5f284b4c..662e321c 100644 --- a/src/ge/graph/passes/identify_reference_pass.h +++ b/src/ge/graph/passes/mark_graph_unknown_status_pass.h @@ -14,16 +14,15 @@ * limitations under the License. */ -#ifndef GE_GRAPH_PASSES_IDENTIFY_REFERENCE_PASS_H_ -#define GE_GRAPH_PASSES_IDENTIFY_REFERENCE_PASS_H_ - -#include "graph/passes/base_pass.h" +#ifndef GE_GRAPH_PASSES_MARK_GRAPH_UNKNOWN_STATUS_PASS_H_ +#define GE_GRAPH_PASSES_MARK_GRAPH_UNKNOWN_STATUS_PASS_H_ +#include "graph/graph.h" +#include "inc/graph_pass.h" namespace ge { -class IdentifyReferencePass : public BaseNodePass { +class MarkGraphUnknownStatusPass : public GraphPass { public: - Status Run(NodePtr &node) override; + Status Run(ComputeGraphPtr graph); }; } // namespace ge - -#endif // GE_GRAPH_PASSES_IDENTIFY_REFERENCE_PASS_H_ +#endif // GE_GRAPH_PASSES_MARK_GRAPH_UNKNOWN_STATUS_PASS_H_ diff --git a/src/ge/graph/passes/mark_same_addr_pass.cc b/src/ge/graph/passes/mark_same_addr_pass.cc new file mode 100644 index 00000000..0ed151d3 --- /dev/null +++ b/src/ge/graph/passes/mark_same_addr_pass.cc @@ -0,0 +1,66 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/mark_same_addr_pass.h" + +namespace ge { +bool MarkSameAddrPass::IsNextNodeExpected(const ge::NodePtr &cur_node, const vector &next_nodes, + int &out_anchor_idx) { + for (auto out_anchor : cur_node->GetAllOutDataAnchors()) { + if (out_anchor == nullptr) { + continue; + } + for (auto in_anchor : out_anchor->GetPeerInDataAnchors()) { + if (in_anchor == nullptr) { + continue; + } + auto dst_node = in_anchor->GetOwnerNode(); + if (dst_node == nullptr) { + continue; + } + if (std::count(next_nodes.begin(), next_nodes.end(), dst_node->GetType()) > 0) { + out_anchor_idx = out_anchor->GetIdx(); + GELOGD("Current node is %s, next node is %s.", cur_node->GetName().c_str(), dst_node->GetName().c_str()); + return true; + } + } + } + return false; +} + +Status MarkSameAddrPass::Run(ComputeGraphPtr graph) { + GELOGD("MarkSameAddrPass begin."); + GE_CHECK_NOTNULL(graph); + if (graph->GetGraphUnknownFlag()) { + GELOGD("Graph[%s] is unknown shape, do not need to set fixed addr attr.", graph->GetName().c_str()); + return SUCCESS; + } + + int out_anchor_idx = 0; + for (const ge::NodePtr &node : graph->GetDirectNode()) { + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + vector next_nodes = {STREAMSWITCH, STREAMSWITCHN, LABELSWITCHBYINDEX}; + if (IsNextNodeExpected(node, next_nodes, out_anchor_idx)) { + string tensor_name = op_desc->GetOutputNameByIndex(out_anchor_idx); + (void)ge::AttrUtils::SetStr(node->GetOpDesc(), ATTR_DYNAMIC_SHAPE_FIXED_ADDR, tensor_name); + (void)ge::AttrUtils::SetInt(node->GetOpDesc(), ATTR_DYNAMIC_SHAPE_FIXED_ADDR_INDEX, out_anchor_idx); + } + } + GELOGD("MarkSameAddrPass end."); + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/passes/mark_same_addr_pass.h b/src/ge/graph/passes/mark_same_addr_pass.h new file mode 100644 index 00000000..ebfcf6b2 --- /dev/null +++ b/src/ge/graph/passes/mark_same_addr_pass.h @@ -0,0 +1,32 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/graph.h" +#include "inc/graph_pass.h" + +#ifndef GE_GRAPH_PASSES_MARK_SAME_ADDR_PASS_H_ +#define GE_GRAPH_PASSES_MARK_SAME_ADDR_PASS_H_ + +namespace ge { +class MarkSameAddrPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph); + + private: + bool IsNextNodeExpected(const ge::NodePtr &cur_node, const vector &next_nodes, int &out_anchor_idx); +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_MARK_SAME_ADDR_PASS_H_ diff --git a/src/ge/graph/passes/memcpy_addr_async_pass.cc b/src/ge/graph/passes/memcpy_addr_async_pass.cc new file mode 100644 index 00000000..7cbacc23 --- /dev/null +++ b/src/ge/graph/passes/memcpy_addr_async_pass.cc @@ -0,0 +1,245 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/memcpy_addr_async_pass.h" + +#include "common/ge/ge_util.h" +#include "framework/common/debug/log.h" +#include "graph/utils/node_utils.h" + +namespace ge { +Status MemcpyAddrAsyncPass::Run(ComputeGraphPtr graph) { + GE_CHECK_NOTNULL(graph); + for (auto &node : graph->GetAllNodes()) { + auto op_desc = node->GetOpDesc(); + GE_IF_BOOL_EXEC(op_desc == nullptr, continue); + + if (op_desc->GetType() == STREAMSWITCHN || op_desc->GetType() == STREAMMERGE) { + Status ret = AddMemcpyAddrAsyncNode(graph, node); + if (ret != SUCCESS) { + GELOGE(ret, "AddMemcpyAddrAsyncNode failed."); + return ret; + } + } + } + return SUCCESS; +} + +Status MemcpyAddrAsyncPass::AddMemcpyAddrAsyncNode(const ComputeGraphPtr &graph, const NodePtr &node) { + GELOGI("Start AddMemcpyAddrAsyncNode for %s.", node->GetName().c_str()); + for (InDataAnchorPtr &in_data_anchor : node->GetAllInDataAnchors()) { + OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); + NodePtr in_node = peer_out_anchor->GetOwnerNode(); + + if (in_node->GetType() == DATA) { + ComputeGraphPtr owner_graph = in_node->GetOwnerComputeGraph(); + GE_CHECK_NOTNULL(owner_graph); + // Data is in parent_graph + if (owner_graph->GetParentGraph() == nullptr) { + GELOGI("Need to insert MemcpyAddrAsync directly when data in parent graph."); + NodePtr memcpy_addr_async_node = CreateMemcpyAddrAsyncNode(graph, peer_out_anchor, node); + GE_IF_BOOL_EXEC(memcpy_addr_async_node == nullptr, GELOGE(INTERNAL_ERROR, "CreateMemcpyAddrAsyncNode failed."); + return INTERNAL_ERROR); + + Status ret = InsertMemcpyAddrAsyncNode(peer_out_anchor, in_data_anchor, memcpy_addr_async_node); + GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGE(ret, "InsertMemcpyAddrAsyncNode failed."); return ret); + } else { + uint32_t parent_index = 0; + if (!AttrUtils::GetInt(in_node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, parent_index)) { + GELOGE(INTERNAL_ERROR, "Failed to get parent index of %s", in_node->GetName().c_str()); + return INTERNAL_ERROR; + } + // Data is in sub_graph + GELOGI("Need to find data in parent graph, then insert MemcpyAddrAsync."); + NodePtr parent_node = owner_graph->GetParentNode(); + user_data_for_known_ = in_node; + out_of_user_data_for_known_ = node; + peer_out_anchor_for_known_ = peer_out_anchor; + in_anchor_for_known_ = in_data_anchor; + FindUserData(parent_node, parent_index); + if (find_user_data_) { + GELOGI("Insert memcpy_addr_async for non_dynamic."); + GE_CHECK_NOTNULL(peer_out_anchor_); + NodePtr memcpy_addr_async_node = CreateMemcpyAddrAsyncNode(graph, peer_out_anchor_, out_of_user_data_); + GE_IF_BOOL_EXEC(memcpy_addr_async_node == nullptr, + GELOGE(INTERNAL_ERROR, "CreateMemcpyAddrAsyncNode failed."); + return INTERNAL_ERROR); + + Status ret = InsertMemcpyAddrAsyncNode(peer_out_anchor_, in_anchor_, memcpy_addr_async_node); + GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGE(ret, "InsertMemcpyAddrAsyncNode failed."); return ret); + } + if (find_user_data_for_known_) { + GELOGI("Insert memcpy_addr_async for known graph."); + auto sub_graph = user_data_for_known_->GetOwnerComputeGraph(); + NodePtr memcpy_addr_async_node = + CreateMemcpyAddrAsyncNode(sub_graph, peer_out_anchor_for_known_, out_of_user_data_for_known_); + GE_IF_BOOL_EXEC(memcpy_addr_async_node == nullptr, + GELOGE(INTERNAL_ERROR, "CreateMemcpyAddrAsyncNode for known failed."); + return INTERNAL_ERROR); + + Status ret = + InsertMemcpyAddrAsyncNode(peer_out_anchor_for_known_, in_anchor_for_known_, memcpy_addr_async_node); + GE_IF_BOOL_EXEC(ret != SUCCESS, GELOGE(ret, "InsertMemcpyAddrAsyncNode for known failed."); return ret); + } + } + } + } + return SUCCESS; +} + +void MemcpyAddrAsyncPass::FindUserDataForKnown(const NodePtr &parent_node, uint32_t &parent_index) { + GELOGI("Start FindUserDataForKnown of %s.", parent_node->GetName().c_str()); + if (user_data_for_known_->GetOpDesc() == nullptr) { + GELOGI("Cannot get op_desc of %s.", user_data_for_known_->GetName().c_str()); + return; + } + string src_var_name; + if (ge::AttrUtils::GetStr(user_data_for_known_->GetOpDesc(), REF_VAR_SRC_VAR_NAME, src_var_name)) { + GELOGI("The data in known graph is variable, no need to insert memcpy_addr_async."); + find_user_data_for_known_ = false; + return; + } else { + find_user_data_for_known_ = true; + } +} + +void MemcpyAddrAsyncPass::FindUserDataForNonDynamic(const ge::NodePtr &parent_node, uint32_t &parent_index) { + GELOGI("Start to FindUserDataForNonDynamic of %s.", parent_node->GetName().c_str()); + InDataAnchorPtr in_data_anchor = parent_node->GetInDataAnchor(parent_index); + OutDataAnchorPtr out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(out_anchor == nullptr, + GELOGE(INTERNAL_ERROR, "Cannot find out_anchor of %s.", parent_node->GetName().c_str()); + return ); + NodePtr in_node = out_anchor->GetOwnerNode(); + GELOGI("in_node of parent_node is %s.", in_node->GetName().c_str()); + if (in_node->GetType() == DATA) { + if (in_node->GetOwnerComputeGraph()->GetParentGraph() != nullptr) { + // DATA is in sub graph again, update user_data of known firstly + user_data_for_known_ = in_node; + out_of_user_data_for_known_ = parent_node; + peer_out_anchor_for_known_ = out_anchor; + in_anchor_for_known_ = in_data_anchor; + NodePtr pre_in_node = in_node->GetOwnerComputeGraph()->GetParentNode(); + if (!AttrUtils::GetInt(in_node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, parent_index)) { + GELOGE(INTERNAL_ERROR, "Failed to refresh parent index of %s", in_node->GetName().c_str()); + return; + } + FindUserData(pre_in_node, parent_index); + } else { + // DATA is in parent graph and not has input + user_data_ = in_node; + out_of_user_data_ = parent_node; + peer_out_anchor_ = out_anchor; + in_anchor_ = in_data_anchor; + find_user_data_ = true; + GELOGI("%s connect with %s, will insert memcpyaddr.", user_data_->GetName().c_str(), + out_of_user_data_->GetName().c_str()); + } + } else if (in_node->GetType() == IF || in_node->GetType() == WHILE || in_node->GetType() == CASE) { + if (!AttrUtils::GetInt(parent_node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, parent_index)) { + GELOGE(INTERNAL_ERROR, "Failed to refresh parent index of %s", in_node->GetName().c_str()); + return; + } + FindUserData(in_node, parent_index); + } else { + GELOGI("%s connect with %s, which is not user_data.", parent_node->GetName().c_str(), in_node->GetName().c_str()); + find_user_data_ = false; + } +} + +void MemcpyAddrAsyncPass::FindUserData(const NodePtr &parent_node, uint32_t &parent_index) { + auto parent_op_desc = parent_node->GetOpDesc(); + if (parent_op_desc == nullptr) { + GELOGI("Cannot get op_desc of %s.", parent_node->GetName().c_str()); + return; + } + bool is_unknown_shape = false; + if (parent_node->GetType() == PARTITIONEDCALL && + AttrUtils::GetBool(parent_op_desc, ATTR_NAME_IS_UNKNOWN_SHAPE, is_unknown_shape) && !is_unknown_shape) { + FindUserDataForKnown(parent_node, parent_index); + } else { + FindUserDataForNonDynamic(parent_node, parent_index); + } +} + +NodePtr MemcpyAddrAsyncPass::CreateMemcpyAddrAsyncNode(const ComputeGraphPtr &graph, + const OutDataAnchorPtr &out_data_anchor, + const NodePtr &out_of_user_data) { + GELOGI("Start CreateMemcpyAddrAsyncNode."); + OpDescPtr pre_op_desc = out_data_anchor->GetOwnerNode()->GetOpDesc(); + GE_CHK_BOOL_EXEC(pre_op_desc != nullptr, return nullptr, "Op_desc of pre node is invalid."); + std::string node_name = pre_op_desc->GetName() + "_" + MEMCPYADDRASYNC; + + OpDescPtr op_desc = MakeShared(node_name, MEMCPYADDRASYNC); + GE_CHECK_NOTNULL_EXEC(op_desc, return nullptr); + + if (op_desc->AddInputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add memcpy_addr_async input desc failed."); + return nullptr; + } + + if (op_desc->AddOutputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add memcpy_addr_async output desc failed."); + return nullptr; + } + + int64_t stream_id = out_of_user_data->GetOpDesc()->GetStreamId(); + op_desc->SetStreamId(stream_id); + GELOGI("SetStreamId: Node %s assign stream is %ld.", op_desc->GetName().c_str(), stream_id); + bool labeled_input = false; + (void)ge::AttrUtils::GetBool(out_of_user_data->GetOpDesc(), ATTR_NAME_NODE_CONNECT_INPUT, labeled_input); + if (labeled_input) { + if (!ge::AttrUtils::SetBool(out_of_user_data->GetOpDesc(), ATTR_NAME_NODE_CONNECT_INPUT, false)) { + GELOGE(FAILED, "Failed to unset attr %s for node %s.", ATTR_NAME_NODE_CONNECT_INPUT.c_str(), + out_of_user_data->GetName().c_str()); + return nullptr; + } + if (!ge::AttrUtils::SetBool(op_desc, ATTR_NAME_NODE_CONNECT_INPUT, true)) { + GELOGE(FAILED, "Failed to set attr %s for node %s.", ATTR_NAME_NODE_CONNECT_INPUT.c_str(), + op_desc->GetName().c_str()); + return nullptr; + } + } + + NodePtr memcpy_addr_async_node = graph->AddNodeAfter(op_desc, out_data_anchor->GetOwnerNode()); + GE_CHECK_NOTNULL_EXEC(memcpy_addr_async_node, return nullptr); + + return memcpy_addr_async_node; +} + +Status MemcpyAddrAsyncPass::InsertMemcpyAddrAsyncNode(const OutDataAnchorPtr &out_anchor, + const InDataAnchorPtr &in_anchor, const NodePtr &node) { + // insert memcpy_addr of each user_data and out_of_user_data + if (GraphUtils::RemoveEdge(out_anchor, in_anchor) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Remove edge of %s and %s failed.", out_anchor->GetOwnerNode()->GetName().c_str(), + in_anchor->GetOwnerNode()->GetName().c_str()); + return INTERNAL_ERROR; + } + if (GraphUtils::AddEdge(out_anchor, node->GetInDataAnchor(0)) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add edge of %s and %s failed.", out_anchor->GetOwnerNode()->GetName().c_str(), + node->GetName().c_str()); + return INTERNAL_ERROR; + } + if (GraphUtils::AddEdge(node->GetOutDataAnchor(0), in_anchor) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add edge of %s and %s failed.", node->GetName().c_str(), + in_anchor->GetOwnerNode()->GetName().c_str()); + return INTERNAL_ERROR; + } + return SUCCESS; +} + +} // namespace ge diff --git a/src/ge/graph/passes/memcpy_addr_async_pass.h b/src/ge/graph/passes/memcpy_addr_async_pass.h new file mode 100644 index 00000000..9d99e505 --- /dev/null +++ b/src/ge/graph/passes/memcpy_addr_async_pass.h @@ -0,0 +1,51 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_MEMCPY_ADDR_ASYNC_PASS_H_ +#define GE_GRAPH_PASSES_MEMCPY_ADDR_ASYNC_PASS_H_ + +#include "inc/graph_pass.h" + +namespace ge { + +class MemcpyAddrAsyncPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph); + + private: + Status AddMemcpyAddrAsyncNode(const ComputeGraphPtr &graph, const NodePtr &node); + void FindUserData(const NodePtr &node, uint32_t &parent_index); + void FindUserDataForKnown(const NodePtr &parent_node, uint32_t &parent_index); + void FindUserDataForNonDynamic(const ge::NodePtr &parent_node, uint32_t &parent_index); + + NodePtr CreateMemcpyAddrAsyncNode(const ComputeGraphPtr &graph, const OutDataAnchorPtr &out_data_anchor, + const NodePtr &out_of_user_data); + Status InsertMemcpyAddrAsyncNode(const OutDataAnchorPtr &out_anchor, const InDataAnchorPtr &in_anchor, + const NodePtr &node); + + NodePtr user_data_; + NodePtr out_of_user_data_; + OutDataAnchorPtr peer_out_anchor_; + InDataAnchorPtr in_anchor_; + bool find_user_data_ = false; + NodePtr user_data_for_known_; + NodePtr out_of_user_data_for_known_; + OutDataAnchorPtr peer_out_anchor_for_known_; + InDataAnchorPtr in_anchor_for_known_; + bool find_user_data_for_known_ = false; +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_MEMCPY_ADDR_ASYNC_PASS_H_ diff --git a/src/ge/graph/passes/merge_pass.cc b/src/ge/graph/passes/merge_pass.cc index f4114474..8e691518 100644 --- a/src/ge/graph/passes/merge_pass.cc +++ b/src/ge/graph/passes/merge_pass.cc @@ -66,7 +66,7 @@ Status MergePass::Run(NodePtr &node) { AddRePassNode(end_node); } for (const auto &delete_node : del_nodes) { - AddNodeDeleted(delete_node.get()); + AddNodeDeleted(delete_node); } return ret; } diff --git a/src/ge/graph/passes/merge_to_stream_merge_pass.cc b/src/ge/graph/passes/merge_to_stream_merge_pass.cc new file mode 100644 index 00000000..b785ddfa --- /dev/null +++ b/src/ge/graph/passes/merge_to_stream_merge_pass.cc @@ -0,0 +1,234 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/merge_to_stream_merge_pass.h" +#include "common/ge/ge_util.h" +#include "ge/ge_api_types.h" +#include "graph/common/omg_util.h" + +namespace ge { +Status MergeToStreamMergePass::Run(ComputeGraphPtr graph) { + GELOGD("MergeToStreamMergePass Enter"); + + bypass_nodes_.clear(); + for (const auto &node : graph->GetDirectNode()) { + if ((node->GetType() != MERGE) && (node->GetType() != REFMERGE)) { + continue; + } + + OpDescPtr merge_op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(merge_op_desc); + if (merge_op_desc->HasAttr(ATTR_INSERT_BY_MBATCH)) { + GE_CHK_STATUS_RET(AddMemcpyAsyncNodes(graph, node, true), "Merge add memcpy node failed."); + GE_CHK_STATUS_RET(SetStreamLabel(node, node->GetName()), "Set stream label failed"); + } else { + GE_CHK_STATUS_RET(ReplaceMergeNode(graph, node), "Add StreamMerge node failed."); + } + } + + for (const auto &node : bypass_nodes_) { + GE_CHK_BOOL_EXEC(GraphUtils::RemoveNodeWithoutRelink(graph, node) == GRAPH_SUCCESS, return FAILED, + "Remove merge node failed."); + } + + GELOGD("MergeToStreamMergePass Leave"); + return SUCCESS; +} + +/// +/// @brief Replace Merge Op +/// @param [in] graph +/// @param [in] merge_node +/// @return Status +/// +Status MergeToStreamMergePass::ReplaceMergeNode(const ComputeGraphPtr &graph, const NodePtr &merge_node) { + OpDescPtr merge_op_desc = merge_node->GetOpDesc(); + GE_CHECK_NOTNULL(merge_op_desc); + + const std::string &node_name = merge_node->GetName(); + GELOGI("Create StreamMerge Op, name=%s.", node_name.c_str()); + OpDescPtr op_desc = MakeShared(node_name, STREAMMERGE); + if (op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, StreamMerge:%s.", node_name.c_str()); + return FAILED; + } + + for (const InDataAnchorPtr &in_anchor : merge_node->GetAllInDataAnchors()) { + GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(merge_op_desc->GetInputDesc(in_anchor->GetIdx())) == GRAPH_SUCCESS, + return FAILED, "Create StreamMerge op: add input desc failed."); + } + + for (const OutDataAnchorPtr &out_anchor : merge_node->GetAllOutDataAnchors()) { + GE_CHK_BOOL_EXEC(op_desc->AddOutputDesc(merge_op_desc->GetOutputDesc(out_anchor->GetIdx())) == GRAPH_SUCCESS, + return FAILED, "Create StreamMerge op: add output desc failed."); + } + + NodePtr stream_merge = graph->AddNode(op_desc); + GE_CHK_BOOL_EXEC(stream_merge != nullptr, return FAILED, "Insert StreamMerge node failed."); + GE_CHK_STATUS_RET(MoveEdges(merge_node, stream_merge), "Move edges failed."); + bypass_nodes_.insert(merge_node); + + if (merge_op_desc->HasAttr(ATTR_NAME_NEXT_ITERATION)) { + std::string next_iteration_name; + GE_IF_BOOL_EXEC(!AttrUtils::GetStr(merge_op_desc, ATTR_NAME_NEXT_ITERATION, next_iteration_name), + GELOGE(INTERNAL_ERROR, "Get ATTR_NAME_NEXT_ITERATION failed"); + return INTERNAL_ERROR); + GE_CHK_STATUS_RET(SetNextIteration(stream_merge, next_iteration_name), "Set next iteration failed"); + } + + return AddMemcpyAsyncNodes(graph, stream_merge, false); +} + +/// +/// @brief Add MemcpyAsync Op as StreamMerge in_node +/// @param [in] graph +/// @param [in] node +/// @param [in] multi_batch_flag +/// @return Status +/// +Status MergeToStreamMergePass::AddMemcpyAsyncNodes(const ComputeGraphPtr &graph, const NodePtr &node, + bool multi_batch_flag) { + GE_CHK_BOOL_EXEC(node != nullptr, return FAILED, "Param of pre node is null."); + for (const InDataAnchorPtr &in_data_anchor : node->GetAllInDataAnchors()) { + OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); + NodePtr in_node = peer_out_anchor->GetOwnerNode(); + const std::string &type = in_node->GetType(); + // For WhileLoop no need memcpy & active for merge. + GE_IF_BOOL_EXEC((type == ENTER) || (type == REFENTER) || (type == NEXTITERATION) || (type == REFNEXTITERATION), + continue); + + const std::string &memcpy_name = node->GetName() + "_input_" + std::to_string(in_data_anchor->GetIdx()); + NodePtr memcpy_node = CreateMemcpyAsyncNode(graph, memcpy_name, peer_out_anchor, multi_batch_flag); + GE_CHK_BOOL_EXEC(memcpy_node != nullptr, return FAILED, "Create MemcpyAsync node failed."); + GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor), "MemcpyAsync node remove edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(peer_out_anchor, memcpy_node->GetInDataAnchor(0)), + "MemcpyAsync node add edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(memcpy_node->GetOutDataAnchor(0), in_data_anchor), + "MemcpyAsync node add edge failed."); + + NodePtr active_node = CreateActiveNode(graph, memcpy_node); + GE_CHK_BOOL_EXEC(active_node != nullptr, return FAILED, "Create StreamActive node failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(active_node->GetOutControlAnchor(), node->GetInControlAnchor()), + "StreamActive add ctrl edge failed."); + if (SetActiveLabelList(active_node, {node->GetName()}) != SUCCESS) { + GELOGE(FAILED, "SetActiveLabelList for node %s failed.", active_node->GetName().c_str()); + return FAILED; + } + } + + return SUCCESS; +} + +/// +/// @brief Add MemcpyAsync Node +/// @param [in] graph +/// @param [in] name +/// @param [in] out_data_anchor +/// @param [in] multi_batch_flag +/// @return ge::NodePtr +/// +NodePtr MergeToStreamMergePass::CreateMemcpyAsyncNode(const ComputeGraphPtr &graph, const std::string &name, + const OutDataAnchorPtr &out_data_anchor, bool multi_batch_flag) { + GE_CHK_BOOL_EXEC(out_data_anchor != nullptr, return nullptr, "Param of input node is null."); + OpDescPtr pre_op_desc = out_data_anchor->GetOwnerNode()->GetOpDesc(); + GE_CHK_BOOL_EXEC(pre_op_desc != nullptr, return nullptr, "OpDesc of pre node is invalid."); + + const std::string &memcpy_type = multi_batch_flag ? MEMCPYADDRASYNC : MEMCPYASYNC; + const std::string &node_name = name + "_" + memcpy_type; + GELOGI("Create MemcpyAsync op:%s.", node_name.c_str()); + OpDescPtr op_desc = MakeShared(node_name, memcpy_type); + if (op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, MemcpyAsync:%s.", node_name.c_str()); + return nullptr; + } + + GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) == GRAPH_SUCCESS, + return nullptr, "Create MemcpyAsync op: add input desc failed."); + GE_CHK_BOOL_EXEC(op_desc->AddOutputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) == GRAPH_SUCCESS, + return nullptr, "Create MemcpyAsync op: add output desc failed."); + + return graph->AddNode(op_desc); +} + +/// +/// @brief Create Active Op +/// @param [in] graph +/// @param [in] node +/// @return ge::NodePtr +/// +NodePtr MergeToStreamMergePass::CreateActiveNode(const ComputeGraphPtr &graph, const NodePtr &node) { + const std::string &node_name = node->GetName() + "_" + STREAMACTIVE; + GELOGI("Create StreamActive op:%s.", node_name.c_str()); + OpDescPtr op_desc = MakeShared(node_name, STREAMACTIVE); + if (op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, StreamActive:%s.", node_name.c_str()); + return nullptr; + } + + NodePtr active_node = graph->AddNode(op_desc); + GE_CHK_BOOL_EXEC(active_node != nullptr, return nullptr, "Create StreamActive node failed."); + GE_IF_BOOL_EXEC(GraphUtils::AddEdge(node->GetOutControlAnchor(), active_node->GetInControlAnchor()) != SUCCESS, + GELOGE(INTERNAL_ERROR, "add edge failed"); + return nullptr); + GE_IF_BOOL_EXEC(SetSwitchBranchNodeLabel(active_node, node_name) != SUCCESS, + GELOGE(INTERNAL_ERROR, "set switch branch node label failed"); + return nullptr); + + return active_node; +} + +/// +/// @brief move edges from old_node to new_node +/// @param [in] old_node +/// @param [in] new_node +/// @return Status +/// +Status MergeToStreamMergePass::MoveEdges(const NodePtr &old_node, const NodePtr &new_node) { + for (const InDataAnchorPtr &in_data_anchor : old_node->GetAllInDataAnchors()) { + OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); + + GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor), "Merge remove in data edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(peer_out_anchor, new_node->GetInDataAnchor(in_data_anchor->GetIdx())), + "StreamMerge add in data edge failed."); + } + + for (const OutDataAnchorPtr &out_data_anchor : old_node->GetAllOutDataAnchors()) { + for (const InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(out_data_anchor, peer_in_anchor), "Merge remove out data edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(new_node->GetOutDataAnchor(out_data_anchor->GetIdx()), peer_in_anchor), + "StreamMerge add out data edge failed."); + } + } + + for (const NodePtr &in_ctrl_node : old_node->GetInControlNodes()) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(in_ctrl_node->GetOutControlAnchor(), old_node->GetInControlAnchor()), + "Merge remove in ctrl edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(in_ctrl_node->GetOutControlAnchor(), new_node->GetInControlAnchor()), + "StreamMerge add in ctrl edge failed."); + } + + for (const NodePtr &out_ctrl_node : old_node->GetOutControlNodes()) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(old_node->GetOutControlAnchor(), out_ctrl_node->GetInControlAnchor()), + "Merge remove out ctrl edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(new_node->GetOutControlAnchor(), out_ctrl_node->GetInControlAnchor()), + "StreamMerge add out ctrl edge failed."); + } + + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/passes/merge_to_stream_merge_pass.h b/src/ge/graph/passes/merge_to_stream_merge_pass.h new file mode 100644 index 00000000..9f713989 --- /dev/null +++ b/src/ge/graph/passes/merge_to_stream_merge_pass.h @@ -0,0 +1,75 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_MERGE_TO_STREAM_MERGE_PASS_H_ +#define GE_GRAPH_PASSES_MERGE_TO_STREAM_MERGE_PASS_H_ + +#include "inc/graph_pass.h" + +namespace ge { +class MergeToStreamMergePass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph); + + private: + /// + /// @brief Replace Merge Op + /// @param [in] graph + /// @param [in] merge_node + /// @return Status + /// + Status ReplaceMergeNode(const ComputeGraphPtr &graph, const NodePtr &merge_node); + + /// + /// @brief Add MemcpyAsync Op as StreamMerge in_node + /// @param [in] graph + /// @param [in] node + /// @param [in] multi_batch_flag + /// @return Status + /// + Status AddMemcpyAsyncNodes(const ComputeGraphPtr &graph, const NodePtr &node, bool multi_batch_flag); + + /// + /// @brief Add MemcpyAsync Node + /// @param [in] graph + /// @param [in] name + /// @param [in] out_data_anchor + /// @param [in] multi_batch_flag + /// @return ge::NodePtr + /// + NodePtr CreateMemcpyAsyncNode(const ComputeGraphPtr &graph, const std::string &name, + const OutDataAnchorPtr &out_data_anchor, bool multi_batch_flag); + + /// + /// @brief Create Active Op + /// @param [in] graph + /// @param [in] node + /// @return ge::NodePtr + /// + NodePtr CreateActiveNode(const ComputeGraphPtr &graph, const NodePtr &node); + + /// + /// @brief move edges from old_node to new_node + /// @param [in] old_node + /// @param [in] new_node + /// @return Status + /// + Status MoveEdges(const NodePtr &old_node, const NodePtr &new_node); + + std::set bypass_nodes_; +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_MERGE_TO_STREAM_MERGE_PASS_H_ diff --git a/src/ge/graph/passes/multi_batch_pass.cc b/src/ge/graph/passes/multi_batch_pass.cc index bb0050be..7d484a25 100644 --- a/src/ge/graph/passes/multi_batch_pass.cc +++ b/src/ge/graph/passes/multi_batch_pass.cc @@ -29,10 +29,13 @@ #include "graph/debug/ge_attr_define.h" #include "graph/utils/type_utils.h" +using std::string; +using std::vector; + namespace ge { Status MultiBatchPass::Run(ComputeGraphPtr graph) { GELOGD("MultiBatchPass Enter"); - GE_CHECK_NOTNULL(graph); + if (graph->GetParentGraph() != nullptr) { GELOGI("Subgraph %s skip the MultiBatchPass.", graph->GetName().c_str()); return SUCCESS; @@ -44,26 +47,32 @@ Status MultiBatchPass::Run(ComputeGraphPtr graph) { return SUCCESS; } if (ret != SUCCESS) { - GELOGE(FAILED, "FindPredValue fail."); + GELOGE(FAILED, "FindPredValue failed."); + return FAILED; + } + + if (GetDynamicType() != SUCCESS) { + GELOGE(FAILED, "Get dynamic type failed."); return FAILED; } std::vector> batch_shape; - if (!CheckSwitchN(batch_shape)) { - GELOGE(FAILED, "CheckSwitchN fail."); + vector> combined_batch; + if (!CheckSwitchN(batch_shape, combined_batch)) { + GELOGE(FAILED, "CheckSwitchN failed."); return FAILED; } FindSwitchOutNodes(batch_shape.size()); - if (ReplaceSwitchN(graph, pred_value, batch_shape) != SUCCESS) { - GELOGE(FAILED, "Replace SwitchN nodes fail."); + if (ReplaceSwitchN(graph, pred_value, batch_shape, combined_batch) != SUCCESS) { + GELOGE(FAILED, "Replace SwitchN nodes failed."); return FAILED; } - for (NodePtr &node : bypass_nodes_) { - if (graph->RemoveNode(node) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Remove SwitchN nodes %s fail.", node->GetName().c_str()); + for (const NodePtr &node : bypass_nodes_) { + if (GraphUtils::RemoveNodeWithoutRelink(graph, node) != GRAPH_SUCCESS) { + GELOGE(FAILED, "Remove SwitchN nodes %s failed.", node->GetName().c_str()); return FAILED; } } @@ -79,19 +88,19 @@ Status MultiBatchPass::Run(ComputeGraphPtr graph) { /// @return Status /// Status MultiBatchPass::FindPredValue(const ComputeGraphPtr &graph, OutDataAnchorPtr &pred_value) { - for (NodePtr &node : graph->GetDirectNode()) { + for (const NodePtr &node : graph->GetDirectNode()) { if (node->GetType() != SWITCHN) { continue; } InDataAnchorPtr in_data_anchor = node->GetInDataAnchor(SWITCH_PRED_INPUT); if (in_data_anchor == nullptr) { - GELOGE(FAILED, "FindPredInput fail, in_data_anchor is null, node:%s.", node->GetName().c_str()); + GELOGE(FAILED, "FindPredInput failed, in_data_anchor is null, node:%s.", node->GetName().c_str()); return FAILED; } OutDataAnchorPtr pred_input = in_data_anchor->GetPeerOutAnchor(); if (pred_input == nullptr) { - GELOGE(FAILED, "FindPredInput fail, pred_input is null, node:%s.", node->GetName().c_str()); + GELOGE(FAILED, "FindPredInput failed, pred_input is null, node:%s.", node->GetName().c_str()); return FAILED; } @@ -110,7 +119,7 @@ Status MultiBatchPass::FindPredValue(const ComputeGraphPtr &graph, OutDataAnchor } if (pred_value == nullptr) { - GELOGE(FAILED, "FindPredInput fail, pred_value is null."); + GELOGE(FAILED, "FindPredInput failed, pred_value is null."); return FAILED; } @@ -119,14 +128,47 @@ Status MultiBatchPass::FindPredValue(const ComputeGraphPtr &graph, OutDataAnchor } /// +/// @brief Get dynamic type: dynamic batch size: 1, dynamic image size: 2, dynamic dims: 3 +/// @return Status +/// +Status MultiBatchPass::GetDynamicType() { + for (const auto &switchn : switch_n_nodes_) { + auto switchn_desc = switchn->GetOpDesc(); + GE_CHECK_NOTNULL(switchn_desc); + int32_t dynamic_type = static_cast(FIXED); + if (!AttrUtils::GetInt(switchn_desc, ATTR_DYNAMIC_TYPE, dynamic_type)) { + GELOGE(FAILED, "Get attr ATTR_DYNAMIC_TYPE of node: %s failed.", switchn->GetName().c_str()); + return FAILED; + } + if (dynamic_type == static_cast(FIXED)) { + GELOGE(FAILED, "Attr ATTR_DYNAMIC_TYPE shouldn't be 0."); + return FAILED; + } + if (dynamic_type_ != static_cast(FIXED) && dynamic_type_ != dynamic_type) { + GELOGE(FAILED, "Attr ATTR_DYNAMIC_TYPE of all switchn node should be same, while one is %d and another is %d.", + dynamic_type, dynamic_type_); + return FAILED; + } + dynamic_type_ = dynamic_type; + } + if (dynamic_type_ == static_cast(FIXED)) { + GELOGE(FAILED, "Attr ATTR_DYNAMIC_TYPE shouldn't be 0."); + return FAILED; + } + + return SUCCESS; +} + +/// /// @brief Check SwitchN nodes /// @param [out] batch_shape +/// @param [out] combined_batch /// @return bool /// -bool MultiBatchPass::CheckSwitchN(std::vector> &batch_shape) { +bool MultiBatchPass::CheckSwitchN(vector> &batch_shape, vector> &combined_batch) { // Check if output_num of different SwitchN is same uint32_t batch_num = 0; - for (NodePtr &node : switch_n_nodes_) { + for (const NodePtr &node : switch_n_nodes_) { uint32_t tmp_num = node->GetAllOutDataAnchorsSize(); if (batch_num == 0) { batch_num = tmp_num; @@ -136,45 +178,79 @@ bool MultiBatchPass::CheckSwitchN(std::vector> &batch_shape } } + if (!GetBatchInfo(batch_num, batch_shape, combined_batch)) { + GELOGE(FAILED, "Get batch info failed."); + return false; + } + + if (batch_shape.empty()) { + GELOGE(FAILED, "batch_shape is empty."); + return false; + } + if (combined_batch.empty()) { + GELOGE(FAILED, "combined_batch is empty."); + return false; + } + size_t dim_num = batch_shape[0].size(); + size_t combined_dim_num = combined_batch[0].size(); + for (uint32_t i = 1; i < batch_num; i++) { + size_t tmp_dim_num = batch_shape[i].size(); + if (dim_num != tmp_dim_num) { + GELOGE(FAILED, "Dim num of batch_shape not equal, batch_0:%zu, batch_%u:%zu.", dim_num, i, tmp_dim_num); + return false; + } + size_t tmp_combined_dim_num = combined_batch[i].size(); + if (combined_dim_num != tmp_combined_dim_num) { + GELOGE(FAILED, "Dim num of combined_batch not equal, batch_0:%zu, batch_%u:%zu.", dim_num, i, tmp_dim_num); + return false; + } + } + + return true; +} + +/// +/// @brief Check SwitchN nodes +/// @param [in] batch_num +/// @param [out] batch_shape +/// @param [out] combined_batch +/// @return bool +/// +bool MultiBatchPass::GetBatchInfo(uint32_t batch_num, vector> &batch_shape, + vector> &combined_batch) { // Check if output_shape of different SwitchN is same - std::vector> idx_batch_shape; + vector> idx_batch_shape; + vector> idx_combined_batch; for (uint32_t i = 0; i < batch_num; i++) { idx_batch_shape.clear(); - for (NodePtr &node : switch_n_nodes_) { - std::vector output_dims; + idx_combined_batch.clear(); + for (const NodePtr &node : switch_n_nodes_) { OpDescPtr op_desc = node->GetOpDesc(); if (op_desc == nullptr) { - GELOGE(FAILED, "CheckDims fail, get op_desc fail, node: %s.", node->GetName().c_str()); + GELOGE(FAILED, "CheckDims failed, get op_desc failed, node: %s.", node->GetName().c_str()); return false; } + vector output_dims; if (!AttrUtils::GetListInt(op_desc->GetOutputDesc(i), ATTR_NAME_SWITCHN_PRED_VALUE, output_dims)) { - GELOGE(FAILED, "CheckDims fail, get attr ATTR_NAME_SWITCHN_PRED_VALUE fail, batch_index=%u.", i); + GELOGE(FAILED, "CheckDims failed, get attr ATTR_NAME_SWITCHN_PRED_VALUE failed, batch_index=%u.", i); return false; } idx_batch_shape.emplace_back(output_dims); + output_dims.clear(); + if (!AttrUtils::GetListInt(op_desc->GetOutputDesc(i), ATTR_NAME_COMBINED_DYNAMIC_DIMS, output_dims)) { + GELOGE(FAILED, "CheckDims failed, get attr ATTR_NAME_COMBINED_DYNAMIC_DIMS failed, batch_index=%u.", i); + return false; + } + idx_combined_batch.emplace_back(output_dims); } if (!CheckDims(idx_batch_shape)) { - GELOGE(FAILED, "CheckDims fail, batch_index=%u.", i); + GELOGE(FAILED, "CheckDims failed, batch_index=%u.", i); return false; } batch_shape.emplace_back(idx_batch_shape[0]); + combined_batch.emplace_back(idx_combined_batch[0]); } - - // Check if dim_num of different batch is same - if (batch_shape.empty()) { - GELOGE(FAILED, "batch_shape is empty."); - return false; - } - uint32_t dim_num = batch_shape[0].size(); - for (uint32_t i = 1; i < batch_num; i++) { - uint32_t tmp_dim_num = batch_shape[i].size(); - if (dim_num != tmp_dim_num) { - GELOGE(FAILED, "dim_num not equal, batch_0:%u, batch_%u:%u.", dim_num, i, tmp_dim_num); - return false; - } - } - return true; } @@ -187,11 +263,11 @@ void MultiBatchPass::FindSwitchOutNodes(uint32_t batch_num) { std::vector output_nodes; for (uint32_t i = 0; i < batch_num; i++) { output_nodes.clear(); - for (NodePtr &node : switch_n_nodes_) { + for (const NodePtr &node : switch_n_nodes_) { // idx is promised to be valid OutDataAnchorPtr out_data_anchor = node->GetOutDataAnchor(i); GE_CHECK_NOTNULL_JUST_RETURN(out_data_anchor); - for (InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { + for (const InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { output_nodes.emplace_back(peer_in_anchor->GetOwnerNode()); } } @@ -206,35 +282,37 @@ void MultiBatchPass::FindSwitchOutNodes(uint32_t batch_num) { /// @param [in] graph /// @param [in] pred_value /// @param [in] batch_shape +/// @param [in] combined_batch /// @return Status /// -Status MultiBatchPass::ReplaceSwitchN(ComputeGraphPtr &graph, OutDataAnchorPtr &pred_value, - const std::vector> &batch_shape) { +Status MultiBatchPass::ReplaceSwitchN(const ComputeGraphPtr &graph, const OutDataAnchorPtr &pred_value, + const vector> &batch_shape, + const vector> &combined_batch) { NodePtr pred_value_node = pred_value->GetOwnerNode(); // Create SwitchCase node - const std::string switch_case_name = pred_value_node->GetName() + "_" + STREAMSWITCHN; - NodePtr switch_case = CreateSwitchCaseNode(graph, switch_case_name, pred_value, batch_shape); + const std::string &switch_case_name = pred_value_node->GetName() + "_" + STREAMSWITCHN; + NodePtr switch_case = CreateSwitchCaseNode(graph, switch_case_name, pred_value, batch_shape, combined_batch); if (switch_case == nullptr) { - GELOGE(FAILED, "CreateSwitchCaseNode %s fail.", switch_case_name.c_str()); + GELOGE(FAILED, "CreateSwitchCaseNode %s failed.", switch_case_name.c_str()); return FAILED; } - for (NodePtr &switch_n_node : switch_n_nodes_) { + for (const NodePtr &switch_n_node : switch_n_nodes_) { if (BypassSwitchN(switch_n_node, switch_case) != SUCCESS) { - GELOGE(FAILED, "Bypass SwitchN %s fail.", switch_case_name.c_str()); + GELOGE(FAILED, "Bypass SwitchN %s failed.", switch_case_name.c_str()); return FAILED; } } // Add switchCase input edge if (GraphUtils::AddEdge(pred_value, switch_case->GetInDataAnchor(0)) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Add SwitchCase in_data_edge fail, %s->%s.", pred_value_node->GetName().c_str(), + GELOGE(FAILED, "Add SwitchCase in_data_edge failed, %s->%s.", pred_value_node->GetName().c_str(), switch_case->GetName().c_str()); return FAILED; } if (AttachLabel(switch_case) != SUCCESS) { - GELOGE(FAILED, "AttachLabel fail."); + GELOGE(FAILED, "AttachLabel failed."); return FAILED; } @@ -248,7 +326,7 @@ Status MultiBatchPass::ReplaceSwitchN(ComputeGraphPtr &graph, OutDataAnchorPtr & /// bool MultiBatchPass::CheckDims(const std::vector> &output_shape) const { if (output_shape.empty()) { - GELOGE(FAILED, "CheckDims fail: output_shape is empty."); + GELOGE(FAILED, "CheckDims failed: output_shape is empty."); return false; } @@ -257,7 +335,7 @@ bool MultiBatchPass::CheckDims(const std::vector> &output_s for (size_t i = 1; i < num; i++) { size_t tmp_dim_num = output_shape[i].size(); if (dim_num != tmp_dim_num) { - GELOGE(FAILED, "CheckDims fail: dim_num not equal, output_0:%zu, output_%zu:%zu.", dim_num, i, tmp_dim_num); + GELOGE(FAILED, "CheckDims failed: dim_num not equal, output_0:%zu, output_%zu:%zu.", dim_num, i, tmp_dim_num); return false; } } @@ -271,7 +349,7 @@ bool MultiBatchPass::CheckDims(const std::vector> &output_s for (size_t j = 1; j < num; j++) { int64_t tmp_dim_value = output_shape[j][i]; if (dim_value != tmp_dim_value) { - GELOGE(FAILED, "CheckDims fail: dim_value not equal, dim_index=%zu, dim_value_0:%ld, dim_value_%zu:%ld.", i, + GELOGE(FAILED, "CheckDims failed: dim_value not equal, dim_index=%zu, dim_value_0:%ld, dim_value_%zu:%ld.", i, dim_value, j, tmp_dim_value); return false; } @@ -287,43 +365,54 @@ bool MultiBatchPass::CheckDims(const std::vector> &output_s /// @param [in] name /// @param [in] pred_value /// @param [in] batch_shape +/// @param [in] combined_batch /// @return ge::NodePtr /// -NodePtr MultiBatchPass::CreateSwitchCaseNode(ComputeGraphPtr &graph, const std::string &name, +NodePtr MultiBatchPass::CreateSwitchCaseNode(const ComputeGraphPtr &graph, const std::string &name, const OutDataAnchorPtr &pred_value, - const std::vector> &batch_shape) { + const vector> &batch_shape, + const vector> &combined_batch) { OpDescPtr op_desc = MakeShared(name, STREAMSWITCHN); if (op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "Create op_desc failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } GELOGI("Create StreamSwitchN op:%s.", name.c_str()); OpDescPtr pred_desc = pred_value->GetOwnerNode()->GetOpDesc(); if (pred_desc == nullptr) { - GELOGE(FAILED, "Get pred_desc fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "Get pred_desc failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } if (op_desc->AddInputDesc(pred_desc->GetOutputDesc(pred_value->GetIdx())) != GRAPH_SUCCESS) { - GELOGE(FAILED, "AddInputDesc fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "AddInputDesc failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } NodePtr switch_case_node = graph->AddNode(op_desc); if (switch_case_node == nullptr) { - GELOGE(FAILED, "Create node fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "Create node failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } uint32_t batch_num = static_cast(batch_shape.size()); if (!AttrUtils::SetInt(op_desc, ATTR_NAME_BATCH_NUM, batch_num)) { - GELOGE(FAILED, "set attr ATTR_NAME_BATCH_NUM fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "set attr ATTR_NAME_BATCH_NUM failed, StreamSwitchN:%s.", name.c_str()); + return nullptr; + } + if (!AttrUtils::SetInt(op_desc, ATTR_DYNAMIC_TYPE, dynamic_type_)) { + GELOGE(FAILED, "Set attr ATTR_DYNAMIC_TYPE failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } for (uint32_t i = 0; i < batch_num; i++) { - const std::string attr_name = ATTR_NAME_PRED_VALUE + "_" + std::to_string(i); + const std::string &attr_name = ATTR_NAME_PRED_VALUE + "_" + std::to_string(i); if (!AttrUtils::SetListInt(op_desc, attr_name, batch_shape[i])) { - GELOGE(FAILED, "set attr ATTR_NAME_PRED_VALUE fail, StreamSwitchN:%s.", name.c_str()); + GELOGE(FAILED, "set attr ATTR_NAME_PRED_VALUE failed, StreamSwitchN:%s.", name.c_str()); + return nullptr; + } + const string &attr_combined_batch = ATTR_NAME_COMBINED_BATCH + "_" + std::to_string(i); + if (!AttrUtils::SetListInt(op_desc, attr_combined_batch, combined_batch[i])) { + GELOGE(FAILED, "set attr ATTR_NAME_COMBINED_BATCH failed, StreamSwitchN:%s.", name.c_str()); return nullptr; } } @@ -337,43 +426,43 @@ NodePtr MultiBatchPass::CreateSwitchCaseNode(ComputeGraphPtr &graph, const std:: /// @param [in] switch_case /// @return Status /// -Status MultiBatchPass::BypassSwitchN(NodePtr &switch_n_node, NodePtr &switch_case) { +Status MultiBatchPass::BypassSwitchN(const NodePtr &switch_n_node, const NodePtr &switch_case) { InDataAnchorPtr in_data_anchor = switch_n_node->GetInDataAnchor(SWITCH_DATA_INPUT); if (in_data_anchor == nullptr) { - GELOGE(FAILED, "Check in_data_anchor fail, SwitchN:%s.", switch_n_node->GetName().c_str()); + GELOGE(FAILED, "Check in_data_anchor failed, SwitchN:%s.", switch_n_node->GetName().c_str()); return FAILED; } OutDataAnchorPtr peer_data_anchor = in_data_anchor->GetPeerOutAnchor(); if (peer_data_anchor == nullptr) { - GELOGE(FAILED, "Check peer_data_anchor fail, SwitchN:%s.", switch_n_node->GetName().c_str()); + GELOGE(FAILED, "Check peer_data_anchor failed, SwitchN:%s.", switch_n_node->GetName().c_str()); return FAILED; } NodePtr data_input = peer_data_anchor->GetOwnerNode(); // Remove SwitchN data input if (GraphUtils::RemoveEdge(peer_data_anchor, in_data_anchor) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Remove SwitchN in_data_edge fail, %s->%s.", data_input->GetName().c_str(), + GELOGE(FAILED, "Remove SwitchN in_data_edge failed, %s->%s.", data_input->GetName().c_str(), switch_n_node->GetName().c_str()); return FAILED; } if (GraphUtils::AddEdge(data_input->GetOutControlAnchor(), switch_case->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Add StreamSwitchN in_control_edge fail, %s->%s.", data_input->GetName().c_str(), + GELOGE(FAILED, "Add StreamSwitchN in_control_edge failed, %s->%s.", data_input->GetName().c_str(), switch_case->GetName().c_str()); return FAILED; } // Add SwitchCase control output - for (OutDataAnchorPtr &out_data_anchor : switch_n_node->GetAllOutDataAnchors()) { - for (InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { + for (const OutDataAnchorPtr &out_data_anchor : switch_n_node->GetAllOutDataAnchors()) { + for (const InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { NodePtr data_output = peer_in_anchor->GetOwnerNode(); if ((GraphUtils::RemoveEdge(out_data_anchor, peer_in_anchor) != GRAPH_SUCCESS) || (GraphUtils::AddEdge(peer_data_anchor, peer_in_anchor) != GRAPH_SUCCESS)) { - GELOGE(FAILED, "Bypass SwitchN data_edge fail, %s->%s->%s.", data_input->GetName().c_str(), + GELOGE(FAILED, "Bypass SwitchN data_edge failed, %s->%s->%s.", data_input->GetName().c_str(), switch_n_node->GetName().c_str(), data_output->GetName().c_str()); return FAILED; } if (GraphUtils::AddEdge(switch_case->GetOutControlAnchor(), data_output->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Add SwitchCase out_control_edge fail, %s->%s.", switch_case->GetName().c_str(), + GELOGE(FAILED, "Add SwitchCase out_control_edge failed, %s->%s.", switch_case->GetName().c_str(), data_output->GetName().c_str()); return FAILED; } @@ -390,17 +479,17 @@ Status MultiBatchPass::BypassSwitchN(NodePtr &switch_n_node, NodePtr &switch_cas /// @param [in] switch_case_node /// @return Status /// -Status MultiBatchPass::AttachLabel(NodePtr &switch_case_node) { +Status MultiBatchPass::AttachLabel(const NodePtr &switch_case_node) { std::vector stream_label_list; for (uint32_t i = 0; i < static_cast(batch_head_nodes_.size()); i++) { if (AttachBatchLabel(i) != SUCCESS) { - GELOGE(FAILED, "AttachBatchLabel fail, batch_idx=%u", i); + GELOGE(FAILED, "AttachBatchLabel failed, batch_idx=%u", i); return FAILED; } - const std::string stream_label = "stream_label_batch_" + std::to_string(i); + const std::string &stream_label = "stream_label_batch_" + std::to_string(i); if (AttachStreamLabel(i, stream_label) != SUCCESS) { - GELOGE(FAILED, "AttachStreamLabel fail, stream_label=%s", stream_label.c_str()); + GELOGE(FAILED, "AttachStreamLabel failed, stream_label=%s", stream_label.c_str()); return FAILED; } stream_label_list.emplace_back(stream_label); @@ -416,11 +505,11 @@ Status MultiBatchPass::AttachLabel(NodePtr &switch_case_node) { /// Status MultiBatchPass::AttachBatchLabel(uint32_t batch_idx) { std::stack nodes; - for (auto &node : batch_head_nodes_[batch_idx]) { + for (const auto &node : batch_head_nodes_[batch_idx]) { nodes.push(node); } - const std::string batch_label = "Batch_" + std::to_string(batch_idx); + const std::string &batch_label = "Batch_" + std::to_string(batch_idx); std::unordered_set handled_nodes; while (!nodes.empty()) { NodePtr cur_node = nodes.top(); @@ -434,7 +523,7 @@ Status MultiBatchPass::AttachBatchLabel(uint32_t batch_idx) { if (cur_desc->HasAttr(ATTR_NAME_BATCH_LABEL)) { std::string tmp_label; if (!AttrUtils::GetStr(cur_desc, ATTR_NAME_BATCH_LABEL, tmp_label)) { - GELOGE(FAILED, "get attr ATTR_NAME_BATCH_LABEL fail, node: %s.", cur_desc->GetName().c_str()); + GELOGE(FAILED, "get attr ATTR_NAME_BATCH_LABEL failed, node: %s.", cur_desc->GetName().c_str()); return FAILED; } if (tmp_label != batch_label) { @@ -445,14 +534,14 @@ Status MultiBatchPass::AttachBatchLabel(uint32_t batch_idx) { } GELOGD("Attach batch_label %s to node %s.", batch_label.c_str(), cur_desc->GetName().c_str()); if (!AttrUtils::SetStr(cur_desc, ATTR_NAME_BATCH_LABEL, batch_label)) { - GELOGE(FAILED, "set attr ATTR_NAME_BATCH_LABEL fail, node:%s.", cur_desc->GetName().c_str()); + GELOGE(FAILED, "set attr ATTR_NAME_BATCH_LABEL failed, node:%s.", cur_desc->GetName().c_str()); return FAILED; } - for (auto &out_node : cur_node->GetOutAllNodes()) { + for (const auto &out_node : cur_node->GetOutAllNodes()) { OpDescPtr op_desc = out_node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); - const std::string type = op_desc->GetType(); + const std::string &type = op_desc->GetType(); if ((type == MERGE) && (op_desc->HasAttr(ATTR_INSERT_BY_MBATCH))) { continue; } @@ -476,7 +565,7 @@ Status MultiBatchPass::AttachBatchLabel(uint32_t batch_idx) { /// Status MultiBatchPass::AttachStreamLabel(uint32_t batch_idx, const std::string &stream_label) { std::stack nodes; - for (auto &node : batch_head_nodes_[batch_idx]) { + for (const auto &node : batch_head_nodes_[batch_idx]) { nodes.push(node); } @@ -493,11 +582,11 @@ Status MultiBatchPass::AttachStreamLabel(uint32_t batch_idx, const std::string & GELOGD("Attach stream_label %s to node %s.", stream_label.c_str(), cur_desc->GetName().c_str()); if (SetStreamLabel(cur_node, stream_label) != SUCCESS) { - GELOGE(FAILED, "SetStreamLabel fail, node:%s.", cur_node->GetName().c_str()); + GELOGE(FAILED, "Set stream_label failed, node:%s.", cur_node->GetName().c_str()); return FAILED; } - for (auto &out_node : cur_node->GetOutAllNodes()) { + for (const auto &out_node : cur_node->GetOutAllNodes()) { nodes.push(out_node); } diff --git a/src/ge/graph/passes/multi_batch_pass.h b/src/ge/graph/passes/multi_batch_pass.h index 6e3f5e46..8f14ec0a 100644 --- a/src/ge/graph/passes/multi_batch_pass.h +++ b/src/ge/graph/passes/multi_batch_pass.h @@ -29,22 +29,28 @@ class MultiBatchPass : public GraphPass { private: Status FindPredValue(const ComputeGraphPtr &graph, OutDataAnchorPtr &pred_value); - bool CheckSwitchN(std::vector> &batch_shape); + Status GetDynamicType(); + bool CheckSwitchN(std::vector> &batch_shape, std::vector> &combined_batch); + bool GetBatchInfo(uint32_t batch_num, std::vector> &batch_shape, + std::vector> &combined_batch); void FindSwitchOutNodes(uint32_t batch_num); - Status ReplaceSwitchN(ComputeGraphPtr &graph, OutDataAnchorPtr &pred_value, - const std::vector> &batch_shape); + Status ReplaceSwitchN(const ComputeGraphPtr &graph, const OutDataAnchorPtr &pred_value, + const std::vector> &batch_shape, + const std::vector> &combined_batch); bool CheckDims(const std::vector> &output_shape) const; - NodePtr CreateSwitchCaseNode(ComputeGraphPtr &graph, const std::string &name, const OutDataAnchorPtr &pred_value, - const std::vector> &batch_shape); - Status BypassSwitchN(NodePtr &switch_n_node, NodePtr &switch_case_node); - Status AttachLabel(NodePtr &switch_case_node); + NodePtr CreateSwitchCaseNode(const ComputeGraphPtr &graph, const std::string &name, + const OutDataAnchorPtr &pred_value, const std::vector> &batch_shape, + const std::vector> &combined_batch); + Status BypassSwitchN(const NodePtr &switch_n_node, const NodePtr &switch_case_node); + Status AttachLabel(const NodePtr &switch_case_node); Status AttachBatchLabel(uint32_t batch_idx); Status AttachStreamLabel(uint32_t batch_idx, const std::string &stream_label); std::vector switch_n_nodes_; std::vector bypass_nodes_; std::vector> batch_head_nodes_; + int32_t dynamic_type_ = 0; }; } // namespace ge #endif // GE_GRAPH_PASSES_MULTI_BATCH_PASS_H_ diff --git a/src/ge/graph/passes/net_output_pass.cc b/src/ge/graph/passes/net_output_pass.cc index 3c83d8ac..dd17f99c 100644 --- a/src/ge/graph/passes/net_output_pass.cc +++ b/src/ge/graph/passes/net_output_pass.cc @@ -22,15 +22,21 @@ #include #include +#include "common/ge/ge_util.h" #include "framework/common/debug/ge_log.h" #include "framework/common/ge_inner_error_codes.h" -#include "common/ge/ge_util.h" +#include "framework/omg/omg_inner_types.h" +#include "graph/debug/ge_attr_define.h" #include "graph/passes/pass_utils.h" #include "graph/utils/tensor_utils.h" #include "graph/utils/type_utils.h" -#include "graph/debug/ge_attr_define.h" namespace ge { +static std::map output_type_str_to_datatype = { + {"FP32", ge::DT_FLOAT}, {"FP16", ge::DT_FLOAT16}, {"INT8", ge::DT_INT8}, {"INT16", ge::DT_INT16}, + {"UINT16", ge::DT_UINT16}, {"UINT8", ge::DT_UINT8}, {"INT32", ge::DT_INT32}, {"INT64", ge::DT_INT64}, + {"UINT32", ge::DT_UINT32}, {"UINT64", ge::DT_UINT64}, {"DOUBLE", ge::DT_DOUBLE}}; + Status NetOutputPass::GetRetvalOutputInfo(const ge::NodePtr &node, std::map &retval_node_index_map) { GE_CHECK_NOTNULL(node); @@ -135,18 +141,6 @@ Status NetOutputPass::CheckOutputNodeInfo(const ComputeGraphPtr &graph, const st return SUCCESS; } -void NetOutputPass::AddInOutForNetOutputOp(const ge::ComputeGraphPtr &graph, const ge::OpDescPtr &net_output_desc, - const ge::NodePtr &src_node, int32_t src_index) { - /// Get the output attribute of src_node, - /// and set to the input/output of net_out_node. - if (src_node == nullptr || src_node->GetOpDesc() == nullptr || net_output_desc == nullptr) { - GELOGE(INTERNAL_ERROR, "src node or net output desc is null."); - return; - } - ge::GeTensorDesc out_desc = src_node->GetOpDesc()->GetOutputDesc(src_index); - GE_IF_BOOL_EXEC(net_output_desc->AddInputDesc(out_desc) != SUCCESS, GELOGW("add input desc failed"); return ); -} - Status NetOutputPass::RemoveUnusedNode(const ge::ComputeGraphPtr &graph) { std::vector node_to_delete; // Delete _Retval operator. @@ -401,6 +395,7 @@ Status NetOutputPass::ProcessWithNetoutput(const ge::ComputeGraphPtr &graph, con GELOGE(INTERNAL_ERROR, "Update net output desc failed."); return INTERNAL_ERROR; } + if (UnLink(graph, output_node) != SUCCESS) { GELOGE(INTERNAL_ERROR, "UnLink connection between netoutput node and user set target node"); return INTERNAL_ERROR; @@ -415,6 +410,10 @@ Status NetOutputPass::ProcessWithNetoutput(const ge::ComputeGraphPtr &graph, con Status NetOutputPass::AddCtrlEdgesBetweenLeafAndNetOutput(const ge::ComputeGraphPtr &graph, const ge::NodePtr &net_out_node) { GE_CHECK_NOTNULL(net_out_node); + if (!domi::GetContext().user_out_nodes.empty()) { + GELOGI("No need to add ctrl edge to netoutput because user out nodes have been set."); + return SUCCESS; + } for (const auto &node : graph->GetDirectNode()) { if (node == nullptr || node->GetOpDesc() == nullptr || node->GetOpDesc()->GetType() == NETOUTPUT) { continue; @@ -430,7 +429,7 @@ Status NetOutputPass::AddCtrlEdgesBetweenLeafAndNetOutput(const ge::ComputeGraph return SUCCESS; } -Status NetOutputPass::CreateNetOutputNode(OpDescPtr &net_output_desc, ge::ComputeGraphPtr &graph) { +Status NetOutputPass::CreateNetOutputNode(OpDescPtr &net_output_desc, const ge::ComputeGraphPtr &graph) { // Only flush subgraph name string node_name = (graph->GetParentGraph() != nullptr) ? (graph->GetName() + "_" + NODE_NAME_NET_OUTPUT) : NODE_NAME_NET_OUTPUT; @@ -451,83 +450,185 @@ Status NetOutputPass::Run(ge::ComputeGraphPtr graph) { } GELOGI("NetOutputPass Run."); NodePtr output_node = graph->FindFirstNodeMatchType(NETOUTPUT); - OpDescPtr net_output_desc = nullptr; - std::vector output_nodes_info; - // save user targets node SaveAndRemoveTargets(graph); // If graph already has a netoutput node, doesn't need to create it again. if (output_node != nullptr) { (void)AttrUtils::SetListStr(output_node->GetOpDesc(), ATTR_NAME_DATA_DUMP_ORIGIN_OP_NAMES, std::move(std::vector())); - return ProcessWithNetoutput(graph, output_node); - } else { - if (CreateNetOutputNode(net_output_desc, graph) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Get net output nodes failed."); + if (ProcessWithNetoutput(graph, output_node) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Process with netoutput node failed."); return INTERNAL_ERROR; } - Status ret = GetOutputNode(graph, output_nodes_info); - if (ret != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Get net output nodes failed."); + } else { + if (AddNetOutputNodeToGraph(graph, output_node) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Set user define dtype and format for netoutput failed."); return INTERNAL_ERROR; } - GELOGI("[NETOUTPUT PASS] OutNodesInfo size:%zu, Targets Size:%zu, is_include_special_node_:%d", - graph->GetGraphOutNodesInfo().size(), graph->GetGraphTargetNodesInfo().size(), is_include_special_node_); - // If user does not set out nodes and targets and no retval node, return false - bool is_valid = (graph->GetGraphOutNodesInfo().size() == 0) && (graph->GetGraphTargetNodesInfo().size() == 0) && - (is_include_special_node_ == false); - if (is_valid) { - GELOGI("[NETOUTPUT PASS] output_nodes and target_nodes and special nodes is empty!It means no need netoutput!"); - return SUCCESS; - } - GELOGI("[NETOUTPUT PASS] Output node size:%lu.", output_nodes_info.size()); - if (output_nodes_info.empty()) { - // because retval node is contained by output_nodes_info, here means targets is non-empty - auto net_output_node = graph->AddNode(net_output_desc); - if (net_output_node == nullptr) { - GELOGE(INTERNAL_ERROR, "Add output node failed."); - return INTERNAL_ERROR; - } - GE_CHK_STATUS_RET(AddCtrlEdgeForTargets(net_output_node), "add ctrl edge for targets failed"); - // Add true stream, netoutput is 0 - GE_IF_BOOL_EXEC(!ge::AttrUtils::SetInt(net_output_node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, 0), - GELOGE(INTERNAL_ERROR, "set ATTR_NAME_TRUE_BRANCH_STREAM failed"); - return INTERNAL_ERROR); - return SUCCESS; - } - std::vector is_input_const; - for (auto iter = output_nodes_info.begin(); iter != output_nodes_info.end();) { - ge::NodePtr src_node = iter->output_node; - if (src_node == nullptr) { - continue; - } - int32_t src_index = iter->node_output_index; - // if src_node is in targets_, no need to Add in and out for netoutput - auto it = targets_.find(src_node); - if (it != targets_.end()) { - iter = output_nodes_info.erase(iter); - GELOGD("node [%s] is in processed targets, do not add inout for netoutput!", src_node->GetName().c_str()); - continue; - } - AddInOutForNetOutputOp(graph, net_output_desc, src_node, src_index); - is_input_const.push_back(PassUtils::IsConstant(src_node)); - ++iter; - } - net_output_desc->SetIsInputConst(is_input_const); + } + // Add userdef attrs to netoutput node + return SetUserDefDTypeAndFormatFromAtcParams(output_node); +} + +Status NetOutputPass::AddNetOutputNodeToGraph(const ge::ComputeGraphPtr &graph, NodePtr &output_node) { + OpDescPtr net_output_desc = nullptr; + if (CreateNetOutputNode(net_output_desc, graph) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Get net output nodes failed."); + return INTERNAL_ERROR; + } + std::vector output_nodes_info; + if (GetOutputNode(graph, output_nodes_info) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Get net output nodes failed."); + return INTERNAL_ERROR; + } + GELOGI("[NETOUTPUT PASS] OutNodesInfo size:%zu, Targets Size:%zu, is_include_special_node_:%d", + graph->GetGraphOutNodesInfo().size(), graph->GetGraphTargetNodesInfo().size(), is_include_special_node_); + // If user does not set out nodes and targets and no retval node, return false + if ((graph->GetGraphOutNodesInfo().empty()) && (graph->GetGraphTargetNodesInfo().empty()) && + !is_include_special_node_) { + GELOGI("[NETOUTPUT PASS] output_nodes and target_nodes and special nodes is empty!It means no need netoutput!"); + return SUCCESS; + } + GELOGI("[NETOUTPUT PASS] Output node size:%lu.", output_nodes_info.size()); + if (output_nodes_info.empty()) { + // because retval node is contained by output_nodes_info, here means targets is non-empty output_node = graph->AddNode(net_output_desc); if (output_node == nullptr) { GELOGE(INTERNAL_ERROR, "Add output node failed."); return INTERNAL_ERROR; } - if (AddEdgesForNetOutput(graph, output_node, output_nodes_info) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Add edges for net output node failed."); - return INTERNAL_ERROR; + GE_CHK_STATUS_RET(AddCtrlEdgeForTargets(output_node), "add ctrl edge for targets failed"); + // Add true stream, netoutput is 0 + GE_IF_BOOL_EXEC(!ge::AttrUtils::SetInt(output_node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, 0), + GELOGE(INTERNAL_ERROR, "set ATTR_NAME_TRUE_BRANCH_STREAM failed"); + return INTERNAL_ERROR); + return SUCCESS; + } + + AddInOutForNetOutputOp(graph, net_output_desc, output_nodes_info); + output_node = graph->AddNode(net_output_desc); + if (output_node == nullptr) { + GELOGE(INTERNAL_ERROR, "Add output node failed."); + return INTERNAL_ERROR; + } + if (AddEdgesForNetOutput(graph, output_node, output_nodes_info) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add edges for net output node failed."); + return INTERNAL_ERROR; + } + if (AddCtrlEdgesBetweenLeafAndNetOutput(graph, output_node) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Add control edges between leaf and netoutput failed."); + return INTERNAL_ERROR; + } + GELOGI("Add NetOutput node success."); + return SUCCESS; +} +void NetOutputPass::AddInOutForNetOutputOp(const ComputeGraphPtr &graph, OpDescPtr &net_output_desc, + vector &output_nodes_info) { + std::vector is_input_const; + for (auto iter = output_nodes_info.begin(); iter != output_nodes_info.end();) { + NodePtr src_node = iter->output_node; + if (src_node == nullptr) { + continue; } - if (AddCtrlEdgesBetweenLeafAndNetOutput(graph, output_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Add control edges between leaf and netoutput failed."); - return INTERNAL_ERROR; + int32_t src_index = iter->node_output_index; + // if src_node is in targets_, no need to Add in and out for netoutput + auto it = targets_.find(src_node); + if (it != targets_.end()) { + iter = output_nodes_info.erase(iter); + GELOGD("node [%s] is in processed targets, do not add inout for netoutput!", src_node->GetName().c_str()); + continue; + } + /// Get the output attribute of src_node, + /// and set to the input/output of net_out_node. + if (src_node == nullptr || src_node->GetOpDesc() == nullptr || net_output_desc == nullptr) { + GELOGE(INTERNAL_ERROR, "src node or net output desc is null."); + return; + } + ge::GeTensorDesc out_desc = src_node->GetOpDesc()->GetOutputDesc(src_index); + GE_IF_BOOL_EXEC(net_output_desc->AddInputDesc(out_desc) != SUCCESS, GELOGW("add input desc failed"); return ); + is_input_const.push_back(PassUtils::IsConstant(src_node)); + ++iter; + } + net_output_desc->SetIsInputConst(is_input_const); +} + +bool NeedUpdateOutputByOutputTypeParm(std::string &output_type, NodePtr &src_node, uint32_t src_index, + ge::DataType &dt) { + if (output_type_str_to_datatype.find(output_type) != output_type_str_to_datatype.end()) { + dt = output_type_str_to_datatype[output_type]; + return true; + } + + auto op_desc = src_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + vector output_data_type_vec; + vector index_vec; + if ((ge::AttrUtils::GetListDataType(op_desc, "_output_dt_list", output_data_type_vec)) && + (ge::AttrUtils::GetListInt(op_desc, "_output_dt_index", index_vec))) { + if (output_data_type_vec.size() != index_vec.size()) { + GELOGW("output_dt_list size is not match output_dt_index size"); + return false; + } + for (uint32_t i = 0; i < index_vec.size(); ++i) { + if (index_vec[i] == src_index) { + dt = output_data_type_vec[i]; + return true; + } } - GELOGI("Add NetOutput node success."); + } + return false; +} + +Status NetOutputPass::SetUserDefDTypeAndFormatFromAtcParams(const NodePtr &output_node) { + if (output_node == nullptr) { + GELOGI("[NETOUTPUT PASS] The graph no need netoutput node!"); + return SUCCESS; + } + auto output_type = domi::GetContext().output_type; + auto op_desc = output_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + std::vector userdef_dtypes; + std::vector userdef_formats; + + ge::DataType output_data_type = ge::DT_FLOAT; + for (const auto &in_anchor : output_node->GetAllInDataAnchors()) { + auto index = static_cast(in_anchor->GetIdx()); + auto peer_out = in_anchor->GetPeerOutAnchor(); + if (peer_out == nullptr) { + // If user set target, peer_out anchor will be unlinked. + continue; + } + auto src_index = static_cast(peer_out->GetIdx()); + auto src_node = peer_out->GetOwnerNode(); + GE_CHECK_NOTNULL(src_node); + + // Update datatype + if (NeedUpdateOutputByOutputTypeParm(output_type, src_node, src_index, output_data_type)) { + GELOGD("Add user-define datatype:%s to netoutput node.", + TypeUtils::DataTypeToSerialString(output_data_type).c_str()); + userdef_dtypes.push_back( + std::to_string(index).append(":").append(TypeUtils::DataTypeToSerialString(output_data_type))); + continue; + } + // Output_node is not set,check if is_output_adjust_hw_layout is set + OpDescPtr src_op_desc = src_node->GetOpDesc(); + GE_CHECK_NOTNULL(src_op_desc); + bool set_fp16_nc1hwc0 = false; + (void)AttrUtils::GetBool(src_op_desc, "output_set_fp16_nc1hwc0", set_fp16_nc1hwc0); + if (set_fp16_nc1hwc0) { + // Set DT_FLOAT16 & FORMAT_NC1HWC0 + userdef_dtypes.push_back(std::to_string(index).append(":").append(TypeUtils::DataTypeToSerialString(DT_FLOAT16))); + userdef_formats.push_back( + std::to_string(index).append(":").append(TypeUtils::FormatToSerialString(FORMAT_NC1HWC0))); + } + } + if (!userdef_dtypes.empty() && !ge::AttrUtils::SetListStr(op_desc, ATTR_ATC_USER_DEFINE_DATATYPE, userdef_dtypes)) { + GELOGE(INTERNAL_ERROR, "Set user_define_dtype attr list for netoutput failed."); + return INTERNAL_ERROR; + } + if (!userdef_formats.empty() && !ge::AttrUtils::SetListStr(op_desc, ATTR_ATC_USER_DEFINE_FORMAT, userdef_formats)) { + GELOGE(INTERNAL_ERROR, "Set user_define_format attr list for netoutput failed."); + return INTERNAL_ERROR; } return SUCCESS; } diff --git a/src/ge/graph/passes/net_output_pass.h b/src/ge/graph/passes/net_output_pass.h index 5edf24fc..567d1246 100644 --- a/src/ge/graph/passes/net_output_pass.h +++ b/src/ge/graph/passes/net_output_pass.h @@ -73,7 +73,7 @@ class NetOutputPass : public GraphPass { /// @return OTHERS: Execution failed /// @author /// - Status CreateNetOutputNode(OpDescPtr &net_output_desc, ge::ComputeGraphPtr &graph); + Status CreateNetOutputNode(OpDescPtr &net_output_desc, const ge::ComputeGraphPtr &graph); /// /// Check if the network output node is legal @@ -89,13 +89,12 @@ class NetOutputPass : public GraphPass { /// Set input and output for the NetOutput node /// @param [in] graph: Input ComputeGraph /// @param [in] net_output_desc: OpDesc of the NetOutput node - /// @param [in] src_node: Source node of the NetOutput - /// @param [in] src_index: Output index of the Source node + /// @param [in] output_nodes_info: RetvalInfos of the NetOutput /// @return void /// @author /// - void AddInOutForNetOutputOp(const ge::ComputeGraphPtr &graph, const ge::OpDescPtr &net_output_desc, - const ge::NodePtr &src_node, int32_t src_index); + void AddInOutForNetOutputOp(const ComputeGraphPtr &graph, OpDescPtr &net_output_desc, + vector &output_nodes_info); /// /// Delete unwanted _Retval/Save/Summary nodes @@ -199,6 +198,25 @@ class NetOutputPass : public GraphPass { /// bool CheckNodeIsInOutputNodes(const ge::ComputeGraphPtr &graph, const ge::NodePtr &node); + /// + /// Add netoutput node to graph with output node infos + /// @param [in] graph: ComputeGraph + /// @param [in] output_node: shared_ptr to netoutput node + /// @return SUCCESS: Execution succeed + /// @return OTHERS: Execution failed + /// @author + /// + Status AddNetOutputNodeToGraph(const ge::ComputeGraphPtr &graph, NodePtr &output_node); + + /// + /// Add user_def_dtype & format for netoutput node + /// @param [in] output_node: The netOutput node + /// @return SUCCESS: Execution succeed + /// @return OTHERS: Execution failed + /// @author + /// + Status SetUserDefDTypeAndFormatFromAtcParams(const ge::NodePtr &output_node); + bool is_include_special_node_ = false; std::set targets_; friend class ReUpdateNetOutputPass; diff --git a/src/ge/graph/passes/next_iteration_pass.cc b/src/ge/graph/passes/next_iteration_pass.cc index 138ad86b..12cde11e 100644 --- a/src/ge/graph/passes/next_iteration_pass.cc +++ b/src/ge/graph/passes/next_iteration_pass.cc @@ -16,19 +16,8 @@ #include "graph/passes/next_iteration_pass.h" -#include -#include -#include -#include -#include - #include "common/ge/ge_util.h" -#include "framework/common/debug/ge_log.h" -#include "framework/common/debug/log.h" -#include "framework/common/ge_inner_error_codes.h" -#include "framework/common/types.h" #include "graph/common/omg_util.h" -#include "graph/debug/ge_attr_define.h" namespace ge { Status NextIterationPass::Run(ComputeGraphPtr graph) { @@ -41,24 +30,24 @@ Status NextIterationPass::Run(ComputeGraphPtr graph) { if ((type != ENTER) && (type != REFENTER)) { continue; } - if (HandleEnterNode(node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "HandleEnterNode for node %s fail.", node->GetName().c_str()); + if (GroupEnterNode(node) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Group enter_node %s failed.", node->GetName().c_str()); return INTERNAL_ERROR; } } if (FindWhileGroups() != SUCCESS) { - GELOGE(INTERNAL_ERROR, "FindWhileGroups fail"); + GELOGE(INTERNAL_ERROR, "Find while groups failed."); return INTERNAL_ERROR; } if (!VerifyWhileGroup()) { - GELOGE(INTERNAL_ERROR, "VerifyWhileGroup fail"); + GELOGE(INTERNAL_ERROR, "Verify while groups failed."); return INTERNAL_ERROR; } if (HandleWhileGroup(graph) != SUCCESS) { - GELOGE(FAILED, "HandleWhileGroup fail"); + GELOGE(FAILED, "Handle while groups failed."); return FAILED; } @@ -67,16 +56,16 @@ Status NextIterationPass::Run(ComputeGraphPtr graph) { } /// -/// @brief Handle Enter node +/// @brief Group Enter node /// @param [in] enter_node /// @return Status /// -Status NextIterationPass::HandleEnterNode(const NodePtr &enter_node) { +Status NextIterationPass::GroupEnterNode(const NodePtr &enter_node) { OpDescPtr enter_desc = enter_node->GetOpDesc(); GE_CHECK_NOTNULL(enter_desc); std::string frame_name; if (!ge::AttrUtils::GetStr(enter_desc, ENTER_ATTR_FRAME_NAME, frame_name) || frame_name.empty()) { - GELOGE(FAILED, "Get attr ENTER_ATTR_FRAME_NAME fail, node: %s", enter_desc->GetName().c_str()); + GELOGE(FAILED, "Get attr ENTER_ATTR_FRAME_NAME failed, node: %s", enter_desc->GetName().c_str()); return FAILED; } @@ -84,7 +73,7 @@ Status NextIterationPass::HandleEnterNode(const NodePtr &enter_node) { if (iter == loop_group_map_.end()) { LoopCondGroupPtr loop_group = MakeShared(); if (loop_group == nullptr) { - GELOGE(FAILED, "MakeShared for LoopCondGroup fail."); + GELOGE(FAILED, "MakeShared for LoopCondGroup failed."); return FAILED; } loop_group->enter_nodes.emplace_back(enter_node); @@ -101,40 +90,42 @@ Status NextIterationPass::HandleEnterNode(const NodePtr &enter_node) { /// @return Status /// Status NextIterationPass::FindWhileGroups() { - for (auto &loop_group_iter : loop_group_map_) { - const std::string frame_name = loop_group_iter.first; - for (auto &enter_node : loop_group_iter.second->enter_nodes) { - for (auto &out_node : enter_node->GetOutAllNodes()) { - const std::string type = out_node->GetType(); + for (const auto &loop_group_iter : loop_group_map_) { + const std::string &frame_name = loop_group_iter.first; + for (const auto &enter_node : loop_group_iter.second->enter_nodes) { + for (const auto &out_node : enter_node->GetOutAllNodes()) { + const std::string &type = out_node->GetType(); if ((type != MERGE) && (type != REFMERGE)) { continue; } NodePtr next_node = nullptr; if (FindTargetNode(out_node, NEXTITERATION, true, next_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Get NextIteration node fail, frame_name: %s.", frame_name.c_str()); + GELOGE(INTERNAL_ERROR, "Get NextIteration node failed, frame_name: %s.", frame_name.c_str()); return INTERNAL_ERROR; } + loop_group_iter.second->merge_next_pairs.emplace_back(std::make_pair(out_node, next_node)); NodePtr switch_node = nullptr; if (FindTargetNode(out_node, SWITCH, false, switch_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Get Switch node fail, frame_name: %s.", frame_name.c_str()); + GELOGE(INTERNAL_ERROR, "Get Switch node failed, frame_name: %s.", frame_name.c_str()); return INTERNAL_ERROR; } + if (switch_node == nullptr) { + continue; + } NodePtr loop_cond = nullptr; if (FindTargetNode(switch_node, LOOPCOND, true, loop_cond) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Get LoopCond node fail, frame_name: %s.", frame_name.c_str()); + GELOGE(INTERNAL_ERROR, "Get LoopCond node failed, frame_name: %s.", frame_name.c_str()); return INTERNAL_ERROR; } - if (loop_group_iter.second->loop_cond == nullptr) { loop_group_iter.second->loop_cond = loop_cond; } else if (loop_group_iter.second->loop_cond != loop_cond) { GELOGE(FAILED, "Multi LoopCond nodes exist, frame_name: %s.", frame_name.c_str()); return FAILED; } - loop_group_iter.second->merge_next_pairs.emplace_back(std::make_pair(out_node, next_node)); } } } @@ -148,21 +139,21 @@ Status NextIterationPass::FindWhileGroups() { /// bool NextIterationPass::VerifyWhileGroup() { // map - for (auto &loop_group_iter : loop_group_map_) { - const std::string frame_name = loop_group_iter.first; + for (const auto &loop_group_iter : loop_group_map_) { + const std::string &frame_name = loop_group_iter.first; if (frame_name.empty()) { - GELOGE(INTERNAL_ERROR, "VerifyWhileGroup fail, frame_name is empty."); + GELOGE(INTERNAL_ERROR, "Verify while group failed, frame_name is empty."); return false; } if (loop_group_iter.second->loop_cond == nullptr) { - GELOGE(INTERNAL_ERROR, "VerifyWhileGroup fail, LoopCond is null, frame_name: %s.", frame_name.c_str()); + GELOGE(INTERNAL_ERROR, "Verify while group failed, LoopCond is null, frame_name: %s.", frame_name.c_str()); return false; } - for (auto &pair_iter : loop_group_iter.second->merge_next_pairs) { + for (const auto &pair_iter : loop_group_iter.second->merge_next_pairs) { if ((pair_iter.first == nullptr) || (pair_iter.second == nullptr)) { - GELOGE(INTERNAL_ERROR, "VerifyWhileGroup fail, merge_node/next_node is null, frame_name: %s.", + GELOGE(INTERNAL_ERROR, "Verify while group failed, merge_node/next_node is null, frame_name: %s.", frame_name.c_str()); return false; } @@ -178,51 +169,51 @@ bool NextIterationPass::VerifyWhileGroup() { /// @return Status /// Status NextIterationPass::HandleWhileGroup(ComputeGraphPtr &graph) { - for (auto &loop_cond_iter : loop_group_map_) { - std::string cond_name = loop_cond_iter.second->loop_cond->GetName(); - GELOGI("HandleWhileGroup, LoopCond node: %s.", cond_name.c_str()); + for (const auto &loop_cond_iter : loop_group_map_) { + const std::string &cond_name = loop_cond_iter.second->loop_cond->GetName(); + GELOGI("Handle while group, LoopCond node: %s.", cond_name.c_str()); - // Create Active node, Enter->Active->Merge, NextItaration->Active->Merge + // Create Active node, Enter->Active->Merge, NextIteration->Active->Merge NodePtr enter_active = CreateActiveNode(graph, cond_name + "_Enter_" + STREAMACTIVE); NodePtr next_active = CreateActiveNode(graph, cond_name + "_Next_" + STREAMACTIVE); if ((enter_active == nullptr) || (next_active == nullptr)) { - GELOGE(INTERNAL_ERROR, "CreateActiveNode fail, cond_name: %s.", cond_name.c_str()); + GELOGE(INTERNAL_ERROR, "Create active node failed, cond_name: %s.", cond_name.c_str()); return INTERNAL_ERROR; } - for (auto &enter_node : loop_cond_iter.second->enter_nodes) { + for (const auto &enter_node : loop_cond_iter.second->enter_nodes) { // Enter --> Active if (GraphUtils::AddEdge(enter_node->GetOutControlAnchor(), enter_active->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "Add control edge fail"); + GELOGE(INTERNAL_ERROR, "Add control edge failed."); return INTERNAL_ERROR; } } - for (auto &pair : loop_cond_iter.second->merge_next_pairs) { + for (const auto &pair : loop_cond_iter.second->merge_next_pairs) { NodePtr merge_node = pair.first; NodePtr next_node = pair.second; // Active --> Merge if (GraphUtils::AddEdge(enter_active->GetOutControlAnchor(), merge_node->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "Add control edge fail"); + GELOGE(INTERNAL_ERROR, "Add control edge failed."); return INTERNAL_ERROR; } // NextIteration --> Active if (GraphUtils::AddEdge(next_node->GetOutControlAnchor(), next_active->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "Add control edge fail"); + GELOGE(INTERNAL_ERROR, "Add control edge failed."); return INTERNAL_ERROR; } // break link between NextIteration and Merge if (BreakNextIteration(next_node, merge_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "BreakNextIteration failed"); + GELOGE(INTERNAL_ERROR, "Break NextIteration failed"); return INTERNAL_ERROR; } } if ((SetActiveLabelList(enter_active, {cond_name}) != SUCCESS) || (SetActiveLabelList(next_active, {cond_name}) != SUCCESS)) { - GELOGE(INTERNAL_ERROR, "SetActiveLabelList failed"); + GELOGE(INTERNAL_ERROR, "Set attr ACTIVE_LABEL_LIST failed."); return INTERNAL_ERROR; } } @@ -245,12 +236,12 @@ NodePtr NextIterationPass::CreateActiveNode(ComputeGraphPtr &graph, const std::s GELOGI("Create StreamActive op:%s.", op_desc->GetName().c_str()); NodePtr active_node = graph->AddNode(op_desc); if (active_node == nullptr) { - GELOGE(INTERNAL_ERROR, "Create node[%s] fail.", name.c_str()); + GELOGE(INTERNAL_ERROR, "Create node[%s] failed.", name.c_str()); return nullptr; } if (SetSwitchBranchNodeLabel(active_node, name) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "SetSwitchBranchNodeLabel for node: %s failed.", active_node->GetName().c_str()); + GELOGE(INTERNAL_ERROR, "Set attr SWITCH_BRANCH_NODE_LABEL for node: %s failed.", active_node->GetName().c_str()); return nullptr; } @@ -268,18 +259,18 @@ Status NextIterationPass::BreakNextIteration(const NodePtr &next_node, NodePtr & GELOGE(PARAM_INVALID, "merge node or next node is null."); return PARAM_INVALID; } - for (auto &in_anchor : merge_node->GetAllInDataAnchors()) { + for (const auto &in_anchor : merge_node->GetAllInDataAnchors()) { OutDataAnchorPtr out_anchor = in_anchor->GetPeerOutAnchor(); if ((out_anchor == nullptr) || (out_anchor->GetOwnerNode() != next_node)) { continue; } if (GraphUtils::RemoveEdge(out_anchor, in_anchor) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Remove data edge fail, %s->%s.", next_node->GetName().c_str(), + GELOGE(INTERNAL_ERROR, "Remove data edge failed, %s->%s.", next_node->GetName().c_str(), merge_node->GetName().c_str()); return INTERNAL_ERROR; } if (SetNextIteration(merge_node, next_node->GetName()) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "SetNextIteration for node %s fail.", merge_node->GetName().c_str()); + GELOGE(INTERNAL_ERROR, "Set attr NEXT_ITERATION for node %s failed.", merge_node->GetName().c_str()); return INTERNAL_ERROR; } } @@ -302,16 +293,16 @@ Status NextIterationPass::FindTargetNode(const NodePtr &node, const std::string } std::vector nodes; if (is_input) { - for (auto &tmp_node : node->GetInDataNodes()) { + for (const auto &tmp_node : node->GetInDataNodes()) { nodes.emplace_back(tmp_node); } } else { - for (auto &tmp_node : node->GetOutDataNodes()) { + for (const auto &tmp_node : node->GetOutDataNodes()) { nodes.emplace_back(tmp_node); } } - for (auto &tmp_node : nodes) { + for (const auto &tmp_node : nodes) { const std::string type = tmp_node->GetType(); if ((target_type == LOOPCOND) && (type == target_type)) { target_node = tmp_node; @@ -322,14 +313,15 @@ Status NextIterationPass::FindTargetNode(const NodePtr &node, const std::string } } - if (target_node == nullptr) { - GELOGE(INTERNAL_ERROR, "Find node %s fail", target_type.c_str()); + if ((target_type != SWITCH) && (target_node == nullptr)) { + GELOGE(INTERNAL_ERROR, "Find node %s failed.", target_type.c_str()); return INTERNAL_ERROR; } return SUCCESS; } + /// -/// @brief Clear Status, uesd for subgraph pass +/// @brief Clear Status, used for subgraph pass /// @return SUCCESS /// Status NextIterationPass::ClearStatus() { diff --git a/src/ge/graph/passes/next_iteration_pass.h b/src/ge/graph/passes/next_iteration_pass.h index 4bbced4f..4cdf4b51 100644 --- a/src/ge/graph/passes/next_iteration_pass.h +++ b/src/ge/graph/passes/next_iteration_pass.h @@ -17,12 +17,6 @@ #ifndef GE_GRAPH_PASSES_NEXT_ITERATION_PASS_H_ #define GE_GRAPH_PASSES_NEXT_ITERATION_PASS_H_ -#include -#include -#include -#include -#include - #include "inc/graph_pass.h" struct LoopCondGroup { @@ -37,15 +31,64 @@ namespace ge { class NextIterationPass : public GraphPass { public: Status Run(ComputeGraphPtr graph); + + /// + /// @brief Clear Status, used for subgraph pass + /// @return SUCCESS + /// Status ClearStatus() override; private: - Status HandleEnterNode(const NodePtr &enter_node); + /// + /// @brief Group Enter node + /// @param [in] enter_node + /// @return Status + /// + Status GroupEnterNode(const NodePtr &enter_node); + + /// + /// @brief Find while groups + /// @return Status + /// Status FindWhileGroups(); + + /// + /// @brief Verify if valid + /// @return bool + /// bool VerifyWhileGroup(); + + /// + /// @brief Handle while group + /// @param [in] graph + /// @return Status + /// Status HandleWhileGroup(ComputeGraphPtr &graph); + + /// + /// @brief Create Active Node + /// @param [in] graph + /// @param [in] name + /// @return ge::NodePtr + /// NodePtr CreateActiveNode(ComputeGraphPtr &graph, const std::string &name); + + /// + /// @brief Break NextIteration Link & add name to merge attr + /// @param [in] next_node + /// @param [in] merge_node + /// @return Status + /// Status BreakNextIteration(const NodePtr &next_node, NodePtr &merge_node); + + /// + /// @brief find target node + /// @param [in] node + /// @param [in] target_type + /// @param [in] is_input + /// @param [out] target_node + /// @return Status + /// Status FindTargetNode(const NodePtr &node, const std::string &target_type, bool is_input, NodePtr &target_node); // map diff --git a/src/ge/graph/passes/pass_manager.cc b/src/ge/graph/passes/pass_manager.cc index eec33eef..5be54f0a 100644 --- a/src/ge/graph/passes/pass_manager.cc +++ b/src/ge/graph/passes/pass_manager.cc @@ -19,6 +19,7 @@ #include "common/types.h" #include "common/util.h" #include "graph/utils/node_utils.h" +#include "graph/common/ge_call_wrapper.h" #include "omg/omg_inner_types.h" namespace ge { diff --git a/src/ge/graph/passes/permute_pass.cc b/src/ge/graph/passes/permute_pass.cc index f5fd9dc5..3c0dfd4e 100644 --- a/src/ge/graph/passes/permute_pass.cc +++ b/src/ge/graph/passes/permute_pass.cc @@ -33,7 +33,6 @@ using domi::TENSORFLOW; namespace ge { Status PermutePass::Run(ComputeGraphPtr graph) { - GE_TIMESTAMP_START(PermutePass); GE_CHECK_NOTNULL(graph); std::vector isolate_nodes; for (NodePtr &node : graph->GetDirectNode()) { @@ -116,8 +115,6 @@ Status PermutePass::Run(ComputeGraphPtr graph) { GE_RETURN_WITH_LOG_IF_ERROR(graph->RemoveNode(node), "[%s]:remove permute node failed", node->GetOpDesc()->GetName().c_str()); }); - - GE_TIMESTAMP_END(PermutePass, "GraphManager::PermutePass"); return SUCCESS; } } // namespace ge diff --git a/src/ge/graph/passes/print_op_pass.h b/src/ge/graph/passes/print_op_pass.h index 64bf6573..15b0badc 100644 --- a/src/ge/graph/passes/print_op_pass.h +++ b/src/ge/graph/passes/print_op_pass.h @@ -31,6 +31,6 @@ class PrintOpPass : public BaseNodePass { public: Status Run(ge::NodePtr &node) override; }; -}; // namespace ge +} // namespace ge #endif // GE_GRAPH_PASSES_PRINT_OP_PASS_H_ diff --git a/src/ge/graph/passes/ref_identity_delete_op_pass.cc b/src/ge/graph/passes/ref_identity_delete_op_pass.cc new file mode 100644 index 00000000..5bc0fad6 --- /dev/null +++ b/src/ge/graph/passes/ref_identity_delete_op_pass.cc @@ -0,0 +1,225 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "ref_identity_delete_op_pass.h" +#include +#include +#include "graph/common/transop_util.h" + +namespace ge { +Status RefIdentityDeleteOpPass::Run(ComputeGraphPtr graph) { + GE_CHECK_NOTNULL(graph); + for (auto &node : graph->GetAllNodes()) { + if (node->GetType() != REFIDENTITY) { + continue; + } + int input_index = 0; + NodePtr ref_node = GetRefNode(node, input_index); + CHECK_FALSE_EXEC(GetRefNode(node, input_index) != nullptr, + GELOGE(FAILED, "Ref node of RefIdentity[%s] not found", node->GetName().c_str()); + return FAILED); + CHECK_FALSE_EXEC(DealNoOutputRef(ref_node, node, input_index, graph) == SUCCESS, + GELOGE(FAILED, "Ref identity [%s] delete failed", node->GetName().c_str()); + return FAILED); + } + return SUCCESS; +} + +NodePtr RefIdentityDeleteOpPass::GetRefNode(const NodePtr &node, int &input_index) { + OutDataAnchorPtr out_anchor = node->GetOutDataAnchor(0); + CHECK_FALSE_EXEC(out_anchor != nullptr, return nullptr); + for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { + CHECK_FALSE_EXEC(peer_in_anchor != nullptr, continue); + auto peer_node = peer_in_anchor->GetOwnerNode(); + CHECK_FALSE_EXEC(peer_node != nullptr, continue); + const auto &peer_op_desc = peer_node->GetOpDesc(); + CHECK_FALSE_EXEC(peer_op_desc != nullptr, return nullptr); + const auto &peer_input_desc = peer_op_desc->GetInputDescPtr(static_cast(peer_in_anchor->GetIdx())); + if (!peer_input_desc->GetRefPortIndex().empty()) { + input_index = peer_in_anchor->GetIdx(); + return peer_node; + } + } + return nullptr; +} + +Status RefIdentityDeleteOpPass::DealNoOutputRef(const NodePtr &node, const NodePtr &ref_identity, int input_index, + const ComputeGraphPtr &graph) { + NodePtr first_node = nullptr; + NodePtr variable_ref = GetVariableRef(node, ref_identity, first_node); + if (variable_ref == nullptr) { + GELOGE(FAILED, "[RefIdentityDeleteOpPass]Can not find variable ref for %s:%d", node->GetName().c_str(), + input_index); + return FAILED; + } + if (first_node->GetName() != variable_ref->GetName()) { + // Remove the control edge between ref node and variable ref + // Add a control edge between ref node and trans node + // +-----------+ +-----------+ + // +---------+RefIdentity| +-----------+RefIdentity| + // | +-----+-----+ | +-----+-----+ + // | | | | + // | v | v + // +-----v-----+ +----+----+ +-----v-----+ +----+----+ + // | TransNode | | RefNode | ==> | TransNode +<--C--+ RefNode | + // +-----+-----+ +----+----+ +-----+-----+ +---------+ + // | | | + // v C v + // +-----+-----+ | +-----+-----+ + // |VariableRef+<--------+ |VariableRef| + // +-----------+ +-----------+ + auto ret = ge::GraphUtils::AddEdge(node->GetOutControlAnchor(), first_node->GetInControlAnchor()); + if (ret != SUCCESS) { + GELOGE(FAILED, "Add control edge between ref node and trans node failed"); + return FAILED; + } + ret = ge::GraphUtils::RemoveEdge(node->GetOutControlAnchor(), variable_ref->GetInControlAnchor()); + if (ret != SUCCESS) { + GELOGE(FAILED, "Remove control edge between ref node and its peer node failed"); + return FAILED; + } + } else { + // +-----------+ +-----------+ + // +-----------+RefIdentity| +-----------+RefIdentity| + // | +-----+-----+ | +-----+-----+ + // | | | | + // | v | v + // +-----v-----+ +----+----+ +-----v-----+ +----+----+ + // |VariableRef+<--C--+ RefNode | ==> |VariableRef+<--C--+ RefNode | + // +-----+-----+ +----+----+ +-----------+ +----+----+ + // | | | + // | v v + // | +---+----+ +---+----+ + // +-----C------>+ | | | + // +--------+ +--------+ + auto ret = RemoveUselessControlEdge(node, variable_ref); + if (ret != SUCCESS) { + GELOGE(FAILED, "Remove useless control edge failed."); + return FAILED; + } + } + // remove ref identity + if (GraphUtils::IsolateNode(ref_identity, {0}) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Isolate removed node: %s, type: %s failed", ref_identity->GetName().c_str(), + variable_ref->GetType().c_str()); + return FAILED; + } + if (GraphUtils::RemoveNodeWithoutRelink(graph, ref_identity) != GRAPH_SUCCESS) { + GELOGE(INTERNAL_ERROR, "Remove node: %s, type: %s without relink failed", ref_identity->GetName().c_str(), + ref_identity->GetType().c_str()); + return FAILED; + } + return SUCCESS; +} + +ge::NodePtr RefIdentityDeleteOpPass::GetVariableRef(const NodePtr &ref, const NodePtr &ref_identity, + NodePtr &first_node) { + const auto &ref_identity_out_anchor = ref_identity->GetOutDataAnchor(0); + if (ref_identity_out_anchor == nullptr) { + return nullptr; + } + for (auto &peer_in_anchor : ref_identity_out_anchor->GetPeerInDataAnchors()) { + const auto &peer_node = peer_in_anchor->GetOwnerNode(); + if (peer_node == nullptr || peer_node->GetName() == ref->GetName()) { + continue; + } + // DFS to find variable ref node. + std::stack nodes_to_check; + nodes_to_check.push(peer_node); + GELOGI("[RefIdentityDeleteOpPass]Start to search variable ref node from %s.", peer_node->GetName().c_str()); + NodePtr cur_node = nullptr; + while (!nodes_to_check.empty()) { + cur_node = nodes_to_check.top(); + nodes_to_check.pop(); + const auto &type = cur_node->GetType(); + if (type == VARIABLE && CheckControlEdge(ref, cur_node)) { + // Target variable ref node found. + GELOGI("[RefIdentityDeleteOpPass]variable ref node[%s] found.", cur_node->GetName().c_str()); + first_node = peer_node; + return cur_node; + } + + int data_index = TransOpUtil::GetTransOpDataIndex(type); + if (data_index < 0) { + GELOGI("[RefIdentityDeleteOpPass]Find node[%s] that is not trans op[%s], stop to search its output.", + cur_node->GetName().c_str(), type.c_str()); + continue; + } + const auto &cur_out_anchor = cur_node->GetOutDataAnchor(0); + if (cur_out_anchor == nullptr) { + GELOGI("[RefIdentityDeleteOpPass]Get out anchor of [%s] failed, stop to search its output.", + cur_node->GetName().c_str()); + continue; + } + for (const auto &cur_peer_in_anchor : cur_out_anchor->GetPeerInDataAnchors()) { + const auto &cur_peer_node = cur_peer_in_anchor->GetOwnerNode(); + if (cur_peer_node == nullptr) { + continue; + } + nodes_to_check.push(cur_peer_node); + } + } + GELOGI("[RefIdentityDeleteOpPass]Can not find variable ref node from %s.", peer_node->GetName().c_str()); + } + GELOGI("[RefIdentityDeleteOpPass]Can not find variable ref node, return nullptr."); + return nullptr; +} + +bool RefIdentityDeleteOpPass::CheckControlEdge(const NodePtr &ref, const NodePtr &variable_ref) { + const auto &control_out_anchor = ref->GetOutControlAnchor(); + if (control_out_anchor == nullptr) { + return false; + } + const string &variable_ref_name = variable_ref->GetName(); + for (const auto &peer_in_control_anchor : control_out_anchor->GetPeerInControlAnchors()) { + const auto &node = peer_in_control_anchor->GetOwnerNode(); + if (node != nullptr && node->GetName() == variable_ref_name) { + return true; + } + } + return false; +} + +Status RefIdentityDeleteOpPass::RemoveUselessControlEdge(const NodePtr &ref, const NodePtr &variable_ref) { + map out_nodes_map; + for (const auto &out_anchor : ref->GetAllOutDataAnchors()) { + for (const auto &peer_in_anchor : out_anchor->GetPeerAnchors()) { + const auto &peer_node = peer_in_anchor->GetOwnerNode(); + if (peer_node == nullptr) { + continue; + } + out_nodes_map[peer_node->GetName()] = peer_node; + } + } + const auto &out_control_anchor = variable_ref->GetOutControlAnchor(); + GE_CHECK_NOTNULL(out_control_anchor); + for (const auto &peer_in_control_anchor : out_control_anchor->GetPeerInControlAnchors()) { + const auto &peer_node = peer_in_control_anchor->GetOwnerNode(); + if (peer_node == nullptr) { + continue; + } + if (out_nodes_map.find(peer_node->GetName()) != out_nodes_map.end()) { + auto ret = ge::GraphUtils::RemoveEdge(out_control_anchor, peer_in_control_anchor); + if (ret != SUCCESS) { + GELOGE(FAILED, "Remove control edge between variable ref node[%s] and ref node's peer node[%s] failed", + variable_ref->GetName().c_str(), peer_node->GetName().c_str()); + return FAILED; + } + } + } + return SUCCESS; +} +} // namespace ge diff --git a/src/ge/graph/passes/ref_identity_delete_op_pass.h b/src/ge/graph/passes/ref_identity_delete_op_pass.h new file mode 100644 index 00000000..3e42def4 --- /dev/null +++ b/src/ge/graph/passes/ref_identity_delete_op_pass.h @@ -0,0 +1,40 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_REF_IDENTITY_DELETE_OP_PASS_H_ +#define GE_GRAPH_PASSES_REF_IDENTITY_DELETE_OP_PASS_H_ + +#include +#include +#include "framework/common/ge_inner_error_codes.h" +#include "inc/graph_pass.h" + +namespace ge { +class RefIdentityDeleteOpPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph); + + private: + Status DealNoOutputRef(const NodePtr &node, const NodePtr &ref_identity, int input_index, + const ComputeGraphPtr &graph); + NodePtr GetVariableRef(const NodePtr &ref, const NodePtr &ref_identity, NodePtr &first_node); + bool CheckControlEdge(const NodePtr &ref, const NodePtr &variable_ref); + Status RemoveUselessControlEdge(const NodePtr &ref, const NodePtr &variable_ref); + NodePtr GetRefNode(const NodePtr &node, int &input_index); +}; +} // namespace ge + +#endif // GE_GRAPH_PASSES_REF_IDENTITY_DELETE_OP_PASS_H_ diff --git a/src/ge/graph/passes/reshape_recovery_pass.cc b/src/ge/graph/passes/reshape_recovery_pass.cc index 787c8d83..07b08de9 100644 --- a/src/ge/graph/passes/reshape_recovery_pass.cc +++ b/src/ge/graph/passes/reshape_recovery_pass.cc @@ -30,6 +30,10 @@ NodePtr CreateReshape(const ConstGeTensorDescPtr &src, const ConstGeTensorDescPt if (ret != GRAPH_SUCCESS) { return nullptr; } + ret = reshape->AddInputDesc("shape", GeTensorDesc(GeShape(), Format(), DT_INT32)); + if (ret != GRAPH_SUCCESS) { + return nullptr; + } ret = reshape->AddOutputDesc("y", *dst); if (ret != GRAPH_SUCCESS) { return nullptr; @@ -49,7 +53,10 @@ Status InsertReshapeIfNeed(const NodePtr &node) { GE_CHECK_NOTNULL(dst_node); GE_CHECK_NOTNULL(dst_node->GetOpDesc()); auto dst_tensor = dst_node->GetOpDesc()->GetInputDescPtr(dst_anchor->GetIdx()); - if (src_tensor->GetShape().GetDims() != dst_tensor->GetShape().GetDims()) { + bool is_need_insert_reshape = src_tensor->GetShape().GetDims() != UNKNOWN_RANK && + dst_tensor->GetShape().GetDims() != UNKNOWN_RANK && + src_tensor->GetShape().GetDims() != dst_tensor->GetShape().GetDims(); + if (is_need_insert_reshape) { auto reshape = CreateReshape(src_tensor, dst_tensor, node->GetOwnerComputeGraph()); GE_CHECK_NOTNULL(reshape); auto ret = GraphUtils::InsertNodeBetweenDataAnchors(src_anchor, dst_anchor, reshape); diff --git a/src/ge/graph/passes/resource_pair_add_control_pass.cc b/src/ge/graph/passes/resource_pair_add_control_pass.cc index c5be9600..bba8ee71 100644 --- a/src/ge/graph/passes/resource_pair_add_control_pass.cc +++ b/src/ge/graph/passes/resource_pair_add_control_pass.cc @@ -28,7 +28,6 @@ #include "graph/utils/tensor_adapter.h" namespace { -const char *const kSeparate = "/"; const std::map kResourcePairType = {{"StackPush", "StackPop"}}; const std::set kResourceTypes = {"StackPush", "StackPop"}; } // namespace @@ -41,15 +40,16 @@ Status ResourcePairAddControlPass::Run(ComputeGraphPtr graph) { // find all node of condition type, store with type and scope prefix key for (auto &node : graph->GetDirectNode()) { GE_CHECK_NOTNULL(node); - if (kResourceTypes.find(node->GetType()) != kResourceTypes.end()) { + auto node_type = node->GetType(); + if (kResourceTypes.find(node_type) != kResourceTypes.end()) { std::string node_name = node->GetName(); - std::string node_prefix; - size_t last_separate_index = node_name.find_last_of(kSeparate); - if (last_separate_index != std::string::npos) { - node_prefix = node_name.substr(0, last_separate_index); + std::string node_key(node_name); + std::size_t found = node_name.rfind(node_type); + if (found != std::string::npos) { + node_key.replace(found, node_type.size(), ""); } - prefix_2_node_per_type[node->GetType()][node_prefix] = node; - GELOGD("ResourcePairAddControlPass insert prefix:%s, op_name:%s, op_type:%s", node_prefix.c_str(), + prefix_2_node_per_type[node_type][node_key] = node; + GELOGD("ResourcePairAddControlPass insert node_key:%s, op_name:%s, op_type:%s", node_key.c_str(), node_name.c_str(), node->GetType().c_str()); } } diff --git a/src/ge/graph/passes/resource_pair_remove_control_pass.cc b/src/ge/graph/passes/resource_pair_remove_control_pass.cc index de3537f0..00d97798 100644 --- a/src/ge/graph/passes/resource_pair_remove_control_pass.cc +++ b/src/ge/graph/passes/resource_pair_remove_control_pass.cc @@ -28,7 +28,6 @@ #include "graph/utils/tensor_adapter.h" namespace { -const char *const kSeparate = "/"; const std::map kResourcePairType = {{"StackPush", "StackPop"}}; const std::set kResourceTypes = {"StackPush", "StackPop"}; } // namespace @@ -41,15 +40,16 @@ Status ResourcePairRemoveControlPass::Run(ComputeGraphPtr graph) { // find all node of condition type, store with type and scope prefix key for (auto &node : graph->GetDirectNode()) { GE_CHECK_NOTNULL(node); - if (kResourceTypes.find(node->GetType()) != kResourceTypes.end()) { + auto node_type = node->GetType(); + if (kResourceTypes.find(node_type) != kResourceTypes.end()) { std::string node_name = node->GetName(); - std::string node_prefix; - size_t last_separate_index = node_name.find_last_of(kSeparate); - if (last_separate_index != std::string::npos) { - node_prefix = node_name.substr(0, last_separate_index); + std::string node_key(node_name); + std::size_t found = node_name.rfind(node_type); + if (found != std::string::npos) { + node_key.replace(found, node_type.size(), ""); } - prefix_2_node_per_type[node->GetType()][node_prefix] = node; - GELOGD("ResourcePairRemoveControlPass insert prefix:%s, op_name:%s, op_type:%s", node_prefix.c_str(), + prefix_2_node_per_type[node_type][node_key] = node; + GELOGD("ResourcePairRemoveControlPass insert node_key:%s, op_name:%s, op_type:%s", node_key.c_str(), node_name.c_str(), node->GetType().c_str()); } } diff --git a/src/ge/graph/passes/same_transdata_breadth_fusion_pass.cc b/src/ge/graph/passes/same_transdata_breadth_fusion_pass.cc index 3b4e4c19..d51f52e1 100644 --- a/src/ge/graph/passes/same_transdata_breadth_fusion_pass.cc +++ b/src/ge/graph/passes/same_transdata_breadth_fusion_pass.cc @@ -22,7 +22,6 @@ #include #include "common/ge_inner_error_codes.h" #include "common/types.h" -#include "framework/common/debug/ge_log.h" #include "graph/debug/ge_attr_define.h" #include "graph/utils/graph_utils.h" #include "graph/utils/op_desc_utils.h" @@ -117,20 +116,44 @@ void SameTransdataBreadthFusionPass::InsertSameTransdataNodeIndex(int anchors_in same_transdata_nodes.push_back(anchors_index); } +std::set SameTransdataBreadthFusionPass::GetInControlIdentityNodes(const NodePtr &node, + int subgraph_index) { + std::set in_node_names; + for (const auto &in_node : node->GetInControlNodes()) { + if (in_node->GetType() == IDENTITY) { + in_node_names.insert(in_node->GetName()); + } + } + for (const auto &subgraph_node : before_transdata_nodes_[subgraph_index]) { + for (const auto &in_node : subgraph_node->GetInControlNodes()) { + if (in_node->GetType() == IDENTITY) { + in_node_names.insert(in_node->GetName()); + } + } + } + GELOGD("control in nodes for %s(%d): %zu", node->GetName().c_str(), subgraph_index, in_node_names.size()); + return in_node_names; +} + void SameTransdataBreadthFusionPass::GetSameTransdataNode(vector &same_transdata_nodes) { auto iter = all_transdata_nodes_.begin(); same_transdata_nodes.push_back(iter->first); + auto node_for_compare_in_anchor = iter->second; GE_CHECK_NOTNULL_JUST_RETURN(node_for_compare_in_anchor); auto node_for_compare = node_for_compare_in_anchor->GetOwnerNode(); + + // Get op-desc, input/output desc, in-control-edges-from-identity, as the compare-key auto op_desc_for_compare = node_for_compare->GetOpDesc(); GE_CHECK_NOTNULL_JUST_RETURN(op_desc_for_compare); string op_compare_stream_label; (void)AttrUtils::GetStr(op_desc_for_compare, ATTR_NAME_STREAM_LABEL, op_compare_stream_label); + auto op_compare_in_ctrl_nodes = GetInControlIdentityNodes(node_for_compare, iter->first); auto input_desc_for_compare = op_desc_for_compare->GetInputDescPtr(node_for_compare_in_anchor->GetIdx()); GE_CHECK_NOTNULL_JUST_RETURN(input_desc_for_compare); auto output_desc_for_compare = op_desc_for_compare->GetOutputDescPtr(0); GE_CHECK_NOTNULL_JUST_RETURN(output_desc_for_compare); + iter = all_transdata_nodes_.erase(iter); while (iter != all_transdata_nodes_.end()) { auto in_anchor = iter->second; @@ -149,12 +172,14 @@ void SameTransdataBreadthFusionPass::GetSameTransdataNode(vector &same_tran auto output_desc_tmp = op_desc_tmp->GetOutputDescPtr(0); string op_tmp_stream_label; (void)AttrUtils::GetStr(op_desc_tmp, ATTR_NAME_STREAM_LABEL, op_tmp_stream_label); + auto op_tmp_in_ctrl_nodes = GetInControlIdentityNodes(node_tmp, iter->first); GE_CHECK_NOTNULL_JUST_RETURN(input_desc_tmp); GE_CHECK_NOTNULL_JUST_RETURN(output_desc_tmp); if ((op_compare_stream_label == op_tmp_stream_label) && (input_desc_tmp->GetFormat() == input_desc_for_compare->GetFormat()) && - (output_desc_tmp->GetFormat() == output_desc_for_compare->GetFormat())) { + (output_desc_tmp->GetFormat() == output_desc_for_compare->GetFormat()) && + (op_compare_in_ctrl_nodes == op_tmp_in_ctrl_nodes)) { GELOGD("same transdata node:%s, src node:%s", node_tmp->GetName().c_str(), node_for_compare->GetName().c_str()); InsertSameTransdataNodeIndex(iter->first, same_transdata_nodes); iter = all_transdata_nodes_.erase(iter); @@ -339,14 +364,13 @@ graphStatus SameTransdataBreadthFusionPass::ReLinkTransdataControlOutput2PreNode } graphStatus SameTransdataBreadthFusionPass::Run(ComputeGraphPtr graph) { - GE_TIMESTAMP_START(SameTransdataBreadthFusionPass); GELOGI("[SameTransdataBreadthFusionPass]: optimize begin."); if (graph == nullptr) { return GRAPH_SUCCESS; } for (auto &node : graph->GetDirectNode()) { - if (IsTransOp(node) || node->GetOutDataNodes().size() <= 1) { + if (IsTransOp(node) || node->GetOutDataNodesSize() <= 1) { continue; } @@ -374,7 +398,6 @@ graphStatus SameTransdataBreadthFusionPass::Run(ComputeGraphPtr graph) { } GELOGI("[SameTransdataBreadthFusionPass]: Optimize success."); - GE_TIMESTAMP_END(SameTransdataBreadthFusionPass, "GraphManager::SameTransdataBreadthFusionPass"); return GRAPH_SUCCESS; } diff --git a/src/ge/graph/passes/same_transdata_breadth_fusion_pass.h b/src/ge/graph/passes/same_transdata_breadth_fusion_pass.h index f4b44a59..a6a3bb26 100644 --- a/src/ge/graph/passes/same_transdata_breadth_fusion_pass.h +++ b/src/ge/graph/passes/same_transdata_breadth_fusion_pass.h @@ -42,7 +42,7 @@ class SameTransdataBreadthFusionPass : public GraphPass { void GetSubGraphNodesInfo(); void EraseInvalidAnchorsPair(); - + std::set GetInControlIdentityNodes(const NodePtr &node, int subgraph_index); OpDescPtr GetCastOp(const GeTensorDesc &in_desc, const GeTensorDesc &out_desc); graphStatus AddCastNode(const ComputeGraphPtr &graph, int anchors_index, OutDataAnchorPtr &pre_out_anchor, diff --git a/src/ge/graph/passes/set_input_output_offset_pass.cc b/src/ge/graph/passes/set_input_output_offset_pass.cc new file mode 100644 index 00000000..58c3be85 --- /dev/null +++ b/src/ge/graph/passes/set_input_output_offset_pass.cc @@ -0,0 +1,285 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/set_input_output_offset_pass.h" + +#include "runtime/mem.h" + +namespace ge { +Status SetInputOutputOffsetPass::Run(ComputeGraphPtr graph) { + GE_CHECK_NOTNULL(graph); + for (auto &node : graph->GetDirectNode()) { + GE_CHECK_NOTNULL(node->GetOpDesc()); + vector connect_input; + (void)AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_NODE_CONNECT_INPUT, connect_input); + if (!connect_input.empty()) { + Status ret = SetInputOffset(node, connect_input); + if (ret != SUCCESS) { + GELOGE(ret, "SetInputOffset failed."); + return ret; + } + } + vector connect_output; + (void)AttrUtils::GetListInt(node->GetOpDesc(), ATTR_NAME_NODE_CONNECT_OUTPUT, connect_output); + if (!connect_output.empty()) { + Status ret = SetOutputOffset(node, connect_output); + if (ret != SUCCESS) { + GELOGE(ret, "SetOutputOffset failed."); + return ret; + } + } + } + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetInputOffsetForFusion(const std::vector &memory_type, + const ge::NodePtr &node) { + GELOGI("Start to SetInputOffsetForFusion for %s", node->GetName().c_str()); + auto op_desc = node->GetOpDesc(); + for (size_t i = 0; i < memory_type.size(); ++i) { + if (memory_type.at(i) != RT_MEMORY_L1) { + std::vector input_offset_of_node; + input_offset_of_node = op_desc->GetInputOffset(); + if (input_offset_of_node.size() < i) { + GELOGE(PARAM_INVALID, "not get input_offset of %zu", i); + return PARAM_INVALID; + } + int64_t input_offset = input_offset_of_node.at(i); + GELOGI("input_offset of %s is %ld.", node->GetName().c_str(), input_offset); + auto in_anchor = node->GetInDataAnchor(i); + GE_IF_BOOL_EXEC(in_anchor == nullptr, continue); + auto peer_out_anchor = in_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); + int out_index = peer_out_anchor->GetIdx(); + auto data_op_desc = peer_out_anchor->GetOwnerNode()->GetOpDesc(); + GE_CHECK_NOTNULL(data_op_desc); + int64_t out_offset = data_op_desc->GetOutputOffset().at(out_index); + GELOGI("output_offset of %s is %ld.", peer_out_anchor->GetOwnerNode()->GetName().c_str(), out_offset); + vector zero_copy_basic_offset; + vector zero_copy_relative_offset; + + (void)ge::AttrUtils::GetListInt(data_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset); + (void)ge::AttrUtils::GetListInt(data_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset); + zero_copy_basic_offset.emplace_back(out_offset); + int64_t relative_offset = input_offset - out_offset; + zero_copy_relative_offset.emplace_back(relative_offset); + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(data_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset), + GELOGE(FAILED, "SetListInt of zero_copy_basic_offset failed."); + return FAILED); + GE_CHK_BOOL_EXEC( + ge::AttrUtils::SetListInt(data_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset), + GELOGE(FAILED, "SetListInt of zero_copy_relative_offset failed."); + return FAILED); + } + } + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetInputOffsetForHcom(const ge::NodePtr &node, const vector &connect_input) { + GELOGI("Start SetInputOffsetForHcom for %s.", node->GetName().c_str()); + + auto op_desc = node->GetOpDesc(); + vector input_offset_of_node; + input_offset_of_node = node->GetOpDesc()->GetInputOffset(); + for (size_t input_index = 0; input_index < connect_input.size(); ++input_index) { + int connect_input_index = connect_input.at(input_index); + int64_t input_offset = input_offset_of_node.at(connect_input_index); + NodePtr in_data = node->GetInDataNodes().at(connect_input_index); + auto in_op_desc = in_data->GetOpDesc(); + GE_CHECK_NOTNULL(in_op_desc); + if (in_op_desc->GetType() == DATA) { + int64_t output_offset = in_op_desc->GetOutputOffset().at(0); + if (output_offset == input_offset) { + continue; + } else { + vector zero_copy_basic_offset; + vector zero_copy_relative_offset; + (void)ge::AttrUtils::GetListInt(in_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset); + (void)ge::AttrUtils::GetListInt(in_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset); + GELOGI("input offset from %s to %s is %ld to %ld.", in_op_desc->GetName().c_str(), op_desc->GetName().c_str(), + output_offset, input_offset); + int64_t relative_offset = input_offset - output_offset; + zero_copy_basic_offset.emplace_back(output_offset); + zero_copy_relative_offset.emplace_back(relative_offset); + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(in_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset), + GELOGE(FAILED, "SetListInt of zero_copy_basic_offset failed."); + return FAILED); + GE_CHK_BOOL_EXEC( + ge::AttrUtils::SetListInt(in_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset), + GELOGE(FAILED, "SetListInt of zero_copy_relative_offset failed."); + return FAILED); + } + } + } + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetInputOffset(const NodePtr &node, const vector &connect_input) { + GELOGI("Start to SetInputOffset for %s.", node->GetName().c_str()); + std::vector memory_type; + auto op_desc = node->GetOpDesc(); + (void)ge::AttrUtils::GetListInt(op_desc, ATTR_NAME_INPUT_MEM_TYPE_LIST, memory_type); + if (!memory_type.empty()) { + Status ret = SetInputOffsetForFusion(memory_type, node); + if (ret != SUCCESS) { + GELOGE(ret, "SetInputOffsetForFusion failed."); + return ret; + } + } + // Data->Hcom + bool is_input_continuous = false; + (void)ge::AttrUtils::GetBool(op_desc, ATTR_NAME_CONTINUOUS_INPUT, is_input_continuous); + if (is_input_continuous) { + Status ret = SetInputOffsetForHcom(node, connect_input); + if (ret != SUCCESS) { + GELOGE(ret, "SetInputOffsetForHcom failed."); + return ret; + } + } + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetOutputOffsetForConcat(const NodePtr &node) { + GELOGI("Start SetOutputOffsetForConcat for %s.", node->GetName().c_str()); + auto op_desc = node->GetOpDesc(); + std::vector output_offset_of_concat; + output_offset_of_concat = op_desc->GetOutputOffset(); + // phony_concat has one output + GE_IF_BOOL_EXEC(output_offset_of_concat.size() != 1, + GELOGE(PARAM_INVALID, "%s should has one output.", node->GetName().c_str()); + return PARAM_INVALID); + NodePtr net_output = node->GetOutDataNodes().at(0); + auto out_op_desc = net_output->GetOpDesc(); + GE_CHECK_NOTNULL(out_op_desc); + vector zero_copy_basic_offset; + vector zero_copy_relative_offset; + (void)ge::AttrUtils::GetListInt(out_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset); + (void)ge::AttrUtils::GetListInt(out_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset); + + int64_t basic_offset = output_offset_of_concat.at(0); + GELOGI("output_offset of %s is %ld.", op_desc->GetName().c_str(), basic_offset); + for (InDataAnchorPtr &in_anchor : node->GetAllInDataAnchors()) { + OutDataAnchorPtr peer_out_anchor = in_anchor->GetPeerOutAnchor(); + GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); + NodePtr in_node = peer_out_anchor->GetOwnerNode(); + auto out_index = peer_out_anchor->GetIdx(); + std::vector output_offset_of_in_node; + GE_CHECK_NOTNULL(in_node->GetOpDesc()); + output_offset_of_in_node = in_node->GetOpDesc()->GetOutputOffset(); + GELOGI("input offset from %s to %s is %ld.", in_node->GetName().c_str(), op_desc->GetName().c_str(), + output_offset_of_in_node.at(out_index)); + int64_t relative_offset = output_offset_of_in_node.at(out_index) - basic_offset; + zero_copy_basic_offset.emplace_back(basic_offset); + zero_copy_relative_offset.emplace_back(relative_offset); + } + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(out_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset), + GELOGE(FAILED, "SetListInt of zero_copy_basic_offset failed."); + return FAILED); + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(out_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset), + GELOGE(FAILED, "SetListInt of zero_copy_relative_offset failed."); + return FAILED); + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetOutputOffsetForHcom(const NodePtr &node, const vector &connect_output) { + GELOGI("Start SetOutputOffsetForHcom, %s connect with %zu output.", node->GetName().c_str(), connect_output.size()); + vector output_offset_of_node; + output_offset_of_node = node->GetOpDesc()->GetOutputOffset(); + int connect_output_index = connect_output.at(0); + int64_t basic_offset = output_offset_of_node.at(connect_output_index); + GELOGI("basic_offset of %s is %ld.", node->GetName().c_str(), basic_offset); + + NodePtr net_output = node->GetOutDataNodes().at(connect_output_index); + auto out_op_desc = net_output->GetOpDesc(); + GE_CHECK_NOTNULL(out_op_desc); + vector zero_copy_basic_offset; + vector zero_copy_relative_offset; + (void)ge::AttrUtils::GetListInt(out_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset); + (void)ge::AttrUtils::GetListInt(out_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset); + + for (auto &out_anchor : node->GetAllOutDataAnchors()) { + GE_IF_BOOL_EXEC(out_anchor == nullptr, continue); + for (auto &in_anchor : out_anchor->GetPeerInDataAnchors()) { + GE_IF_BOOL_EXEC(in_anchor == nullptr, continue); + if (in_anchor->GetOwnerNode()->GetType() == NETOUTPUT && out_anchor->GetIdx() != connect_output_index) { + continue; + } else { + NodePtr out_node = in_anchor->GetOwnerNode(); + auto in_index = in_anchor->GetIdx(); + std::vector input_offset_of_out_node; + GE_CHECK_NOTNULL(out_node->GetOpDesc()); + input_offset_of_out_node = out_node->GetOpDesc()->GetInputOffset(); + GELOGI("input offset from %s to %s is %ld.", node->GetName().c_str(), out_node->GetName().c_str(), + input_offset_of_out_node.at(in_index)); + int64_t relative_offset = input_offset_of_out_node.at(in_index) - basic_offset; + zero_copy_basic_offset.emplace_back(basic_offset); + zero_copy_relative_offset.emplace_back(relative_offset); + } + } + } + + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(out_op_desc, ATTR_ZERO_COPY_BASIC_OFFSET, zero_copy_basic_offset), + GELOGE(FAILED, "SetListInt of zero_copy_basic_offset failed."); + return FAILED); + GE_CHK_BOOL_EXEC(ge::AttrUtils::SetListInt(out_op_desc, ATTR_ZERO_COPY_RELATIVE_OFFSET, zero_copy_relative_offset), + GELOGE(FAILED, "SetListInt of zero_copy_relative_offset failed."); + return FAILED); + return SUCCESS; +} + +Status SetInputOutputOffsetPass::SetOutputOffset(const NodePtr &node, const vector &connect_output) { + GELOGI("Start SetOutputOffset of %s.", node->GetName().c_str()); + bool attr_no_task = false; + bool get_attr_no_task = ge::AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_NOTASK, attr_no_task); + if (get_attr_no_task && attr_no_task) { + bool is_input_continuous = false; + (void)ge::AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_CONTINUOUS_INPUT, is_input_continuous); + bool buffer_fusion = CheckBufferFusion(node); + // A/B/C -> Phony_concat -> Netoutput : input_continuous + if (is_input_continuous || buffer_fusion) { + Status ret = SetOutputOffsetForConcat(node); + if (ret != SUCCESS) { + GELOGE(ret, "SetOutputOffsetForConcat failed."); + return ret; + } + } + } + // allreduce->netoutput : output_continuous + bool is_output_continuous = false; + (void)ge::AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_CONTINUOUS_OUTPUT, is_output_continuous); + if (is_output_continuous) { + Status ret = SetOutputOffsetForHcom(node, connect_output); + if (ret != SUCCESS) { + GELOGE(ret, "SetOutputOffsetForHcom failed."); + return ret; + } + } + return SUCCESS; +} + +bool SetInputOutputOffsetPass::CheckBufferFusion(const NodePtr &node) { + for (auto &in_node : node->GetInDataNodes()) { + GE_CHECK_NOTNULL(in_node); + auto op_desc = in_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (!op_desc->HasAttr(ATTR_NAME_OUTPUT_OFFSET_FOR_BUFFER_FUSION)) { + GELOGI("The node: %s not have ATTR_NAME_OUTPUT_OFFSET_FOR_BUFFER_FUSION.", node->GetName().c_str()); + return false; + } + } + return true; +} +} // namespace ge \ No newline at end of file diff --git a/src/ge/graph/passes/set_input_output_offset_pass.h b/src/ge/graph/passes/set_input_output_offset_pass.h new file mode 100644 index 00000000..24f9f6c4 --- /dev/null +++ b/src/ge/graph/passes/set_input_output_offset_pass.h @@ -0,0 +1,38 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_SET_INPUT_OUTPUT_OFFSET_PASS_H_ +#define GE_GRAPH_PASSES_SET_INPUT_OUTPUT_OFFSET_PASS_H_ + +#include "inc/graph_pass.h" + +namespace ge { +class SetInputOutputOffsetPass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph) override; + + private: + Status SetInputOffset(const NodePtr &node, const vector &connect_input); + Status SetOutputOffset(const NodePtr &node, const vector &connect_output); + Status SetInputOffsetForFusion(const std::vector &memory_type, const ge::NodePtr &node); + Status SetInputOffsetForHcom(const NodePtr &node, const vector &connect_input); + Status SetOutputOffsetForConcat(const NodePtr &node); + Status SetOutputOffsetForHcom(const NodePtr &node, const vector &connect_output); + + bool CheckBufferFusion(const NodePtr &node); +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_SET_INPUT_OUTPUT_OFFSET_PASS_H_ diff --git a/src/ge/graph/passes/subgraph_pass.cc b/src/ge/graph/passes/subgraph_pass.cc index d759aa12..80ce995a 100644 --- a/src/ge/graph/passes/subgraph_pass.cc +++ b/src/ge/graph/passes/subgraph_pass.cc @@ -15,7 +15,6 @@ */ #include "graph/passes/subgraph_pass.h" -#include #include "graph/utils/node_utils.h" #include "graph/utils/op_desc_utils.h" #include "graph/utils/tensor_utils.h" @@ -67,13 +66,13 @@ Status SubgraphPass::Run(ComputeGraphPtr graph) { /** * @ingroup ge - * @brief Check Subgraph NetOutput node + * @brief Check Subgraph Input node * @param [in] graph: ComputeGraph. - * @param [in] node: NetOutput node in Subgraph. + * @param [in] node: Data node in Subgraph. * @return: 0 for SUCCESS / others for FAILED */ Status SubgraphPass::SubgraphInputNode(const ComputeGraphPtr &graph, const NodePtr &node) { - GELOGD("Hadle input_node %s for graph %s.", node->GetName().c_str(), graph->GetName().c_str()); + GELOGD("Handle input_node %s for graph %s.", node->GetName().c_str(), graph->GetName().c_str()); // Data has and only has one output bool input_continues_required_flag = false; OutDataAnchorPtr out_data_anchor = node->GetOutDataAnchor(0); @@ -86,7 +85,7 @@ Status SubgraphPass::SubgraphInputNode(const ComputeGraphPtr &graph, const NodeP // Data->InputContinuesRequiredOp in subgraph need memcpy. if (input_continues_required_flag) { GELOGD("Data %s output_node required continues input.", node->GetName().c_str()); - std::string name = node->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); + std::string name = node->GetName() + "_output_0_Memcpy"; if (InsertMemcpyNode(graph, out_data_anchor, in_anchors, name) != SUCCESS) { GELOGE(FAILED, "Insert memcpy after %s failed.", node->GetName().c_str()); return FAILED; @@ -123,7 +122,7 @@ Status SubgraphPass::SubgraphInputNode(const ComputeGraphPtr &graph, const NodeP GE_CHECK_NOTNULL(peer_out_anchor); GELOGD("Constant input %s links to While %s.", peer_out_anchor->GetOwnerNode()->GetName().c_str(), parent_node->GetName().c_str()); - std::string name = in_node->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); + std::string name = parent_node->GetName() + "_input_" + std::to_string(in_data_anchor->GetIdx()) + "_Memcpy"; if (InsertMemcpyNode(parent_graph, peer_out_anchor, {in_data_anchor}, name) != SUCCESS) { GELOGE(FAILED, "Insert memcpy between %s and %s failed.", peer_out_anchor->GetOwnerNode()->GetName().c_str(), parent_node->GetName().c_str()); @@ -136,7 +135,7 @@ Status SubgraphPass::SubgraphInputNode(const ComputeGraphPtr &graph, const NodeP /** * @ingroup ge - * @brief Check Subgraph NetOutput node + * @brief Check Subgraph Output node * @param [in] graph: ComputeGraph. * @param [in] node: NetOutput node in Subgraph. * @return: 0 for SUCCESS / others for FAILED @@ -153,14 +152,14 @@ Status SubgraphPass::SubgraphOutputNode(const ComputeGraphPtr &graph, const Node // 1. Const->NetOutput in subgraph // 2. AtomicOp->NetOutput in subgraph // 3. OutputContinuesRequiredOp->NetOutput in subgraph - // 4. Data->NetOutput in subgraph but not while body + // 4. Data->NetOutput in subgraph but parent_node is not while std::string op_type; bool insert_flag = NodeUtils::GetConstOpType(in_node, op_type) || IsAtomicRequired(in_node, peer_out_anchor->GetIdx()) || IsOutputContinuesRequired(in_node) || - ((in_node->GetType() == DATA) && !IsWhileBodyOutput(in_data_anchor)); + ((in_node->GetType() == DATA) && (kWhileOpTypes.count(graph->GetParentNode()->GetType()) == 0)); if (insert_flag) { - GELOGI("Insert MemcpyAsync node between %s and %s.", node->GetName().c_str(), in_node->GetName().c_str()); - std::string name = in_node->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); + GELOGD("Insert MemcpyAsync node between %s and %s.", in_node->GetName().c_str(), node->GetName().c_str()); + std::string name = node->GetName() + "_input_" + std::to_string(in_data_anchor->GetIdx()) + "_Memcpy"; if (InsertMemcpyNode(graph, peer_out_anchor, {in_data_anchor}, name) != SUCCESS) { GELOGE(FAILED, "Insert memcpy between %s and %s failed.", in_node->GetName().c_str(), node->GetName().c_str()); return FAILED; @@ -186,8 +185,8 @@ Status SubgraphPass::WhileInputNodes(const ComputeGraphPtr &graph, const NodePtr GE_CHECK_NOTNULL(in_node); // Input->While and Input link to other nodes need insert memcpy if (peer_out_anchor->GetPeerInDataAnchors().size() > 1) { - GELOGI("Input %s of While %s links to other nodes.", in_node->GetName().c_str(), node->GetName().c_str()); - std::string name = in_node->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); + GELOGD("Input %s of While %s links to other nodes.", in_node->GetName().c_str(), node->GetName().c_str()); + std::string name = node->GetName() + "_input_" + std::to_string(in_data_anchor->GetIdx()) + "_Memcpy"; if (InsertMemcpyNode(graph, peer_out_anchor, {in_data_anchor}, name) != SUCCESS) { GELOGE(FAILED, "Insert memcpy between %s and %s failed.", in_node->GetName().c_str(), node->GetName().c_str()); return FAILED; @@ -206,231 +205,121 @@ Status SubgraphPass::WhileInputNodes(const ComputeGraphPtr &graph, const NodePtr * @return: 0 for SUCCESS / others for FAILED */ Status SubgraphPass::WhileBodySubgraph(const ComputeGraphPtr &graph, const NodePtr &node) { - ComputeGraphPtr while_body = GetWhileBodySubgraph(graph, node); + // index of body_subgraph is 1 + ComputeGraphPtr while_body = NodeUtils::GetSubgraph(*node, 1); if (while_body == nullptr) { GELOGE(FAILED, "while_body of %s is NULL.", node->GetName().c_str()); return FAILED; } - NodePtr output_node = while_body->FindFirstNodeMatchType(NETOUTPUT); - if (output_node == nullptr) { - GELOGE(FAILED, "net_output_node not exist in graph %s.", while_body->GetName().c_str()); - return FAILED; - } - OpDescPtr output_desc = output_node->GetOpDesc(); - GE_CHECK_NOTNULL(output_desc); - std::unordered_map> node_to_attr_index; - for (const InDataAnchorPtr &in_data_anchor : output_node->GetAllInDataAnchors()) { - uint32_t index = 0; - if (!AttrUtils::GetInt(output_desc->GetInputDesc(in_data_anchor->GetIdx()), ATTR_NAME_PARENT_NODE_INDEX, index)) { - GELOGE(FAILED, "Get attr PARENT_NODE_INDEX failed, node %s:%u.", output_node->GetName().c_str(), - in_data_anchor->GetIdx()); - return FAILED; + std::vector data_nodes; + std::set bypass_index; + NodePtr output_node = nullptr; + for (const auto &n : while_body->GetDirectNode()) { + const std::string &type = n->GetType(); + if (type == DATA) { + if (CheckInsertInputMemcpy(n, bypass_index)) { + data_nodes.emplace_back(n); + } + } else if (type == NETOUTPUT) { + if (output_node == nullptr) { + output_node = n; + } else { + GELOGE(FAILED, "while_body %s exists multi NetOutput nodes.", while_body->GetName().c_str()); + return FAILED; + } } - MarkOutputIndex(in_data_anchor->GetPeerOutAnchor(), index, node_to_attr_index); } - - std::set data_nodes; - std::set netoutput_input_indexes; - GetExchangeInOut(node_to_attr_index, data_nodes, netoutput_input_indexes); - return InsertMemcpyInWhileBody(while_body, data_nodes, output_node, netoutput_input_indexes); -} - -/** - * @ingroup ge - * @brief Get body subgraph of While op - * @param [in] graph: ComputeGraph. - * @param [in] node: While node. - * @return: body subgraph - */ -ComputeGraphPtr SubgraphPass::GetWhileBodySubgraph(const ComputeGraphPtr &graph, const NodePtr &node) { - OpDescPtr op_desc = node->GetOpDesc(); - if (op_desc == nullptr) { - GELOGE(FAILED, "op_desc is NULL."); - return nullptr; - } - - const std::vector &subgraph_instance_names = op_desc->GetSubgraphInstanceNames(); - std::string body_instance_name; - for (const std::string &instance_name : subgraph_instance_names) { - std::string subgraph_name; - if (op_desc->GetSubgraphNameByInstanceName(instance_name, subgraph_name) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Get subgraph_name by instance_name %s failed, node:%s.", instance_name.c_str(), - node->GetName().c_str()); - return nullptr; - } - if (subgraph_name == ATTR_NAME_WHILE_BODY) { - body_instance_name = instance_name; - break; - } + if (output_node == nullptr) { + GELOGE(FAILED, "while_body %s has no output.", while_body->GetName().c_str()); + return FAILED; } - ComputeGraphPtr root_graph = GraphUtils::FindRootGraph(graph); - if (root_graph == nullptr) { - GELOGE(FAILED, "root_graph is NULL."); - return nullptr; + if ((InsertInputMemcpy(while_body, data_nodes) != SUCCESS) || + (InsertOutputMemcpy(while_body, output_node, bypass_index) != SUCCESS)) { + GELOGE(FAILED, "Insert memcpy node in while_body %s failed.", while_body->GetName().c_str()); + return FAILED; } - return root_graph->GetSubgraph(body_instance_name); + return SUCCESS; } /** * @ingroup ge - * @brief Mark output parent_node_index - * @param [in] peer_out_anchor: peer_out_anchor of NetOutput - * @param [in] index: parent_node_index of NetOutput - * @param [out] node_to_attr_index: key for node in subgraph, value for parent_node_index - * @return: void + * @brief Insert input memcpy node in while_body + * @param [in] graph: while_body + * @param [in] data_nodes: data_nodes + * @return: 0 for SUCCESS / others for FAILED */ -void SubgraphPass::MarkOutputIndex(const OutDataAnchorPtr &peer_out_anchor, uint32_t index, - std::unordered_map> &node_to_attr_index) { - if (peer_out_anchor == nullptr) { - return; - } - std::set visited_nodes; - std::stack nodes; - nodes.emplace(peer_out_anchor->GetOwnerNode()); - while (!nodes.empty()) { - NodePtr cur_node = nodes.top(); - nodes.pop(); - if (visited_nodes.count(cur_node) > 0) { - continue; - } - node_to_attr_index[cur_node].emplace_back(index); - for (const NodePtr &in_node : cur_node->GetInDataNodes()) { - nodes.emplace(in_node); - } - visited_nodes.emplace(cur_node); +Status SubgraphPass::InsertInputMemcpy(const ComputeGraphPtr &graph, const std::vector &data_nodes) { + if (data_nodes.empty()) { + GELOGD("No need to insert input memcpy node in while_body %s.", graph->GetName().c_str()); + return SUCCESS; } -} - -/** - * @ingroup ge - * @brief Get data_nodes / input_indexes of netoutput if need insert memcpy - * @param [in] node_to_attr_index: key for node in subgraph, value for parent_node_index - * @param [out] data_nodes: data_nodes need insert memcpy - * @param [out] netoutput_input_indexes: input_indexes of netoutput need insert memcpy - * @return: void - */ -void SubgraphPass::GetExchangeInOut(const std::unordered_map> &node_to_attr_index, - std::set &data_nodes, std::set &netoutput_input_indexes) { - for (const auto &item : node_to_attr_index) { - NodePtr node = item.first; - uint32_t input_index = 0; - if ((node->GetType() != DATA) || !AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, input_index)) { - continue; - } - if (item.second.empty() || ((item.second.size() == 1) && (item.second[0] == input_index))) { - continue; - } - data_nodes.emplace(node); + std::string in_name = graph->GetName() + "_input_Memcpy"; + OpDescBuilder in_builder(in_name, MEMCPYASYNC); + for (size_t i = 0; i < data_nodes.size(); i++) { // Data node has and only has one output - OutDataAnchorPtr out_data_anchor = node->GetOutDataAnchor(0); - if (out_data_anchor == nullptr) { - continue; - } - for (const InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { - NodePtr out_node = peer_in_anchor->GetOwnerNode(); - if ((out_node->GetType() != NETOUTPUT) || (out_node->GetOpDesc() == nullptr)) { - continue; - } - uint32_t output_index = 0; - GeTensorDesc input_tensor = out_node->GetOpDesc()->GetInputDesc(peer_in_anchor->GetIdx()); - if (!AttrUtils::GetInt(input_tensor, ATTR_NAME_PARENT_NODE_INDEX, output_index)) { - continue; - } - if (input_index != output_index) { - netoutput_input_indexes.emplace(peer_in_anchor->GetIdx()); - } - } + in_builder.AddInput("x" + std::to_string(i), data_nodes[i]->GetOpDesc()->GetOutputDesc(0)) + .AddOutput("y" + std::to_string(i), data_nodes[i]->GetOpDesc()->GetOutputDesc(0)); } -} - -/** - * @ingroup ge - * @brief Insert memcpy node in while_body - * @param [in] graph: while_body - * @param [in] data_nodes: data_nodes need insert memcpy - * @param [in] output_node: NetOutput in while_body - * @param [in] netoutput_input_indexes: input_indexes of netoutput need insert memcpy - * @return: 0 for SUCCESS / others for FAILED - */ -Status SubgraphPass::InsertMemcpyInWhileBody(const ComputeGraphPtr &graph, const std::set &data_nodes, - const NodePtr &output_node, - const std::set &netoutput_input_indexes) { - for (const NodePtr &data_node : data_nodes) { + GELOGD("Insert memcpy after data_nodes of while_body %s.", graph->GetName().c_str()); + NodePtr in_memcpy = graph->AddNode(in_builder.Build()); + GE_CHECK_NOTNULL(in_memcpy); + for (size_t i = 0; i < data_nodes.size(); i++) { // Data node has and only has one output - OutDataAnchorPtr out_data_anchor = data_node->GetOutDataAnchor(0); + OutDataAnchorPtr out_data_anchor = data_nodes[i]->GetOutDataAnchor(0); std::vector in_anchors; for (const InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { in_anchors.emplace_back(peer_in_anchor); } - std::string name = data_node->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); - GELOGD("Insert memcpy after while_body %s input_node %s.", graph->GetName().c_str(), data_node->GetName().c_str()); - if (InsertMemcpyNode(graph, out_data_anchor, in_anchors, name) != SUCCESS) { - GELOGE(FAILED, "Insert MemcpyAsync node %s after %s failed.", name.c_str(), data_node->GetName().c_str()); - return FAILED; - } - } - - for (uint32_t index : netoutput_input_indexes) { - InDataAnchorPtr in_data_anchor = output_node->GetInDataAnchor(index); - GE_CHECK_NOTNULL(in_data_anchor); - OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(peer_out_anchor); - std::string name = - peer_out_anchor->GetOwnerNode()->GetName() + "_" + MEMCPYASYNC + "_" + std::to_string(memcpy_num_++); - GELOGD("Insert memcpy after while_body %s output %u.", graph->GetName().c_str(), index); - if (InsertMemcpyNode(graph, peer_out_anchor, {in_data_anchor}, name) != SUCCESS) { - GELOGE(FAILED, "Insert MemcpyAsync node %s after %s failed.", name.c_str(), - peer_out_anchor->GetOwnerNode()->GetName().c_str()); + if (InsertNodeBetween(out_data_anchor, in_anchors, in_memcpy, i, i) != SUCCESS) { + GELOGE(FAILED, "Insert MemcpyAsync %s in while_body %s failed.", in_name.c_str(), graph->GetName().c_str()); return FAILED; } } - std::set memcpy_nodes; - std::set loop_body_nodes; - for (const NodePtr &data_node : data_nodes) { - // data_node has only one output node - NodePtr memcpy_node = data_node->GetOutDataNodes().at(0); - GE_CHECK_NOTNULL(memcpy_node); - memcpy_nodes.emplace(memcpy_node); - for (const NodePtr &out_node : memcpy_node->GetOutDataNodes()) { - loop_body_nodes.insert(out_node); - } - } - return InsertNoOp(graph, memcpy_nodes, loop_body_nodes); + return SUCCESS; } /** * @ingroup ge - * @brief Insert NoOp node between memcpy_nodes and loop_body_nodes + * @brief Insert output memcpy node in while_body * @param [in] graph: while_body - * @param [in] memcpy_nodes - * @param [in] loop_body_nodes + * @param [in] output_node: NetOutput + * @param [in] bypass_index * @return: 0 for SUCCESS / others for FAILED */ -Status SubgraphPass::InsertNoOp(const ComputeGraphPtr &graph, const std::set &memcpy_nodes, - const std::set &loop_body_nodes) { - if (memcpy_nodes.empty() || loop_body_nodes.empty()) { +Status SubgraphPass::InsertOutputMemcpy(const ComputeGraphPtr &graph, const NodePtr &output_node, + const std::set &bypass_index) { + if (output_node->GetAllInDataAnchorsSize() == bypass_index.size()) { + GELOGD("No need to insert output memcpy node in while_body %s, output_size=%zu, bypass_num=%zu.", + graph->GetName().c_str(), output_node->GetAllInDataAnchorsSize(), bypass_index.size()); return SUCCESS; } - OpDescBuilder noop_desc_builder("NoOp_for_Control", NOOP); - OpDescPtr noop_desc = noop_desc_builder.Build(); - NodePtr noop_node = graph->AddNode(noop_desc); - GE_CHECK_NOTNULL(noop_node); - for (const NodePtr &memcpy_node : memcpy_nodes) { - if (GraphUtils::AddEdge(memcpy_node->GetOutControlAnchor(), noop_node->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Add ctrl edge %s->%s failed.", memcpy_node->GetName().c_str(), noop_node->GetName().c_str()); - return FAILED; + std::string out_name = graph->GetName() + "_output_Memcpy"; + OpDescBuilder out_builder(out_name, MEMCPYASYNC); + for (size_t i = 0; i < output_node->GetAllInDataAnchorsSize(); i++) { + if (bypass_index.count(i) == 0) { + out_builder.AddInput("x" + std::to_string(i), output_node->GetOpDesc()->GetInputDesc(i)) + .AddOutput("y" + std::to_string(i), output_node->GetOpDesc()->GetInputDesc(i)); } } - for (const NodePtr &loop_body_node : loop_body_nodes) { - if (GraphUtils::AddEdge(noop_node->GetOutControlAnchor(), loop_body_node->GetInControlAnchor()) != GRAPH_SUCCESS) { - GELOGE(FAILED, "Add ctrl edge %s->%s failed.", noop_node->GetName().c_str(), loop_body_node->GetName().c_str()); - return FAILED; + GELOGD("Insert memcpy before NetOutput of while_body %s.", graph->GetName().c_str()); + NodePtr out_memcpy = graph->AddNode(out_builder.Build()); + GE_CHECK_NOTNULL(out_memcpy); + size_t cnt = 0; + for (size_t i = 0; i < output_node->GetAllInDataAnchorsSize(); i++) { + if (bypass_index.count(i) == 0) { + InDataAnchorPtr in_data_anchor = output_node->GetInDataAnchor(i); + OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); + if (InsertNodeBetween(peer_out_anchor, {in_data_anchor}, out_memcpy, cnt, cnt) != SUCCESS) { + GELOGE(FAILED, "Insert MemcpyAsync %s in while_body %s failed.", out_name.c_str(), graph->GetName().c_str()); + return FAILED; + } + cnt++; } } @@ -439,28 +328,39 @@ Status SubgraphPass::InsertNoOp(const ComputeGraphPtr &graph, const std::setnetoutput in while body - * @param [in] in_data_anchor - * @return: true for data->netoutput in while body / for false for others + * @brief Check is data->netoutput without change in while body + * @param [in] node: data node + * @param [out] bypass_index + * @return: false for data->netoutput without change in while body / for true for others */ -bool SubgraphPass::IsWhileBodyOutput(const InDataAnchorPtr &in_data_anchor) { - // Check is subgraph - NodePtr parent_node = in_data_anchor->GetOwnerNode()->GetOwnerComputeGraph()->GetParentNode(); - if (parent_node == nullptr) { - return false; +bool SubgraphPass::CheckInsertInputMemcpy(const NodePtr &node, std::set &bypass_index) { + uint32_t input_index = 0; + if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, input_index)) { + return true; } - // Check if parent_node is While - if (kWhileOpTypes.count(parent_node->GetType()) == 0) { - return false; + // Data node has and only has one output + OutDataAnchorPtr out_data_anchor = node->GetOutDataAnchor(0); + if ((out_data_anchor == nullptr) || (out_data_anchor->GetPeerInDataAnchors().size() != 1)) { + return true; + } + InDataAnchorPtr peer_in_anchor = out_data_anchor->GetPeerInDataAnchors().at(0); + if (peer_in_anchor->GetOwnerNode()->GetType() != NETOUTPUT) { + return true; } - // While cond / body - OpDescPtr op_desc = in_data_anchor->GetOwnerNode()->GetOpDesc(); - if (op_desc == nullptr) { - return false; + OpDescPtr op_desc = peer_in_anchor->GetOwnerNode()->GetOpDesc(); + uint32_t output_index = 0; + if ((op_desc == nullptr) || + !AttrUtils::GetInt(op_desc->GetInputDesc(peer_in_anchor->GetIdx()), ATTR_NAME_PARENT_NODE_INDEX, output_index)) { + return true; } - return AttrUtils::HasAttr(op_desc->GetInputDesc(in_data_anchor->GetIdx()), ATTR_NAME_PARENT_NODE_INDEX); + + if (input_index != output_index) { + return true; + } + bypass_index.insert(peer_in_anchor->GetIdx()); + return false; } /** @@ -542,7 +442,7 @@ Status SubgraphPass::InsertMemcpyNode(const ComputeGraphPtr &graph, const OutDat OpDescPtr op_desc = op_desc_builder.AddInput("x", in_node->GetOpDesc()->GetOutputDesc(0)) .AddOutput("y", in_node->GetOpDesc()->GetOutputDesc(0)) .Build(); - if (GraphUtils::InsertNodeBefore(out_anchor, in_anchors, graph->AddNode(op_desc)) != GRAPH_SUCCESS) { + if (GraphUtils::InsertNodeAfter(out_anchor, in_anchors, graph->AddNode(op_desc)) != GRAPH_SUCCESS) { GELOGE(FAILED, "Insert MemcpyAsync node %s after %s failed.", name.c_str(), in_node->GetName().c_str()); return FAILED; } @@ -550,4 +450,33 @@ Status SubgraphPass::InsertMemcpyNode(const ComputeGraphPtr &graph, const OutDat return SUCCESS; } +/// +/// @brief Insert node: src->insert_node:input_index, insert_node:output_index->dst +/// @param [in] src +/// @param [in] dsts +/// @param [in] insert_node +/// @param [in] input_index +/// @param [in] output_index +/// @return Status +/// +Status SubgraphPass::InsertNodeBetween(const OutDataAnchorPtr &src, const std::vector &dsts, + const NodePtr &insert_node, uint32_t input_index, uint32_t output_index) { + if (GraphUtils::AddEdge(src, insert_node->GetInDataAnchor(input_index)) != GRAPH_SUCCESS) { + GELOGE(FAILED, "Add data_edge %s:%d->%s:%u failed.", src->GetOwnerNode()->GetName().c_str(), src->GetIdx(), + insert_node->GetName().c_str(), input_index); + return FAILED; + } + for (const auto &dst : dsts) { + GELOGD("Insert node %s between %s->%s.", insert_node->GetName().c_str(), src->GetOwnerNode()->GetName().c_str(), + dst->GetOwnerNode()->GetName().c_str()); + if ((GraphUtils::RemoveEdge(src, dst) != GRAPH_SUCCESS) || + (GraphUtils::AddEdge(insert_node->GetOutDataAnchor(output_index), dst) != GRAPH_SUCCESS)) { + GELOGE(FAILED, "Replace data_edge %s:%d->%s:%d by %s:%u->%s:%d failed.", src->GetOwnerNode()->GetName().c_str(), + src->GetIdx(), dst->GetOwnerNode()->GetName().c_str(), dst->GetIdx(), insert_node->GetName().c_str(), + output_index, dst->GetOwnerNode()->GetName().c_str(), dst->GetIdx()); + return FAILED; + } + } + return SUCCESS; +} } // namespace ge diff --git a/src/ge/graph/passes/subgraph_pass.h b/src/ge/graph/passes/subgraph_pass.h index 2308b1bd..7ff2019f 100644 --- a/src/ge/graph/passes/subgraph_pass.h +++ b/src/ge/graph/passes/subgraph_pass.h @@ -17,12 +17,6 @@ #ifndef GE_GRAPH_PASSES_SUBGRAPH_PASS_H_ #define GE_GRAPH_PASSES_SUBGRAPH_PASS_H_ -#include -#include -#include -#include - -#include "graph/types.h" #include "inc/graph_pass.h" namespace ge { @@ -75,65 +69,32 @@ class SubgraphPass : public GraphPass { /** * @ingroup ge - * @brief Get body subgraph of While op - * @param [in] graph: ComputeGraph. - * @param [in] node: While node. - * @return: body subgraph - */ - ComputeGraphPtr GetWhileBodySubgraph(const ComputeGraphPtr &graph, const NodePtr &node); - - /** - * @ingroup ge - * @brief Mark output parent_node_index - * @param [in] peer_out_anchor: peer_out_anchor of NetOutput - * @param [in] index: parent_node_index of NetOutput - * @param [out] node_to_attr_index: key for node in subgraph, value for parent_node_index - * @return: void - */ - void MarkOutputIndex(const OutDataAnchorPtr &peer_out_anchor, uint32_t index, - std::unordered_map> &node_to_attr_index); - - /** - * @ingroup ge - * @brief Get data_nodes / input_indexes of netoutput if need insert memcpy - * @param [in] node_to_attr_index: key for node in subgraph, value for parent_node_index - * @param [out] data_nodes: data_nodes need insert memcpy - * @param [out] netoutput_input_indexes: input_indexes of netoutput need insert memcpy - * @return: void - */ - void GetExchangeInOut(const std::unordered_map> &node_to_attr_index, - std::set &data_nodes, std::set &netoutput_input_indexes); - - /** - * @ingroup ge - * @brief Insert memcpy node in while_body + * @brief Insert input memcpy node in while_body * @param [in] graph: while_body - * @param [in] data_nodes: data_nodes need insert memcpy - * @param [in] output_node: NetOutput in while_body - * @param [in] netoutput_input_indexes: input_indexes of netoutput need insert memcpy + * @param [in] data_nodes: data_nodes * @return: 0 for SUCCESS / others for FAILED */ - Status InsertMemcpyInWhileBody(const ComputeGraphPtr &graph, const std::set &data_nodes, - const NodePtr &output_node, const std::set &netoutput_input_indexes); + Status InsertInputMemcpy(const ComputeGraphPtr &graph, const std::vector &data_nodes); /** * @ingroup ge - * @brief Insert NoOp node between memcpy_nodes and loop_body_nodes + * @brief Insert output memcpy node in while_body * @param [in] graph: while_body - * @param [in] memcpy_nodes - * @param [in] loop_body_nodes + * @param [in] output_node: NetOutput + * @param [in] bypass_index * @return: 0 for SUCCESS / others for FAILED */ - Status InsertNoOp(const ComputeGraphPtr &graph, const std::set &memcpy_nodes, - const std::set &loop_body_nodes); + Status InsertOutputMemcpy(const ComputeGraphPtr &graph, const NodePtr &output_node, + const std::set &bypass_index); /** * @ingroup ge - * @brief Check is Data->NetOutput in while body - * @param [in] in_data_anchor - * @return: true for Data->NetOutput in while body / false for others + * @brief Check is data->netoutput without change in while body + * @param [in] node: data node + * @param [out] bypass_index + * @return: false for data->netoutput without change in while body / for true for others */ - bool IsWhileBodyOutput(const InDataAnchorPtr &in_data_anchor); + bool CheckInsertInputMemcpy(const NodePtr &node, std::set &bypass_index); /** * @ingroup ge @@ -172,8 +133,17 @@ class SubgraphPass : public GraphPass { Status InsertMemcpyNode(const ComputeGraphPtr &graph, const OutDataAnchorPtr &out_anchor, const std::vector &in_anchors, const std::string &name); - // Append index for new memcpy node. - uint32_t memcpy_num_{0}; + /// + /// @brief Insert node: src->insert_node:input_index, insert_node:output_index->dst + /// @param [in] src + /// @param [in] dsts + /// @param [in] insert_node + /// @param [in] input_index + /// @param [in] output_index + /// @return Status + /// + Status InsertNodeBetween(const OutDataAnchorPtr &src, const std::vector &dsts, + const NodePtr &insert_node, uint32_t input_index, uint32_t output_index); }; } // namespace ge #endif // GE_GRAPH_PASSES_SUBGRAPH_PASS_H_ diff --git a/src/ge/graph/passes/switch_dead_branch_elimination.cc b/src/ge/graph/passes/switch_dead_branch_elimination.cc index f398d8df..dd7ace60 100644 --- a/src/ge/graph/passes/switch_dead_branch_elimination.cc +++ b/src/ge/graph/passes/switch_dead_branch_elimination.cc @@ -171,7 +171,7 @@ Status SwitchDeadBranchElimination::Run(NodePtr &node) { AddRePassNode(end_node); } for (const auto &delete_node : del_nodes) { - AddNodeDeleted(delete_node.get()); + AddNodeDeleted(delete_node); } } diff --git a/src/ge/graph/passes/switch_logic_remove_pass.cc b/src/ge/graph/passes/switch_logic_remove_pass.cc index be84a582..dafa3ae1 100644 --- a/src/ge/graph/passes/switch_logic_remove_pass.cc +++ b/src/ge/graph/passes/switch_logic_remove_pass.cc @@ -145,7 +145,7 @@ Status SwitchLogicRemovePass::RemoveSwitchNodeLogically(int parent_index, NodePt GE_CHECK_NOTNULL(node); GELOGD("Remove node %s from inactivate branch from switch %s", node->GetName().c_str(), switch_node->GetName().c_str()); - AddNodeDeleted(node.get()); + AddNodeDeleted(node); } for (auto &node : end_nodes) { GE_CHECK_NOTNULL(node); diff --git a/src/ge/graph/passes/switch_op_pass.cc b/src/ge/graph/passes/switch_op_pass.cc deleted file mode 100644 index ed3e9b36..00000000 --- a/src/ge/graph/passes/switch_op_pass.cc +++ /dev/null @@ -1,1227 +0,0 @@ -/** - * Copyright 2019-2020 Huawei Technologies 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. - */ - -#include "graph/passes/switch_op_pass.h" -#include -#include -#include -#include -#include -#include -#include -#include "common/ge/ge_util.h" -#include "framework/common/debug/ge_log.h" -#include "framework/common/debug/log.h" -#include "framework/common/ge_inner_error_codes.h" -#include "framework/common/types.h" -#include "ge/ge_api_types.h" -#include "graph/common/omg_util.h" -#include "graph/debug/ge_attr_define.h" -#include "graph/ge_context.h" -#include "graph/utils/type_utils.h" - -namespace ge { -Status SwitchOpPass::Run(ComputeGraphPtr graph) { - GELOGD("SwitchOpPass Enter"); - GE_CHK_STATUS_RET(CheckCycleDependence(graph), "CheckCycleDependence fail."); - - for (auto &switch_node : switch_nodes_) { - GE_CHK_STATUS_RET(ReplaceSwitchNode(graph, switch_node), "Add StreamSwitch node fail."); - } - - for (auto &merge_node : merge_nodes_) { - OpDescPtr merge_op_desc = merge_node->GetOpDesc(); - GE_CHECK_NOTNULL(merge_op_desc); - if (merge_op_desc->HasAttr(ATTR_INSERT_BY_MBATCH)) { - GE_CHK_STATUS_RET(AddMemcpyAsyncNodes(graph, merge_node, true), "Merge add memcpy node fail."); - GE_CHK_STATUS_RET(SetStreamLabel(merge_node, merge_node->GetName()), "Set stream label failed"); - } else { - GE_CHK_STATUS_RET(ReplaceMergeNode(graph, merge_node), "Add StreamMerge node fail."); - } - } - - GE_CHK_STATUS_RET(CombineSwitchNode(graph), "Combine StreamSwitch nodes fail."); - - for (auto &node : bypass_nodes_) { - GE_CHK_BOOL_EXEC(graph->RemoveNode(node) == GRAPH_SUCCESS, return FAILED, "Remove switch node fail."); - } - - for (auto &node : stream_switch_nodes_) { - for (auto &out_ctrl_node : node->GetOutControlNodes()) { - MarkHeadNodes(out_ctrl_node, node); - } - } - - for (auto &node : need_label_nodes_) { - OpDescPtr op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - if (!op_desc->HasAttr(ATTR_NAME_STREAM_LABEL)) { - GE_CHK_STATUS_RET(UpdateCondBranch(node), "Set cond branch fail, start node:%s", node->GetName().c_str()); - } - } - - GE_CHK_STATUS_RET(UpdateEnterNode(), "UpdateEnterNode fail."); - - GELOGD("SwitchOpPass Leave"); - return SUCCESS; -} - -/// -/// @brief Replace Switch Op -/// @param [in] graph -/// @param [in] switch_node -/// @return Status -/// -Status SwitchOpPass::ReplaceSwitchNode(ComputeGraphPtr &graph, NodePtr &switch_node) { - std::string type; - GE_CHK_STATUS_RET(GetOriginalType(switch_node, type), "Get node type fail."); - GE_CHK_BOOL_EXEC((type == SWITCH) || (type == REFSWITCH), return FAILED, "Type of input node is not switch."); - - OutDataAnchorPtr peer_data_anchor = nullptr; - OutDataAnchorPtr peer_cond_anchor = nullptr; - GE_CHK_BOOL_EXEC(BypassSwitchNode(switch_node, peer_data_anchor, peer_cond_anchor) == SUCCESS, return FAILED, - "Bypass switch node %s fail.", switch_node->GetName().c_str()); - GE_CHECK_NOTNULL(peer_data_anchor); - GE_CHECK_NOTNULL(peer_cond_anchor); - OpDescPtr cond_desc = peer_cond_anchor->GetOwnerNode()->GetOpDesc(); - GE_CHECK_NOTNULL(cond_desc); - DataType cond_data_type = cond_desc->GetOutputDesc(peer_cond_anchor->GetIdx()).GetDataType(); - GE_CHK_BOOL_EXEC(cond_data_type == DT_BOOL, return FAILED, - "SwitchNode not support datatype %s, datatype of cond_input should be bool", - TypeUtils::DataTypeToSerialString(cond_data_type).c_str()); - - OpDescPtr switch_desc = switch_node->GetOpDesc(); - GE_CHECK_NOTNULL(switch_desc); - bool cyclic_flag = switch_desc->HasAttr(ATTR_NAME_CYCLIC_DEPENDENCE_FLAG); - - std::set out_node_list; - for (OutDataAnchorPtr &out_data_anchor : switch_node->GetAllOutDataAnchors()) { - bool true_branch_flag = (static_cast(out_data_anchor->GetIdx()) == SWITCH_TRUE_OUTPUT); - NodePtr stream_switch = nullptr; - out_node_list.clear(); - for (auto &peer_in_anchor : out_data_anchor->GetPeerAnchors()) { - GE_IF_BOOL_EXEC(stream_switch == nullptr, { - std::string suffix = (true_branch_flag ? "_t" : "_f"); - stream_switch = CreateStreamSwitchNode(graph, switch_node, suffix, peer_cond_anchor); - GE_CHK_BOOL_EXEC(stream_switch != nullptr, return FAILED, "Create stream_switch node fail."); - if (SetSwitchTrueBranchFlag(stream_switch, true_branch_flag) != SUCCESS) { - GELOGE(FAILED, "SetSwitchTrueBranchFlag for node %s fail.", stream_switch->GetName().c_str()); - return FAILED; - } - if (MarkBranchs(peer_cond_anchor, stream_switch, true_branch_flag) != SUCCESS) { - GELOGE(FAILED, "MarkBranchs for stream_switch %s fail.", stream_switch->GetName().c_str()); - return FAILED; - } - - if (!cyclic_flag) { - GE_CHK_STATUS(GraphUtils::AddEdge(peer_data_anchor->GetOwnerNode()->GetOutControlAnchor(), - stream_switch->GetInControlAnchor()), - "StreamSwitch node add ctl edge fail."); - } - }); - - GE_CHK_STATUS(GraphUtils::RemoveEdge(out_data_anchor, peer_in_anchor), "Remove Switch data output fail."); - - NodePtr out_node = peer_in_anchor->GetOwnerNode(); - GE_CHK_STATUS_RET(GetOriginalType(out_node, type), "Get node type fail."); - if ((type == MERGE) || (type == REFMERGE)) { - NodePtr memcpy_node = CreateMemcpyAsyncNode(graph, peer_data_anchor, false); - GE_CHK_BOOL_EXEC(memcpy_node != nullptr, return FAILED, "Create memcpy_async node fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(peer_data_anchor, memcpy_node->GetInDataAnchor(0)), - "MemcpyAsync node add edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(memcpy_node->GetOutDataAnchor(0), peer_in_anchor), - "MemcpyAsync node add edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(stream_switch->GetOutControlAnchor(), memcpy_node->GetInControlAnchor()), - "MemcpyAsync node add ctl edge fail."); - out_node_list.insert(memcpy_node->GetName()); - } else { - GE_CHK_STATUS(GraphUtils::AddEdge(peer_data_anchor, peer_in_anchor), "StreamSwitch node add edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(stream_switch->GetOutControlAnchor(), out_node->GetInControlAnchor()), - "StreamSwitch node add ctl edge fail."); - out_node_list.insert(out_node->GetName()); - } - } - GE_IF_BOOL_EXEC(stream_switch != nullptr, { - CopyControlEdges(switch_node, stream_switch, true); - switch_node_map_[stream_switch] = out_node_list; - if (SetOriginalNodeName(stream_switch, switch_node->GetName()) != SUCCESS) { - GELOGE(FAILED, "SetOriginalNodeName for node %s fail.", stream_switch->GetName().c_str()); - return FAILED; - } - }); - } - - RemoveControlEdges(switch_node); - (void)bypass_nodes_.insert(switch_node); - - return SUCCESS; -} - -/// -/// @brief Replace Merge Op -/// @param [in] graph -/// @param [in] merge_node -/// @return Status -/// -Status SwitchOpPass::ReplaceMergeNode(ComputeGraphPtr &graph, NodePtr &merge_node) { - std::string type; - GE_CHK_STATUS_RET(GetOriginalType(merge_node, type), "Get node type fail."); - GE_CHK_BOOL_EXEC((type == MERGE) || (type == REFMERGE), return FAILED, "Type of input node is not merge."); - - OpDescPtr merge_op_desc = merge_node->GetOpDesc(); - GE_CHECK_NOTNULL(merge_op_desc); - - const std::string node_name = merge_node->GetName(); - GELOGI("Create StreamMerge Op, name=%s.", node_name.c_str()); - OpDescPtr op_desc = MakeShared(node_name, STREAMMERGE); - if (op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, StreamMerge:%s.", node_name.c_str()); - return FAILED; - } - - for (InDataAnchorPtr &in_anchor : merge_node->GetAllInDataAnchors()) { - GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(merge_op_desc->GetInputDesc(in_anchor->GetIdx())) == GRAPH_SUCCESS, - return FAILED, "Create StreamMerge op: add input desc fail."); - } - - for (OutDataAnchorPtr &out_anchor : merge_node->GetAllOutDataAnchors()) { - GE_CHK_BOOL_EXEC(op_desc->AddOutputDesc(merge_op_desc->GetOutputDesc(out_anchor->GetIdx())) == GRAPH_SUCCESS, - return FAILED, "Create StreamMerge op: add output desc fail."); - } - - NodePtr stream_merge = graph->AddNode(op_desc); - GE_CHK_BOOL_EXEC(stream_merge != nullptr, return FAILED, "Insert StreamMerge node fail."); - - for (InDataAnchorPtr &in_data_anchor : merge_node->GetAllInDataAnchors()) { - OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); - GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); - - GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor), "Remove Merge data input fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(peer_out_anchor, stream_merge->GetInDataAnchor(in_data_anchor->GetIdx())), - "StreamMerge node add edge fail."); - } - - for (OutDataAnchorPtr &out_data_anchor : merge_node->GetAllOutDataAnchors()) { - for (InDataAnchorPtr &peer_in_anchor : out_data_anchor->GetPeerInDataAnchors()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(out_data_anchor, peer_in_anchor), "Remove Merge data output fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(stream_merge->GetOutDataAnchor(out_data_anchor->GetIdx()), peer_in_anchor), - "StreamMerge node add edge fail."); - } - } - - ReplaceControlEdges(merge_node, stream_merge); - - if (merge_op_desc->HasAttr(ATTR_NAME_NEXT_ITERATION)) { - std::string next_iteration_name; - GE_IF_BOOL_EXEC(!AttrUtils::GetStr(merge_op_desc, ATTR_NAME_NEXT_ITERATION, next_iteration_name), - GELOGE(INTERNAL_ERROR, "get ATTR_NAME_NEXT_ITERATION failed"); - return INTERNAL_ERROR); - - GE_CHK_STATUS_RET(SetNextIteration(stream_merge, next_iteration_name), "set next iteration failed"); - } else { - need_label_nodes_.emplace_back(stream_merge); - } - - (void)bypass_nodes_.insert(merge_node); - - GE_CHK_STATUS_RET(AddMemcpyAsyncNodes(graph, stream_merge, false), "StreamMerge add memcpy node fail."); - - return SUCCESS; -} - -/// -/// @brief Create StreamSwitch Node -/// @param [in] graph -/// @param [in] switch_node -/// @param [in] suffix -/// @param [in] peer_cond_anchor -/// @return ge::NodePtr -/// -NodePtr SwitchOpPass::CreateStreamSwitchNode(ComputeGraphPtr &graph, const NodePtr &switch_node, - const std::string &suffix, OutDataAnchorPtr &peer_cond_anchor) { - GE_CHK_BOOL_EXEC(switch_node != nullptr, return nullptr, "Param of merge node is null."); - OpDescPtr switch_op_desc = switch_node->GetOpDesc(); - GE_CHK_BOOL_EXEC(switch_op_desc != nullptr, return nullptr, "OpDesc of Switch node is invalid."); - GE_IF_BOOL_EXEC(switch_op_desc->GetInputsSize() != SWITCH_INPUT_NUM, { - GELOGE(FAILED, "Switch input param invalid, input_size=%lu, should be %u", switch_op_desc->GetInputsSize(), - SWITCH_INPUT_NUM); - return nullptr; - }); - - const std::string node_name = switch_node->GetName() + "_" + STREAMSWITCH + suffix; - GELOGI("Create StreamSwitch, name=%s.", node_name.c_str()); - OpDescPtr op_desc = MakeShared(node_name, STREAMSWITCH); - if (op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, StreamSwitch:%s.", node_name.c_str()); - return nullptr; - } - // mark hccl group id - std::string hccl_group_id; - if (AttrUtils::GetStr(switch_node->GetOpDesc(), ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id)) { - (void)AttrUtils::SetStr(op_desc, ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id); - GELOGI("Set attr ATTR_NAME_HCCL_FUSED_GROUP for Stream_Switch%s, value is %s.", node_name.c_str(), - hccl_group_id.c_str()); - } else { - GELOGI("Can not find attr ATTR_NAME_HCCL_FUSED_GROUP for node %s.", switch_node->GetName().c_str()); - } - - if (!AttrUtils::SetInt(op_desc, ATTR_NAME_SWITCH_DATA_TYPE, RT_SWITCH_INT32) || - !AttrUtils::SetInt(op_desc, ATTR_NAME_STREAM_SWITCH_COND, (int64_t)RT_EQUAL)) { - GELOGE(INTERNAL_ERROR, "set int failed"); - return nullptr; - } - - // Already checked, first input is Variable will passed, second is condition will checked. - GeTensorDesc cond_input_desc = switch_op_desc->GetInputDesc(SWITCH_PRED_INPUT); - GeTensorDesc input_desc(GeShape(cond_input_desc.GetShape().GetDims()), cond_input_desc.GetFormat(), DT_INT32); - GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(input_desc) == GRAPH_SUCCESS, return nullptr, - "Create StreamSwitch node: add input desc fail."); - GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(input_desc) == GRAPH_SUCCESS, return nullptr, - "Create StreamSwitch node: add input desc fail."); - - NodePtr stream_switch = graph->AddNode(op_desc); - GE_CHK_BOOL_EXEC(stream_switch != nullptr, return nullptr, "Insert StreamSwitch node fail."); - - GE_CHK_STATUS(GraphUtils::AddEdge(peer_cond_anchor, stream_switch->GetInDataAnchor(0)), - "StreamSwitch node add cond edge fail."); - - return stream_switch; -} - -/// -/// @brief Add MemcpyAsync Node -/// @param [in] graph -/// @param [in] in_node -/// @param [in] multi_batch_flag -/// @return ge::NodePtr -/// -NodePtr SwitchOpPass::CreateMemcpyAsyncNode(ComputeGraphPtr &graph, const OutDataAnchorPtr &out_data_anchor, - bool multi_batch_flag) { - GE_CHK_BOOL_EXEC(out_data_anchor != nullptr, return nullptr, "Param of input node is null."); - OpDescPtr pre_op_desc = out_data_anchor->GetOwnerNode()->GetOpDesc(); - GE_CHK_BOOL_EXEC(pre_op_desc != nullptr, return nullptr, "OpDesc of pre node is invalid."); - - std::string memcpy_type = multi_batch_flag ? MEMCPYADDRASYNC : MEMCPYASYNC; - std::string node_name = pre_op_desc->GetName() + "_" + memcpy_type; - node_name = CheckDuplicateName(node_name); - GELOGI("Create MemcpyAsync op:%s.", node_name.c_str()); - OpDescPtr op_desc = MakeShared(node_name, memcpy_type); - if (op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, MemcpyAsync:%s.", node_name.c_str()); - return nullptr; - } - - GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) == GRAPH_SUCCESS, - return nullptr, "Create MemcpyAsync op: add input desc fail."); - GE_CHK_BOOL_EXEC(op_desc->AddOutputDesc(pre_op_desc->GetOutputDesc(out_data_anchor->GetIdx())) == GRAPH_SUCCESS, - return nullptr, "Create MemcpyAsync op: add output desc fail."); - - NodePtr memcpy_node = graph->AddNode(op_desc); - GE_CHK_BOOL_EXEC(memcpy_node != nullptr, return nullptr, "Insert MemcpyAsync node fail."); - - return memcpy_node; -} - -/// -/// @brief Combine switch nodes link to same cond -/// @param [in] graph -/// @return Status -/// -Status SwitchOpPass::CombineSwitchNode(ComputeGraphPtr &graph) { - for (auto iter = cond_node_map_.begin(); iter != cond_node_map_.end(); ++iter) { - for (auto group_iter = iter->second.begin(); group_iter != iter->second.end(); ++group_iter) { - OutDataAnchorPtr peer_cond_anchor = iter->first; - GE_CHECK_NOTNULL(peer_cond_anchor); - std::list false_switch_list = group_iter->second[SWITCH_FALSE_OUTPUT]; - std::list true_switch_list = group_iter->second[SWITCH_TRUE_OUTPUT]; - std::set same_cond_switch; - same_cond_switch.insert(false_switch_list.begin(), false_switch_list.end()); - same_cond_switch.insert(true_switch_list.begin(), true_switch_list.end()); - - NodePtr cond_node = peer_cond_anchor->GetOwnerNode(); - GELOGI("CombineSwitchNode: cond_node=%s", cond_node->GetName().c_str()); - - NodePtr cast_node = CreateCastOp(graph, peer_cond_anchor); - GE_CHK_BOOL_EXEC(cast_node != nullptr, return FAILED, "Create cast_node fail."); - - NodePtr active_node = CreateActiveNode(graph, cond_node); - GE_CHK_BOOL_EXEC(active_node != nullptr, return FAILED, "Create StreamActive node fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(cast_node->GetOutControlAnchor(), active_node->GetInControlAnchor()), - "StreamActive add ctl edge fail."); - if (SetActiveLabelList(active_node, {cast_node->GetName()}) != SUCCESS) { - GELOGE(FAILED, "SetActiveLabelList for node %s fail.", active_node->GetName().c_str()); - return FAILED; - } - - const std::string cond_group = cond_node->GetName(); - for (uint32_t i = 0; i < SWITCH_OUTPUT_NUM; ++i) { - bool true_branch_flag = (i == SWITCH_TRUE_OUTPUT); - std::list &switch_list = (true_branch_flag ? true_switch_list : false_switch_list); - GE_IF_BOOL_EXEC(switch_list.empty(), continue); - - // select first stream_switch - NodePtr stream_switch = switch_list.front(); - OpDescPtr switch_desc = stream_switch->GetOpDesc(); - GE_CHECK_NOTNULL(switch_desc); - std::string node_name = cond_group + "/" + STREAMSWITCH + (true_branch_flag ? "_t" : "_f"); - node_name = CheckDuplicateName(node_name); - switch_desc->SetName(node_name); - stream_switch_nodes_.emplace_back(stream_switch); - need_label_nodes_.emplace_back(stream_switch); - - // 0_input: original pred input, 1_input: constant node - GE_CHK_STATUS_RET(AddConstNode(graph, stream_switch), "Add const node fail"); - GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_cond_anchor, stream_switch->GetInDataAnchor(0)), - "StreamSwitch remove data edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(cast_node->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(0)), - "Cast add data edge fail."); - - for (NodePtr &node : switch_list) { - GE_CHECK_NOTNULL(node); - GE_IF_BOOL_EXEC(node != stream_switch, { - GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_cond_anchor, node->GetInDataAnchor(0)), - "StreamSwitch remove data edge fail."); - }); - GE_CHK_STATUS(ModifySwitchInCtlEdges(node, cast_node, same_cond_switch), "ModifySwitchInCtlEdges fail"); - GE_CHK_STATUS(ModifySwitchOutCtlEdges(node, stream_switch, active_node), "ModifySwitchOutCtlEdges fail"); - } - - GE_CHK_STATUS(GraphUtils::AddEdge(active_node->GetOutControlAnchor(), stream_switch->GetInControlAnchor()), - "StreamActive add ctl edge fail."); - } - } - } - return SUCCESS; -} - -/// -/// @brief Create Active Op -/// @param [in] graph -/// @param [in] cond_node -/// @return ge::NodePtr -/// -NodePtr SwitchOpPass::CreateActiveNode(ComputeGraphPtr &graph, NodePtr &node) { - GE_CHK_BOOL_EXEC(node != nullptr, return nullptr, "Param of pre cond_node is null."); - std::string node_name = node->GetName() + "_" + STREAMACTIVE; - node_name = CheckDuplicateName(node_name); - GELOGI("Create StreamActive op:%s.", node_name.c_str()); - OpDescPtr op_desc = MakeShared(node_name, STREAMACTIVE); - if (op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, StreamActive:%s.", node_name.c_str()); - return nullptr; - } - - NodePtr active_node = graph->AddNode(op_desc); - GE_CHK_BOOL_EXEC(active_node != nullptr, return nullptr, "Create StreamActive node fail."); - - GE_IF_BOOL_EXEC(GraphUtils::AddEdge(node->GetOutControlAnchor(), active_node->GetInControlAnchor()) != SUCCESS, - GELOGE(INTERNAL_ERROR, "add edge failed"); - return nullptr); - - GE_IF_BOOL_EXEC(SetSwitchBranchNodeLabel(active_node, node_name) != SUCCESS, - GELOGE(INTERNAL_ERROR, "set switch branch node label failed"); - return nullptr); - - return active_node; -} - -/// -/// @brief Add MemcpyAsync Op as StreamMerge in_node -/// @param [in] graph -/// @param [in] node -/// @param [in] multi_batch_flag -/// @return Status -/// -Status SwitchOpPass::AddMemcpyAsyncNodes(ComputeGraphPtr &graph, NodePtr &node, bool multi_batch_flag) { - GE_CHK_BOOL_EXEC(node != nullptr, return FAILED, "Param of pre node is null."); - for (InDataAnchorPtr &in_data_anchor : node->GetAllInDataAnchors()) { - OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); - GE_IF_BOOL_EXEC(peer_out_anchor == nullptr, continue); - NodePtr in_node = peer_out_anchor->GetOwnerNode(); - - const std::string type = in_node->GetType(); - // For WhileLoop no need memcpy & active for merge. - GE_IF_BOOL_EXEC((type == ENTER) || (type == REFENTER) || (type == NEXTITERATION) || (type == REFNEXTITERATION), - continue); - - GE_IF_BOOL_EXEC(type != MEMCPYASYNC, { - in_node = CreateMemcpyAsyncNode(graph, peer_out_anchor, multi_batch_flag); - GE_CHK_BOOL_EXEC(in_node != nullptr, return FAILED, "Create MemcpyAsync node fail."); - GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor), "MemcpyAsync node remove edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(peer_out_anchor, in_node->GetInDataAnchor(0)), - "MemcpyAsync node add edge fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(in_node->GetOutDataAnchor(0), in_data_anchor), - "MemcpyAsync node add edge fail."); - }); - - NodePtr active_node = CreateActiveNode(graph, in_node); - GE_CHK_BOOL_EXEC(active_node != nullptr, return FAILED, "Create StreamActive node fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(active_node->GetOutControlAnchor(), node->GetInControlAnchor()), - "StreamActive add ctl edge fail."); - if (SetActiveLabelList(active_node, {node->GetName()}) != SUCCESS) { - GELOGE(FAILED, "SetActiveLabelList for node %s fail.", active_node->GetName().c_str()); - return FAILED; - } - } - - return SUCCESS; -} - -/// -/// @brief Bypass Switch Node -/// @param [in] switch_node -/// @param [out] peer_data_anchor -/// @param [out] peer_cond_anchor -/// @return Status -/// -Status SwitchOpPass::BypassSwitchNode(NodePtr &switch_node, OutDataAnchorPtr &peer_data_anchor, - OutDataAnchorPtr &peer_cond_anchor) { - GE_CHK_BOOL_EXEC(switch_node != nullptr, return FAILED, "Switch_node is null."); - for (uint32_t idx = 0; idx < SWITCH_INPUT_NUM; ++idx) { - InDataAnchorPtr in_data_anchor = switch_node->GetInDataAnchor(idx); - GE_CHK_BOOL_EXEC(in_data_anchor != nullptr, return FAILED, "node[%s]Check Switch input anchor fail.", - switch_node->GetName().c_str()); - OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); - GE_CHK_BOOL_EXEC(peer_out_anchor != nullptr, return FAILED, "node[%s]Check Pre node output anchor fail.", - switch_node->GetName().c_str()); - // Remove Switch data input. - GE_CHK_STATUS_RET(GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor), "remove edge failed"); - - if (idx == SWITCH_DATA_INPUT) { - peer_data_anchor = peer_out_anchor; - } else { - if (FindSwitchCondInput(false, peer_out_anchor) != SUCCESS) { - GELOGE(FAILED, "FindSwitchCondInput fail, switch=%s", switch_node->GetName().c_str()); - return FAILED; - } - peer_cond_anchor = peer_out_anchor; - } - } - - return SUCCESS; -} - -/// -/// @brief Find Switch cond input -/// @param [in] pass_switch_flag -/// @param [out] peer_cond_anchor -/// @return Status -/// -Status SwitchOpPass::FindSwitchCondInput(bool pass_switch_flag, OutDataAnchorPtr &peer_cond_anchor) { - NodePtr tmp_node = nullptr; - string type; - bool need_pass_type = true; - while (need_pass_type) { - if (tmp_node == nullptr) { - GE_CHECK_NOTNULL(peer_cond_anchor); - tmp_node = peer_cond_anchor->GetOwnerNode(); - } else { - InDataAnchorPtr in_data_anchor = tmp_node->GetInDataAnchor(SWITCH_DATA_INPUT); - GE_CHECK_NOTNULL(in_data_anchor); - peer_cond_anchor = in_data_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(peer_cond_anchor); - tmp_node = peer_cond_anchor->GetOwnerNode(); - } - - GE_CHK_STATUS_RET(GetOriginalType(tmp_node, type), "Get node type fail"); - need_pass_type = (pass_switch_flag && ((type == SWITCH) || (type == REFSWITCH))); - } - - return SUCCESS; -} - -int64_t SwitchOpPass::GetGroupId(const NodePtr &node) { - string tailing_optimization_option; - bool is_tailing_optimization = false; - auto ret = GetContext().GetOption(OPTION_EXEC_ENABLE_TAILING_OPTIMIZATION, tailing_optimization_option); - if (ret == GRAPH_SUCCESS) { - // "1" means it's True from frontend option - is_tailing_optimization = (tailing_optimization_option == "1"); - GELOGI("Option ge.exec.isTailingOptimization is %s", tailing_optimization_option.c_str()); - } - if (!is_tailing_optimization) { - return 0; - } - - string hccl_group_id; - if (!AttrUtils::GetStr(node->GetOpDesc(), ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id)) { - GELOGI("Node is %s, can not find hccl group id", node->GetName().c_str()); - return 0; - } - auto key_index = hccl_group_id.find_last_of('_'); - auto key_num = hccl_group_id.substr(key_index + 1, hccl_group_id.length() - key_index); - GELOGI("Node is %s,Hccl group id is %s, key_num is %s", node->GetName().c_str(), hccl_group_id.c_str(), - key_num.c_str()); - int64_t num = atoi(key_num.c_str()); - if (num == 0) { - return 0; - } - GELOGI("Hccl group id is %s, group id is %ld", hccl_group_id.c_str(), num); - return num; -} - -/// -/// @brief Mark Switch Branch -/// @param [in] peer_cond_anchor -/// @param [in] stream_switch -/// @param [in] true_branch_flag -/// @return Status -/// -Status SwitchOpPass::MarkBranchs(OutDataAnchorPtr &peer_cond_anchor, NodePtr &stream_switch, bool true_branch_flag) { - uint32_t index = true_branch_flag ? SWITCH_TRUE_OUTPUT : SWITCH_FALSE_OUTPUT; - GE_CHECK_NOTNULL(stream_switch); - auto it = cond_node_map_.find(peer_cond_anchor); - if (it != cond_node_map_.end()) { - int64_t switch_group_id = GetGroupId(stream_switch); - auto switch_group_it = it->second.find(switch_group_id); - if (switch_group_it == it->second.end()) { - std::list false_node_list; - std::list true_node_list; - std::list &node_list = true_branch_flag ? true_node_list : false_node_list; - node_list.emplace_back(stream_switch); - std::vector> switch_list; - switch_list.emplace_back(false_node_list); - switch_list.emplace_back(true_node_list); - (void)it->second.emplace(switch_group_id, switch_list); - } else { - GE_IF_BOOL_EXEC(switch_group_it->second.size() != SWITCH_OUTPUT_NUM, { - GELOGE(INTERNAL_ERROR, "cond_node_map_ check size fail, node: %s", stream_switch->GetName().c_str()); - return FAILED; - }); - switch_group_it->second[index].emplace_back(stream_switch); - } - } else { - int64_t switch_group_id = GetGroupId(stream_switch); - map>> switch_group_map; - std::list false_node_list; - std::list true_node_list; - std::list &node_list = true_branch_flag ? true_node_list : false_node_list; - node_list.emplace_back(stream_switch); - std::vector> switch_list; - switch_list.emplace_back(false_node_list); - switch_list.emplace_back(true_node_list); - (void)switch_group_map.emplace(switch_group_id, switch_list); - auto result = cond_node_map_.insert( - std::pair>>>(peer_cond_anchor, switch_group_map)); - GE_IF_BOOL_EXEC(!result.second, { - GELOGE(INTERNAL_ERROR, "cond_node_map_ insert fail, node: %s", stream_switch->GetName().c_str()); - return FAILED; - }); - } - return SUCCESS; -} - -/// -/// @brief Create cast node -/// @param [in] graph -/// @param [in] peer_cond_anchor -/// @return NodePtr -/// -NodePtr SwitchOpPass::CreateCastOp(ComputeGraphPtr &graph, OutDataAnchorPtr &peer_cond_anchor) { - GE_CHK_BOOL_EXEC(peer_cond_anchor != nullptr, return nullptr, "Param of pre cond_node is null."); - OpDescPtr cond_desc = peer_cond_anchor->GetOwnerNode()->GetOpDesc(); - GE_CHK_BOOL_EXEC(cond_desc != nullptr, return nullptr, "Get cond_desc fail."); - - std::string cast_name = cond_desc->GetName() + "_" + CAST; - cast_name = CheckDuplicateName(cast_name); - GELOGI("Create cast_node: %s, input datatype:DT_BOOL, out datatype:DT_INT32", cast_name.c_str()); - OpDescPtr cast_desc = MakeShared(cast_name, CAST); - if (cast_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, Cast:%s.", cast_name.c_str()); - return nullptr; - } - if (!(AttrUtils::SetInt(cast_desc, CAST_ATTR_SRCT, (int64_t)DT_BOOL) && - AttrUtils::SetInt(cast_desc, CAST_ATTR_DSTT, (int64_t)DT_INT32) && - AttrUtils::SetInt(cast_desc, CAST_ATTR_DST_TYPE, (int64_t)DT_INT32) && - AttrUtils::SetBool(cast_desc, CAST_ATTR_TRUNCATE, false))) { - GELOGE(FAILED, "Set CAST_ATTR_SRCT or CAST_ATTR_DSTT or CAST_ATTR_DST_TYPE or CAST_ATTR_TRUNCATE fail, node: %s.", - cast_name.c_str()); - return nullptr; - } - GeTensorDesc tensor_desc = cond_desc->GetOutputDesc(peer_cond_anchor->GetIdx()); - tensor_desc.SetDataType(DT_BOOL); - GE_CHK_BOOL_EXEC(cast_desc->AddInputDesc(tensor_desc) == SUCCESS, return nullptr, "Cast_node add input desc fail."); - tensor_desc.SetDataType(DT_INT32); - GE_CHK_BOOL_EXEC(cast_desc->AddOutputDesc(tensor_desc) == SUCCESS, return nullptr, "Cast_node add output desc fail."); - - NodePtr cast_node = graph->AddNode(cast_desc); - GE_CHK_BOOL_EXEC(cast_node != nullptr, return nullptr, "Create cast_node fail."); - - GE_CHK_STATUS(GraphUtils::AddEdge(peer_cond_anchor, cast_node->GetInDataAnchor(0)), "Cast add data edge fail."); - - return cast_node; -} - -/// -/// @brief Add const node as switch input1 -/// @param [in] graph -/// @param [in] stream_switch -/// @return Status -/// -Status SwitchOpPass::AddConstNode(ComputeGraphPtr &graph, NodePtr &stream_switch) { - GE_CHK_BOOL_EXEC(stream_switch != nullptr, return FAILED, "stream_switch is null."); - OpDescPtr op_desc = stream_switch->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - bool value = false; - GE_CHK_BOOL_EXEC(AttrUtils::GetBool(op_desc, ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG, value), return FAILED, - "StreamSwitch get attr TRUE_BRANCH_STREAM fail."); - - const std::string const_node_name = op_desc->GetName() + "_Constant_" + (value ? "t" : "f"); - GELOGI("Create const op: %s", const_node_name.c_str()); - OpDescPtr const_op_desc = MakeShared(const_node_name, CONSTANT); - if (const_op_desc == nullptr) { - GELOGE(FAILED, "Create op_desc fail, Constant:%s.", const_node_name.c_str()); - return FAILED; - } - - auto resize_value = (int32_t)value; - GeTensorDesc data_desc = op_desc->GetInputDesc(1); - GeTensorPtr const_value = - MakeShared(data_desc, reinterpret_cast(&resize_value), sizeof(int32_t)); - if (const_value == nullptr) { - GELOGE(FAILED, "Create tensor fail."); - return FAILED; - } - GE_CHK_BOOL_EXEC(AttrUtils::SetTensor(const_op_desc, ATTR_NAME_WEIGHTS, const_value), return FAILED); - GE_CHK_BOOL_EXEC(const_op_desc->AddOutputDesc(data_desc) == GRAPH_SUCCESS, return FAILED, - "Create Const op: add output desc fail."); - - NodePtr const_node = graph->AddNode(const_op_desc); - GE_CHK_BOOL_EXEC(const_node != nullptr, return FAILED, "Insert Const node fail."); - GE_CHK_STATUS(GraphUtils::AddEdge(const_node->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(1)), - "StreamSwitch node add ctl edge fail."); - - return SUCCESS; -} - -/// -/// @brief update cond branch -/// @param [in] node -/// @return Status -/// -Status SwitchOpPass::UpdateCondBranch(NodePtr &node) { - std::string stream_label; - std::unordered_set branch_nodes; - std::unordered_set handled_set; - std::stack nodes; - nodes.push(node); - - static const std::set end_type_set = {STREAMSWITCH, STREAMMERGE, MERGE}; - bool merge_flag = false; - bool exit_flag = false; - bool net_output_flag = false; - - while (!nodes.empty()) { - NodePtr cur_node = nodes.top(); - nodes.pop(); - if (handled_set.count(cur_node) > 0) { - continue; - } - GE_CHECK_NOTNULL(cur_node); - if (UpdateAttachFlag(cur_node, stream_label, merge_flag, exit_flag, net_output_flag) != SUCCESS) { - GELOGE(FAILED, "UpdateAttachFlag fail, cur_node: %s.", cur_node->GetName().c_str()); - return FAILED; - } - - const std::string type = cur_node->GetType(); - for (auto &out_node : cur_node->GetOutAllNodes()) { - const std::string out_type = out_node->GetType(); - bool stop_flag = (end_type_set.count(out_type) > 0) || - ((branch_head_nodes_.count(out_node) > 0) && (branch_head_nodes_[out_node] != node)) || - (((type == ENTER) || (type == REFENTER)) && (out_type != STREAMACTIVE)); - if (!stop_flag) { - nodes.push(out_node); - GELOGD("branch_nodes insert %s", out_node->GetName().c_str()); - branch_nodes.insert(out_node); - } - } - handled_set.insert(cur_node); - } - - if (node->GetType() == STREAMSWITCH) { - GE_CHK_STATUS_RET(SetActiveLabelList(node, {stream_label}), "set active_label_list failed"); - } - - bool attach_flag = (merge_flag || exit_flag) && net_output_flag; - if (attach_flag) { - GELOGI("No need to keep on attaching label."); - return SUCCESS; - } - - for (NodePtr tmp_node : branch_nodes) { - GELOGD("Attach label %s to node: %s", stream_label.c_str(), tmp_node->GetName().c_str()); - GE_CHK_STATUS_RET(SetStreamLabel(tmp_node, stream_label), "set stream label failed"); - } - - return SUCCESS; -} - -/// -/// @brief update attach flag -/// @param [in] node -/// @param [out] stream_label -/// @param [out] merge_flag -/// @param [out] exit_flag -/// @param [out] net_output_flag -/// @return Status -/// -Status SwitchOpPass::UpdateAttachFlag(const NodePtr &node, std::string &stream_label, bool &merge_flag, bool &exit_flag, - bool &net_output_flag) { - const std::string type = node->GetType(); - if (type == STREAMSWITCH) { - if (node->GetInDataNodes().empty()) { - GELOGE(INTERNAL_ERROR, "cur_node %s has no input_data_node", node->GetName().c_str()); - return INTERNAL_ERROR; - } - stream_label = node->GetInDataNodes().at(0)->GetName(); - GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "set stream label failed"); - bool value = false; - OpDescPtr op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - GE_CHK_BOOL_EXEC(AttrUtils::GetBool(op_desc, ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG, value), return FAILED, - "StreamSwitch get attr TRUE_BRANCH_STREAM fail."); - stream_label += (value ? "_t" : "_f"); - } else if (type == STREAMMERGE) { - stream_label = node->GetName(); - GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "set stream label failed"); - merge_flag = true; - } else if ((type == EXIT) || (type == REFEXIT)) { - GE_CHK_STATUS_RET(SetStreamLabel(node, stream_label), "set stream label failed"); - exit_flag = true; - } else if (type == NETOUTPUT) { - net_output_flag = true; - } - - return SUCCESS; -} - -/// -/// @brief update loop branch -/// @param [in] enter_nodes -/// @param [in] stream_label -/// @return Status -/// -Status SwitchOpPass::UpdateLoopBranch(const std::stack &enter_nodes, const std::string &stream_label) { - std::stack nodes(enter_nodes); - NodePtr cur_node = nullptr; - while (!nodes.empty()) { - cur_node = nodes.top(); - nodes.pop(); - for (NodePtr &out_node : cur_node->GetOutAllNodes()) { - OpDescPtr out_desc = out_node->GetOpDesc(); - GE_CHECK_NOTNULL(out_desc); - if (out_desc->HasAttr(ATTR_NAME_STREAM_LABEL)) { - continue; - } - GELOGD("Attach label %s to node: %s", stream_label.c_str(), out_node->GetName().c_str()); - GE_CHK_STATUS_RET(SetStreamLabel(out_node, stream_label), "set stream label failed"); - nodes.push(out_node); - } - } - - return SUCCESS; -} - -/// -/// @brief update enter nodes -/// @return Status -/// -Status SwitchOpPass::UpdateEnterNode() { - std::unordered_map> enter_active_map; - for (auto &enter_node : enter_nodes_) { - for (auto &out_ctrl_node : enter_node->GetOutControlNodes()) { - if (out_ctrl_node->GetType() != STREAMACTIVE) { - continue; - } - auto iter = enter_active_map.find(out_ctrl_node); - if (iter == enter_active_map.end()) { - enter_active_map[out_ctrl_node] = {enter_node}; - } else { - iter->second.emplace_back(enter_node); - } - } - } - - for (auto &pair : enter_active_map) { - std::string stream_label; - NodePtr active_node = pair.first; - GE_CHECK_NOTNULL(active_node); - OpDescPtr active_desc = active_node->GetOpDesc(); - GE_CHECK_NOTNULL(active_desc); - (void)AttrUtils::GetStr(active_desc, ATTR_NAME_STREAM_LABEL, stream_label); - if (stream_label.empty()) { - stream_label = active_desc->GetName(); - GE_CHK_STATUS_RET(SetStreamLabel(active_node, stream_label), "set stream label failed"); - } - std::stack enter_nodes; - for (auto &enter_node : pair.second) { - GE_CHK_STATUS_RET(SetStreamLabel(enter_node, stream_label), "set stream label failed"); - enter_nodes.emplace(enter_node); - } - - std::vector active_label_list; - if (!AttrUtils::GetListStr(active_desc, ATTR_NAME_ACTIVE_LABEL_LIST, active_label_list) || - (active_label_list.size() != 1) || active_label_list[0].empty()) { - GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ACTIVE_LABEL_LIST fail, node: %s", active_desc->GetName().c_str()); - return INTERNAL_ERROR; - } - if (UpdateLoopBranch(enter_nodes, active_label_list[0]) != SUCCESS) { - GELOGE(FAILED, "UpdateLoopBranch fail."); - return FAILED; - } - } - - return SUCCESS; -} - -/// -/// @brief Check duplicate node_name -/// @param [in] node_name -/// @return std::string -/// -std::string SwitchOpPass::CheckDuplicateName(const std::string &node_name) { - std::string tmp_name = node_name; - auto iter = node_num_map_.find(tmp_name); - if (iter != node_num_map_.end()) { - tmp_name = tmp_name + "_" + std::to_string(iter->second); - (iter->second)++; - } else { - node_num_map_[tmp_name] = 1; - } - return tmp_name; -} - -/// -/// @brief Check cyclic dependence -/// @param [in] graph -/// @return Status -/// -Status SwitchOpPass::CheckCycleDependence(ComputeGraphPtr &graph) { - std::string type; - std::unordered_map> cond_switch_map; - for (NodePtr &node : graph->GetDirectNode()) { - GE_CHK_STATUS_RET(GetOriginalType(node, type), "Get node type fail"); - if ((type == SWITCH) || (type == REFSWITCH)) { - InDataAnchorPtr in_cond_anchor = node->GetInDataAnchor(SWITCH_PRED_INPUT); - GE_CHK_BOOL_EXEC(in_cond_anchor != nullptr, return INTERNAL_ERROR, "Check Switch in_cond_anchor fail."); - OutDataAnchorPtr peer_out_anchor = in_cond_anchor->GetPeerOutAnchor(); - GE_CHK_BOOL_EXEC(peer_out_anchor != nullptr, return INTERNAL_ERROR, "Check Switch peer_out_anchor fail."); - if (FindSwitchCondInput(true, peer_out_anchor) != SUCCESS) { - GELOGE(FAILED, "FindSwitchCondInput fail, switch=%s", node->GetName().c_str()); - return FAILED; - } - - NodePtr cond_node = peer_out_anchor->GetOwnerNode(); - auto iter = cond_switch_map.find(cond_node); - if (iter == cond_switch_map.end()) { - cond_switch_map[cond_node] = {node}; - } else { - iter->second.emplace_back(node); - } - - switch_nodes_.emplace_back(node); - } else if ((type == MERGE) || (type == REFMERGE)) { - merge_nodes_.emplace_back(node); - } else if ((type == ENTER) || (type == REFENTER)) { - enter_nodes_.emplace_back(node); - } - } - - MarkCycleDependence(cond_switch_map); - - return SUCCESS; -} - -/// -/// @brief Mark cyclic dependence -/// @param [in] graph -/// @param [in] cond_switch_map -/// @return void -/// -void SwitchOpPass::MarkCycleDependence(const std::unordered_map> &cond_switch_map) { - std::stack out_nodes; - NodePtr tmp_node = nullptr; - std::unordered_set handled_set; - for (auto &iter : cond_switch_map) { - std::set switch_nodes(iter.second.begin(), iter.second.end()); - for (auto &switch_node : switch_nodes) { - GE_CHECK_NOTNULL_JUST_RETURN(switch_node); - GELOGD("CheckCycleDependence: cond_node=%s, switch=%s", iter.first->GetName().c_str(), - switch_node->GetName().c_str()); - for (const NodePtr &node : switch_node->GetOutAllNodes()) { - out_nodes.push(node); - } - } - handled_set.clear(); - while (!out_nodes.empty()) { - tmp_node = out_nodes.top(); - GE_CHECK_NOTNULL_JUST_RETURN(tmp_node); - out_nodes.pop(); - if (handled_set.count(tmp_node) > 0) { - continue; - } - GELOGD("CheckCycleDependence: tmp_node=%s", tmp_node->GetName().c_str()); - for (NodePtr &out_node : tmp_node->GetOutAllNodes()) { - if (switch_nodes.find(out_node) == switch_nodes.end()) { - out_nodes.push(out_node); - continue; - } - GE_IF_BOOL_EXEC(SetCyclicDependenceFlag(out_node) != SUCCESS, GELOGW("set cyclic dependence failed"); return ); - auto map_iter = switch_cyclic_map_.find(out_node); - if (map_iter == switch_cyclic_map_.end()) { - switch_cyclic_map_[out_node] = {tmp_node->GetName()}; - } else { - map_iter->second.insert(tmp_node->GetName()); - } - } - handled_set.insert(tmp_node); - } - } - - return; -} - -/// -/// @brief Modify in ctl edge for switch_node -/// @param [in] switch_node -/// @param [in] cast_node -/// @param [in] same_cond_switch -/// @return Status -/// -Status SwitchOpPass::ModifySwitchInCtlEdges(NodePtr &switch_node, NodePtr &cast_node, - const std::set &same_cond_switch) { - GE_CHECK_NOTNULL(switch_node); - GE_CHECK_NOTNULL(cast_node); - GELOGI("ModifySwitchInCtlEdges: switch_node=%s, active_node=%s", switch_node->GetName().c_str(), - cast_node->GetName().c_str()); - - std::string orig_switch_name = switch_node->GetName(); - OpDescPtr switch_desc = switch_node->GetOpDesc(); - GE_CHECK_NOTNULL(switch_desc); - if (!AttrUtils::GetStr(switch_desc, ATTR_NAME_ORIG_NODE_NAME, orig_switch_name) || orig_switch_name.empty()) { - GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ORIG_NODE_NAME fail, node: %s", switch_desc->GetName().c_str()); - return INTERNAL_ERROR; - } - - for (NodePtr &in_ctl_node : switch_node->GetInControlNodes()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(in_ctl_node->GetOutControlAnchor(), switch_node->GetInControlAnchor()), - "Remove ctl edge fail."); - GE_IF_BOOL_EXEC(!in_ctl_node->GetOutControlAnchor()->IsLinkedWith(cast_node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(in_ctl_node->GetOutControlAnchor(), cast_node->GetInControlAnchor()), - "Add ctl edge fail."); - }); - - GE_IF_BOOL_EXEC(in_ctl_node->GetType() != STREAMSWITCH, continue); - if (same_cond_switch.count(in_ctl_node) > 0) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(in_ctl_node->GetOutControlAnchor(), cast_node->GetInControlAnchor()), - "Remove ctl edge fail."); - continue; - } - auto find_res1 = switch_node_map_.find(in_ctl_node); - GE_IF_BOOL_EXEC(find_res1 == switch_node_map_.end(), { - GELOGE(INTERNAL_ERROR, "StreamSwitch node %s not found in switch_node_map_.", in_ctl_node->GetName().c_str()); - return INTERNAL_ERROR; - }); - auto find_res2 = find_res1->second.find(orig_switch_name); - auto find_res3 = find_res1->second.find(cast_node->GetName()); - GE_IF_BOOL_EXEC((find_res2 != find_res1->second.end()) && (find_res3 == find_res1->second.end()), { - find_res1->second.erase(find_res2); - find_res1->second.insert(cast_node->GetName()); - continue; - }); - } - - return SUCCESS; -} - -/// -/// @brief Modify out ctl edge for switch_node -/// @param [in] switch_node -/// @param [in] stream_switch -/// @param [in] active_node -/// @return Status -/// -Status SwitchOpPass::ModifySwitchOutCtlEdges(NodePtr &switch_node, NodePtr &stream_switch, NodePtr &active_node) { - GE_CHECK_NOTNULL(switch_node); - GE_CHECK_NOTNULL(stream_switch); - GE_CHECK_NOTNULL(active_node); - GELOGI("ModifySwitchOutCtlEdges: switch_node=%s, stream_switch=%s, active_node=%s", switch_node->GetName().c_str(), - stream_switch->GetName().c_str(), active_node->GetName().c_str()); - auto find_res = switch_node_map_.find(switch_node); - GE_IF_BOOL_EXEC(find_res == switch_node_map_.end(), { - GELOGE(INTERNAL_ERROR, "StreamSwitch node %s not found in switch_node_map_.", switch_node->GetName().c_str()); - return INTERNAL_ERROR; - }); - GE_IF_BOOL_EXEC(find_res->second.empty(), { - GELOGE(INTERNAL_ERROR, "true_nodes of StreamSwitch node %s is empty.", switch_node->GetName().c_str()); - return INTERNAL_ERROR; - }); - - for (NodePtr &node : switch_node->GetOutControlNodes()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(switch_node->GetOutControlAnchor(), node->GetInControlAnchor()), - "Remove ctl edge fail."); - OpDescPtr op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - std::string orig_name = op_desc->GetName(); - GE_IF_BOOL_EXEC(op_desc->HasAttr(ATTR_NAME_ORIG_NODE_NAME), { - if (!AttrUtils::GetStr(op_desc, ATTR_NAME_ORIG_NODE_NAME, orig_name) || orig_name.empty()) { - GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ORIG_NODE_NAME fail, node: %s.", op_desc->GetName().c_str()); - return INTERNAL_ERROR; - } - }); - if (find_res->second.find(orig_name) == find_res->second.end()) { - auto active_out_control_anchor = active_node->GetOutControlAnchor(); - GE_CHECK_NOTNULL(active_out_control_anchor); - GE_IF_BOOL_EXEC(!active_out_control_anchor->IsLinkedWith(node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(active_out_control_anchor, node->GetInControlAnchor()), "Add ctl edge fail."); - }); - } else { - auto stream_switch_out_control_anchor = stream_switch->GetOutControlAnchor(); - GE_CHECK_NOTNULL(stream_switch_out_control_anchor); - GE_IF_BOOL_EXEC(!stream_switch_out_control_anchor->IsLinkedWith(node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(stream_switch_out_control_anchor, node->GetInControlAnchor()), - "Add ctl edge fail."); - }); - } - } - - GE_IF_BOOL_EXEC(switch_node != stream_switch, (void)bypass_nodes_.insert(switch_node)); - - return SUCCESS; -} - -/// -/// @brief Copy Control Edges -/// @param [in] old_node -/// @param [in] new_node -/// @param [in] input_check_flag -/// @return void -/// -void SwitchOpPass::CopyControlEdges(NodePtr &old_node, NodePtr &new_node, bool input_check_flag) { - GE_CHECK_NOTNULL_JUST_RETURN(old_node); - GE_CHECK_NOTNULL_JUST_RETURN(new_node); - GE_IF_BOOL_EXEC(old_node == new_node, return ); - auto iter = switch_cyclic_map_.find(old_node); - bool check_flag = input_check_flag && (iter != switch_cyclic_map_.end()); - for (NodePtr &node : old_node->GetInControlNodes()) { - if (check_flag && (iter->second.count(node->GetName()) > 0)) { - for (auto &out_node : old_node->GetOutAllNodes()) { - auto out_control_anchor = node->GetOutControlAnchor(); - GE_CHECK_NOTNULL_JUST_RETURN(out_control_anchor); - GE_IF_BOOL_EXEC(!out_control_anchor->IsLinkedWith(out_node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(out_control_anchor, out_node->GetInControlAnchor()), "Add ctl edge fail."); - }); - } - } else { - auto out_control_anchor = node->GetOutControlAnchor(); - GE_CHECK_NOTNULL_JUST_RETURN(out_control_anchor); - GE_IF_BOOL_EXEC(!out_control_anchor->IsLinkedWith(new_node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(out_control_anchor, new_node->GetInControlAnchor()), "Add in ctl edge fail."); - }); - } - } - - for (NodePtr &node : old_node->GetOutControlNodes()) { - GE_IF_BOOL_EXEC(!new_node->GetOutControlAnchor()->IsLinkedWith(node->GetInControlAnchor()), { - GE_CHK_STATUS(GraphUtils::AddEdge(new_node->GetOutControlAnchor(), node->GetInControlAnchor()), - "Add out ctl edge fail."); - }); - } -} - -/// -/// @brief Remove Control Edges -/// @param [in] node -/// @return void -/// -void SwitchOpPass::RemoveControlEdges(NodePtr &node) { - GE_CHECK_NOTNULL_JUST_RETURN(node); - for (NodePtr &in_node : node->GetInControlNodes()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(in_node->GetOutControlAnchor(), node->GetInControlAnchor()), - "Remove in ctl edge fail."); - } - - for (auto &out_data_anchor : node->GetAllOutDataAnchors()) { - for (auto &in_ctrl_anchor : out_data_anchor->GetPeerInControlAnchors()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(out_data_anchor, in_ctrl_anchor), "Remove in ctl edge fail."); - } - } - - auto out_control_anchor = node->GetOutControlAnchor(); - GE_CHECK_NOTNULL_JUST_RETURN(out_control_anchor); - for (auto &peer_anchor : out_control_anchor->GetPeerAnchors()) { - GE_CHK_STATUS(GraphUtils::RemoveEdge(out_control_anchor, peer_anchor), "Remove out ctl edge fail."); - } -} - -/// -/// @brief Replace Control Edges -/// @param [in] old_node -/// @param [in] new_node -/// @return void -/// -void SwitchOpPass::ReplaceControlEdges(NodePtr &old_node, NodePtr &new_node) { - GE_IF_BOOL_EXEC(old_node == new_node, return ); - CopyControlEdges(old_node, new_node); - RemoveControlEdges(old_node); -} - -/// -/// @brief Mark node as head_node of stream_switch -/// @param [in] node -/// @param [in] stream_switch -/// @return void -/// -void SwitchOpPass::MarkHeadNodes(const NodePtr &node, const NodePtr &stream_switch) { - std::stack nodes; - nodes.push(node); - std::set visited; - while (!nodes.empty()) { - NodePtr cur_node = nodes.top(); - nodes.pop(); - if (visited.count(cur_node) > 0) { - continue; - } - GELOGD("branch_head_node %s of stream_switch %s", cur_node->GetName().c_str(), stream_switch->GetName().c_str()); - branch_head_nodes_[cur_node] = stream_switch; - if ((cur_node->GetType() == IDENTITY) || (cur_node->GetType() == IDENTITYN)) { - for (auto &out_node : cur_node->GetOutAllNodes()) { - nodes.push(out_node); - } - } - visited.insert(cur_node); - } -} - -/// -/// @brief Clear Status, uesd for subgraph pass -/// @return -/// -Status SwitchOpPass::ClearStatus() { - switch_nodes_.clear(); - merge_nodes_.clear(); - enter_nodes_.clear(); - switch_cyclic_map_.clear(); - bypass_nodes_.clear(); - branch_head_nodes_.clear(); - stream_switch_nodes_.clear(); - need_label_nodes_.clear(); - cond_node_map_.clear(); - switch_node_map_.clear(); - node_num_map_.clear(); - return SUCCESS; -} -} // namespace ge diff --git a/src/ge/graph/passes/switch_to_stream_switch_pass.cc b/src/ge/graph/passes/switch_to_stream_switch_pass.cc new file mode 100644 index 00000000..ef8879dd --- /dev/null +++ b/src/ge/graph/passes/switch_to_stream_switch_pass.cc @@ -0,0 +1,755 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "graph/passes/switch_to_stream_switch_pass.h" +#include +#include "common/ge/ge_util.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/debug/log.h" +#include "framework/common/ge_inner_error_codes.h" +#include "framework/common/types.h" +#include "ge/ge_api_types.h" +#include "graph/common/omg_util.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/ge_context.h" +#include "graph/utils/type_utils.h" + +namespace ge { +Status SwitchToStreamSwitchPass::Run(ComputeGraphPtr graph) { + GELOGD("SwitchToStreamSwitchPass Enter"); + + GE_CHK_STATUS_RET(CheckCycleDependence(graph), "Check cyclic dependence failed."); + for (const auto &switch_node : switch_nodes_) { + GE_CHK_STATUS_RET(ReplaceSwitchNode(graph, switch_node), "Replace Switch by StreamSwitch failed."); + } + GE_CHK_STATUS_RET(CombineSwitchNode(graph), "Combine StreamSwitch nodes failed."); + + for (const auto &node : bypass_nodes_) { + GE_CHK_BOOL_EXEC(graph->IsolateNode(node) == GRAPH_SUCCESS, return FAILED, "Isolate node failed."); + GE_CHK_BOOL_EXEC(GraphUtils::RemoveNodeWithoutRelink(graph, node) == GRAPH_SUCCESS, return FAILED, + "Remove switch node failed."); + } + + GELOGD("SwitchToStreamSwitchPass Leave"); + return SUCCESS; +} + +/// +/// @brief Clear Status, used for subgraph pass +/// @return +/// +Status SwitchToStreamSwitchPass::ClearStatus() { + switch_nodes_.clear(); + switch_cyclic_map_.clear(); + bypass_nodes_.clear(); + stream_switch_nodes_.clear(); + cond_node_map_.clear(); + switch_node_map_.clear(); + node_num_map_.clear(); + return SUCCESS; +} + +/// +/// @brief Check cyclic dependence +/// @param [in] graph +/// @return Status +/// +Status SwitchToStreamSwitchPass::CheckCycleDependence(const ComputeGraphPtr &graph) { + std::string type; + std::unordered_map> cond_switch_map; + for (const NodePtr &node : graph->GetDirectNode()) { + GE_CHK_STATUS_RET(GetOriginalType(node, type), "Get node type failed."); + if ((type == SWITCH) || (type == REFSWITCH)) { + InDataAnchorPtr in_cond_anchor = node->GetInDataAnchor(SWITCH_PRED_INPUT); + GE_CHECK_NOTNULL(in_cond_anchor); + OutDataAnchorPtr peer_out_anchor = in_cond_anchor->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(peer_out_anchor); + if (FindSwitchCondInput(true, peer_out_anchor) != SUCCESS) { + GELOGE(FAILED, "Find pred_input for switch_node %s failed.", node->GetName().c_str()); + return FAILED; + } + + NodePtr cond_node = peer_out_anchor->GetOwnerNode(); + auto iter = cond_switch_map.find(cond_node); + if (iter == cond_switch_map.end()) { + cond_switch_map[cond_node] = {node}; + } else { + iter->second.emplace_back(node); + } + switch_nodes_.emplace_back(node); + } + } + + MarkCycleDependence(cond_switch_map); + return SUCCESS; +} + +/// +/// @brief Mark cyclic dependence +/// @param [in] graph +/// @param [in] cond_switch_map +/// @return void +/// +void SwitchToStreamSwitchPass::MarkCycleDependence( + const std::unordered_map> &cond_switch_map) { + std::stack out_nodes; + NodePtr tmp_node = nullptr; + std::unordered_set visited; + for (const auto &iter : cond_switch_map) { + std::set switch_nodes(iter.second.begin(), iter.second.end()); + for (const auto &switch_node : switch_nodes) { + GELOGD("MarkCycleDependence: cond_node=%s, switch=%s.", iter.first->GetName().c_str(), + switch_node->GetName().c_str()); + for (const auto &node : switch_node->GetOutAllNodes()) { + out_nodes.push(node); + } + } + visited.clear(); + while (!out_nodes.empty()) { + tmp_node = out_nodes.top(); + out_nodes.pop(); + if (visited.count(tmp_node) > 0) { + continue; + } + GELOGD("MarkCycleDependence: tmp_node=%s.", tmp_node->GetName().c_str()); + for (const NodePtr &out_node : tmp_node->GetOutAllNodes()) { + if (switch_nodes.find(out_node) == switch_nodes.end()) { + out_nodes.push(out_node); + continue; + } + GE_IF_BOOL_EXEC(SetCyclicDependenceFlag(out_node) != SUCCESS, GELOGW("set cyclic dependence attr failed."); + return ); + auto map_iter = switch_cyclic_map_.find(out_node); + if (map_iter == switch_cyclic_map_.end()) { + switch_cyclic_map_[out_node] = {tmp_node->GetName()}; + } else { + map_iter->second.insert(tmp_node->GetName()); + } + } + visited.insert(tmp_node); + } + } + + return; +} + +/// +/// @brief Replace Switch Op +/// @param [in] graph +/// @param [in] switch_node +/// @return Status +/// +Status SwitchToStreamSwitchPass::ReplaceSwitchNode(const ComputeGraphPtr &graph, const NodePtr &switch_node) { + OutDataAnchorPtr peer_data_anchor = nullptr; + OutDataAnchorPtr peer_cond_anchor = nullptr; + GE_CHK_BOOL_EXEC(BypassSwitchNode(switch_node, peer_data_anchor, peer_cond_anchor) == SUCCESS, return FAILED, + "Bypass switch node %s failed.", switch_node->GetName().c_str()); + GE_CHECK_NOTNULL(peer_data_anchor); + GE_CHECK_NOTNULL(peer_cond_anchor); + OpDescPtr cond_desc = peer_cond_anchor->GetOwnerNode()->GetOpDesc(); + GE_CHECK_NOTNULL(cond_desc); + DataType cond_data_type = cond_desc->GetOutputDesc(peer_cond_anchor->GetIdx()).GetDataType(); + GE_CHK_BOOL_EXEC(cond_data_type == DT_BOOL, return FAILED, + "pred_input of Switch only support DT_BOOL data_type, but %s exactly.", + TypeUtils::DataTypeToSerialString(cond_data_type).c_str()); + + OpDescPtr switch_desc = switch_node->GetOpDesc(); + GE_CHECK_NOTNULL(switch_desc); + bool cyclic_flag = switch_desc->HasAttr(ATTR_NAME_CYCLIC_DEPENDENCE_FLAG); + std::set out_node_list; + for (const auto &out_data_anchor : switch_node->GetAllOutDataAnchors()) { + bool true_branch_flag = (static_cast(out_data_anchor->GetIdx()) == SWITCH_TRUE_OUTPUT); + NodePtr stream_switch = nullptr; + out_node_list.clear(); + for (const auto &peer_in_anchor : out_data_anchor->GetPeerAnchors()) { + GE_IF_BOOL_EXEC(stream_switch == nullptr, { + stream_switch = CreateStreamSwitchNode(graph, switch_node, true_branch_flag ? "_t" : "_f", peer_cond_anchor); + GE_CHK_BOOL_EXEC(stream_switch != nullptr, return FAILED, "Create stream_switch node failed."); + if (SetSwitchTrueBranchFlag(stream_switch, true_branch_flag) != SUCCESS) { + GELOGE(FAILED, "SetSwitchTrueBranchFlag for node %s failed.", stream_switch->GetName().c_str()); + return FAILED; + } + if (MarkBranches(peer_cond_anchor, stream_switch, true_branch_flag) != SUCCESS) { + GELOGE(FAILED, "Mark branches for stream_switch %s failed.", stream_switch->GetName().c_str()); + return FAILED; + } + + if (!cyclic_flag) { + GE_CHK_STATUS(GraphUtils::AddEdge(peer_data_anchor->GetOwnerNode()->GetOutControlAnchor(), + stream_switch->GetInControlAnchor()), + "StreamSwitch node add ctl edge failed."); + } + }); + + GE_CHK_STATUS(GraphUtils::RemoveEdge(out_data_anchor, peer_in_anchor), "Remove Switch data output failed."); + + NodePtr out_node = peer_in_anchor->GetOwnerNode(); + GE_CHK_STATUS(GraphUtils::AddEdge(peer_data_anchor, peer_in_anchor), "StreamSwitch node add edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(stream_switch->GetOutControlAnchor(), out_node->GetInControlAnchor()), + "StreamSwitch node add ctl edge failed."); + out_node_list.insert(out_node->GetName()); + } + + GE_IF_BOOL_EXEC(stream_switch != nullptr, { + MoveCtrlEdges(switch_node, stream_switch); + switch_node_map_[stream_switch] = out_node_list; + if (SetOriginalNodeName(stream_switch, switch_node->GetName()) != SUCCESS) { + GELOGE(FAILED, "SetOriginalNodeName for node %s failed.", stream_switch->GetName().c_str()); + return FAILED; + } + }); + } + + (void)bypass_nodes_.insert(switch_node); + return SUCCESS; +} + +/// +/// @brief Bypass Switch Node +/// @param [in] switch_node +/// @param [out] peer_data_anchor +/// @param [out] peer_cond_anchor +/// @return Status +/// +Status SwitchToStreamSwitchPass::BypassSwitchNode(const NodePtr &switch_node, OutDataAnchorPtr &peer_data_anchor, + OutDataAnchorPtr &peer_cond_anchor) { + for (uint32_t idx = 0; idx < SWITCH_INPUT_NUM; ++idx) { + InDataAnchorPtr in_data_anchor = switch_node->GetInDataAnchor(idx); + GE_CHECK_NOTNULL(in_data_anchor); + OutDataAnchorPtr peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(peer_out_anchor); + // Remove Switch data input. + if (GraphUtils::RemoveEdge(peer_out_anchor, in_data_anchor) != GRAPH_SUCCESS) { + GELOGE(FAILED, "Remove data edge %s->%s failed.", peer_out_anchor->GetOwnerNode()->GetName().c_str(), + switch_node->GetName().c_str()); + return FAILED; + } + + if (idx == SWITCH_DATA_INPUT) { + peer_data_anchor = peer_out_anchor; + } else { + if (FindSwitchCondInput(false, peer_out_anchor) != SUCCESS) { + GELOGE(FAILED, "Find pred_input for switch_node %s failed.", switch_node->GetName().c_str()); + return FAILED; + } + peer_cond_anchor = peer_out_anchor; + } + } + + return SUCCESS; +} + +/// +/// @brief Find Switch cond input +/// @param [in] pass_switch_flag +/// @param [out] peer_cond_anchor +/// @return Status +/// +Status SwitchToStreamSwitchPass::FindSwitchCondInput(bool pass_switch_flag, OutDataAnchorPtr &peer_cond_anchor) { + NodePtr tmp_node = nullptr; + string type; + bool need_pass_type = true; + while (need_pass_type) { + if (tmp_node == nullptr) { + tmp_node = peer_cond_anchor->GetOwnerNode(); + } else { + InDataAnchorPtr in_data_anchor = tmp_node->GetInDataAnchor(SWITCH_DATA_INPUT); + GE_CHECK_NOTNULL(in_data_anchor); + peer_cond_anchor = in_data_anchor->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(peer_cond_anchor); + tmp_node = peer_cond_anchor->GetOwnerNode(); + } + + GE_CHK_STATUS_RET(GetOriginalType(tmp_node, type), "Get node type failed."); + need_pass_type = (pass_switch_flag && ((type == SWITCH) || (type == REFSWITCH))); + } + + return SUCCESS; +} + +/// +/// @brief Create StreamSwitch Node +/// @param [in] graph +/// @param [in] switch_node +/// @param [in] suffix +/// @param [in] peer_cond_anchor +/// @return ge::NodePtr +/// +NodePtr SwitchToStreamSwitchPass::CreateStreamSwitchNode(const ComputeGraphPtr &graph, const NodePtr &switch_node, + const std::string &suffix, + const OutDataAnchorPtr &peer_cond_anchor) { + OpDescPtr switch_op_desc = switch_node->GetOpDesc(); + GE_CHK_BOOL_EXEC(switch_op_desc != nullptr, return nullptr, "OpDesc of Switch node is invalid."); + GE_IF_BOOL_EXEC(switch_op_desc->GetInputsSize() != SWITCH_INPUT_NUM, { + GELOGE(FAILED, "Switch input param invalid, input_size=%lu, should be %u.", switch_op_desc->GetInputsSize(), + SWITCH_INPUT_NUM); + return nullptr; + }); + + const std::string &node_name = switch_node->GetName() + "_" + STREAMSWITCH + suffix; + GELOGI("Create StreamSwitch, name=%s.", node_name.c_str()); + OpDescPtr op_desc = MakeShared(node_name, STREAMSWITCH); + if (op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, StreamSwitch:%s.", node_name.c_str()); + return nullptr; + } + + // mark hccl group id + std::string hccl_group_id; + if (AttrUtils::GetStr(switch_node->GetOpDesc(), ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id)) { + (void)AttrUtils::SetStr(op_desc, ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id); + GELOGD("Set attr ATTR_NAME_HCCL_FUSED_GROUP for Stream_Switch %s, value is %s.", node_name.c_str(), + hccl_group_id.c_str()); + } + + if (!AttrUtils::SetInt(op_desc, ATTR_NAME_SWITCH_DATA_TYPE, RT_SWITCH_INT32) || + !AttrUtils::SetInt(op_desc, ATTR_NAME_STREAM_SWITCH_COND, (int64_t)RT_EQUAL)) { + GELOGE(INTERNAL_ERROR, "set int failed"); + return nullptr; + } + + // Already checked, first input is Variable will passed, second is condition will checked. + GeTensorDesc cond_input_desc = switch_op_desc->GetInputDesc(SWITCH_PRED_INPUT); + GeTensorDesc input_desc(GeShape(cond_input_desc.GetShape().GetDims()), cond_input_desc.GetFormat(), DT_INT32); + GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(input_desc) == GRAPH_SUCCESS, return nullptr, + "Create StreamSwitch node: add input desc failed."); + GE_CHK_BOOL_EXEC(op_desc->AddInputDesc(input_desc) == GRAPH_SUCCESS, return nullptr, + "Create StreamSwitch node: add input desc failed."); + + NodePtr stream_switch = graph->AddNode(op_desc); + GE_CHK_BOOL_EXEC(stream_switch != nullptr, return nullptr, "Insert StreamSwitch node failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(peer_cond_anchor, stream_switch->GetInDataAnchor(0)), + "StreamSwitch node add cond edge failed."); + + return stream_switch; +} + +/// +/// @brief Mark Switch Branch +/// @param [in] peer_cond_anchor +/// @param [in] stream_switch +/// @param [in] true_branch_flag +/// @return Status +/// +Status SwitchToStreamSwitchPass::MarkBranches(const OutDataAnchorPtr &peer_cond_anchor, const NodePtr &stream_switch, + bool true_branch_flag) { + uint32_t index = true_branch_flag ? SWITCH_TRUE_OUTPUT : SWITCH_FALSE_OUTPUT; + auto it = cond_node_map_.find(peer_cond_anchor); + if (it != cond_node_map_.end()) { + int64_t switch_group_id = GetGroupId(stream_switch); + auto switch_group_it = it->second.find(switch_group_id); + if (switch_group_it == it->second.end()) { + std::list false_node_list; + std::list true_node_list; + std::list &node_list = true_branch_flag ? true_node_list : false_node_list; + node_list.emplace_back(stream_switch); + std::vector> switch_list; + switch_list.emplace_back(false_node_list); + switch_list.emplace_back(true_node_list); + it->second[switch_group_id] = switch_list; + } else { + GE_IF_BOOL_EXEC(switch_group_it->second.size() != SWITCH_OUTPUT_NUM, { + GELOGE(INTERNAL_ERROR, "Check size failed, node: %s", stream_switch->GetName().c_str()); + return FAILED; + }); + switch_group_it->second[index].emplace_back(stream_switch); + } + } else { + int64_t switch_group_id = GetGroupId(stream_switch); + map>> switch_group_map; + std::list false_node_list; + std::list true_node_list; + std::list &node_list = true_branch_flag ? true_node_list : false_node_list; + node_list.emplace_back(stream_switch); + std::vector> switch_list; + switch_list.emplace_back(false_node_list); + switch_list.emplace_back(true_node_list); + switch_group_map[switch_group_id] = switch_list; + cond_node_map_[peer_cond_anchor] = switch_group_map; + } + return SUCCESS; +} + +/// +/// @brief Get group_id for switch_node +/// @param [in] node +/// @return group_id +/// +int64_t SwitchToStreamSwitchPass::GetGroupId(const NodePtr &node) { + string tailing_optimization_option; + bool is_tailing_optimization = false; + if (GetContext().GetOption(OPTION_EXEC_ENABLE_TAILING_OPTIMIZATION, tailing_optimization_option) == GRAPH_SUCCESS) { + // "1" means it's True from frontend option + is_tailing_optimization = (tailing_optimization_option == "1"); + GELOGI("Option ge.exec.isTailingOptimization is %s", tailing_optimization_option.c_str()); + } + if (!is_tailing_optimization) { + return 0; + } + + string hccl_group_id; + if (!AttrUtils::GetStr(node->GetOpDesc(), ATTR_NAME_HCCL_FUSED_GROUP, hccl_group_id)) { + GELOGI("Node %s can not find hccl group id.", node->GetName().c_str()); + return 0; + } + auto key_index = hccl_group_id.find_last_of('_'); + auto key_num = hccl_group_id.substr(key_index + 1, hccl_group_id.length() - key_index); + GELOGI("Node:%s, hccl_group_id=%s, key_num=%s", node->GetName().c_str(), hccl_group_id.c_str(), key_num.c_str()); + int64_t num = atoi(key_num.c_str()); + if (num == 0) { + return 0; + } + + GELOGI("Hccl_group_id is %s, group_id is %ld", hccl_group_id.c_str(), num); + return num; +} + +/// +/// @brief Combine switch nodes link to same cond +/// @param [in] graph +/// @return Status +/// +Status SwitchToStreamSwitchPass::CombineSwitchNode(const ComputeGraphPtr &graph) { + for (auto iter = cond_node_map_.begin(); iter != cond_node_map_.end(); ++iter) { + for (auto group_iter = iter->second.begin(); group_iter != iter->second.end(); ++group_iter) { + std::list false_switch_list = group_iter->second[SWITCH_FALSE_OUTPUT]; + std::list true_switch_list = group_iter->second[SWITCH_TRUE_OUTPUT]; + std::set same_cond_switch; + same_cond_switch.insert(false_switch_list.begin(), false_switch_list.end()); + same_cond_switch.insert(true_switch_list.begin(), true_switch_list.end()); + + OutDataAnchorPtr peer_cond_anchor = iter->first; + NodePtr cond_node = peer_cond_anchor->GetOwnerNode(); + GELOGI("CombineSwitchNode: cond_node=%s.", cond_node->GetName().c_str()); + + NodePtr cast_node = CreateCastOp(graph, peer_cond_anchor); + GE_CHK_BOOL_EXEC(cast_node != nullptr, return FAILED, "Create cast_node failed."); + + NodePtr active_node = CreateActiveNode(graph, cond_node); + GE_CHK_BOOL_EXEC(active_node != nullptr, return FAILED, "Create StreamActive node failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(cast_node->GetOutControlAnchor(), active_node->GetInControlAnchor()), + "StreamActive add ctl edge failed."); + if (SetActiveLabelList(active_node, {cast_node->GetName()}) != SUCCESS) { + GELOGE(FAILED, "Set active_label_list attr for node %s failed.", active_node->GetName().c_str()); + return FAILED; + } + + const std::string &cond_group = cond_node->GetName(); + for (uint32_t i = 0; i < SWITCH_OUTPUT_NUM; ++i) { + bool true_branch_flag = (i == SWITCH_TRUE_OUTPUT); + std::list &switch_list = (true_branch_flag ? true_switch_list : false_switch_list); + GE_IF_BOOL_EXEC(switch_list.empty(), continue); + + // select first stream_switch + NodePtr stream_switch = switch_list.front(); + OpDescPtr switch_desc = stream_switch->GetOpDesc(); + GE_CHECK_NOTNULL(switch_desc); + switch_desc->SetName(CheckDuplicateName(cond_group + "/" + STREAMSWITCH + (true_branch_flag ? "_t" : "_f"))); + stream_switch_nodes_.emplace_back(stream_switch); + + // 0_input: original pred input, 1_input: constant node + GE_CHK_STATUS_RET(AddConstNode(graph, stream_switch), "Add const node failed."); + GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_cond_anchor, stream_switch->GetInDataAnchor(0)), + "StreamSwitch remove data edge failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(cast_node->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(0)), + "Cast add data edge failed."); + + for (const NodePtr &node : switch_list) { + GE_IF_BOOL_EXEC(node != stream_switch, { + GE_CHK_STATUS(GraphUtils::RemoveEdge(peer_cond_anchor, node->GetInDataAnchor(0)), + "StreamSwitch remove data edge failed."); + }); + GE_CHK_STATUS(ModifySwitchInCtlEdges(node, cast_node, same_cond_switch), "ModifySwitchInCtlEdges failed."); + GE_CHK_STATUS(ModifySwitchOutCtlEdges(node, stream_switch, active_node), "ModifySwitchOutCtlEdges failed."); + } + + GE_CHK_STATUS(GraphUtils::AddEdge(active_node->GetOutControlAnchor(), stream_switch->GetInControlAnchor()), + "StreamActive add ctl edge failed."); + } + } + } + return SUCCESS; +} + +/// +/// @brief Create Active Op +/// @param [in] graph +/// @param [in] cond_node +/// @return ge::NodePtr +/// +NodePtr SwitchToStreamSwitchPass::CreateActiveNode(const ComputeGraphPtr &graph, const NodePtr &node) { + const std::string &node_name = CheckDuplicateName(node->GetName() + "_" + STREAMACTIVE); + GELOGI("Create StreamActive op:%s.", node_name.c_str()); + OpDescPtr op_desc = MakeShared(node_name, STREAMACTIVE); + if (op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, StreamActive:%s.", node_name.c_str()); + return nullptr; + } + + NodePtr active_node = graph->AddNode(op_desc); + GE_CHK_BOOL_EXEC(active_node != nullptr, return nullptr, "Create StreamActive node failed."); + + GE_IF_BOOL_EXEC(GraphUtils::AddEdge(node->GetOutControlAnchor(), active_node->GetInControlAnchor()) != SUCCESS, + GELOGE(INTERNAL_ERROR, "add edge failed"); + return nullptr); + + GE_IF_BOOL_EXEC(SetSwitchBranchNodeLabel(active_node, node_name) != SUCCESS, + GELOGE(INTERNAL_ERROR, "set switch branch node label failed"); + return nullptr); + + return active_node; +} + +/// +/// @brief Create cast node +/// @param [in] graph +/// @param [in] peer_cond_anchor +/// @return NodePtr +/// +NodePtr SwitchToStreamSwitchPass::CreateCastOp(const ComputeGraphPtr &graph, const OutDataAnchorPtr &peer_cond_anchor) { + OpDescPtr cond_desc = peer_cond_anchor->GetOwnerNode()->GetOpDesc(); + GE_CHK_BOOL_EXEC(cond_desc != nullptr, return nullptr, "Get cond_desc failed."); + + const std::string &cast_name = CheckDuplicateName(cond_desc->GetName() + "_" + CAST); + GELOGI("Create cast_node: %s, input datatype:DT_BOOL, out datatype:DT_INT32", cast_name.c_str()); + OpDescPtr cast_desc = MakeShared(cast_name, CAST); + if (cast_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, Cast:%s.", cast_name.c_str()); + return nullptr; + } + if (!(AttrUtils::SetInt(cast_desc, CAST_ATTR_SRCT, (int64_t)DT_BOOL) && + AttrUtils::SetInt(cast_desc, CAST_ATTR_DSTT, (int64_t)DT_INT32) && + AttrUtils::SetInt(cast_desc, CAST_ATTR_DST_TYPE, (int64_t)DT_INT32) && + AttrUtils::SetBool(cast_desc, CAST_ATTR_TRUNCATE, false))) { + GELOGE(FAILED, "Set CAST_ATTR_SRCT or CAST_ATTR_DSTT or CAST_ATTR_DST_TYPE or CAST_ATTR_TRUNCATE failed, node: %s.", + cast_name.c_str()); + return nullptr; + } + + GeTensorDesc tensor_desc = cond_desc->GetOutputDesc(peer_cond_anchor->GetIdx()); + tensor_desc.SetDataType(DT_BOOL); + GE_CHK_BOOL_EXEC(cast_desc->AddInputDesc(tensor_desc) == SUCCESS, return nullptr, "Cast_node add input desc failed."); + tensor_desc.SetDataType(DT_INT32); + GE_CHK_BOOL_EXEC(cast_desc->AddOutputDesc(tensor_desc) == SUCCESS, return nullptr, + "Cast_node add output desc failed."); + + NodePtr cast_node = graph->AddNode(cast_desc); + GE_CHK_BOOL_EXEC(cast_node != nullptr, return nullptr, "Create cast_node failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(peer_cond_anchor, cast_node->GetInDataAnchor(0)), "Cast add data edge failed."); + + return cast_node; +} + +/// +/// @brief Add const node as switch input1 +/// @param [in] graph +/// @param [in] stream_switch +/// @return Status +/// +Status SwitchToStreamSwitchPass::AddConstNode(const ComputeGraphPtr &graph, const NodePtr &stream_switch) { + OpDescPtr op_desc = stream_switch->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + bool value = false; + GE_CHK_BOOL_EXEC(AttrUtils::GetBool(op_desc, ATTR_NAME_SWITCH_TRUE_BRANCH_FLAG, value), return FAILED, + "StreamSwitch get attr TRUE_BRANCH_STREAM failed."); + + const std::string &const_node_name = op_desc->GetName() + "_Constant_" + (value ? "t" : "f"); + GELOGI("Create const op: %s", const_node_name.c_str()); + OpDescPtr const_op_desc = MakeShared(const_node_name, CONSTANT); + if (const_op_desc == nullptr) { + GELOGE(FAILED, "Create op_desc failed, Constant:%s.", const_node_name.c_str()); + return FAILED; + } + + auto resize_value = (int32_t)value; + GeTensorDesc data_desc = op_desc->GetInputDesc(1); + GeTensorPtr const_value = + MakeShared(data_desc, reinterpret_cast(&resize_value), sizeof(int32_t)); + if (const_value == nullptr) { + GELOGE(FAILED, "Create tensor failed."); + return FAILED; + } + GE_CHK_BOOL_EXEC(AttrUtils::SetTensor(const_op_desc, ATTR_NAME_WEIGHTS, const_value), return FAILED); + GE_CHK_BOOL_EXEC(const_op_desc->AddOutputDesc(data_desc) == GRAPH_SUCCESS, return FAILED, + "Create Const op: add output desc failed."); + + NodePtr const_node = graph->AddNode(const_op_desc); + GE_CHK_BOOL_EXEC(const_node != nullptr, return FAILED, "Insert Const node failed."); + GE_CHK_STATUS(GraphUtils::AddEdge(const_node->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(1)), + "StreamSwitch node add ctl edge failed."); + + return SUCCESS; +} + +/// +/// @brief Modify in ctl edge for switch_node +/// @param [in] switch_node +/// @param [in] cast_node +/// @param [in] same_cond_switch +/// @return Status +/// +Status SwitchToStreamSwitchPass::ModifySwitchInCtlEdges(const NodePtr &switch_node, const NodePtr &cast_node, + const std::set &same_cond_switch) { + GELOGI("ModifySwitchInCtlEdges: switch_node=%s, active_node=%s", switch_node->GetName().c_str(), + cast_node->GetName().c_str()); + std::string orig_switch_name = switch_node->GetName(); + OpDescPtr switch_desc = switch_node->GetOpDesc(); + GE_CHECK_NOTNULL(switch_desc); + if (!AttrUtils::GetStr(switch_desc, ATTR_NAME_ORIG_NODE_NAME, orig_switch_name) || orig_switch_name.empty()) { + GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ORIG_NODE_NAME failed, node: %s", switch_desc->GetName().c_str()); + return INTERNAL_ERROR; + } + + for (const NodePtr &in_ctl_node : switch_node->GetInControlNodes()) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(in_ctl_node->GetOutControlAnchor(), switch_node->GetInControlAnchor()), + "Remove ctl edge failed."); + GE_IF_BOOL_EXEC(!in_ctl_node->GetOutControlAnchor()->IsLinkedWith(cast_node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(in_ctl_node->GetOutControlAnchor(), cast_node->GetInControlAnchor()), + "Add ctl edge failed."); + }); + + GE_IF_BOOL_EXEC(in_ctl_node->GetType() != STREAMSWITCH, continue); + if (same_cond_switch.count(in_ctl_node) > 0) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(in_ctl_node->GetOutControlAnchor(), cast_node->GetInControlAnchor()), + "Remove ctl edge failed."); + continue; + } + + auto find_res1 = switch_node_map_.find(in_ctl_node); + GE_IF_BOOL_EXEC(find_res1 == switch_node_map_.end(), { + GELOGE(INTERNAL_ERROR, "StreamSwitch node %s not found in switch_node_map_.", in_ctl_node->GetName().c_str()); + return INTERNAL_ERROR; + }); + auto find_res2 = find_res1->second.find(orig_switch_name); + auto find_res3 = find_res1->second.find(cast_node->GetName()); + GE_IF_BOOL_EXEC((find_res2 != find_res1->second.end()) && (find_res3 == find_res1->second.end()), { + find_res1->second.erase(find_res2); + find_res1->second.insert(cast_node->GetName()); + continue; + }); + } + + return SUCCESS; +} + +/// +/// @brief Modify out ctl edge for switch_node +/// @param [in] switch_node +/// @param [in] stream_switch +/// @param [in] active_node +/// @return Status +/// +Status SwitchToStreamSwitchPass::ModifySwitchOutCtlEdges(const NodePtr &switch_node, const NodePtr &stream_switch, + const NodePtr &active_node) { + GELOGI("ModifySwitchOutCtlEdges: switch_node=%s, stream_switch=%s, active_node=%s", switch_node->GetName().c_str(), + stream_switch->GetName().c_str(), active_node->GetName().c_str()); + auto find_res = switch_node_map_.find(switch_node); + GE_IF_BOOL_EXEC(find_res == switch_node_map_.end(), { + GELOGE(INTERNAL_ERROR, "StreamSwitch node %s not found in switch_node_map_.", switch_node->GetName().c_str()); + return INTERNAL_ERROR; + }); + GE_IF_BOOL_EXEC(find_res->second.empty(), { + GELOGE(INTERNAL_ERROR, "true_nodes of StreamSwitch node %s is empty.", switch_node->GetName().c_str()); + return INTERNAL_ERROR; + }); + + for (const NodePtr &node : switch_node->GetOutControlNodes()) { + GE_CHK_STATUS(GraphUtils::RemoveEdge(switch_node->GetOutControlAnchor(), node->GetInControlAnchor()), + "Remove ctl edge failed."); + OpDescPtr op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + std::string orig_name = op_desc->GetName(); + GE_IF_BOOL_EXEC(op_desc->HasAttr(ATTR_NAME_ORIG_NODE_NAME), { + if (!AttrUtils::GetStr(op_desc, ATTR_NAME_ORIG_NODE_NAME, orig_name) || orig_name.empty()) { + GELOGE(INTERNAL_ERROR, "Get attr ATTR_NAME_ORIG_NODE_NAME failed, node: %s.", op_desc->GetName().c_str()); + return INTERNAL_ERROR; + } + }); + if (find_res->second.find(orig_name) == find_res->second.end()) { + auto active_out_ctrl_anchor = active_node->GetOutControlAnchor(); + GE_CHECK_NOTNULL(active_out_ctrl_anchor); + GE_IF_BOOL_EXEC(!active_out_ctrl_anchor->IsLinkedWith(node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(active_out_ctrl_anchor, node->GetInControlAnchor()), "Add ctl edge failed."); + }); + } else { + auto switch_out_ctrl_anchor = stream_switch->GetOutControlAnchor(); + GE_CHECK_NOTNULL(switch_out_ctrl_anchor); + GE_IF_BOOL_EXEC(!switch_out_ctrl_anchor->IsLinkedWith(node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(switch_out_ctrl_anchor, node->GetInControlAnchor()), "Add ctl edge failed."); + }); + } + } + + GE_IF_BOOL_EXEC(switch_node != stream_switch, (void)bypass_nodes_.insert(switch_node)); + return SUCCESS; +} + +/// +/// @brief Check duplicate node_name +/// @param [in] node_name +/// @return std::string +/// +std::string SwitchToStreamSwitchPass::CheckDuplicateName(const std::string &node_name) { + std::string tmp_name = node_name; + auto iter = node_num_map_.find(tmp_name); + if (iter != node_num_map_.end()) { + tmp_name = tmp_name + "_" + std::to_string(iter->second); + (iter->second)++; + } else { + node_num_map_[tmp_name] = 1; + } + return tmp_name; +} + +/// +/// @brief Move Control Edges +/// @param [in] old_node +/// @param [in] new_node +/// @return void +/// +void SwitchToStreamSwitchPass::MoveCtrlEdges(const NodePtr &old_node, const NodePtr &new_node) { + GE_IF_BOOL_EXEC(old_node == new_node, return ); + auto iter = switch_cyclic_map_.find(old_node); + bool check_flag = (iter != switch_cyclic_map_.end()); + for (const NodePtr &in_node : old_node->GetInControlNodes()) { + auto out_ctrl_anchor = in_node->GetOutControlAnchor(); + GE_CHECK_NOTNULL_JUST_RETURN(out_ctrl_anchor); + if (check_flag && (iter->second.count(in_node->GetName()) > 0)) { + for (const auto &out_node : old_node->GetOutAllNodes()) { + GE_IF_BOOL_EXEC(!out_ctrl_anchor->IsLinkedWith(out_node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(out_ctrl_anchor, out_node->GetInControlAnchor()), + "Add in ctrl edge failed."); + }); + } + } else { + GE_IF_BOOL_EXEC(!out_ctrl_anchor->IsLinkedWith(new_node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(out_ctrl_anchor, new_node->GetInControlAnchor()), "Add in ctrl edge failed."); + }); + } + GE_CHK_STATUS(GraphUtils::RemoveEdge(out_ctrl_anchor, old_node->GetInControlAnchor()), + "Remove in ctrl edge failed."); + } + + for (const NodePtr &out_node : old_node->GetOutControlNodes()) { + GE_IF_BOOL_EXEC(!new_node->GetOutControlAnchor()->IsLinkedWith(out_node->GetInControlAnchor()), { + GE_CHK_STATUS(GraphUtils::AddEdge(new_node->GetOutControlAnchor(), out_node->GetInControlAnchor()), + "Add out ctrl edge failed."); + }); + GE_CHK_STATUS(GraphUtils::RemoveEdge(old_node->GetOutControlAnchor(), out_node->GetInControlAnchor()), + "Remove out ctrl edge failed."); + } +} +} // namespace ge diff --git a/src/ge/graph/passes/switch_op_pass.h b/src/ge/graph/passes/switch_to_stream_switch_pass.h similarity index 61% rename from src/ge/graph/passes/switch_op_pass.h rename to src/ge/graph/passes/switch_to_stream_switch_pass.h index 202b919c..15fe9dce 100644 --- a/src/ge/graph/passes/switch_op_pass.h +++ b/src/ge/graph/passes/switch_to_stream_switch_pass.h @@ -14,15 +14,9 @@ * limitations under the License. */ -#ifndef GE_GRAPH_PASSES_SWITCH_OP_PASS_H_ -#define GE_GRAPH_PASSES_SWITCH_OP_PASS_H_ - -#include -#include -#include -#include -#include -#include +#ifndef GE_GRAPH_PASSES_SWITCH_TO_STREAM_SWITCH_PASS_H_ +#define GE_GRAPH_PASSES_SWITCH_TO_STREAM_SWITCH_PASS_H_ + #include "inc/graph_pass.h" namespace ge { @@ -91,78 +85,158 @@ namespace ge { +-----------+ +-----------+ +-----------+ +-----| Less |----+ +-----------+ */ -class SwitchOpPass : public GraphPass { +class SwitchToStreamSwitchPass : public GraphPass { public: Status Run(ComputeGraphPtr graph); + + /// + /// @brief Clear Status, used for subgraph pass + /// @return + /// Status ClearStatus() override; private: - Status ReplaceSwitchNode(ComputeGraphPtr &graph, NodePtr &switch_node); - - Status ReplaceMergeNode(ComputeGraphPtr &graph, NodePtr &merge_node); - - NodePtr CreateStreamSwitchNode(ComputeGraphPtr &graph, const NodePtr &switch_node, const std::string &suffix, - OutDataAnchorPtr &peer_cond_anchor); - - NodePtr CreateMemcpyAsyncNode(ComputeGraphPtr &graph, const OutDataAnchorPtr &out_data_anchor, bool multi_batch_flag); - - Status CombineSwitchNode(ComputeGraphPtr &graph); - - NodePtr CreateActiveNode(ComputeGraphPtr &graph, NodePtr &node); - - Status AddMemcpyAsyncNodes(ComputeGraphPtr &graph, NodePtr &stream_merge_node, bool multi_batch_flag); - - Status BypassSwitchNode(NodePtr &switch_node, OutDataAnchorPtr &peer_data_anchor, OutDataAnchorPtr &peer_cond_anchor); + /// + /// @brief Check cyclic dependence + /// @param [in] graph + /// @return Status + /// + Status CheckCycleDependence(const ComputeGraphPtr &graph); + + /// + /// @brief Mark cyclic dependence + /// @param [in] graph + /// @param [in] cond_switch_map + /// @return void + /// + void MarkCycleDependence(const std::unordered_map> &cond_switch_map); + /// + /// @brief Replace Switch Op + /// @param [in] graph + /// @param [in] switch_node + /// @return Status + /// + Status ReplaceSwitchNode(const ComputeGraphPtr &graph, const NodePtr &switch_node); + + /// + /// @brief Bypass Switch Node + /// @param [in] switch_node + /// @param [out] peer_data_anchor + /// @param [out] peer_cond_anchor + /// @return Status + /// + Status BypassSwitchNode(const NodePtr &switch_node, OutDataAnchorPtr &peer_data_anchor, + OutDataAnchorPtr &peer_cond_anchor); + + /// + /// @brief Find Switch cond input + /// @param [in] pass_switch_flag + /// @param [out] peer_cond_anchor + /// @return Status + /// Status FindSwitchCondInput(bool pass_switch_flag, OutDataAnchorPtr &peer_cond_anchor); - Status MarkBranchs(OutDataAnchorPtr &peer_cond_anchor, NodePtr &stream_switch_node, bool true_branch_flag); - - NodePtr CreateCastOp(ComputeGraphPtr &graph, OutDataAnchorPtr &peer_cond_anchor); - - Status AddConstNode(ComputeGraphPtr &graph, NodePtr &stream_switch_node); - - Status UpdateCondBranch(NodePtr &node); - - Status UpdateAttachFlag(const NodePtr &node, std::string &stream_label, bool &merge_flag, bool &exit_flag, - bool &net_output_flag); - - Status UpdateLoopBranch(const std::stack &enter_nodes, const std::string &stream_label); - - Status UpdateEnterNode(); + /// + /// @brief Create StreamSwitch Node + /// @param [in] graph + /// @param [in] switch_node + /// @param [in] suffix + /// @param [in] peer_cond_anchor + /// @return ge::NodePtr + /// + NodePtr CreateStreamSwitchNode(const ComputeGraphPtr &graph, const NodePtr &switch_node, const std::string &suffix, + const OutDataAnchorPtr &peer_cond_anchor); + + /// + /// @brief Mark Switch Branch + /// @param [in] peer_cond_anchor + /// @param [in] stream_switch + /// @param [in] true_branch_flag + /// @return Status + /// + Status MarkBranches(const OutDataAnchorPtr &peer_cond_anchor, const NodePtr &stream_switch_node, + bool true_branch_flag); + + /// + /// @brief Get group_id for switch_node + /// @param [in] node + /// @return group_id + /// + int64_t GetGroupId(const NodePtr &node); + /// + /// @brief Combine switch nodes link to same cond + /// @param [in] graph + /// @return Status + /// + Status CombineSwitchNode(const ComputeGraphPtr &graph); + + /// + /// @brief Create cast node + /// @param [in] graph + /// @param [in] peer_cond_anchor + /// @return NodePtr + /// + NodePtr CreateCastOp(const ComputeGraphPtr &graph, const OutDataAnchorPtr &peer_cond_anchor); + + /// + /// @brief Create Active Op + /// @param [in] graph + /// @param [in] cond_node + /// @return ge::NodePtr + /// + NodePtr CreateActiveNode(const ComputeGraphPtr &graph, const NodePtr &node); + + /// + /// @brief Add const node as switch input1 + /// @param [in] graph + /// @param [in] stream_switch + /// @return Status + /// + Status AddConstNode(const ComputeGraphPtr &graph, const NodePtr &stream_switch_node); + + /// + /// @brief Modify in ctl edge for switch_node + /// @param [in] switch_node + /// @param [in] cast_node + /// @param [in] same_cond_switch + /// @return Status + /// + Status ModifySwitchInCtlEdges(const NodePtr &switch_node, const NodePtr &cast_node, + const std::set &same_cond_switch); + + /// + /// @brief Modify out ctl edge for switch_node + /// @param [in] switch_node + /// @param [in] stream_switch + /// @param [in] active_node + /// @return Status + /// + Status ModifySwitchOutCtlEdges(const NodePtr &switch_node, const NodePtr &stream_switch, const NodePtr &active_node); + + /// + /// @brief Check duplicate node_name + /// @param [in] node_name + /// @return std::string + /// std::string CheckDuplicateName(const std::string &node_name); - Status CheckCycleDependence(ComputeGraphPtr &graph); - - void MarkCycleDependence(const std::unordered_map> &cond_switch_map); - - Status ModifySwitchInCtlEdges(NodePtr &switch_node, NodePtr &cast_node, const std::set &same_cond_switch); - - Status ModifySwitchOutCtlEdges(NodePtr &switch_node, NodePtr &stream_switch, NodePtr &active_node); - - void CopyControlEdges(NodePtr &old_node, NodePtr &new_node, bool input_check_flag = false); - - void RemoveControlEdges(NodePtr &node); - - void ReplaceControlEdges(NodePtr &old_node, NodePtr &new_node); - - int64_t GetGroupId(const NodePtr &node); - - void MarkHeadNodes(const NodePtr &node, const NodePtr &stream_switch); + /// + /// @brief Move Control Edges + /// @param [in] old_node + /// @param [in] new_node + /// @return void + /// + void MoveCtrlEdges(const NodePtr &old_node, const NodePtr &new_node); std::vector switch_nodes_; - std::vector merge_nodes_; - std::vector enter_nodes_; std::unordered_map> switch_cyclic_map_; - std::set bypass_nodes_; - std::unordered_map branch_head_nodes_; std::vector stream_switch_nodes_; - std::vector need_label_nodes_; std::unordered_map>>> cond_node_map_; std::unordered_map> switch_node_map_; std::unordered_map node_num_map_; }; } // namespace ge -#endif // GE_GRAPH_PASSES_SWITCH_OP_PASS_H_ +#endif // GE_GRAPH_PASSES_SWITCH_TO_STREAM_SWITCH_PASS_H_ diff --git a/src/ge/graph/passes/transop_breadth_fusion_pass.cc b/src/ge/graph/passes/transop_breadth_fusion_pass.cc index 53f9e825..d8df4a22 100644 --- a/src/ge/graph/passes/transop_breadth_fusion_pass.cc +++ b/src/ge/graph/passes/transop_breadth_fusion_pass.cc @@ -19,14 +19,12 @@ #include #include -#include "framework/common/debug/ge_log.h" #include "common/types.h" #include "graph/common/transop_util.h" #include "graph/utils/node_utils.h" namespace ge { Status TransOpBreadthFusionPass::Run(ge::ComputeGraphPtr graph) { - GE_TIMESTAMP_START(TransOpBreadthFusionPass); if (graph == nullptr) { return SUCCESS; } @@ -47,7 +45,6 @@ Status TransOpBreadthFusionPass::Run(ge::ComputeGraphPtr graph) { } } } - GE_TIMESTAMP_END(TransOpBreadthFusionPass, "GraphManager::TransOpBreadthFusionPass"); return SUCCESS; } diff --git a/src/ge/graph/passes/transop_depth_fusion_pass.cc b/src/ge/graph/passes/transop_depth_fusion_pass.cc index c0c854b6..afeca3c4 100644 --- a/src/ge/graph/passes/transop_depth_fusion_pass.cc +++ b/src/ge/graph/passes/transop_depth_fusion_pass.cc @@ -17,7 +17,6 @@ #include "graph/passes/transop_depth_fusion_pass.h" #include -#include "framework/common/debug/ge_log.h" #include "common/ge_inner_error_codes.h" #include "common/types.h" #include "graph/compute_graph.h" @@ -29,7 +28,6 @@ namespace ge { graphStatus TransOpDepthFusionPass::Run(ComputeGraphPtr graph) { - GE_TIMESTAMP_START(TransOpDepthFusionPass); GELOGI("[TransOpDepthFusionPass]: optimize in depth begin..."); if (graph == nullptr) { return GRAPH_SUCCESS; @@ -53,7 +51,6 @@ graphStatus TransOpDepthFusionPass::Run(ComputeGraphPtr graph) { } } GELOGI("[TransOpDepthFusionPass]: Optimize in depth success..."); - GE_TIMESTAMP_END(TransOpDepthFusionPass, "GraphManager::TransOpDepthFusionPass"); return GRAPH_SUCCESS; } diff --git a/src/ge/graph/passes/transop_symmetry_elimination_pass.cc b/src/ge/graph/passes/transop_symmetry_elimination_pass.cc index 38b6684b..887079f8 100644 --- a/src/ge/graph/passes/transop_symmetry_elimination_pass.cc +++ b/src/ge/graph/passes/transop_symmetry_elimination_pass.cc @@ -15,22 +15,26 @@ */ #include "transop_symmetry_elimination_pass.h" +#include "common/formats/utils/formats_trans_utils.h" #include "framework/common/debug/ge_log.h" #include "framework/common/util.h" #include "graph/common/transop_util.h" +#include "graph/debug/ge_attr_define.h" #include "graph/utils/graph_utils.h" +#include "graph/utils/node_utils.h" #include "graph/utils/type_utils.h" +#include "types.h" namespace { const int kTransOpOutIndex = 0; -static std::map precision_loss_transfer_map = {{ge::DT_FLOAT, ge::DT_BOOL}}; - +const std::set white_list_op{ge::TRANSPOSED, ge::RESHAPE, ge::REFORMAT, ge::CAST, ge::TRANSDATA}; +std::map precision_loss_transfer_map = {{ge::DT_FLOAT, ge::DT_BOOL}}; } // namespace namespace ge { Status TransOpSymmetryEliminationPass::Run(NodePtr &node) { GE_CHECK_NOTNULL(node); GE_CHECK_NOTNULL(node->GetOpDesc()); - if (!TransOpUtil::IsTransOp(node)) { + if (white_list_op.find(node->GetType()) == white_list_op.end()) { return SUCCESS; } GELOGD("Symmetry Elimination Pass in."); @@ -41,9 +45,8 @@ Status TransOpSymmetryEliminationPass::Run(NodePtr &node) { GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNode()); GE_CHECK_NOTNULL(peer_in_anchor->GetOwnerNode()->GetOpDesc()); if (!CheckCanBeEliminated(node, peer_in_anchor)) { - break; + continue; } - auto dst_node = peer_in_anchor->GetOwnerNode(); Status ret = EliminateTransOp(node, out_anchor, dst_node, peer_in_anchor); if (ret != SUCCESS) { @@ -71,12 +74,33 @@ bool TransOpSymmetryEliminationPass::CheckCanBeEliminated(const ge::NodePtr &src dst_node->GetType().c_str(), dst_in_anchor->GetIdx()); return false; } - if (!DescAreSymmetry(src_node, dst_node) || !CheckPrecisionLoss(src_node)) { - GELOGD("Not satisfied symmetry or has precision loss, ignore pass."); - return false; + if (src_node->GetType() == ge::RESHAPE) { + GE_CHECK_NOTNULL(src_node->GetOpDesc()); + auto unknown_dims_num = GetUnknownDimsNum(src_node->GetOpDesc()->GetInputDesc(0)); + if (unknown_dims_num != 0 && (unknown_dims_num == UNKNOWN_DIM_NUM || unknown_dims_num > 1)) { + GELOGD( + "Pre node %s is reshape op which input is dynamic shape and has more than one unknown dimension. " + "Ignore pass.", + src_node->GetName().c_str()); + return false; + } + } else if (src_node->GetType() == ge::TRANSPOSED) { + if (!JudgeTransposeDBack2Raw(src_node, dst_node)) { + GELOGD("Two Transpose op src node %s dst node %s will change the raw data. Ignore pass.", + src_node->GetName().c_str(), dst_node->GetName().c_str()); + return false; + } + } else if (src_node->GetType() == ge::TRANSDATA) { + auto unknown_dims_num = GetUnknownDimsNum(src_node->GetOpDesc()->GetInputDesc(0)); + if (unknown_dims_num == UNKNOWN_DIM_NUM) { + GELOGD("Pre node %s is transdata op which input is dynamic shape and all dimension are unknown(-2). Ignore pass.", + src_node->GetName().c_str()); + return false; + } } - return true; + return CheckPrecisionLoss(src_node) && DescAreSymmetry(src_node, dst_node); } + bool TransOpSymmetryEliminationPass::DescAreSymmetry(const NodePtr &src_node, const NodePtr &dst_node) { const auto &src_input_desc = src_node->GetOpDesc()->MutableInputDesc(0); const auto &dst_output_desc = dst_node->GetOpDesc()->MutableOutputDesc(0); @@ -89,15 +113,28 @@ bool TransOpSymmetryEliminationPass::DescAreSymmetry(const NodePtr &src_node, co const auto &dst_output_format = dst_output_desc->GetFormat(); const auto &dst_output_shape = dst_output_desc->GetShape().GetDims(); + bool is_symmetry = true; if (src_node->GetType() == CAST && dst_node->GetType() == CAST) { bool is_format_symmetry = (src_input_format == dst_output_format) || (dst_output_format == FORMAT_ND) || (src_input_format == FORMAT_ND); - return (src_input_dtype == dst_output_dtype) && is_format_symmetry; + is_symmetry = (src_input_dtype == dst_output_dtype) && is_format_symmetry; } else { - return (src_input_dtype == dst_output_dtype) && (src_input_shape == dst_output_shape) && - (src_input_format == dst_output_format); + is_symmetry = (src_input_dtype == dst_output_dtype) && (src_input_shape == dst_output_shape) && + (src_input_format == dst_output_format); } + if (!is_symmetry) { + GELOGD( + "Not satisfied symmetry. ignore pass.\n" + "Src node %s input type: %s format: %s shape: %s, " + "dst node %s output type: %s format: %s shape: %s. ", + src_node->GetName().c_str(), TypeUtils::DataTypeToSerialString(src_input_dtype).c_str(), + TypeUtils::FormatToSerialString(src_input_format).c_str(), formats::ShapeToString(src_input_shape).c_str(), + dst_node->GetName().c_str(), TypeUtils::DataTypeToSerialString(dst_output_dtype).c_str(), + TypeUtils::FormatToSerialString(dst_output_format).c_str(), formats::ShapeToString(dst_output_shape).c_str()); + } + return is_symmetry; } + bool TransOpSymmetryEliminationPass::CheckPrecisionLoss(const ge::NodePtr &src_node) { auto idx = TransOpUtil::GetTransOpDataIndex(src_node); auto input_desc = src_node->GetOpDesc()->GetInputDesc(idx); @@ -106,13 +143,62 @@ bool TransOpSymmetryEliminationPass::CheckPrecisionLoss(const ge::NodePtr &src_n auto dst_dtype = output_desc.GetDataType(); auto iter = precision_loss_transfer_map.find(src_dtype); if (iter != precision_loss_transfer_map.end() && iter->second == dst_dtype) { - GELOGW("Node %s transfer data type from %s to %s ,it will cause precision loss.", src_node->GetName().c_str(), - TypeUtils::DataTypeToSerialString(src_dtype).c_str(), TypeUtils::DataTypeToSerialString(dst_dtype).c_str()); + GELOGW("Node %s transfer data type from %s to %s ,it will cause precision loss. ignore pass.", + src_node->GetName().c_str(), TypeUtils::DataTypeToSerialString(src_dtype).c_str(), + TypeUtils::DataTypeToSerialString(dst_dtype).c_str()); return false; } return true; } +int TransOpSymmetryEliminationPass::GetUnknownDimsNum(const GeTensorDesc &node_desc) { + // + // unknown_dims_num != 0 , is dynamic shape + // unknown_dims_num = UNKNOWN_DIM_NUM , all dims are unknown + // unknown_dims_num = n , n > 0 , has n dims unknown + // + int unknown_dims_num = 0; + auto ge_shape = node_desc.GetShape(); + for (const auto dim : ge_shape.GetDims()) { + if (dim == UNKNOWN_DIM_NUM) { + return UNKNOWN_DIM_NUM; + } + if (dim == UNKNOWN_DIM) { + ++unknown_dims_num; + } + } + return unknown_dims_num; +} + +bool TransOpSymmetryEliminationPass::JudgeTransposeDBack2Raw(const NodePtr &src_node, const NodePtr &dst_node) { + // + // A transpose to C : A---->(perm_1)---->B---->(perm_2)---->C + // we want to judge A is equal with C or not + // suppose A = C then: + // 1. B[i] = A[perm_1[i]] + // 2. C[i] = B[perm_2[i]] + // 3. combine 1 and 2 then: C[i] = A[perm_1[perm_2[i]]] + // which we get through 3: i = perm_1[perm_2[i]] + // + vector src_node_perm; + AttrUtils::GetListInt(src_node->GetOpDesc(), ge::PERMUTE_ATTR_PERM, src_node_perm); + vector dst_node_perm; + AttrUtils::GetListInt(dst_node->GetOpDesc(), ge::PERMUTE_ATTR_PERM, dst_node_perm); + + if (src_node_perm.size() != dst_node_perm.size()) { + return false; + } + for (size_t src_index = 0; src_index < src_node_perm.size(); ++src_index) { + if (dst_node_perm[src_index] >= static_cast(src_node_perm.size())) { + return false; + } + if (static_cast(src_index) != src_node_perm[dst_node_perm[src_index]]) { + return false; + } + } + return true; +} + Status TransOpSymmetryEliminationPass::EliminateTransOp(NodePtr &src_node, const OutDataAnchorPtr &src_out_anchor, NodePtr &dst_node, const InDataAnchorPtr &dst_in_anchor) { // Two transform nodes can be offset like A->T1->T2->B @@ -140,7 +226,18 @@ Status TransOpSymmetryEliminationPass::EliminateTransOp(NodePtr &src_node, const GELOGE(FAILED, "Copy control edge from %s to %s failed.", src_node->GetName().c_str(), dst_node->GetName().c_str()); return ret; } - // 4.IsolateAndDelete T2, A will link to B automatically, and all control edge will also relink. + // 4.Add control edge from T1 other input to T2, like reshape second input + for (const auto &in_node : src_node->GetInDataNodes()) { + if (in_node->GetName() == pre_normal_node->GetName()) { + continue; + } + ret = GraphUtils::AddEdge(in_node->GetOutControlAnchor(), dst_node->GetInControlAnchor()); + if (ret != GRAPH_SUCCESS) { + GELOGE(FAILED, "Add control edge from %s to %s failed.", in_node->GetName().c_str(), dst_node->GetName().c_str()); + return ret; + } + } + // 5.IsolateAndDelete T2, A will link to B automatically, and all control edge will also relink. ret = IsolateAndDeleteNode(dst_node, {0}); if (ret != GRAPH_SUCCESS) { GELOGE(INTERNAL_ERROR, "Isolate removed node: %s, type: %s failed", dst_node->GetName().c_str(), @@ -148,16 +245,16 @@ Status TransOpSymmetryEliminationPass::EliminateTransOp(NodePtr &src_node, const return ret; } GELOGI("Trans op symmetry eliminate successfully. Node %s has been removed.", dst_node->GetName().c_str()); - // 5.If T1 has no data out, isolate and deleted it. + // 6.If T1 has no data out, isolate and deleted it. if (src_node->GetOutDataNodesSize() == 0) { - // 5.1 Copy out control to pre normal node + // 6.1 Copy out control to pre normal node ret = GraphUtils::CopyOutCtrlEdges(src_node, pre_normal_node); if (ret != GRAPH_SUCCESS) { GELOGE(FAILED, "Copy control edge from %s to %s failed.", src_node->GetName().c_str(), dst_node->GetName().c_str()); return ret; } - // 5.2 Isolate and delete T1 + // 6.2 Isolate and delete T1 ret = IsolateAndDeleteNode(src_node, {}); if (ret != GRAPH_SUCCESS) { GELOGE(INTERNAL_ERROR, "Isolate removed node: %s, type: %s failed", src_node->GetName().c_str(), diff --git a/src/ge/graph/passes/transop_symmetry_elimination_pass.h b/src/ge/graph/passes/transop_symmetry_elimination_pass.h index b0cff0c9..7f7409b7 100644 --- a/src/ge/graph/passes/transop_symmetry_elimination_pass.h +++ b/src/ge/graph/passes/transop_symmetry_elimination_pass.h @@ -44,6 +44,21 @@ class TransOpSymmetryEliminationPass : public BaseNodePass { static bool DescAreSymmetry(const NodePtr &src_node, const NodePtr &dst_node); /// + /// get the number of unknown shape of node + /// @param node_desc: node to be checked + /// @return 0 , is not dynamic shape; UNKNOWN_DIM_NUM , all dims are unknown; n , n > 0 , has n dims unknown + /// + static int GetUnknownDimsNum(const GeTensorDesc &node_desc); + + /// + /// judge after two transposed op transform the raw data will be the same + /// @param src_node: first transposed op + /// @param dst_node: second transposed op + /// @return True or False, same or not + /// + static bool JudgeTransposeDBack2Raw(const NodePtr &src_node, const NodePtr &dst_node); + + /// /// two transform nodes can not be offset if there is precision loss, like FP32->BOOL BOOL->FP32. /// keep this pair of transform nodes if it has precision loss. /// @param src_node: the front node diff --git a/src/ge/graph/passes/transop_without_reshape_fusion_pass.cc b/src/ge/graph/passes/transop_without_reshape_fusion_pass.cc index ba4cd031..1d97d9a1 100644 --- a/src/ge/graph/passes/transop_without_reshape_fusion_pass.cc +++ b/src/ge/graph/passes/transop_without_reshape_fusion_pass.cc @@ -22,7 +22,6 @@ #include "common/ge/ge_util.h" #include "common/ge_inner_error_codes.h" #include "common/types.h" -#include "framework/common/debug/ge_log.h" #include "graph/compute_graph.h" #include "graph/debug/ge_attr_define.h" #include "graph/ge_tensor.h" @@ -733,7 +732,6 @@ void TransOpWithoutReshapeFusionPass::RemoveNousedNodes(const ComputeGraphPtr &g } graphStatus TransOpWithoutReshapeFusionPass::Run(ComputeGraphPtr graph) { - GE_TIMESTAMP_START(TransOpWithoutReshapeFusionPass); GELOGI("[TransOpWithoutReshapeFusionPass]: optimize begin."); if (graph == nullptr) { return GRAPH_SUCCESS; @@ -786,7 +784,6 @@ graphStatus TransOpWithoutReshapeFusionPass::Run(ComputeGraphPtr graph) { } } GELOGI("[TransOpWithoutReshapeFusionPass]: Optimize end."); - GE_TIMESTAMP_END(TransOpWithoutReshapeFusionPass, "GraphManager::TransOpWithoutReshapeFusionPass"); return GRAPH_SUCCESS; } diff --git a/src/ge/graph/passes/transpose_transdata_pass.cc b/src/ge/graph/passes/transpose_transdata_pass.cc index 7ac7b7a3..3ac6dea5 100644 --- a/src/ge/graph/passes/transpose_transdata_pass.cc +++ b/src/ge/graph/passes/transpose_transdata_pass.cc @@ -135,7 +135,7 @@ Status TransposeTransDataPass::RemoveTranspose(NodePtr &node) { GE_CHECK_NOTNULL(anchor); anchor->UnlinkAll(); } - AddNodeDeleted(node.get()); + AddNodeDeleted(node); if (GraphUtils::RemoveNodeWithoutRelink(graph, node) != GRAPH_SUCCESS) { GELOGE(FAILED, "[%s] RemoveNodeWithoutRelink failed.", node->GetName().c_str()); return FAILED; diff --git a/src/ge/graph/passes/var_is_initialized_op_pass.cc b/src/ge/graph/passes/var_is_initialized_op_pass.cc index c88db80c..73456a7b 100644 --- a/src/ge/graph/passes/var_is_initialized_op_pass.cc +++ b/src/ge/graph/passes/var_is_initialized_op_pass.cc @@ -191,7 +191,7 @@ Status VarIsInitializedOpPass::ChangeNodeToConstant(NodePtr &node, bool inited) AddRePassNodesWithInOut(const_node); // delete VarIsInitializedOp node from the graph - AddNodeDeleted(node.get()); + AddNodeDeleted(node); return SUCCESS; } diff --git a/src/ge/graph/passes/variable_op_pass.cc b/src/ge/graph/passes/variable_op_pass.cc index 175a049a..8c34cd36 100644 --- a/src/ge/graph/passes/variable_op_pass.cc +++ b/src/ge/graph/passes/variable_op_pass.cc @@ -20,7 +20,6 @@ #include "common/formats/formats.h" #include "common/formats/utils/formats_trans_utils.h" -#include "framework/common/debug/ge_log.h" #include "graph/ge_context.h" #include "graph/graph.h" #include "graph/manager/graph_var_manager.h" @@ -115,7 +114,6 @@ bool IsTransSupport(const TransNodeInfo &trans_info) { } // namespace Status VariableOpPass::Run(ge::ComputeGraphPtr graph) { - GE_TIMESTAMP_START(VariableOpPass); if (graph == nullptr) { GELOGE(INTERNAL_ERROR, "Failed to run variable op pass, null graph"); return INTERNAL_ERROR; @@ -190,9 +188,15 @@ Status VariableOpPass::Run(ge::ComputeGraphPtr graph) { if (UpdateIOFormatInfo(end_iter->output, node_set) != SUCCESS) { return GE_GRAPH_VARIABLE_OP_PASS_FAILED; } + + // renew var desc if the trans_road is all reshape or reformat + ret = RenewVarDesc(graph->GetSessionID(), node, fusion_road); + if (ret != SUCCESS) { + GELOGE(FAILED, "var manager renew var[%s] descriptor failed!", node->GetName().c_str()); + return FAILED; + } } - GE_TIMESTAMP_END(VariableOpPass, "GraphManager::VariableOpPass"); return SUCCESS; } @@ -604,4 +608,28 @@ Status VariableOpPass::RenewVarDesc(ge::ComputeGraphPtr &graph) { } return SUCCESS; } + +Status VariableOpPass::RenewVarDesc(uint64_t session_id, const NodePtr &node, const VarTransRoad &fusion_road) { + // renew var desc if the trans_road is all reshape or reformat + for (auto &road : fusion_road) { + if (road.node_type != RESHAPE && road.node_type != REFORMAT) { + return SUCCESS; + } + } + + if (!ge::VarManager::Instance(session_id)->IsVarExist(node->GetName())) { + GELOGD("var manager does not exist var node[%s]", node->GetName().c_str()); + return SUCCESS; + } + GELOGD("var manager exist var node[%s]", node->GetName().c_str()); + GE_CHECK_NOTNULL(node->GetOpDesc()); + Status ret = ge::VarManager::Instance(session_id)->RenewCurVarDesc(node->GetName(), node->GetOpDesc()); + if (ret != SUCCESS) { + GELOGE(FAILED, "var manager renew var[%s] descriptor failed!", node->GetName().c_str()); + return FAILED; + } + + return SUCCESS; +} + } // namespace ge diff --git a/src/ge/graph/passes/variable_op_pass.h b/src/ge/graph/passes/variable_op_pass.h index 4e194a0c..e17980e9 100644 --- a/src/ge/graph/passes/variable_op_pass.h +++ b/src/ge/graph/passes/variable_op_pass.h @@ -66,6 +66,7 @@ class VariableOpPass : public GraphPass { Status UpdateIOFormatInfo(const GeTensorDesc &final_output, std::set &nodes); Status RenewVarDesc(ge::ComputeGraphPtr &graph); + Status RenewVarDesc(uint64_t session_id, const NodePtr &node, const VarTransRoad &fusion_road); std::map> var_and_var_ref_map_; diff --git a/src/ge/graph/passes/variable_prepare_op_pass.cc b/src/ge/graph/passes/variable_prepare_op_pass.cc index 4db78a46..d93e1003 100644 --- a/src/ge/graph/passes/variable_prepare_op_pass.cc +++ b/src/ge/graph/passes/variable_prepare_op_pass.cc @@ -30,6 +30,7 @@ namespace ge { std::map> VariablePrepareOpPass::ref_node_without_prototype_map_{ {REFSWITCH, {{0, 0}, {0, 1}}}}; + Status VariablePrepareOpPass::Run(ComputeGraphPtr graph) { GE_CHECK_NOTNULL(graph); for (const auto &node : graph->GetDirectNode()) { @@ -62,7 +63,6 @@ Status VariablePrepareOpPass::Run(ComputeGraphPtr graph) { GELOGI("{ %d : %d }", index_iter->first, index_iter->second); } } - return SUCCESS; } @@ -73,10 +73,13 @@ Status VariablePrepareOpPass::DealVariableNode(NodePtr &var_node) { GE_CHECK_NOTNULL(dst_node); InDataAnchorPtr dst_in_data_anchor = dst_node_and_inanchor.second; GE_CHECK_NOTNULL(dst_in_data_anchor); - int out_index = GetWritableNodeOutIndex(dst_node, dst_in_data_anchor->GetIdx()); + auto input_index = dst_in_data_anchor->GetIdx(); + int out_index = GetWritableNodeOutIndex(dst_node, input_index); if (out_index >= 0) { - Status ret = DealWritableNode(dst_node, var_node, out_index); + Status ret = DealWritableNode(dst_node, input_index, var_node); if (ret != SUCCESS) { + GELOGE(FAILED, "Deal writable node[%s] failed, input index: %d, var: %s.", dst_node->GetName().c_str(), + input_index, var_node->GetName().c_str()); return FAILED; } } @@ -84,84 +87,97 @@ Status VariablePrepareOpPass::DealVariableNode(NodePtr &var_node) { return SUCCESS; } -Status VariablePrepareOpPass::DealWritableNode(ge::NodePtr &writable_node, ge::NodePtr &var_node, int out_index) { - GE_CHECK_NOTNULL(writable_node); - GE_CHECK_NOTNULL(var_node); - NodePtr final_writable_node = writable_node; - bool is_have_peer_node = false; - for (auto &dst_node_and_inanchor : writable_node->GetOutDataNodesAndAnchors()) { - NodePtr dst_node = dst_node_and_inanchor.first; - GE_CHECK_NOTNULL(dst_node); - InDataAnchorPtr dst_in_data_anchor = dst_node_and_inanchor.second; - GE_CHECK_NOTNULL(dst_in_data_anchor); - is_have_peer_node = true; - int current_out_index = GetWritableNodeOutIndex(dst_node, dst_in_data_anchor->GetIdx()); - if (current_out_index >= 0) { - final_writable_node = GetFinalWritableNode(dst_node, current_out_index); - out_index = current_out_index; - } - - GE_CHECK_NOTNULL(final_writable_node); - Status ret = AddVariableRef(final_writable_node, var_node, out_index); - if (ret != SUCCESS) { - GELOGE(FAILED, "add variable ref failed"); - return FAILED; +Status VariablePrepareOpPass::DealWritableNode(const ge::NodePtr &writable_node, int input_index, + const ge::NodePtr &var_node) { + // Find the last ref node: + // If the ref input has corresponding output, add variable ref after it. + // If the ref input has no corresponding output, insert RefIdentity and variable ref before it. + // If ref node with control output was found while finding the last ref node, add variable ref after it. + std::stack> nodes_to_check; + nodes_to_check.push({writable_node, input_index}); + while (!nodes_to_check.empty()) { + auto node_index = nodes_to_check.top(); + nodes_to_check.pop(); + auto cur_node = node_index.first; + int cur_input_index = node_index.second; + // Collect ref node after cur node + const auto nodes_size = nodes_to_check.size(); + // Add peer ref output node of current node to stack + CHECK_FALSE_EXEC(GetPeerNodeOfRefInput(cur_node, cur_input_index, nodes_to_check) == SUCCESS, + GELOGE(FAILED, "GetPeerNodeOfRefInput for node[%s] failed.", cur_node->GetName().c_str()); + return FAILED); + auto output_index = GetWritableNodeOutIndex(cur_node, cur_input_index); + CHECK_FALSE_EXEC(output_index >= 0, + GELOGE(FAILED, "Get writable node[%s] ref input[%d]'s corresponding out index failed: %d.", + cur_node->GetName().c_str(), cur_input_index, output_index); + return FAILED); + if (nodes_size == nodes_to_check.size()) { + const auto &op_desc = cur_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + // No need to add variable_ref for frameworkop + if (op_desc->GetType() == FRAMEWORKOP) { + GELOGD("No need to add variable_ref for frameworkop"); + continue; + } + if (static_cast(output_index) < op_desc->GetOutputsSize()) { + // Add variable ref node after ref output for final ref node + CHECK_FALSE_EXEC(AddVariableRef(cur_node, var_node, output_index) == SUCCESS, + GELOGE(FAILED, "Add variable ref failed"); + return FAILED); + } else { + // Insert variable ref node before ref input without corresponding ref output + CHECK_FALSE_EXEC(InsertVariableRef(cur_node, cur_input_index, var_node) == SUCCESS, + GELOGE(FAILED, "Insert variable ref and ref identity failed"); + return FAILED); + } + continue; } - } - if (final_writable_node->GetName() == writable_node->GetName() && !is_have_peer_node) { - Status ret = AddVariableRef(final_writable_node, var_node, out_index); - if (ret != SUCCESS) { - return FAILED; + if (HasControlOut(cur_node)) { + // Add variable ref node after ref output for ref node has control output. + CHECK_FALSE_EXEC(AddVariableRef(cur_node, var_node, output_index) == SUCCESS, + GELOGE(FAILED, "Add variable ref failed"); + return FAILED); } } return SUCCESS; } -NodePtr VariablePrepareOpPass::GetFinalWritableNode(ge::NodePtr &writable_node, int &out_index) { - NodePtr current_node = writable_node; - std::unordered_set seen_node; - while (true) { - if (seen_node.count(current_node.get())) { - GELOGE(FAILED, "There is a ring structure in the graph"); - return nullptr; - } - seen_node.insert(current_node.get()); - OutDataAnchorPtr out_anchor = current_node->GetOutDataAnchor(out_index); - if (out_anchor == nullptr) { - GELOGE(FAILED, "Failed to get data anchor by index %d", out_index); - return nullptr; - } - bool found_writeable_node = false; - auto peer_in_anchors = out_anchor->GetPeerInDataAnchors(); - for (auto &peer_in_anchor : peer_in_anchors) { - if (peer_in_anchor == nullptr) { - GELOGE(FAILED, "peer in data anchor is nullptr, node %s:%s", current_node->GetType().c_str(), - current_node->GetName().c_str()); - continue; - } - - NodePtr peer_node = peer_in_anchor->GetOwnerNode(); - int current_out_index = GetWritableNodeOutIndex(peer_node, peer_in_anchor->GetIdx()); - if (current_out_index >= 0) { - current_node = peer_node; - out_index = current_out_index; - found_writeable_node = true; - break; - } +Status VariablePrepareOpPass::GetPeerNodeOfRefInput(const ge::NodePtr &node, int input_index, + std::stack> &nodes) { + auto output_index = GetWritableNodeOutIndex(node, input_index); + if (output_index == -1) { + GELOGE(PARAM_INVALID, "Node[%s] is not a ref node.", node->GetName().c_str()); + return PARAM_INVALID; + } + const auto &op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + if (static_cast(output_index) == op_desc->GetOutputsSize()) { + return SUCCESS; + } + if (output_index >= static_cast(node->GetAllOutDataAnchorsSize())) { + GELOGW("Can not get %d th output anchor of %s", output_index, node->GetName().c_str()); + return SUCCESS; + } + const auto &out_anchor = node->GetOutDataAnchor(output_index); + GE_CHECK_NOTNULL(out_anchor); + for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) { + auto peer_node = peer_in_anchor->GetOwnerNode(); + if (peer_node == nullptr) { + continue; } - if (!found_writeable_node) { - GELOGD("final writable node is %s", current_node->GetName().c_str()); - return current_node; + const int peer_in_index = peer_in_anchor->GetIdx(); + if (GetWritableNodeOutIndex(peer_node, peer_in_index) != -1) { + nodes.push({peer_node, peer_in_index}); } } + return SUCCESS; } -Status VariablePrepareOpPass::AddVariableRef(ge::NodePtr &final_writable_node, ge::NodePtr &var_node, int index) { +Status VariablePrepareOpPass::AddVariableRef(ge::NodePtr &final_writable_node, const ge::NodePtr &var_node, int index) { GE_CHECK_NOTNULL(final_writable_node); GE_CHECK_NOTNULL(var_node); - - if (final_writable_node->GetType() == FRAMEWORKOP) { - GELOGD("No need to add variable_ref for frameworkop"); + if (index >= static_cast(final_writable_node->GetAllOutDataAnchorsSize())) { + GELOGW("Can not get %d th output anchor of %s", index, final_writable_node->GetName().c_str()); return SUCCESS; } // Check for duplicate creation @@ -181,7 +197,8 @@ Status VariablePrepareOpPass::AddVariableRef(ge::NodePtr &final_writable_node, g // creat variable_ref std::stringstream variable_ref_name; variable_ref_name << "_TO_" << final_writable_node->GetName() << "_REF_" << index; - NodePtr variable_ref_node = CreatVariableRef(var_node->GetName() + variable_ref_name.str(), var_node); + NodePtr variable_ref_node = CreateVariableRef(var_node->GetName() + variable_ref_name.str(), var_node); + GE_CHECK_NOTNULL(variable_ref_node); Status ret_check = CheckStreamLabel(variable_ref_node, final_writable_node); if (ret_check != SUCCESS) { GELOGE(FAILED, "check stream lable failed"); @@ -189,23 +206,12 @@ Status VariablePrepareOpPass::AddVariableRef(ge::NodePtr &final_writable_node, g } GELOGI("Add variable_ref between [%s] and [%s]", var_node->GetName().c_str(), variable_ref_node->GetName().c_str()); - GE_CHECK_NOTNULL(variable_ref_node); - // add control anchor between variable_ref and final peer node + // add control anchor between variable_ref and final peer node // variable_ref_node need to execute before other nodes - auto final_writable_outAnchors = final_writable_node->GetAllOutAnchors(); - for (auto &final_writable_outAnchor : final_writable_outAnchors) { - GE_CHECK_NOTNULL(final_writable_outAnchor); - for (auto &final_writable_peerAnchor : final_writable_outAnchor->GetPeerAnchors()) { - GE_CHECK_NOTNULL(final_writable_peerAnchor); - NodePtr peer_node = final_writable_peerAnchor->GetOwnerNode(); - graphStatus ret = - ge::GraphUtils::AddEdge(variable_ref_node->GetOutControlAnchor(), peer_node->GetInControlAnchor()); - if (ret != GRAPH_SUCCESS) { - GELOGE(FAILED, "add control anchor between variable_ref and final_writable peer node failed"); - return FAILED; - } - } - } + CHECK_FALSE_EXEC(AddControlEdge(final_writable_node, variable_ref_node) == SUCCESS, + GELOGE(FAILED, "Add control edges between variable ref node and output nodes of ref node failed"); + return FAILED); + graphStatus ret = ge::GraphUtils::AddEdge(out_anchor, variable_ref_node->GetInDataAnchor(0)); if (ret != GRAPH_SUCCESS) { GELOGE(FAILED, "add data anchor between variable_ref and final_writable peer node failed"); @@ -214,7 +220,110 @@ Status VariablePrepareOpPass::AddVariableRef(ge::NodePtr &final_writable_node, g return SUCCESS; } -ge::NodePtr VariablePrepareOpPass::CreatVariableRef(const std::string &variable_ref_name, ge::NodePtr &var_node) { +Status VariablePrepareOpPass::InsertVariableRef(ge::NodePtr &node, int in_index, const ge::NodePtr &var_node) { + GE_CHECK_NOTNULL(node); + GE_CHECK_NOTNULL(var_node); + // Check connection between two nodes + const auto in_anchor = node->GetInDataAnchor(in_index); + GE_CHECK_NOTNULL(in_anchor); + auto peer_out_anchor = in_anchor->GetPeerOutAnchor(); + GE_CHECK_NOTNULL(peer_out_anchor); + auto peer_in_node = peer_out_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_in_node); + + // Create ref_identity + std::stringstream ref_identity_name; + ref_identity_name << "RefIdentity_" << peer_in_node->GetName() << "_" << peer_out_anchor->GetIdx() << "_TO_" + << node->GetName() << "_" << in_index; + NodePtr ref_identity_node = CreateRefIdentity(ref_identity_name.str(), node, static_cast(in_index)); + GE_CHECK_NOTNULL(ref_identity_node); + + // Create variable_ref + std::stringstream variable_ref_name; + variable_ref_name << "_TO_" << node->GetName() << "_REF_" << in_index; + NodePtr variable_ref_node = CreateVariableRef(var_node->GetName() + variable_ref_name.str(), var_node); + GE_CHECK_NOTNULL(variable_ref_node); + Status ret_check = CheckStreamLabel(variable_ref_node, node); + if (ret_check != SUCCESS) { + GELOGE(FAILED, "check stream lable failed"); + return FAILED; + } + + GELOGI("Insert variable_ref of [%s] between [%s] and [%s]", var_node->GetName().c_str(), + peer_in_node->GetName().c_str(), node->GetName().c_str()); + // add control anchor between variable_ref and node + // variable_ref_node need to execute before other nodes + CHECK_FALSE_EXEC(AddControlEdge(node, variable_ref_node) == SUCCESS, + GELOGE(FAILED, "Add control edges between variable ref node and output nodes of ref node failed"); + return FAILED); + + // Insert variable ref node between two nodes and remove the original edge. + CHECK_FALSE_EXEC(ge::GraphUtils::RemoveEdge(peer_out_anchor, in_anchor) == SUCCESS, + GELOGE(FAILED, "Remove edge between ref node and its peer node failed"); + return FAILED); + CHECK_FALSE_EXEC(ge::GraphUtils::AddEdge(peer_out_anchor, ref_identity_node->GetInDataAnchor(0)) == SUCCESS, + GELOGE(FAILED, "Add data edge between pre node and ref_identity failed"); + return FAILED); + CHECK_FALSE_EXEC(ge::GraphUtils::AddEdge(ref_identity_node->GetOutDataAnchor(0), in_anchor) == SUCCESS, + GELOGE(FAILED, "Add data edge between ref_identity and ref node failed"); + return FAILED); + + // Add edge from ref identity node to variable ref node. + CHECK_FALSE_EXEC( + ge::GraphUtils::AddEdge(ref_identity_node->GetOutDataAnchor(0), variable_ref_node->GetInDataAnchor(0)) == SUCCESS, + GELOGE(FAILED, "Add data edge between ref_identity and variable_ref failed"); + return FAILED); + CHECK_FALSE_EXEC( + ge::GraphUtils::AddEdge(node->GetOutControlAnchor(), variable_ref_node->GetInControlAnchor()) == SUCCESS, + GELOGE(FAILED, "Add control edge between ref_identity and variable_ref failed"); + return FAILED); + return SUCCESS; +} + +Status VariablePrepareOpPass::AddControlEdge(const ge::NodePtr &node, const ge::NodePtr &variable_ref_node) { + auto out_anchors = node->GetAllOutAnchors(); + for (auto &out_anchor : out_anchors) { + GE_CHECK_NOTNULL(out_anchor); + for (auto &peer_in_anchor : out_anchor->GetPeerAnchors()) { + GE_CHECK_NOTNULL(peer_in_anchor); + NodePtr peer_node = peer_in_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(peer_node); + CHECK_FALSE_EXEC( + ge::GraphUtils::AddEdge(variable_ref_node->GetOutControlAnchor(), peer_node->GetInControlAnchor()) == SUCCESS, + GELOGE(FAILED, "Add control edge between variable_ref and ref node's peer node failed"); + return FAILED); + } + } + return SUCCESS; +} + +ge::NodePtr VariablePrepareOpPass::CreateRefIdentity(const std::string &ref_identity_name, const ge::NodePtr &node, + uint32_t input_index) { + OpDescPtr op_desc = node->GetOpDesc(); + if (op_desc == nullptr) { + GELOGE(FAILED, "opdesc is nullptr"); + return nullptr; + } + + OpDescPtr ref_identity_op_desc = MakeShared(ref_identity_name.c_str(), REFIDENTITY); + if (ref_identity_op_desc == nullptr) { + GELOGE(FAILED, "ref_identity op desc is nullptr"); + return nullptr; + } + + GE_IF_BOOL_EXEC(ref_identity_op_desc->AddOutputDesc(op_desc->GetInputDesc(input_index)) != SUCCESS, + GELOGW("add output desc edge failed"); + return nullptr); + GE_IF_BOOL_EXEC(ref_identity_op_desc->AddInputDesc(op_desc->GetInputDesc(input_index)) != SUCCESS, + GELOGW("add input desc edge failed"); + return nullptr); + NodePtr ref_identity_node = node->GetOwnerComputeGraph()->AddNode(ref_identity_op_desc); + GE_IF_BOOL_EXEC(ref_identity_node == nullptr, GELOGW("ref_identity_node is null"); return nullptr); + return ref_identity_node; +} + +ge::NodePtr VariablePrepareOpPass::CreateVariableRef(const std::string &variable_ref_name, + const ge::NodePtr &var_node) { OpDescPtr var_op_desc = var_node->GetOpDesc(); if (var_op_desc == nullptr) { GELOGE(FAILED, "get var opdesc is nullptr"); @@ -250,7 +359,6 @@ int VariablePrepareOpPass::GetWritableNodeOutIndex(const NodePtr &node, int inpu } GELOGD("get writable node and input index %s:%d", node->GetName().c_str(), input_index); auto node_type = node->GetType(); - if (node_type == FRAMEWORKOP) { std::string original_type; GE_IF_BOOL_EXEC(GetOriginalType(node, original_type) != SUCCESS, GELOGW("Get node original type fail")); @@ -266,25 +374,17 @@ void VariablePrepareOpPass::GenerateRefTypeAndInputOutputMap(const NodePtr &node GELOGW("op_desc in null, please check node:[%s]", node->GetName().c_str()); return; } - for (const auto &out_ancohor : node->GetAllOutDataAnchors()) { - int output_index = out_ancohor->GetIdx(); - string output_name = op_desc->GetOutputNameByIndex(output_index); - GELOGD("output name:[%s]", output_name.c_str()); - - int input_index = op_desc->GetInputIndexByName(output_name); - if (input_index == -1) { + for (const auto &name_index : op_desc->GetAllInputName()) { + // Record the index of output with the same name as input, thinking of them as a pair of ref input and output. + const int out_index = op_desc->GetOutputIndexByName(name_index.first); + if (out_index != -1) { + ref_input_output_map_[node->GetType()][name_index.second] = out_index; continue; } - auto ref_type_and_input_output_iter = ref_input_output_map_.find(node->GetType()); - if (ref_type_and_input_output_iter != ref_input_output_map_.end()) { - auto &input_output_index_map = ref_type_and_input_output_iter->second; - if (input_output_index_map.find(input_index) == input_output_index_map.end()) { - input_output_index_map.emplace(input_index, output_index); - GELOGD("Add RefInputOutputMap %s:{ %d, %d }", node->GetType().c_str(), input_index, output_index); - } - } else { - ref_input_output_map_.insert({node->GetType(), {{input_index, output_index}}}); - GELOGD("Create RefInputOutputMap { %s:{ %d, %d } }", node->GetType().c_str(), input_index, output_index); + // Record the ref input without corresponding output. + const auto &input_desc = op_desc->GetInputDesc(name_index.second); + if (!input_desc.GetRefPortIndex().empty()) { + ref_input_output_map_[node->GetType()][name_index.second] = static_cast(op_desc->GetOutputsSize()); } } } @@ -317,4 +417,15 @@ Status VariablePrepareOpPass::CheckStreamLabel(const ge::NodePtr &var_ref_node, } return SUCCESS; } + +bool VariablePrepareOpPass::HasControlOut(const ge::NodePtr &node) { + const auto &out_control_anchor = node->GetOutControlAnchor(); + for (const auto &peer_in_control_anchor : out_control_anchor->GetPeerInControlAnchors()) { + if (peer_in_control_anchor == nullptr || peer_in_control_anchor->GetOwnerNode() == nullptr) { + continue; + } + return true; + } + return false; +} } // namespace ge diff --git a/src/ge/graph/passes/variable_prepare_op_pass.h b/src/ge/graph/passes/variable_prepare_op_pass.h index c8b9883e..f024a464 100644 --- a/src/ge/graph/passes/variable_prepare_op_pass.h +++ b/src/ge/graph/passes/variable_prepare_op_pass.h @@ -18,6 +18,7 @@ #define GE_GRAPH_PASSES_VARIABLE_PREPARE_OP_PASS_H_ #include +#include #include #include "framework/common/ge_inner_error_codes.h" @@ -30,15 +31,19 @@ class VariablePrepareOpPass : public GraphPass { private: Status DealVariableNode(ge::NodePtr &node); - Status DealWritableNode(ge::NodePtr &writable_node, ge::NodePtr &var_node, int out_index); - NodePtr GetFinalWritableNode(ge::NodePtr &writable_node, int &out_index); - Status AddVariableRef(ge::NodePtr &node, ge::NodePtr &var_node, int index); - NodePtr CreatVariableRef(const std::string &variable_ref_name, ge::NodePtr &var_node); + Status DealWritableNode(const ge::NodePtr &writable_node, int input_index, const ge::NodePtr &var_node); + Status GetPeerNodeOfRefInput(const ge::NodePtr &node, int input_index, std::stack> &nodes); + Status AddVariableRef(ge::NodePtr &node, const ge::NodePtr &var_node, int index); + Status InsertVariableRef(ge::NodePtr &node, int in_index, const ge::NodePtr &var_node); + Status AddControlEdge(const ge::NodePtr &node, const ge::NodePtr &variable_ref_node); + NodePtr CreateVariableRef(const std::string &variable_ref_name, const ge::NodePtr &var_node); + NodePtr CreateRefIdentity(const std::string &ref_identity_name, const ge::NodePtr &node, uint32_t input_index); int GetWritableNodeOutIndex(const NodePtr &node, int input_index); void GenerateRefTypeAndInputOutputMap(const NodePtr &node); int FindRefOutIndex(const std::string &node_type, int input_index, const std::map> &ref_map); Status CheckStreamLabel(const ge::NodePtr &var_ref_node, const ge::NodePtr &final_writable_node); + bool HasControlOut(const ge::NodePtr &node); std::map> ref_input_output_map_; static std::map> ref_node_without_prototype_map_; diff --git a/src/ge/graph/passes/variable_ref_delete_op_pass.cc b/src/ge/graph/passes/variable_ref_delete_op_pass.cc index cd5b9fe9..3487df47 100644 --- a/src/ge/graph/passes/variable_ref_delete_op_pass.cc +++ b/src/ge/graph/passes/variable_ref_delete_op_pass.cc @@ -16,18 +16,16 @@ #include "graph/passes/variable_ref_delete_op_pass.h" #include -#include "framework/common/debug/ge_log.h" namespace ge { Status VariableRefDeleteOpPass::Run(ge::ComputeGraphPtr graph) { - GE_TIMESTAMP_START(VariableRefDeleteOpPass); GE_CHECK_NOTNULL(graph); - - for (auto &node : graph->GetDirectNode()) { - GELOGD("before VariableRefDeleteOpPass, graph has node: %s, and node name: %s", node->GetType().c_str(), - node->GetName().c_str()); + std::set all_var_names; + auto root_graph = GraphUtils::FindRootGraph(graph); + GE_CHECK_NOTNULL(root_graph); + for (const auto &n : root_graph->GetAllNodes()) { + all_var_names.insert(n->GetName()); } - for (auto &node : graph->GetDirectNode()) { GE_CHECK_NOTNULL(node->GetOpDesc()); std::string ref_var_src_var_name; @@ -36,19 +34,17 @@ Status VariableRefDeleteOpPass::Run(ge::ComputeGraphPtr graph) { if (!is_variable_ref) { continue; } + if (all_var_names.count(ref_var_src_var_name) == 0) { + GELOGE(FAILED, "Can not find source variable[%s] of variable ref[%s]", ref_var_src_var_name.c_str(), + node->GetName().c_str()); + return FAILED; + } Status ret = DealVariableRef(graph, node, ref_var_src_var_name); if (ret != SUCCESS) { GELOGE(ret, "variable ref [%s] delete failed", node->GetName().c_str()); return FAILED; } } - - for (auto &node : graph->GetDirectNode()) { - GELOGD("after VariableRefDeleteOpPass, graph has node: %s, and node name: %s", node->GetType().c_str(), - node->GetName().c_str()); - } - GE_TIMESTAMP_END(VariableRefDeleteOpPass, "GraphManager::VariableRefDeleteOpPass"); - return SUCCESS; } @@ -68,23 +64,15 @@ Status VariableRefDeleteOpPass::DealVariableRef(ge::ComputeGraphPtr &graph, ge:: // get previous node of variable_ref NodePtr peer_node = inAnchor0->GetPeerOutAnchor()->GetOwnerNode(); - // add attr [REF_VAR_SRC_VAR_NAME] to the previous node of the variable_ref - GE_CHECK_NOTNULL(peer_node->GetOpDesc()); - bool is_set_str = ge::AttrUtils::SetStr(peer_node->GetOpDesc(), REF_VAR_SRC_VAR_NAME, ref_var_src_var_name); - - ge::NodePtr ref_var_src_var = GraphUtils::FindNodeFromAllNodes(graph, ref_var_src_var_name); - if (ref_var_src_var == nullptr) { - GELOGE(FAILED, "get ref_var_src_var failed"); - return FAILED; + // add attr [REF_VAR_SRC_VAR_NAME] to the previous op output desc of the variable_ref + auto op_desc = peer_node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + auto out_desc = op_desc->MutableOutputDesc(static_cast(index)); + bool is_set_str = ge::AttrUtils::SetStr(out_desc, REF_VAR_SRC_VAR_NAME, ref_var_src_var_name); + if (is_set_str) { + GELOGI("[%s-%d]: add attr [REF_VAR_SRC_VAR_NAME: %s ] ", peer_node->GetName().c_str(), index, + ref_var_src_var_name.c_str()); } - - GE_CHECK_NOTNULL(ref_var_src_var->GetOpDesc()); - bool is_set_index = ge::AttrUtils::SetInt(ref_var_src_var->GetOpDesc(), REF_VAR_PRE_PEER_OUT_INDEX, index); - if (is_set_str && is_set_index) { - GELOGI("[%s]: add attr [REF_VAR_SRC_VAR_NAME: %s ] ", peer_node->GetName().c_str(), ref_var_src_var_name.c_str()); - GELOGI("[%s]: add attr [REF_VAR_PRE_PEER_OUT_INDEX: %d]", ref_var_src_var->GetName().c_str(), index); - } - // remove variable_ref if (GraphUtils::IsolateNode(variable_ref, {0}) != GRAPH_SUCCESS) { GELOGE(INTERNAL_ERROR, "Isolate removed node: %s, type: %s failed", variable_ref->GetName().c_str(), diff --git a/src/ge/graph/passes/variable_ref_useless_control_out_delete_pass.cc b/src/ge/graph/passes/variable_ref_useless_control_out_delete_pass.cc index bd153184..1321cf20 100644 --- a/src/ge/graph/passes/variable_ref_useless_control_out_delete_pass.cc +++ b/src/ge/graph/passes/variable_ref_useless_control_out_delete_pass.cc @@ -17,7 +17,6 @@ #include "variable_ref_useless_control_out_delete_pass.h" namespace ge { - Status VariableRefUselessControlOutDeletePass::Run(ge::ComputeGraphPtr graph) { GE_CHECK_NOTNULL(graph); for (const auto &node : graph->GetDirectNode()) { diff --git a/src/ge/graph/preprocess/graph_preprocess.cc b/src/ge/graph/preprocess/graph_preprocess.cc index 9c82a06d..3d0f1514 100644 --- a/src/ge/graph/preprocess/graph_preprocess.cc +++ b/src/ge/graph/preprocess/graph_preprocess.cc @@ -19,9 +19,12 @@ #include #include #include +#include "common/formats/format_transfers/format_transfer_fractal_nz.h" +#include "common/formats/format_transfers/format_transfer_fractal_z.h" #include "common/formats/format_transfers/format_transfer_nchw_nc1hwc0.h" #include "common/formats/format_transfers/format_transfer_nhwc_nc1hwc0.h" #include "common/formats/format_transfers/format_transfer_transpose.h" +#include "common/formats/utils/formats_trans_utils.h" #include "common/helper/model_helper.h" #include "common/math/math_util.h" #include "common/op/ge_op_utils.h" @@ -32,6 +35,7 @@ #include "graph/common/transop_util.h" #include "graph/debug/ge_attr_define.h" #include "graph/ge_context.h" +#include "graph/shape_refiner.h" #include "graph/manager/graph_var_manager.h" #include "graph/manager/util/rt_context_util.h" #include "graph/optimize/graph_optimize.h" @@ -80,7 +84,9 @@ #include "graph/passes/switch_dead_branch_elimination.h" #include "graph/passes/switch_fusion_pass.h" #include "graph/passes/switch_logic_remove_pass.h" -#include "graph/passes/switch_op_pass.h" +#include "graph/passes/merge_to_stream_merge_pass.h" +#include "graph/passes/switch_to_stream_switch_pass.h" +#include "graph/passes/attach_stream_label_pass.h" #include "graph/passes/switch_split_pass.h" #include "graph/passes/unused_const_pass.h" #include "graph/passes/unused_op_remove_pass.h" @@ -96,7 +102,6 @@ #include "runtime/dev.h" #include "graph/passes/dimension_adjust_pass.h" -#include "graph/passes/identify_reference_pass.h" #include "graph/passes/link_gen_mask_nodes_pass.h" #include "graph/passes/permute_pass.h" #include "graph/passes/reshape_remove_pass.h" @@ -134,14 +139,14 @@ OpDescPtr CreateTensorShape(const GeTensorDesc &data_tensor) { auto dim_cnt = static_cast(dst_ge_shape.GetDimNum()); if (dim_cnt == 0) { // if the dim_cnt is 0, the tensor is a scalar tensor->MutableTensorDesc().SetShape(GeShape()); - int64_t dst_shape = 1; - if (tensor->SetData(reinterpret_cast(&dst_shape), sizeof(int64_t)) != GRAPH_SUCCESS) { + int32_t dst_shape = 1; + if (tensor->SetData(reinterpret_cast(&dst_shape), sizeof(int32_t)) != GRAPH_SUCCESS) { GELOGE(INTERNAL_ERROR, "tensor set data failed"); return nullptr; } } else { tensor->MutableTensorDesc().SetShape(GeShape(std::vector({dim_cnt}))); - unique_ptr dst_shape(new (std::nothrow) int64_t[dim_cnt]()); + unique_ptr dst_shape(new (std::nothrow) int32_t[dim_cnt]()); if (dst_shape == nullptr) { GELOGE(INTERNAL_ERROR, "Create unique ptr failed"); return nullptr; @@ -151,7 +156,7 @@ OpDescPtr CreateTensorShape(const GeTensorDesc &data_tensor) { } GE_IF_BOOL_EXEC( - tensor->SetData(reinterpret_cast(dst_shape.get()), dim_cnt * sizeof(int64_t)) != GRAPH_SUCCESS, + tensor->SetData(reinterpret_cast(dst_shape.get()), dim_cnt * sizeof(int32_t)) != GRAPH_SUCCESS, GELOGE(INTERNAL_ERROR, "tensor set data failed"); return nullptr;) } @@ -451,135 +456,6 @@ VarNamesToRefs CollectVarNamesToRefs(const ComputeGraphPtr &graph) { } return names_to_refs; } -Status AddTransNodeBetweenTwoNodes(OutDataAnchorPtr &src_out, InDataAnchorPtr &insert_in, - OutDataAnchorPtr &insert_out) { - if ((src_out == nullptr) || (insert_in == nullptr) || (insert_out == nullptr)) { - GELOGE(INTERNAL_ERROR, "anchor is nullptr"); - return FAILED; - } - auto vistor = src_out->GetPeerInDataAnchors(); - for (auto it = vistor.begin(); it != vistor.end(); ++it) { - InDataAnchorPtr dst_in = *it; - GE_CHK_STATUS_RET(src_out->Unlink(dst_in), "Unlink the anchor failed"); - GE_CHK_STATUS_RET(insert_out->LinkTo(dst_in), "Link the anchor failed"); - } - GE_CHK_STATUS_RET(src_out->LinkTo(insert_in), "Link the anchor failed"); - return SUCCESS; -} - -NodePtr CreateCastOp(const ge::GeShape &shape, const ge::DataType input_data_type, const ge::DataType output_data_type, - const ge::Format format, NodePtr &node) { - static uint32_t transop_count = 0; - std::string name = std::string("cast_node").append(std::to_string(transop_count++)); - - GELOGI("create cast op:%s, input datatype:%s, out datatype:%s.", name.c_str(), - TypeUtils::DataTypeToSerialString(input_data_type).c_str(), - TypeUtils::DataTypeToSerialString(output_data_type).c_str()); - GeTensorDesc input(shape, format, input_data_type); - input.SetOriginFormat(format); - input.SetOriginShape(shape); - input.SetOriginDataType(input_data_type); - ge::TensorUtils::SetRealDimCnt(input, static_cast(shape.GetDims().size())); - - GeTensorDesc output(shape, format, output_data_type); - output.SetOriginFormat(format); - output.SetOriginShape(shape); - output.SetOriginDataType(output_data_type); - ge::TensorUtils::SetRealDimCnt(output, static_cast(shape.GetDims().size())); - - auto cast_node = CreateTransNode(name, CAST, input, output, node); - GELOGD("Create cast node success."); - return cast_node; -} - -Status ProcessInputFP16(NodePtr &node_ptr, bool &is_dynamic_batch, NodePtr &switchn_node) { - GE_CHECK_NOTNULL(node_ptr); - auto op_desc = node_ptr->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - const GeTensorDescPtr &input = op_desc->MutableInputDesc(0); - GE_CHECK_NOTNULL(input); - ge::DataType src_dtype = input->GetDataType(); - if (src_dtype == DT_FLOAT16) { - GELOGI("The node name, %s dtype is fp16", node_ptr->GetName().c_str()); - return SUCCESS; - } - input->SetDataType(DT_FLOAT16); - input->SetOriginDataType(DT_FLOAT16); - int64_t input_shape_size = 0; - int64_t output_shape_size = 0; - ge::graphStatus input_graph_status = ge::TensorUtils::GetTensorSizeInBytes(*input, input_shape_size); - ge::graphStatus output_graph_status = ge::TensorUtils::GetTensorMemorySizeInBytes(*input, output_shape_size); - if (input_graph_status != ge::GRAPH_SUCCESS && output_graph_status != ge::GRAPH_SUCCESS) { - GELOGE(GRAPH_FAILED, "GetTensorSize failed!"); - return FAILED; - } - ge::TensorUtils::SetSize(*input, input_shape_size); - const GeTensorDescPtr &output = op_desc->MutableOutputDesc(0); - GE_CHECK_NOTNULL(output); - output->SetDataType(DT_FLOAT16); - output->SetOriginDataType(DT_FLOAT16); - ge::TensorUtils::SetSize(*output, output_shape_size); - - if (!is_dynamic_batch) { - NodePtr cast_node = CreateCastOp(output->GetShape(), DT_FLOAT16, src_dtype, output->GetFormat(), node_ptr); - GE_CHECK_NOTNULL(cast_node); - OutDataAnchorPtr src_out = node_ptr->GetOutDataAnchor(0); - InDataAnchorPtr cast_in = cast_node->GetInDataAnchor(0); - OutDataAnchorPtr cast_out = cast_node->GetOutDataAnchor(0); - if (AddTransNodeBetweenTwoNodes(src_out, cast_in, cast_out) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "add node between two nodes failed, src name:%s, cast node name:%s.", - node_ptr->GetName().c_str(), cast_node->GetName().c_str()); - return FAILED; - } - } else { - auto switchn_op_desc = switchn_node->GetOpDesc(); - GE_CHECK_NOTNULL(switchn_op_desc); - const GeTensorDescPtr &switchn_input = switchn_op_desc->MutableInputDesc(0); - GE_CHECK_NOTNULL(switchn_input); - switchn_input->SetDataType(DT_FLOAT16); - switchn_input->SetOriginDataType(DT_FLOAT16); - for (uint32_t i = 0; i < switchn_node->GetAllOutDataAnchorsSize(); ++i) { - const GeTensorDescPtr &switchn_output = switchn_op_desc->MutableOutputDesc(i); - GE_CHECK_NOTNULL(switchn_output); - switchn_output->SetDataType(DT_FLOAT16); - switchn_output->SetOriginDataType(DT_FLOAT16); - NodePtr cast_node = - CreateCastOp(switchn_output->GetShape(), DT_FLOAT16, src_dtype, switchn_output->GetFormat(), node_ptr); - GE_CHECK_NOTNULL(cast_node); - OutDataAnchorPtr src_out = switchn_node->GetOutDataAnchor(i); - InDataAnchorPtr cast_in = cast_node->GetInDataAnchor(0); - OutDataAnchorPtr cast_out = cast_node->GetOutDataAnchor(0); - if (AddTransNodeBetweenTwoNodes(src_out, cast_in, cast_out) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "add node between two nodes failed, src name:%s, cast node name:%s.", - switchn_node->GetName().c_str(), cast_node->GetName().c_str()); - return FAILED; - } - } - } - return SUCCESS; -} - -NodePtr CreateTransdataNode(const ge::GeShape &in_shape, const ge::Format input_format, const ge::GeShape &out_shape, - const ge::Format output_format, const ge::DataType dt, NodePtr &node) { - static uint32_t transop_count = 0; - // Does not involve multithreading. - std::string name = std::string("transdata_node").append(std::to_string(transop_count++)); - - GELOGI("create trandata op:%s, input format:%s, out format:%s.", name.c_str(), - TypeUtils::FormatToSerialString(input_format).c_str(), TypeUtils::FormatToSerialString(output_format).c_str()); - - GeTensorDesc input(in_shape, input_format, dt); - input.SetOriginFormat(input_format); - input.SetOriginShape(in_shape); - input.SetOriginDataType(dt); - - GeTensorDesc output(out_shape, output_format, dt); - output.SetOriginFormat(output_format); - output.SetOriginShape(out_shape); - output.SetOriginDataType(dt); - - return CreateTransNode(name, TRANSDATA, input, output, node); -} Status TransferShape2NC1HWC0(Format src_format, const std::vector &src_shape, DataType dt, Format dst_format, std::vector &dst_shape) { @@ -649,68 +525,40 @@ Status ModifyFormatAndShapeForSingleTensor(const GeTensorDescPtr &input_output) return SUCCESS; } -Status ProcessInputNC1HWC0(NodePtr &node_ptr, bool &is_dynamic_batch, NodePtr &switchn_node) { - GE_CHECK_NOTNULL(node_ptr); - auto op_desc = node_ptr->GetOpDesc(); +Status ModifyDataNetOutputFormatAndShape(OpDescPtr &op_desc, uint32_t index, Format storage_format, + vector &dst_shape_dims) { GE_CHECK_NOTNULL(op_desc); - const GeTensorDescPtr &input = op_desc->MutableInputDesc(0); + const GeTensorDescPtr &input = op_desc->MutableInputDesc(index); GE_CHECK_NOTNULL(input); ge::Format old_format = input->GetFormat(); - ge::GeShape old_shape = input->GetShape(); - bool support = ((old_format == FORMAT_NC1HWC0) || (old_format == FORMAT_NCHW) || (old_format == FORMAT_NHWC)); - if (!support) { - GELOGE(INTERNAL_ERROR, "The format [%s] is unsupported", TypeUtils::FormatToSerialString(old_format).c_str()); - return FAILED; - } - if (old_format == FORMAT_NC1HWC0) { - GELOGI("No need to transfer format"); - return SUCCESS; - } - if (ModifyInputFormatAndShape(node_ptr) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "modify format and shape failed"); - return FAILED; - } - if (!is_dynamic_batch) { - NodePtr trans_node = - CreateTransdataNode(input->GetShape(), FORMAT_NC1HWC0, old_shape, old_format, input->GetDataType(), node_ptr); - GE_CHECK_NOTNULL(trans_node); - OutDataAnchorPtr src_out = node_ptr->GetOutDataAnchor(0); - InDataAnchorPtr trans_in = trans_node->GetInDataAnchor(0); - OutDataAnchorPtr trans_out = trans_node->GetOutDataAnchor(0); - if (AddTransNodeBetweenTwoNodes(src_out, trans_in, trans_out) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "add node between two nodes failed"); - return FAILED; - } - } else { - auto switchn_op_desc = switchn_node->GetOpDesc(); - GE_CHECK_NOTNULL(switchn_op_desc); - const GeTensorDescPtr &switchn_input = switchn_op_desc->MutableInputDesc(0); - if (ModifyFormatAndShapeForSingleTensor(switchn_input) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "modify format and shape failed"); + std::vector old_shape = input->GetShape().GetDims(); + + input->SetShape(ge::GeShape(dst_shape_dims)); + input->SetFormat(storage_format); + + auto output = op_desc->MutableOutputDesc(index); + GE_CHECK_NOTNULL(output); + output->SetShape(ge::GeShape(dst_shape_dims)); + output->SetFormat(storage_format); + + if (!output->MutableShape().IsUnknownShape()) { + int64_t size = 0; + graphStatus graph_status = TensorUtils::GetTensorMemorySizeInBytes(*output, size); + if (graph_status != ge::GRAPH_SUCCESS) { + GELOGE(graph_status, "GetTensorSizeInBytes failed!"); return FAILED; } - for (uint32_t i = 0; i < switchn_node->GetAllOutDataAnchorsSize(); ++i) { - const GeTensorDescPtr &switchn_output = switchn_op_desc->MutableOutputDesc(i); - GE_CHECK_NOTNULL(switchn_output); - old_format = switchn_output->GetFormat(); - old_shape = switchn_output->GetShape(); - if (ModifyFormatAndShapeForSingleTensor(switchn_output) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "modify format and shape failed"); - return FAILED; - } - NodePtr trans_node = CreateTransdataNode(switchn_output->GetShape(), FORMAT_NC1HWC0, old_shape, old_format, - switchn_output->GetDataType(), node_ptr); - GE_CHECK_NOTNULL(trans_node); - OutDataAnchorPtr src_out = switchn_node->GetOutDataAnchor(i); - InDataAnchorPtr cast_in = trans_node->GetInDataAnchor(0); - OutDataAnchorPtr cast_out = trans_node->GetOutDataAnchor(0); - if (AddTransNodeBetweenTwoNodes(src_out, cast_in, cast_out) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "add node between two nodes failed, src name:%s, cast node name:%s.", - switchn_node->GetName().c_str(), trans_node->GetName().c_str()); - return FAILED; - } - } + ge::TensorUtils::SetSize(*input, size); + ge::TensorUtils::SetSize(*output, size); + + GELOGI( + "Modify Data NetOutput format and shape success, node:%s, index:%d, old_shape:%s, old_Format:%s, " + "new_shape:%s, new_format:%s, new_size:%lu", + op_desc->GetName().c_str(), index, formats::JoinToString(old_shape).c_str(), + ge::TypeUtils::FormatToSerialString(old_format).c_str(), formats::JoinToString(dst_shape_dims).c_str(), + ge::TypeUtils::FormatToSerialString(storage_format).c_str(), size); } + return SUCCESS; } @@ -739,44 +587,6 @@ Status CheckIfDynamicBatchScene(NodePtr &data_node, bool &is_dynamic_batch, Node return SUCCESS; } -Status ProcessDataNode(NodePtr &node_ptr) { - bool set_fp16 = false; - if (!ge::AttrUtils::GetBool(node_ptr->GetOpDesc(), "input_fp16", set_fp16) || !set_fp16) { - return SUCCESS; - } - for (auto const &next_node : node_ptr->GetOutNodes()) { - if (next_node->GetType() == AIPP) { - GELOGE(INTERNAL_ERROR, - "This input node [%s] is linked to aipp, can not be set to fp16," - "please check your atc parma insert_op_conf, input_fp16_nodes.", - node_ptr->GetName().c_str()); - return FAILED; - } - } - GELOGI("input_fp16 is found, the node name is %s.", node_ptr->GetName().c_str()); - bool is_dynamic_batch = false; - NodePtr switchn_node = nullptr; - if (CheckIfDynamicBatchScene(node_ptr, is_dynamic_batch, switchn_node)) { - GELOGE(INTERNAL_ERROR, "CheckIfDynamicBatchScene failed"); - return FAILED; - } - if (ProcessInputFP16(node_ptr, is_dynamic_batch, switchn_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "ProcessInputFP16 failed"); - return FAILED; - } - // check if need to set format - bool set_format = false; - if (!ge::AttrUtils::GetBool(node_ptr->GetOpDesc(), "input_set_nc1hwc0", set_format) || !set_format) { - return SUCCESS; - } - GELOGI("The format of node [%s] should be set NC1HWC0.", node_ptr->GetName().c_str()); - if (ProcessInputNC1HWC0(node_ptr, is_dynamic_batch, switchn_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "ProcessInputNC1HWC0 failed"); - return FAILED; - } - return SUCCESS; -} - bool CheckIfSetOutputType(std::string &output_type, ge::DataType &output_data_type) { if (output_type_str_to_datatype.find(output_type) != output_type_str_to_datatype.end()) { output_data_type = output_type_str_to_datatype[output_type]; @@ -794,221 +604,6 @@ bool CheckOpType(const NodePtr &node, const std::string type) { return false; } -Status ProcessFp16Nc1hwc0Dynamic(const OpDescPtr &src_op_desc, NodePtr &node) { - auto merge_out = src_op_desc->MutableOutputDesc(0); - GE_CHECK_NOTNULL(merge_out); - if (ModifyFormatAndShapeForSingleTensor(merge_out) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "modify format and shape failed"); - return FAILED; - } - for (uint32_t i = 0; i < node->GetAllInDataAnchorsSize(); ++i) { - auto merge_in = src_op_desc->MutableInputDesc(i); - GE_CHECK_NOTNULL(merge_in); - ge::Format old_format = merge_in->GetFormat(); - ge::GeShape old_shape = merge_in->GetShape(); - if (ModifyFormatAndShapeForSingleTensor(merge_in) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "modify format and shape failed"); - return FAILED; - } - ge::GeShape new_shape = merge_in->GetShape(); - NodePtr trans_node = CreateTransdataNode(old_shape, old_format, new_shape, FORMAT_NC1HWC0, DT_FLOAT16, node); - GE_CHECK_NOTNULL(trans_node); - const InDataAnchorPtr &dst_in_anchor = node->GetInDataAnchor(i); - GE_CHECK_NOTNULL(dst_in_anchor); - const OutDataAnchorPtr &src_out_anchor = dst_in_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(src_out_anchor); - if (GraphUtils::InsertNodeBetweenDataAnchors(src_out_anchor, dst_in_anchor, trans_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } - return SUCCESS; -} - -Status ProcessNetoutputNodeFp16Nc1hwc0(GeTensorDesc &src_desc, const InDataAnchorPtr &in_anchor, - GeTensorDescPtr &net_output_input_desc, NodePtr &node) { - bool is_dynamic = CheckOpType(node, MERGE); - auto src_op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(src_op_desc); - ge::GeShape src_shape = src_desc.GetShape(); - ge::Format src_format = src_desc.GetFormat(); - ge::DataType src_dtype = src_desc.GetDataType(); - if (src_dtype != DT_FLOAT16) { - if (!is_dynamic) { - auto peer_out = in_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(peer_out); - NodePtr cast_node = CreateCastOp(src_shape, src_dtype, DT_FLOAT16, src_format, node); - GE_CHECK_NOTNULL(cast_node); - if (GraphUtils::InsertNodeBetweenDataAnchors(peer_out, in_anchor, cast_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } else { - // Update outputdesc - const GeTensorDescPtr &merge_output = src_op_desc->MutableOutputDesc(0); - GE_CHECK_NOTNULL(merge_output); - merge_output->SetDataType(DT_FLOAT16); - merge_output->SetOriginDataType(DT_FLOAT16); - // Update input - for (uint32_t i = 0; i < node->GetAllInDataAnchorsSize(); ++i) { - const GeTensorDescPtr &merge_input = src_op_desc->MutableInputDesc(i); - GE_CHECK_NOTNULL(merge_input); - src_shape = merge_input->GetShape(); - src_format = merge_input->GetFormat(); - src_dtype = merge_input->GetDataType(); - merge_input->SetDataType(DT_FLOAT16); - merge_input->SetOriginDataType(DT_FLOAT16); - const InDataAnchorPtr &dst_in_anchor = node->GetInDataAnchor(i); - const OutDataAnchorPtr &src_out_anchor = dst_in_anchor->GetPeerOutAnchor(); - NodePtr cast_node = CreateCastOp(src_shape, src_dtype, DT_FLOAT16, src_format, node); - if (GraphUtils::InsertNodeBetweenDataAnchors(src_out_anchor, dst_in_anchor, cast_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } - } - net_output_input_desc->SetDataType(DT_FLOAT16); - net_output_input_desc->SetOriginDataType(DT_FLOAT16); - } - if (src_format == FORMAT_NC1HWC0) { - GELOGI("Format is NC1HWC0, no need to transfer"); - return SUCCESS; - } - std::vector dst_shape_dims; - std::vector src_shape_dims = src_shape.GetDims(); - if (TransferShape2NC1HWC0(src_format, src_shape_dims, DT_FLOAT16, FORMAT_NC1HWC0, dst_shape_dims) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Trans shape failed"); - return FAILED; - } - ge::GeShape dst_shape(dst_shape_dims); - net_output_input_desc->SetFormat(FORMAT_NC1HWC0); - net_output_input_desc->SetOriginFormat(FORMAT_NC1HWC0); - net_output_input_desc->SetShape(dst_shape); - net_output_input_desc->SetOriginShape(dst_shape); - if (!is_dynamic) { - NodePtr trans_node = CreateTransdataNode(src_shape, src_format, dst_shape, FORMAT_NC1HWC0, DT_FLOAT16, node); - GE_CHECK_NOTNULL(trans_node); - auto peer_out_new = in_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(peer_out_new); - if (GraphUtils::InsertNodeBetweenDataAnchors(peer_out_new, in_anchor, trans_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } else { - if (ProcessFp16Nc1hwc0Dynamic(src_op_desc, node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "ProcessFp16Nc1hwc0Dynamic failed"); - return FAILED; - } - } - return SUCCESS; -} - -Status ProcessOutputDynamic(const NodePtr &src_node, NodePtr &node, ge::DataType &output_data_type) { - OpDescPtr src_op_desc = src_node->GetOpDesc(); - const GeTensorDescPtr &merge_output = src_op_desc->MutableOutputDesc(0); - GE_CHECK_NOTNULL(merge_output); - merge_output->SetDataType(output_data_type); - merge_output->SetOriginDataType(output_data_type); - // Update input - for (uint32_t i = 0; i < src_node->GetAllInDataAnchorsSize(); ++i) { - const GeTensorDescPtr &merge_input = src_op_desc->MutableInputDesc(i); - GE_CHECK_NOTNULL(merge_input); - ge::GeShape src_shape = merge_input->GetShape(); - ge::Format src_format = merge_input->GetFormat(); - ge::DataType src_dtype = merge_input->GetDataType(); - merge_input->SetDataType(output_data_type); - merge_input->SetOriginDataType(output_data_type); - const InDataAnchorPtr &dst_in_anchor = src_node->GetInDataAnchor(i); - GE_CHECK_NOTNULL(dst_in_anchor); - const OutDataAnchorPtr &src_out_anchor = dst_in_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(src_out_anchor); - NodePtr cast_node = CreateCastOp(src_shape, src_dtype, output_data_type, src_format, node); - if (GraphUtils::InsertNodeBetweenDataAnchors(src_out_anchor, dst_in_anchor, cast_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } - return SUCCESS; -} - -Status ProcessNetoutputNode(NodePtr &node, std::string &output_type) { - auto op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - ge::DataType output_data_type = ge::DT_FLOAT; - bool is_set_output_type = CheckIfSetOutputType(output_type, output_data_type); - - for (const auto &in_anchor : node->GetAllInDataAnchors()) { - auto index = static_cast(in_anchor->GetIdx()); - auto peer_out = in_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(peer_out); - auto src_index = static_cast(peer_out->GetIdx()); - auto src_node = peer_out->GetOwnerNode(); - GE_CHECK_NOTNULL(src_node); - bool is_dynamic = CheckOpType(src_node, MERGE); - - OpDescPtr src_op_desc = src_node->GetOpDesc(); - GE_CHECK_NOTNULL(src_op_desc); - auto net_output_input_desc = op_desc->MutableInputDesc(index); - GE_CHECK_NOTNULL(net_output_input_desc); - - ge::GeShape src_shape = src_op_desc->GetOutputDesc(src_index).GetShape(); - ge::Format src_format = src_op_desc->GetOutputDesc(src_index).GetFormat(); - ge::DataType src_dtype = src_op_desc->GetOutputDesc(src_index).GetDataType(); - // Update datatype - if (is_set_output_type) { - GELOGI("Enter into process output_type schedule"); - if (src_dtype == output_data_type) { - GELOGI("Data type is same ,no need to transfer."); - continue; - } - if (!is_dynamic) { - NodePtr cast_node = CreateCastOp(src_shape, src_dtype, output_data_type, src_format, node); - if (GraphUtils::InsertNodeBetweenDataAnchors(peer_out, in_anchor, cast_node) != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "InsertNodeBetweenDataAnchors failed"); - return FAILED; - } - } else { - // Update outputdesc - if (ProcessOutputDynamic(src_node, node, output_data_type) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "ProcessOutputDynamic failed"); - return FAILED; - } - } - net_output_input_desc->SetDataType(output_data_type); - net_output_input_desc->SetOriginDataType(output_data_type); - continue; - } - // output_node is not set,check if is_output_adjust_hw_layout is set - bool set_fp16_nc1hwc0 = false; - if (!is_dynamic) { - (void)AttrUtils::GetBool(src_op_desc, "output_set_fp16_nc1hwc0", set_fp16_nc1hwc0); - } else { - // need check dynamic scene, graph structure: node->merge->netoutput - const InDataAnchorPtr &merge_input_anchor = src_node->GetInDataAnchor(0); - GE_CHECK_NOTNULL(merge_input_anchor); - const OutDataAnchorPtr &src_out_anchor = merge_input_anchor->GetPeerOutAnchor(); - GE_CHECK_NOTNULL(src_out_anchor); - auto src_merge_node = src_out_anchor->GetOwnerNode(); - GE_CHECK_NOTNULL(src_merge_node); - auto src_merge_node_opdesc = src_merge_node->GetOpDesc(); - (void)AttrUtils::GetBool(src_merge_node_opdesc, "output_set_fp16_nc1hwc0", set_fp16_nc1hwc0); - } - if (set_fp16_nc1hwc0) { - GELOGI("Node [%s] should be set FP16 and NC1HWC0", src_op_desc->GetName().c_str()); - if ((src_format != FORMAT_NCHW) && (src_format != FORMAT_NHWC) && (src_format != FORMAT_NC1HWC0)) { - GELOGE(INTERNAL_ERROR, "Format is not one of NCHW, NHWC, NC1HWC0."); - return FAILED; - } - GeTensorDesc src_desc(src_shape, src_format, src_dtype); - if (ProcessNetoutputNodeFp16Nc1hwc0(src_desc, in_anchor, net_output_input_desc, src_node) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Process netoutput fp16 nc1hwc0."); - return FAILED; - } - } - } - return SUCCESS; -} - Status CheckIfNeedSetNdFormat(const NodePtr &node_ptr) { auto op = node_ptr->GetOpDesc(); GE_CHECK_NOTNULL(op); @@ -1054,7 +649,6 @@ Status ProcessInputFP16DynShape(NodePtr &node_ptr, bool &is_dynamic_batch, NodeP return SUCCESS; } input->SetDataType(DT_FLOAT16); - input->SetOriginDataType(DT_FLOAT16); int64_t input_shape_size = 0; int64_t output_shape_size = 0; ge::graphStatus input_graph_status = ge::TensorUtils::GetTensorSizeInBytes(*input, input_shape_size); @@ -1067,7 +661,6 @@ Status ProcessInputFP16DynShape(NodePtr &node_ptr, bool &is_dynamic_batch, NodeP const GeTensorDescPtr &output = op_desc->MutableOutputDesc(0); GE_CHECK_NOTNULL(output); output->SetDataType(DT_FLOAT16); - output->SetOriginDataType(DT_FLOAT16); ge::TensorUtils::SetSize(*output, output_shape_size); if (is_dynamic_batch) { GELOGI("The node [%s] dtype set fp16", switchn_node->GetName().c_str()); @@ -1076,12 +669,10 @@ Status ProcessInputFP16DynShape(NodePtr &node_ptr, bool &is_dynamic_batch, NodeP auto switchn_input = switchn_op_desc->MutableInputDesc(0); GE_CHECK_NOTNULL(switchn_input); switchn_input->SetDataType(DT_FLOAT16); - switchn_input->SetOriginDataType(DT_FLOAT16); for (uint32_t i = 0; i < switchn_node->GetAllOutDataAnchorsSize(); ++i) { const GeTensorDescPtr &switchn_output = switchn_op_desc->MutableOutputDesc(i); GE_CHECK_NOTNULL(switchn_output); switchn_output->SetDataType(DT_FLOAT16); - switchn_output->SetOriginDataType(DT_FLOAT16); } } return SUCCESS; @@ -1100,10 +691,6 @@ Status ProcessInputNC1HWC0DynShape(NodePtr &node_ptr, bool &is_dynamic_batch, No GELOGE(INTERNAL_ERROR, "The format [%s] is unsupported", TypeUtils::FormatToSerialString(old_format).c_str()); return FAILED; } - if (old_format == FORMAT_NC1HWC0) { - GELOGI("No need to transfer format"); - return SUCCESS; - } if (ModifyInputFormatAndShape(node_ptr) != SUCCESS) { GELOGE(INTERNAL_ERROR, "modify format and shape failed"); return FAILED; @@ -1139,7 +726,7 @@ Status ProcessDataNodeDynShape(NodePtr &node_ptr) { } for (auto const &next_node : node_ptr->GetOutNodes()) { if (next_node->GetType() == AIPP) { - ErrorManager::GetInstance().ATCReportErrMessage("E10049", {"opname"}, {node_ptr->GetName()}); + ErrorManager::GetInstance().ATCReportErrMessage("E10034", {"opname"}, {node_ptr->GetName()}); GELOGE(INTERNAL_ERROR, "This input op [%s] is linked to aipp, can not be set to fp16, " "please check your atc parameter --insert_op_conf, --input_fp16_nodes.", @@ -1171,6 +758,42 @@ Status ProcessDataNodeDynShape(NodePtr &node_ptr) { return SUCCESS; } +Status GetStorageFormatAndShape(OpDescPtr &op_desc, const GeTensorDescPtr &tensor_desc_ptr, Format &storage_format, + vector &dst_shape_dims) { + GE_CHECK_NOTNULL(op_desc); + GE_CHECK_NOTNULL(tensor_desc_ptr); + + storage_format = FORMAT_RESERVED; + int64_t format = FORMAT_RESERVED; + dst_shape_dims.clear(); + if (ge::AttrUtils::GetInt(*tensor_desc_ptr, ATTR_NAME_STORAGE_FORMAT, format)) { + storage_format = static_cast(format); + vector storage_shape; + if (ge::AttrUtils::GetListInt(*tensor_desc_ptr, ATTR_NAME_STORAGE_SHAPE, storage_shape)) { + for (auto dim : storage_shape) { + dst_shape_dims.push_back(static_cast(dim)); + } + GELOGI("Update node by storage format, node: [%s], storage_format: [%s], storage_shape:[%s]", + op_desc->GetName().c_str(), TypeUtils::FormatToSerialString(storage_format).c_str(), + formats::JoinToString(storage_shape).c_str()); + } else { + GELOGE(PARAM_INVALID, + "Update node by storage format failed, storage_shape not set. " + "node: [%s], storage_format [%s]", + op_desc->GetName().c_str(), TypeUtils::FormatToSerialString(storage_format).c_str()); + return FAILED; + } + + ge::Format old_format = tensor_desc_ptr->GetFormat(); + auto old_shape = tensor_desc_ptr->GetShape().GetDims(); + if (old_format == storage_format && old_shape == dst_shape_dims) { + GELOGI("Update node by storage format, not changed."); + storage_format = FORMAT_RESERVED; + return SUCCESS; + } + } + return SUCCESS; +} Status ProcessNetoutputNodeFp16Nc1hwc0DynShape(GeTensorDesc &src_desc, GeTensorDescPtr &net_output_input_desc, NodePtr &node) { bool is_dynamic = CheckOpType(node, MERGE); @@ -1180,24 +803,16 @@ Status ProcessNetoutputNodeFp16Nc1hwc0DynShape(GeTensorDesc &src_desc, GeTensorD ge::Format src_format = src_desc.GetFormat(); net_output_input_desc->SetDataType(DT_FLOAT16); - net_output_input_desc->SetOriginDataType(DT_FLOAT16); if (is_dynamic) { auto merge_output = src_op_desc->MutableOutputDesc(0); GE_CHECK_NOTNULL(merge_output); merge_output->SetDataType(DT_FLOAT16); - merge_output->SetOriginDataType(DT_FLOAT16); for (uint32_t i = 0; i < node->GetAllInDataAnchorsSize(); ++i) { auto merge_input = src_op_desc->MutableInputDesc(i); GE_CHECK_NOTNULL(merge_input); merge_input->SetDataType(DT_FLOAT16); - merge_input->SetOriginDataType(DT_FLOAT16); } } - - if (src_format == FORMAT_NC1HWC0) { - GELOGI("Format is NC1HWC0, no need to transfer"); - return SUCCESS; - } std::vector dst_shape_dims; std::vector src_shape_dims = src_shape.GetDims(); if (TransferShape2NC1HWC0(src_format, src_shape_dims, DT_FLOAT16, FORMAT_NC1HWC0, dst_shape_dims) != SUCCESS) { @@ -1291,17 +906,14 @@ Status ProcessNetoutputNodeDynShape(NodePtr &node, std::string &output_type) { if (NeedUpdateOutputByOutputTypeParm(output_type, src_node, src_index, output_data_type)) { GELOGI("Enter into process output_type schedule"); net_output_input_desc->SetDataType(output_data_type); - net_output_input_desc->SetOriginDataType(output_data_type); if (is_dynamic) { auto merge_output = src_op_desc->MutableOutputDesc(0); GE_CHECK_NOTNULL(merge_output); merge_output->SetDataType(output_data_type); - merge_output->SetOriginDataType(output_data_type); for (uint32_t i = 0; i < src_node->GetAllInDataAnchorsSize(); ++i) { auto merge_input = src_op_desc->MutableInputDesc(i); GE_CHECK_NOTNULL(merge_input); merge_input->SetDataType(output_data_type); - merge_input->SetOriginDataType(output_data_type); } } continue; @@ -1337,7 +949,6 @@ Status ProcessNetoutputNodeDynShape(NodePtr &node, std::string &output_type) { } return SUCCESS; } - } // namespace GraphPrepare::GraphPrepare() : compute_graph_(nullptr) {} @@ -1431,6 +1042,8 @@ Status GraphPrepare::Init(const ge::Graph &graph, uint64_t session_id) { if (compute_graph_ != nullptr) { compute_graph_->SetSessionID(session_id); } + session_id_ = session_id; + Status ret = CheckGraph(); if (ret != SUCCESS) { GELOGE(ret, "RunGraph graph check fail, ret:%u", ret); @@ -1442,7 +1055,6 @@ Status GraphPrepare::Init(const ge::Graph &graph, uint64_t session_id) { GELOGE(ret, "RunGraph check ref op fail, ret:%u", ret); return ret; } - return SUCCESS; } @@ -1467,13 +1079,13 @@ Status GraphPrepare::CheckGraph() { } Status GraphPrepare::CheckRefInputNode(const NodePtr &node, const std::string &input_name, - const std::unordered_set &ref_nodes) { + const std::set &ref_nodes) { // Acceptable input types should be ref node, variable or Switch operator, which is issued by ME for dynamic - // lossscale and would be optimized in SwitchOpPass. Since ME dont differentiate between RefSwitch and Switch, - // and only issue Switch. - static std::unordered_set acceptable_types = {ge::VARIABLE, ge::VARIABLEV2, ge::VARHANDLEOP, - ge::REFSWITCH, ge::REFMERGE, ge::REFENTER, - ge::REFNEXTITERATION, ge::REFEXIT, ge::SWITCH}; + // lossscale and would be optimized in SwitchToStreamSwitchPass. + // Since ME dont differentiate between RefSwitch and Switch, and only issue Switch. + static std::set acceptable_types = {ge::VARIABLE, ge::VARIABLEV2, ge::VARHANDLEOP, + ge::REFSWITCH, ge::REFMERGE, ge::REFENTER, + ge::REFNEXTITERATION, ge::REFEXIT, ge::SWITCH}; GE_CHECK_NOTNULL(node); const auto &op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); @@ -1499,7 +1111,6 @@ Status GraphPrepare::CheckRefInputNode(const NodePtr &node, const std::string &i } } bool is_acceptable = (acceptable_types.find(input_type) != acceptable_types.end()); - if (!is_acceptable) { GELOGE(PARAM_INVALID, "The ref input of ref node %s[%s] must be ref node or variable, but %s[%s]isn't.", node->GetName().c_str(), node->GetType().c_str(), input_op_desc->GetName().c_str(), @@ -1512,7 +1123,7 @@ Status GraphPrepare::CheckRefInputNode(const NodePtr &node, const std::string &i Status GraphPrepare::CheckRefOp() { GE_CHECK_NOTNULL(compute_graph_); - std::unordered_set ref_nodes; + std::set ref_nodes; for (const NodePtr &node : compute_graph_->GetDirectNode()) { if (node == nullptr) { GELOGE(PARAM_INVALID, "param [node] must not be null."); @@ -1524,20 +1135,15 @@ Status GraphPrepare::CheckRefOp() { return PARAM_INVALID; } - auto input_names = op_desc->GetAllInputNames(); + auto input_name_index = op_desc->GetAllInputName(); auto outputs = op_desc->GetAllOutputName(); - std::unordered_set all_output_name; - - for (auto &output : outputs) { - all_output_name.insert(output.first); - } - for (const auto &input_name : input_names) { - if (all_output_name.find(input_name) != all_output_name.end()) { - if (CheckRefInputNode(node, input_name, ref_nodes) != SUCCESS) { + for (const auto &name_index : input_name_index) { + if (op_desc->GetOutputIndexByName(name_index.first) != -1) { + if (CheckRefInputNode(node, name_index.first, ref_nodes) != SUCCESS) { GELOGE(PARAM_INVALID, "CheckRefInputNode failed."); return PARAM_INVALID; } - (void)ref_nodes.insert(node); + (void)ref_nodes.insert(node); // no need to check value } } } @@ -1548,7 +1154,7 @@ Status GraphPrepare::SetRtContext(rtContext_t rt_context, rtCtxMode_t mode) { GELOGI("set rt_context %d, device id:%u.", static_cast(mode), ge::GetContext().DeviceId()); GE_CHK_RT_RET(rtCtxCreate(&rt_context, mode, ge::GetContext().DeviceId())); GE_CHK_RT_RET(rtCtxSetCurrent(rt_context)); - RtContextUtil::GetInstance().AddrtContext(rt_context); + RtContextUtil::GetInstance().AddRtContext(session_id_, rt_context); return SUCCESS; } @@ -1566,6 +1172,8 @@ Status GraphPrepare::AdjustDataOpOutput(const NodePtr &node) { int64_t tensor_size = 0; graphStatus graph_status = TensorUtils::GetTensorMemorySizeInBytes(output, tensor_size); if (graph_status != GRAPH_SUCCESS) { + ErrorManager::GetInstance().ATCReportErrMessage("E19012", {"function", "reason"}, + {"GetTensorMemorySizeInBytes", "opname is " + node->GetName()}); GELOGE(graph_status, "GetTensorMemorySizeInBytes failed!"); return FAILED; } @@ -1599,12 +1207,16 @@ Status GraphPrepare::UpdateInput(const std::vector &user_input) { GeTensorDesc desc(user_input[index].GetTensorDesc()); auto format = desc.GetFormat(); auto origin_format = desc.GetOriginFormat(); - bool is_internal = TypeUtils::IsInternalFormat(format) || TypeUtils::IsInternalFormat(origin_format); - bool need_check_internal_format = (!options_.is_single_op) && is_internal; + // data maybe internal format [FRACTAL_NZ] at singleop process such as GEMM. + bool need_check_internal_format = (!IsTansDataOpData(input_node)) && (!options_.is_single_op); if (need_check_internal_format) { - GELOGE(PARAM_INVALID, "Input format %s or origin_format %s is not support.", - TypeUtils::FormatToSerialString(format).c_str(), TypeUtils::FormatToSerialString(origin_format).c_str()); - return FAILED; + bool is_internal = TypeUtils::IsInternalFormat(format) || TypeUtils::IsInternalFormat(origin_format); + if (is_internal) { + GELOGE(PARAM_INVALID, "Input format %s or origin_format %s is not support.", + TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::FormatToSerialString(origin_format).c_str()); + return FAILED; + } } auto data_type = desc.GetDataType(); @@ -1623,7 +1235,8 @@ Status GraphPrepare::UpdateInput(const std::vector &user_input) { GE_IF_BOOL_EXEC(ge::TensorUtils::GetSize(desc, size) != GRAPH_SUCCESS, GELOGE(INTERNAL_ERROR, "TensorUtils GetSize failed"); return FAILED); - if ((size != 0) && (shape_size != size)) { + bool size_check = (size != 0 && shape_size != size); + if (size_check) { GELOGE(PARAM_INVALID, "input data size =%ld, shape_size =%ld.", size, shape_size); return FAILED; } @@ -1742,29 +1355,49 @@ Status GraphPrepare::ResourcePairProcess(const std::string &action) { return SUCCESS; } -Status GraphPrepare::OptimizeAfterInfershapeByAtcParams() { - if (options_.train_graph_flag) { - GELOGI("This is train mode, no need to do this schedule."); - return SUCCESS; - } - GE_RETURN_IF_ERROR(InsertNewOpUtil::Instance().UpdateDataNodeByAipp(compute_graph_)); - for (auto &node_ptr : compute_graph_->GetDirectNode()) { +Status GraphPrepare::UpdateDataNetOutputByStorageFormat() { + for (auto &node_ptr : compute_graph_->GetAllNodes()) { GE_CHECK_NOTNULL(node_ptr); - if (CheckIfNeedSetNdFormat(node_ptr) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Set node [%s] format ND failed", node_ptr->GetName().c_str()); - return FAILED; - } if (node_ptr->GetType() == DATA) { - if (ProcessDataNode(node_ptr) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Process data node failed"); + uint32_t index = 0; + auto op_desc = node_ptr->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + const GeTensorDescPtr input = op_desc->MutableInputDesc(index); + Format storage_format = FORMAT_RESERVED; + vector dst_shape_dims; + if (GetStorageFormatAndShape(op_desc, input, storage_format, dst_shape_dims) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Get storage format for input failed"); + return FAILED; + } + + if (storage_format == FORMAT_RESERVED) { + continue; + } + + if (ModifyDataNetOutputFormatAndShape(op_desc, index, storage_format, dst_shape_dims) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Modify format and shape for inputfailed"); return FAILED; } } if (node_ptr->GetType() == ge::NETOUTPUT) { - if (ProcessNetoutputNode(node_ptr, options_.output_datatype) != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Process netoutput node failed"); - return FAILED; + auto op_desc = node_ptr->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + for (uint32_t index = 0; index < op_desc->GetOutputsSize(); index++) { + const GeTensorDescPtr output = op_desc->MutableOutputDesc(index); + Format storage_format = FORMAT_RESERVED; + vector dst_shape_dims; + if (GetStorageFormatAndShape(op_desc, output, storage_format, dst_shape_dims) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Get storage format from output failed"); + return FAILED; + } + if (storage_format == FORMAT_RESERVED) { + continue; + } + if (ModifyDataNetOutputFormatAndShape(op_desc, index, storage_format, dst_shape_dims) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Modify format and shape for output failed"); + return FAILED; + } } } } @@ -1908,12 +1541,6 @@ Status GraphPrepare::Preprocess(const std::vector &user_input) { ProcessCCEFormat(); - ret = OptimizeAfterInfershapeByAtcParams(); - if (ret != SUCCESS) { - GELOGE(ret, "Optimize for input if set inputfp16 failed."); - return ret; - } - SaveOriginalGraphToOmModel(); GE_TIMESTAMP_START(OptimizeForPreprocess); @@ -1955,9 +1582,7 @@ Status GraphPrepare::PrepareDynShape(ConstGraphPtr graph, const std::vector(options_.framework_type); const Graph &const_graph = *graph; @@ -1972,7 +1597,6 @@ Status GraphPrepare::PrepareDynShape(ConstGraphPtr graph, const std::vectorInferOriginFormat(); + GE_DUMP(compute_graph_, "after_inferformat"); + if (ret != SUCCESS) { + GELOGE(ret, "Prepare Graph inferformat failed"); + return ret; + } InferShapePass infer_shape_pass; + NamesToPass names_to_passes; names_to_passes.emplace_back("InferShapePass", &infer_shape_pass); + GEPass ge_passes(compute_graph_); ret = ge_passes.Run(names_to_passes); + GE_DUMP(compute_graph_, "after_infershape"); if (ret != SUCCESS) { GELOGE(ret, "Run ge_passes infershape for preprocess failed, ret:%u.", ret); return ret; } + ShapeRefiner::ClearContextMap(); return SUCCESS; } Status GraphPrepare::Prepare(ConstGraphPtr graph, const std::vector &user_input, ge::ComputeGraphPtr &compute_graph, VarAccelerateCtrl &var_acc_ctrl, uint64_t session_id) { - // train graph flag - if (options_.train_graph_flag) { - domi::GetContext().train_flag = true; - } domi::GetContext().type = static_cast(options_.framework_type); if (graph == nullptr) { @@ -2071,7 +1699,7 @@ Status GraphPrepare::Prepare(ConstGraphPtr graph, const std::vector &u } GraphOptimize graph_optimize; - if (!domi::GetContext().train_flag) { + if (!options_.train_graph_flag && !domi::GetContext().train_flag) { GE_DUMP(compute_graph_, "BeforeOriginalGraphForQuantize"); GE_TIMESTAMP_START(OptimizeOriginalGraphForQuantize); ret = graph_optimize.OptimizeOriginalGraphForQuantize(compute_graph_); @@ -2273,6 +1901,7 @@ Status GraphPrepare::InferShapeForPreprocess() { } } } + ShapeRefiner::ClearContextMap(); if (ret != SUCCESS) { GELOGE(ret, "Run ge_passes infershape for preprocess failed, ret:%u.", ret); return ret; @@ -2281,6 +1910,14 @@ Status GraphPrepare::InferShapeForPreprocess() { } Status GraphPrepare::PrepareOptimize() { GELOGI("Start optimize for preprocess."); + // check rw type + GraphOptimize graph_optimize; + bool has_conflict = false; + graph_optimize.CheckRWConflict(compute_graph_, has_conflict); + if (has_conflict) { + GELOGE(GRAPH_PARAM_INVALID, "There has rw conflict.Stop optimize."); + return FAILED; + } PassManager original_graph_passes; // Graph pass try { @@ -2302,10 +1939,10 @@ Status GraphPrepare::PrepareOptimize() { GEPass ge_passes(compute_graph_); NamesToPass names_to_passes; EnterPass enter_pass; - PrintOpPass print_pass; names_to_passes.emplace_back("EnterPass", &enter_pass); CondPass cond_pass; names_to_passes.emplace_back("CondPass", &cond_pass); + PrintOpPass print_pass; if (options_.enable_print_op_pass) { names_to_passes.emplace_back("PrintOpPass", &print_pass); } @@ -2478,7 +2115,9 @@ Status GraphPrepare::OptimizeForPreprocess() { (void)graph_pass.AddPass("OptimizeForPreprocess::PrunePass", new PrunePass); (void)graph_pass.AddPass("OptimizeForPreprocess::NextIterationPass", new NextIterationPass); (void)graph_pass.AddPass("OptimizeForPreprocess::ControlTriggerPass", new ControlTriggerPass); - (void)graph_pass.AddPass("OptimizeForPreprocess::SwitchOpPass", new SwitchOpPass); + (void)graph_pass.AddPass("OptimizeForPreprocess::MergeToStreamMergePass", new MergeToStreamMergePass); + (void)graph_pass.AddPass("OptimizeForPreprocess::SwitchToStreamSwitchPass", new SwitchToStreamSwitchPass); + (void)graph_pass.AddPass("OptimizeForPreprocess::AttachStreamLabelPass", new AttachStreamLabelPass); (void)graph_pass.AddPass("OptimizeForPreprocess::HcclMemcpyPass", new HcclMemcpyPass); GE_IF_BOOL_EXEC(options_.train_graph_flag, (void)graph_pass.AddPass("OptimizeForPreprocess::FlowCtrlPass", new FlowCtrlPass);); @@ -2560,8 +2199,6 @@ Status GraphPrepare::NewOptimizeGraphBeforeSubGraph(VarAccelerateCtrl &var_acc_c GEPass ge_passes_for_shape(compute_graph_); NamesToPass names_to_passes_for_shape; - IdentifyReferencePass identify_reference_pass; - names_to_passes_for_shape.emplace_back("IdentifyReferencePass", &identify_reference_pass); CastRemovePass cast_remove_pass; names_to_passes_for_shape.emplace_back("CastRemovePass", &cast_remove_pass); TransposeTransDataPass transpose_transdata_pass; @@ -2693,6 +2330,12 @@ Status GraphPrepare::CheckAndUpdateInput(const std::vector &user_input return SUCCESS; } Status GraphPrepare::UpdateInputOutputByOptions() { + auto ret = UpdateDataNetOutputByStorageFormat(); + if (ret != SUCCESS) { + GELOGE(ret, "Update format acoording to storage format failed."); + return ret; + } + if (options_.train_graph_flag) { GELOGI("This is train mode, no need to do this schedule."); return SUCCESS; @@ -2736,6 +2379,21 @@ bool GraphPrepare::IsBroadCastOpData(const ge::NodePtr &var_node) { return false; } +bool GraphPrepare::IsTansDataOpData(const ge::NodePtr &var_node) { + for (auto &out_anchor : var_node->GetAllOutDataAnchors()) { + GE_RT_FALSE_CHECK_NOTNULL(out_anchor); + for (auto &in_anchor : out_anchor->GetPeerInDataAnchors()) { + GE_RT_FALSE_CHECK_NOTNULL(in_anchor); + ge::NodePtr dst_node = in_anchor->GetOwnerNode(); + GE_RT_FALSE_CHECK_NOTNULL(dst_node); + if (dst_node->GetType() == TRANSDATA) { + return true; + } + } + } + return false; +} + bool GraphPrepare::ConfirmUseOpAndIndexByAnchor(const ge::InDataAnchorPtr &in_anchor, const map> &confirm_ops, ge::NodePtr &use_node) { GE_RT_FALSE_CHECK_NOTNULL(in_anchor); diff --git a/src/ge/graph/preprocess/graph_preprocess.h b/src/ge/graph/preprocess/graph_preprocess.h index b90caa86..343791bd 100644 --- a/src/ge/graph/preprocess/graph_preprocess.h +++ b/src/ge/graph/preprocess/graph_preprocess.h @@ -59,8 +59,7 @@ class GraphPrepare { Status Init(const ge::Graph &graph, uint64_t session_id = 0); Status Preprocess(const std::vector &user_input); Status CheckGraph(); - Status CheckRefInputNode(const NodePtr &node, const std::string &input_name, - const std::unordered_set &ref_nodes); + Status CheckRefInputNode(const NodePtr &node, const std::string &input_name, const std::set &ref_nodes); Status CheckRefOp(); Status SetRtContext(rtContext_t rt_context, rtCtxMode_t mode); Status AdjustDataOpOutput(const NodePtr &node); @@ -69,11 +68,11 @@ class GraphPrepare { Status CheckConstOp(); Status VerifyConstOp(const NodePtr &node); Status CheckUserInput(const std::vector &user_input); + Status UpdateDataNetOutputByStorageFormat(); Status OptimizeForPreprocess(); Status PrepareOptimize(); Status InferShapeForPreprocess(); Status TryDoAipp(); - Status OptimizeAfterInfershapeByAtcParams(); Status UpdateVariableFormats(ComputeGraphPtr &graph); Status UpdateVariableFormatsDynShape(ComputeGraphPtr &graph); Status FormatAndShapeProcess(); @@ -88,6 +87,8 @@ class GraphPrepare { Status UpdateInputOutputByOptions(); bool IsBroadCastOpData(const ge::NodePtr &var_node); + bool IsTansDataOpData(const ge::NodePtr &var_node); + void AdjustBroadCastOpData(const ge::NodePtr &var_node); bool IsAssignOpData(const ge::NodePtr &var_node); @@ -104,6 +105,7 @@ class GraphPrepare { ge::ComputeGraphPtr compute_graph_; GraphManagerOptions options_; + uint64_t session_id_ = 0; }; } // namespace ge #endif // GE_GRAPH_PREPROCESS_GRAPH_PREPROCESS_H_ diff --git a/src/ge/graph/preprocess/insert_op/ge_aipp_op.cc b/src/ge/graph/preprocess/insert_op/ge_aipp_op.cc index f35b6d3a..55c7b427 100644 --- a/src/ge/graph/preprocess/insert_op/ge_aipp_op.cc +++ b/src/ge/graph/preprocess/insert_op/ge_aipp_op.cc @@ -24,6 +24,7 @@ #include "common/dynamic_aipp.h" #include "common/ge/ge_util.h" #include "common/util.h" +#include "common/util/error_manager/error_manager.h" #include "external/graph/operator_factory.h" #include "framework/common/debug/ge_log.h" #include "framework/common/ge_inner_error_codes.h" @@ -51,6 +52,16 @@ } \ } while (0) +#define AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(expr, _status, errormsg) \ + do { \ + bool b = (expr); \ + if (!b) { \ + GELOGE(_status, errormsg); \ + ErrorManager::GetInstance().ATCReportErrMessage("E10043", {"reason"}, {errormsg}); \ + return _status; \ + } \ + } while (0) + namespace { const int32_t DEFAULT_MATRIX_R0C0_YUV2RGB = 298; const int32_t DEFAULT_MATRIX_R0C1_YUV2RGB = 0; @@ -411,86 +422,87 @@ Status AippOp::SetDefaultParams() { Status AippOp::ValidateParams() { GE_CHECK_NOTNULL(aipp_params_); - GE_CHK_BOOL_RET_STATUS(aipp_params_->aipp_mode() != domi::AippOpParams::undefined, PARAM_INVALID, - "when insert AIPP op, aipp_mode must be configured as static or dynamic "); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->var_reci_chn_0_size() <= 1, PARAM_INVALID, - "The parameter var_reci_chn_0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->var_reci_chn_1_size() <= 1, PARAM_INVALID, - "The parameter var_reci_chn_1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->var_reci_chn_2_size() <= 1, PARAM_INVALID, - "The parameter var_reci_chn_2 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->var_reci_chn_3_size() <= 1, PARAM_INVALID, - "The parameter var_reci_chn_3 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r0c0_size() <= 1, PARAM_INVALID, - "The parameter matrix_r0c0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r0c1_size() <= 1, PARAM_INVALID, - "The parameter matrix_r0c1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r0c2_size() <= 1, PARAM_INVALID, - "The parameter matrix_r0c2 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r1c0_size() <= 1, PARAM_INVALID, - "The parameter matrix_r1c0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r1c1_size() <= 1, PARAM_INVALID, - "The parameter matrix_r1c1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r1c2_size() <= 1, PARAM_INVALID, - "The parameter matrix_r1c2 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r2c0_size() <= 1, PARAM_INVALID, - "The parameter matrix_r2c0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r2c1_size() <= 1, PARAM_INVALID, - "The parameter matrix_r2c1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->matrix_r2c2_size() <= 1, PARAM_INVALID, - "The parameter matrix_r2c2 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->output_bias_0_size() <= 1, PARAM_INVALID, - "The parameter output_bias_0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->output_bias_1_size() <= 1, PARAM_INVALID, - "The parameter output_bias_1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->output_bias_2_size() <= 1, PARAM_INVALID, - "The parameter output_bias_2 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->input_bias_0_size() <= 1, PARAM_INVALID, - "The parameter input_bias_0 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->input_bias_1_size() <= 1, PARAM_INVALID, - "The parameter input_bias_1 can not be configed repeatedly"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->input_bias_2_size() <= 1, PARAM_INVALID, - "The parameter input_bias_2 can not be configed repeatedly"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->input_edge_idx_size() <= 1, PARAM_INVALID, - "The parameter input_edge_idx can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->aipp_mode() != domi::AippOpParams::undefined, PARAM_INVALID, + "When insert AIPP op, aipp_mode must be configured as static or dynamic "); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->var_reci_chn_0_size() <= 1, PARAM_INVALID, + "The parameter var_reci_chn_0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->var_reci_chn_1_size() <= 1, PARAM_INVALID, + "The parameter var_reci_chn_1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->var_reci_chn_2_size() <= 1, PARAM_INVALID, + "The parameter var_reci_chn_2 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->var_reci_chn_3_size() <= 1, PARAM_INVALID, + "The parameter var_reci_chn_3 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r0c0_size() <= 1, PARAM_INVALID, + "The parameter matrix_r0c0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r0c1_size() <= 1, PARAM_INVALID, + "The parameter matrix_r0c1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r0c2_size() <= 1, PARAM_INVALID, + "The parameter matrix_r0c2 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r1c0_size() <= 1, PARAM_INVALID, + "The parameter matrix_r1c0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r1c1_size() <= 1, PARAM_INVALID, + "The parameter matrix_r1c1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r1c2_size() <= 1, PARAM_INVALID, + "The parameter matrix_r1c2 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r2c0_size() <= 1, PARAM_INVALID, + "The parameter matrix_r2c0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r2c1_size() <= 1, PARAM_INVALID, + "The parameter matrix_r2c1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->matrix_r2c2_size() <= 1, PARAM_INVALID, + "The parameter matrix_r2c2 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->output_bias_0_size() <= 1, PARAM_INVALID, + "The parameter output_bias_0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->output_bias_1_size() <= 1, PARAM_INVALID, + "The parameter output_bias_1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->output_bias_2_size() <= 1, PARAM_INVALID, + "The parameter output_bias_2 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->input_bias_0_size() <= 1, PARAM_INVALID, + "The parameter input_bias_0 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->input_bias_1_size() <= 1, PARAM_INVALID, + "The parameter input_bias_1 can not be configed repeatedly"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->input_bias_2_size() <= 1, PARAM_INVALID, + "The parameter input_bias_2 can not be configed repeatedly"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->input_edge_idx_size() <= 1, PARAM_INVALID, + "The parameter input_edge_idx can not be configed repeatedly"); const domi::AippOpParams::AippMode aipp_mode = aipp_params_->aipp_mode(); if (aipp_mode == domi::AippOpParams::dynamic) { - GE_CHK_BOOL_RET_STATUS(aipp_params_->max_src_image_size() > 0, PARAM_INVALID, - "for dynamic AIPP params, max_src_image_size must greater than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG( + aipp_params_->max_src_image_size() > 0, PARAM_INVALID, + "For dynamic AIPP params, max_src_image_size must be set which number should be greater than 0"); } else { - GE_CHK_BOOL_RET_STATUS(aipp_params_->input_format() != domi::AippOpParams::UNDEFINED, PARAM_INVALID, - "Input format of AIPP conf is undefined"); - - GE_CHK_BOOL_RET_STATUS(aipp_params_->src_image_size_w() >= 0, PARAM_INVALID, - "src_image_size_w must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->src_image_size_h() >= 0, PARAM_INVALID, - "src_image_size_h must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->load_start_pos_w() >= 0, PARAM_INVALID, - "load_start_pos_w must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->load_start_pos_h() >= 0, PARAM_INVALID, - "load_start_pos_h must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->crop_size_w() >= 0, PARAM_INVALID, - "crop_size_w must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->resize_output_w() >= 0, PARAM_INVALID, - "resize_output_w must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->resize_output_h() >= 0, PARAM_INVALID, - "resize_output_h must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->left_padding_size() >= 0, PARAM_INVALID, - "left_padding_size must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->right_padding_size() >= 0, PARAM_INVALID, - "right_padding_size must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->top_padding_size() >= 0, PARAM_INVALID, - "top_padding_size must not be configed smaller than 0"); - GE_CHK_BOOL_RET_STATUS(aipp_params_->bottom_padding_size() >= 0, PARAM_INVALID, - "bottom_padding_size must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->input_format() != domi::AippOpParams::UNDEFINED, PARAM_INVALID, + "Input format of AIPP conf is undefined"); + + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->src_image_size_w() >= 0, PARAM_INVALID, + "Src_image_size_w must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->src_image_size_h() >= 0, PARAM_INVALID, + "Src_image_size_h must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->load_start_pos_w() >= 0, PARAM_INVALID, + "Load_start_pos_w must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->load_start_pos_h() >= 0, PARAM_INVALID, + "Load_start_pos_h must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->crop_size_w() >= 0, PARAM_INVALID, + "Crop_size_w must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->resize_output_w() >= 0, PARAM_INVALID, + "Resize_output_w must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->resize_output_h() >= 0, PARAM_INVALID, + "Resize_output_h must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->left_padding_size() >= 0, PARAM_INVALID, + "Left_padding_size must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->right_padding_size() >= 0, PARAM_INVALID, + "Right_padding_size must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->top_padding_size() >= 0, PARAM_INVALID, + "Top_padding_size must not be configed smaller than 0"); + AIPP_RETURN_STATUS_AND_REPROT_ERRORMSG(aipp_params_->bottom_padding_size() >= 0, PARAM_INVALID, + "Bottom_padding_size must not be configed smaller than 0"); } return SUCCESS; diff --git a/src/ge/graph/preprocess/insert_op/util_insert_aipp_op.cc b/src/ge/graph/preprocess/insert_op/util_insert_aipp_op.cc index 5fe19869..8bb0c6c4 100644 --- a/src/ge/graph/preprocess/insert_op/util_insert_aipp_op.cc +++ b/src/ge/graph/preprocess/insert_op/util_insert_aipp_op.cc @@ -45,7 +45,7 @@ static void ConvertShape2Nhwc(Format &format, vector &shape_vec) { return; } if (format != FORMAT_NCHW) { - GELOGW("The format is not NCHW, current format is %s", TypeUtils::FormatToSerialString(format).c_str()); + GELOGW("The format is not NCHW, current format is %s.", TypeUtils::FormatToSerialString(format).c_str()); return; } vector shape_vec_tmp; @@ -245,7 +245,6 @@ Status InsertNewOpUtil::UpdatePrevNodeByAipp(NodePtr &node, std::set &s GELOGE(FAILED, "Can not get size from aipp [%s]", aipp_op_desc->GetName().c_str()); return FAILED; } - // Save the input size of aipp node, which will be used in dumping aipp node or fused aipp node (void)AttrUtils::SetInt(aipp_input, ATTR_NAME_INPUT_ORIGIN_SIZE, size); auto in_data_anchor = node->GetInDataAnchor(0); diff --git a/src/ge/graph/preprocess/multi_batch_copy_graph.cc b/src/ge/graph/preprocess/multi_batch_copy_graph.cc index fbe935ec..d1e9fe62 100644 --- a/src/ge/graph/preprocess/multi_batch_copy_graph.cc +++ b/src/ge/graph/preprocess/multi_batch_copy_graph.cc @@ -35,6 +35,9 @@ #include "graph/utils/graph_utils.h" #include "graph/utils/node_utils.h" +using std::string; +using std::vector; + namespace ge { namespace multibatch { namespace { @@ -45,6 +48,7 @@ const int kDataOutIndex = 0; const int kDataInIndex = 0; const int kMergeDataOutIndex = 0; const int kStaticOutput = -1; +const int kDecimal = 10; const size_t kMaxShapesCount = 100; const size_t kMinShapesCount = 2; @@ -126,8 +130,12 @@ Status CalcShape(const std::vector &batch_shape, GeShape &data_shape) { for (size_t i = 0; i < data_shape.GetDimNum(); ++i) { if (data_shape.GetDim(i) < 0) { if (batch_shape_index >= batch_shape.size()) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E19012", {"function", "reason"}, + {"CalcShape", "the batch shape count " + std::to_string(batch_shape.size()) + + " does not match the data shape " + data_shape.ToString()}); GELOGE(PARAM_INVALID, - "Failed to calc tensor shape, the batch shape count %zu, doees not match the data shape %s", + "Failed to calc tensor shape, the batch shape count %zu, does not match the data shape %s", batch_shape.size(), data_shape.ToString().c_str()); return PARAM_INVALID; } @@ -135,6 +143,10 @@ Status CalcShape(const std::vector &batch_shape, GeShape &data_shape) { } } if (batch_shape_index != batch_shape.size()) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E19012", {"function", "reason"}, + {"CalcShape", "the batch shape count " + std::to_string(batch_shape.size()) + " does not match the data shape " + + data_shape.ToString()}); GELOGE(PARAM_INVALID, "Failed to calc tensor shape, the batch shape count %zu, does not match the data shape %s", batch_shape.size(), data_shape.ToString().c_str()); return PARAM_INVALID; @@ -199,9 +211,9 @@ Status CheckDataShape(const std::vector &nodes) { } } if (unknown_shape_count == 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10055"); + ErrorManager::GetInstance().ATCReportErrMessage("E10040"); GELOGE(PARAM_INVALID, - "Need unknow shape data when user set --dynamic_batch_size or --dynamic_image_size, please check."); + "Need unknow shape data when user set --dynamic_batch_size, --dynamic_image_size or --dynamic_dims"); return PARAM_INVALID; } @@ -279,6 +291,8 @@ Status MultiBatchGraphCopyer::CreateNewNodes() { case kNodeOutBatchBranch: ret = InsertMergeForEdgeNode(node); break; + case kNodeNotSupportNode: + break; default: GELOGE(INTERNAL_ERROR, "Unexpected status %d on node %s", static_cast(branch_status), node->GetName().c_str()); @@ -291,7 +305,13 @@ Status MultiBatchGraphCopyer::CreateNewNodes() { } return SUCCESS; } + NodeStatus MultiBatchGraphCopyer::GetNodeStatus(const NodePtr &node) { + // node with subgraph is not supported + if (!(node->GetOpDesc()->GetSubgraphInstanceNames().empty())) { + return kNodeNotSupportNode; + } + if (node->GetType() == NETOUTPUT) { return kNodeOutBatchBranch; } @@ -305,6 +325,7 @@ NodeStatus MultiBatchGraphCopyer::GetNodeStatus(const NodePtr &node) { } return kNodeOutBatchBranch; } + NodePtr MultiBatchGraphCopyer::InsertMergeNode(const NodePtr &node, int index) { if (index < 0) { // the merge node must has data inputs, if origin connection is a control @@ -477,38 +498,38 @@ Status MultiBatchGraphCopyer::CheckArguments() { return PARAM_INVALID; } if (shapes_.size() < kMinShapesCount) { - ErrorManager::GetInstance().ATCReportErrMessage("E10050", {"shapesize", "minshapesize"}, - {std::to_string(shapes_.size()), std::to_string(kMinShapesCount)}); + ErrorManager::GetInstance().ATCReportErrMessage( + "E10035", {"shapesize", "minshapesize"}, {std::to_string(shapes_.size()), std::to_string(kMinShapesCount - 1)}); GELOGE(PARAM_INVALID, - "Input parameter[--dynamic_batch_size or --dynamic_image_size]'s " + "Input parameter[--dynamic_batch_size, --dynamic_image_size or --dynamic_dims]'s " "value size [%zu] must be greater than [%zu].", - shapes_.size(), kMinShapesCount); + shapes_.size(), kMinShapesCount - 1); return PARAM_INVALID; } if (shapes_.size() > kMaxShapesCount) { - ErrorManager::GetInstance().ATCReportErrMessage("E10051", {"shapesize", "maxshapesize"}, - {std::to_string(shapes_.size()), std::to_string(kMaxShapesCount)}); + ErrorManager::GetInstance().ATCReportErrMessage( + "E10036", {"shapesize", "maxshapesize"}, {std::to_string(shapes_.size()), std::to_string(kMaxShapesCount + 1)}); GELOGE(PARAM_INVALID, - "Input parameter[--dynamic_batch_size or --dynamic_image_size]'s " + "Input parameter[--dynamic_batch_size, --dynamic_image_size or --dynamic_dims]'s " "value size [%zu] must be less than [%zu].", - shapes_.size(), kMaxShapesCount); + shapes_.size(), kMaxShapesCount + 1); return PARAM_INVALID; } std::set> shapes_set; size_t shape_size = shapes_.at(0).size(); for (auto &shape : shapes_) { if (shape_size != shape.size()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10052", {"shapesize1", "shapesize2"}, + ErrorManager::GetInstance().ATCReportErrMessage("E10037", {"shapesize1", "shapesize2"}, {std::to_string(shape_size), std::to_string(shape.size())}); GELOGE(PARAM_INVALID, - "Input parameter[--dynamic_batch_size or --dynamic_image_size]'s " + "Input parameter[--dynamic_batch_size, --dynamic_image_size or --dynamic_dims]'s " "value size must be same, first group's size is %zu and another's is %zu.", shape_size, shape.size()); return PARAM_INVALID; } for (auto dim : shape) { if (dim <= 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10053", {"dim"}, {std::to_string(dim)}); + ErrorManager::GetInstance().ATCReportErrMessage("E10038", {"dim"}, {std::to_string(dim)}); GELOGE(PARAM_INVALID, "Invalid dim %ld, all dims must be greater than 0", dim); return PARAM_INVALID; } @@ -516,9 +537,9 @@ Status MultiBatchGraphCopyer::CheckArguments() { shapes_set.insert(shape); } if (shapes_set.size() != shapes_.size()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10054"); + ErrorManager::GetInstance().ATCReportErrMessage("E10039"); GELOGE(PARAM_INVALID, - "Input parameter[--dynamic_batch_size or --dynamic_image_size] exist duplicate shapes, please check"); + "Input parameter[--dynamic_batch_size, --dynamic_image_size or --dynamic_dims] exist duplicate shapes."); return PARAM_INVALID; } return SUCCESS; @@ -673,6 +694,10 @@ Status MultiBatchGraphCopyer::InsertSwitchNForData(const NodePtr &data) { GELOGE(INTERNAL_ERROR, "Failed to add attr value on output %zu tensor", i); return INTERNAL_ERROR; } + if (!AttrUtils::SetListInt(tensor, ATTR_NAME_COMBINED_DYNAMIC_DIMS, shape.GetDims())) { + GELOGE(INTERNAL_ERROR, "Failed to add attr ATTR_NAME_COMBINED_DYNAMIC_DIMS on output %zu tensor", i); + return INTERNAL_ERROR; + } if (switchn_desc->AddOutputDesc("output" + std::to_string(i), tensor) != GRAPH_SUCCESS) { GELOGE(GRAPH_FAILED, "Opdesc AddOutputDesc failed"); return GRAPH_FAILED; @@ -688,6 +713,10 @@ Status MultiBatchGraphCopyer::InsertSwitchNForData(const NodePtr &data) { GELOGE(INTERNAL_ERROR, "Failed to add switchn attr on data node %s", data->GetName().c_str()); return INTERNAL_ERROR; } + if (StampDynamicTypeForSwitchN(switchn_desc) != SUCCESS) { + GELOGE(INTERNAL_ERROR, "Failed to add dynamic type attr on switchn node %s", switchn_desc->GetName().c_str()); + return INTERNAL_ERROR; + } auto switchn = graph_->AddNode(switchn_desc); if (switchn == nullptr) { @@ -697,6 +726,26 @@ Status MultiBatchGraphCopyer::InsertSwitchNForData(const NodePtr &data) { data_nodes_to_switchn_[data.get()] = switchn; return SUCCESS; } + +Status MultiBatchGraphCopyer::StampDynamicTypeForSwitchN(OpDescPtr &switchn_desc) { + GE_CHECK_NOTNULL(switchn_desc); + int32_t dynamic_type = static_cast(FIXED); + if (!domi::GetContext().dynamic_batch_size.empty()) { + dynamic_type = static_cast(DYNAMIC_BATCH); + } + if (!domi::GetContext().dynamic_image_size.empty()) { + dynamic_type = static_cast(DYNAMIC_IMAGE); + } + if (!domi::GetContext().dynamic_dims.empty()) { + dynamic_type = static_cast(DYNAMIC_DIMS); + } + if (!AttrUtils::SetInt(switchn_desc, ATTR_DYNAMIC_TYPE, dynamic_type)) { + GELOGE(INTERNAL_ERROR, "Failed to add dynamic type attr of switchn node %s", switchn_desc->GetName().c_str()); + return INTERNAL_ERROR; + } + return SUCCESS; +} + Status MultiBatchGraphCopyer::InsertMergeForEdgeNode(const NodePtr &node) { for (auto &in_data_anchor : node->GetAllInDataAnchors()) { auto src_out_anchor = in_data_anchor->GetPeerOutAnchor(); @@ -896,7 +945,6 @@ Status MultiBatchGraphCopyer::LinkToNodeOutBranch(const NodePtr &node) { } Status ProcessMultiBatch(ComputeGraphPtr &graph) { - const int kDecimal = 10; std::vector> shapes; if (!domi::GetContext().dynamic_batch_size.empty()) { GELOGD("Found dynamic batch option, value %s", domi::GetContext().dynamic_batch_size.c_str()); @@ -909,25 +957,25 @@ Status ProcessMultiBatch(ComputeGraphPtr &graph) { GELOGI("Found dynamic batch, shape %s", formats::JoinToString(*shapes.rbegin()).c_str()); } } + if (!domi::GetContext().dynamic_image_size.empty()) { GELOGD("Found dynamic image size option, value %s", domi::GetContext().dynamic_image_size.c_str()); - std::vector shape_strs = ge::StringUtils::Split(domi::GetContext().dynamic_image_size, ';'); - for (const auto &shape_str : shape_strs) { - if (shape_str.empty()) { - continue; - } - std::vector shape; - std::vector dims = ge::StringUtils::Split(shape_str, ','); - for (const auto &dim : dims) { - if (dim.empty()) { - continue; - } - shape.emplace_back(std::strtol(dim.c_str(), nullptr, kDecimal)); - } - shapes.emplace_back(shape); + ParseDynamicSize(domi::GetContext().dynamic_image_size, shapes); + + for (const auto &shape : shapes) { GELOGI("Found dynamic image size, shape %s", formats::JoinToString(shape).c_str()); } } + + if (!domi::GetContext().dynamic_dims.empty()) { + GELOGD("Found dynamic dims option, value %s", domi::GetContext().dynamic_dims.c_str()); + ParseDynamicSize(domi::GetContext().dynamic_dims, shapes); + + for (const auto &shape : shapes) { + GELOGI("Found dynamic dims, shape %s", formats::JoinToString(shape).c_str()); + } + } + if (shapes.empty()) { GELOGD("There is no multi-batch options, no need to process multi-batch copy"); return SUCCESS; @@ -941,6 +989,26 @@ Status ProcessMultiBatch(ComputeGraphPtr &graph) { return copyer.CopyGraph(); } +void ParseDynamicSize(string dynamic_size, vector> &shapes) { + std::vector shape_strs = ge::StringUtils::Split(dynamic_size, ';'); + for (const auto &shape_str : shape_strs) { + if (shape_str.empty()) { + continue; + } + std::vector shape; + std::vector dims = ge::StringUtils::Split(shape_str, ','); + for (const auto &dim : dims) { + if (dim.empty()) { + continue; + } + shape.emplace_back(std::strtol(dim.c_str(), nullptr, kDecimal)); + } + if (!shape.empty()) { + shapes.emplace_back(shape); + } + } +} + Status GetDynamicOutputShape(ComputeGraphPtr &graph) { GELOGI("Start to get dynamic output dynamic batch shape msg"); std::vector dynamic_output_dims; diff --git a/src/ge/graph/preprocess/multi_batch_copy_graph.h b/src/ge/graph/preprocess/multi_batch_copy_graph.h index 2500645f..7e317cb0 100644 --- a/src/ge/graph/preprocess/multi_batch_copy_graph.h +++ b/src/ge/graph/preprocess/multi_batch_copy_graph.h @@ -27,12 +27,15 @@ namespace ge { namespace multibatch { Status ProcessMultiBatch(ComputeGraphPtr &graph); +void ParseDynamicSize(std::string dynamic_size, std::vector> &shapes); + Status GetDynamicOutputShape(ComputeGraphPtr &graph); enum NodeStatus { kNodeInBatchBranch, kNodeOutBatchBranch, kNodeStartNode, + kNodeNotSupportNode, }; class MultiBatchGraphCopyer { @@ -53,6 +56,7 @@ class MultiBatchGraphCopyer { NodePtr InsertShapeDataNode(); Status InsertSwitchNForData(const NodePtr &data); + Status StampDynamicTypeForSwitchN(OpDescPtr &switchn_desc); Status UpdateMaxShapeToData(const NodePtr &data); Status InsertMergeForEdgeNode(const NodePtr &node); diff --git a/src/ge/host_aicpu_engine/common/constant/constant.h b/src/ge/host_aicpu_engine/common/constant/constant.h new file mode 100644 index 00000000..998dc7eb --- /dev/null +++ b/src/ge/host_aicpu_engine/common/constant/constant.h @@ -0,0 +1,30 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_COMMON_CONSTANT_CONSTANT_H_ +#define GE_HOST_AICPU_ENGINE_COMMON_CONSTANT_CONSTANT_H_ + +#include + +namespace ge { +namespace host_aicpu { +// engine name +const char kHostAiCpuEngineName[] = "DNN_VM_HOST_AICPU"; +const char kHostAiCpuOpKernelLibName[] = "DNN_VM_HOST_AICPU_OP_STORE"; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_COMMON_CONSTANT_CONSTANT_H_ diff --git a/src/ge/host_aicpu_engine/engine/host_aicpu_engine.cc b/src/ge/host_aicpu_engine/engine/host_aicpu_engine.cc new file mode 100644 index 00000000..12ec5ede --- /dev/null +++ b/src/ge/host_aicpu_engine/engine/host_aicpu_engine.cc @@ -0,0 +1,74 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/engine/host_aicpu_engine.h" +#include +#include +#include +#include "framework/common/debug/ge_log.h" +#include "common/ge/ge_util.h" +#include "host_aicpu_engine/common/constant/constant.h" +#include "host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h" + +namespace ge { +namespace host_aicpu { +HostAiCpuEngine &HostAiCpuEngine::Instance() { + static HostAiCpuEngine instance; + return instance; +} + +Status HostAiCpuEngine::Initialize(const std::map &options) { + if (ops_kernel_store_ == nullptr) { + ops_kernel_store_ = MakeShared(); + if (ops_kernel_store_ == nullptr) { + GELOGE(FAILED, "Make HostAiCpuOpsKernelInfoStore failed."); + return FAILED; + } + } + return SUCCESS; +} + +void HostAiCpuEngine::GetOpsKernelInfoStores(std::map &ops_kernel_map) { + if (ops_kernel_store_ != nullptr) { + // add buildin opsKernel to opsKernelInfoMap + ops_kernel_map[kHostAiCpuOpKernelLibName] = ops_kernel_store_; + } +} + +void HostAiCpuEngine::GetGraphOptimizerObjs(std::map &) { + // no optimizer for host aicpu engine +} + +Status HostAiCpuEngine::Finalize() { + ops_kernel_store_ = nullptr; + return SUCCESS; +} +} // namespace host_aicpu +} // namespace ge + +ge::Status Initialize(const std::map &options) { + return ge::host_aicpu::HostAiCpuEngine::Instance().Initialize(options); +} + +void GetOpsKernelInfoStores(std::map &ops_kernel_map) { + ge::host_aicpu::HostAiCpuEngine::Instance().GetOpsKernelInfoStores(ops_kernel_map); +} + +void GetGraphOptimizerObjs(std::map &graph_optimizers) { + ge::host_aicpu::HostAiCpuEngine::Instance().GetGraphOptimizerObjs(graph_optimizers); +} + +ge::Status Finalize() { return ge::host_aicpu::HostAiCpuEngine::Instance().Finalize(); } diff --git a/src/ge/host_aicpu_engine/engine/host_aicpu_engine.h b/src/ge/host_aicpu_engine/engine/host_aicpu_engine.h new file mode 100644 index 00000000..f8ad71b1 --- /dev/null +++ b/src/ge/host_aicpu_engine/engine/host_aicpu_engine.h @@ -0,0 +1,111 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_ENGINE_HOST_AICPU_ENGINE_H_ +#define GE_HOST_AICPU_ENGINE_ENGINE_HOST_AICPU_ENGINE_H_ + +#include +#include +#include +#include "common/opskernel/ops_kernel_info_store.h" +#include "common/optimizer/graph_optimizer.h" + +using OpsKernelInfoStorePtr = std::shared_ptr; +using GraphOptimizerPtr = std::shared_ptr; + +namespace ge { +namespace host_aicpu { +/** + * host aicpu engine. + * Used for the ops which executes on host. + */ +class HostAiCpuEngine { + public: + /** + * get HostAiCpuEngine instance. + * @return HostAiCpuEngine instance. + */ + static HostAiCpuEngine &Instance(); + + virtual ~HostAiCpuEngine() = default; + + /** + * When Ge start, GE will invoke this interface + * @return The status whether initialize successfully + */ + Status Initialize(const std::map &options); + + /** + * After the initialize, GE will invoke this interface + * to get the Ops kernel Store. + * @param ops_kernel_map The host aicpu's ops kernel info + */ + void GetOpsKernelInfoStores(std::map &ops_kernel_map); + + /** + * After the initialize, GE will invoke this interface + * to get the Graph Optimizer. + * @param graph_optimizers The host aicpu's Graph Optimizer objs + */ + void GetGraphOptimizerObjs(std::map &graph_optimizers); + + /** + * When the graph finished, GE will invoke this interface + * @return The status whether initialize successfully + */ + Status Finalize(); + + HostAiCpuEngine(const HostAiCpuEngine &HostAiCpuEngine) = delete; + HostAiCpuEngine(const HostAiCpuEngine &&HostAiCpuEngine) = delete; + HostAiCpuEngine &operator=(const HostAiCpuEngine &HostAiCpuEngine) = delete; + HostAiCpuEngine &operator=(HostAiCpuEngine &&HostAiCpuEngine) = delete; + + private: + HostAiCpuEngine() = default; + + OpsKernelInfoStorePtr ops_kernel_store_ = nullptr; +}; +} // namespace host_aicpu +} // namespace ge + +extern "C" { + +/** + * When Ge start, GE will invoke this interface + * @return The status whether initialize successfully + */ +ge::Status Initialize(const map &options); + +/** + * After the initialize, GE will invoke this interface to get the Ops kernel Store + * @param ops_kernel_map The host aicpu's ops kernel info + */ +void GetOpsKernelInfoStores(std::map &ops_kernel_map); + +/** + * After the initialize, GE will invoke this interface to get the Graph Optimizer + * @param graph_optimizers The host aicpu's Graph Optimizer objs + */ +void GetGraphOptimizerObjs(std::map &graph_optimizers); + +/** + * When the graph finished, GE will invoke this interface + * @return The status whether initialize successfully + */ +ge::Status Finalize(); +} + +#endif // GE_HOST_AICPU_ENGINE_ENGINE_HOST_AICPU_ENGINE_H_ diff --git a/src/ge/host_aicpu_engine/module.mk b/src/ge/host_aicpu_engine/module.mk new file mode 100644 index 00000000..48dd6a87 --- /dev/null +++ b/src/ge/host_aicpu_engine/module.mk @@ -0,0 +1,57 @@ +LOCAL_PATH := $(call my-dir) + + +local_lib_src_files := engine/host_aicpu_engine.cc \ + ops_kernel_store/host_aicpu_ops_kernel_info.cc \ + ops_kernel_store/op/op_factory.cc \ + ops_kernel_store/op/host_op.cc \ + +local_lib_inc_path := proto/task.proto \ + ${LOCAL_PATH} \ + ${TOPDIR}inc \ + ${TOPDIR}inc/external \ + ${TOPDIR}inc/external/graph \ + $(TOPDIR)libc_sec/include \ + ${TOPDIR}third_party/protobuf/include \ + ${TOPDIR}inc/framework \ + $(TOPDIR)framework/domi \ + +#compiler for host +include $(CLEAR_VARS) +LOCAL_MODULE := libhost_aicpu_engine +LOCAL_CFLAGS += -Werror +LOCAL_CFLAGS += -std=c++11 +LOCAL_LDFLAGS := + +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := libprotobuf \ + libc_sec \ + libslog \ + libgraph \ + libregister \ + libruntime + +LOCAL_SRC_FILES := $(local_lib_src_files) +LOCAL_C_INCLUDES := $(local_lib_inc_path) + +include ${BUILD_HOST_SHARED_LIBRARY} + +#compiler for atc +include $(CLEAR_VARS) +LOCAL_MODULE := atclib/libhost_aicpu_engine +LOCAL_CFLAGS += -Werror +LOCAL_CFLAGS += -std=c++11 +LOCAL_LDFLAGS := + +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := libprotobuf \ + libc_sec \ + libslog \ + libgraph \ + libregister \ + libruntime_compile + +LOCAL_SRC_FILES := $(local_lib_src_files) +LOCAL_C_INCLUDES := $(local_lib_inc_path) + +include ${BUILD_HOST_SHARED_LIBRARY} diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.cc b/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.cc new file mode 100644 index 00000000..4dbedab1 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.cc @@ -0,0 +1,132 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h" +#include +#include "common/constant/constant.h" +#include "ge/ge_api_types.h" +#include "common/ge/ge_util.h" +#include "common/ge_inner_error_codes.h" +#include "framework/common/debug/ge_log.h" +#include "graph/utils/node_utils.h" +#include "graph/utils/tensor_utils.h" +#include "graph/utils/type_utils.h" +#include "op/op_factory.h" +#include "proto/task.pb.h" + +namespace ge { +namespace host_aicpu { +using domi::TaskDef; +using std::map; +using std::string; +using std::vector; + +Status HostAiCpuOpsKernelInfoStore::Initialize(const map &options) { + GELOGI("HostAiCpuOpsKernelInfoStore init start."); + OpInfo default_op_info = {.engine = kHostAiCpuEngineName, + .opKernelLib = kHostAiCpuOpKernelLibName, + .computeCost = 0, + .flagPartial = false, + .flagAsync = false, + .isAtomic = false}; + // Init op_info_map_ + auto all_ops = OpFactory::Instance().GetAllOps(); + for (auto &op : all_ops) { + op_info_map_[op] = default_op_info; + } + + GELOGI("HostAiCpuOpsKernelInfoStore inited success. op num=%zu", op_info_map_.size()); + + return SUCCESS; +} + +Status HostAiCpuOpsKernelInfoStore::Finalize() { + op_info_map_.clear(); + return SUCCESS; +} + +Status HostAiCpuOpsKernelInfoStore::CalcOpRunningParam(Node &ge_node) { + OpDescPtr op_desc = ge_node.GetOpDesc(); + if (op_desc == nullptr) { + GELOGE(FAILED, "CalcOpRunningParam failed, as op desc is null"); + return FAILED; + } + + bool is_shape_unknown = false; + if (NodeUtils::GetNodeUnknownShapeStatus(ge_node, is_shape_unknown) == GRAPH_SUCCESS) { + if (is_shape_unknown) { + GELOGI("op:%s is unknown shape, does not need to calc output size.", ge_node.GetName().c_str()); + return SUCCESS; + } + } + + const string name = ge_node.GetName(); + const string type = ge_node.GetType(); + GELOGD("Calc op[%s:%s] running param, output size=%zu.", name.c_str(), type.c_str(), op_desc->GetOutputsSize()); + + for (size_t i = 0; i < op_desc->GetOutputsSize(); ++i) { + GeTensorDesc output_tensor = op_desc->GetOutputDesc(static_cast(i)); + Format format = output_tensor.GetFormat(); + DataType data_type = output_tensor.GetDataType(); + + int64_t mem_size = 0; + // If mem size has been set, no need reset. + if ((TensorUtils::GetSize(output_tensor, mem_size) == GRAPH_SUCCESS) && (mem_size > 0)) { + GELOGD("Op[%s:%s] out[%zu] mem size has been set, no need calc again, format=%s, data_type=%s, mem_size=%ld.", + name.c_str(), type.c_str(), i, TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::DataTypeToSerialString(data_type).c_str(), mem_size); + continue; + } + + int64_t output_mem_size = 0; + GeShape output_shape = output_tensor.GetShape(); + if ((TensorUtils::CalcTensorMemSize(output_shape, format, data_type, output_mem_size) != GRAPH_SUCCESS) || + (output_mem_size < 0)) { + GELOGE(FAILED, "Calc op[%s:%s] out[%zu] mem size failed, mem_size=%ld, format=%s, data_type=%s.", name.c_str(), + type.c_str(), i, output_mem_size, TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::DataTypeToSerialString(data_type).c_str()); + return FAILED; + } + GELOGI("Calc op[%s:%s] out[%zu] mem size is %ld, format=%s, data_type=%s.", name.c_str(), type.c_str(), i, + output_mem_size, TypeUtils::FormatToSerialString(format).c_str(), + TypeUtils::DataTypeToSerialString(data_type).c_str()); + + TensorUtils::SetSize(output_tensor, output_mem_size); + if (op_desc->UpdateOutputDesc(static_cast(i), output_tensor) != GRAPH_SUCCESS) { + GELOGE(FAILED, "Update op[%s:%s] out[%zu] desc failed, format=%s, data_type=%s.", name.c_str(), type.c_str(), i, + TypeUtils::FormatToSerialString(format).c_str(), TypeUtils::DataTypeToSerialString(data_type).c_str()); + return FAILED; + } + } + GELOGD("Calc op[%s:%s] running param success.", name.c_str(), type.c_str()); + return SUCCESS; +} + +void HostAiCpuOpsKernelInfoStore::GetAllOpsKernelInfo(map &infos) const { infos = op_info_map_; } + +Status HostAiCpuOpsKernelInfoStore::GenerateTask(const Node &node, RunContext &context, vector &tasks) { + // no need to generate device task + return SUCCESS; +} + +bool HostAiCpuOpsKernelInfoStore::CheckSupported(const OpDescPtr &op_desc, std::string &) const { + if (op_desc == nullptr) { + return false; + } + return op_info_map_.count(op_desc->GetType()) > 0; +} +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h b/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h new file mode 100644 index 00000000..a4051b9b --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/host_aicpu_ops_kernel_info.h @@ -0,0 +1,88 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_HOST_AICPU_OPS_KERNEL_INFO_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_HOST_AICPU_OPS_KERNEL_INFO_H_ + +#include +#include +#include + +#include "common/opskernel/ops_kernel_info_store.h" + +namespace ge { +namespace host_aicpu { +class HostAiCpuOpsKernelInfoStore : public OpsKernelInfoStore { + public: + HostAiCpuOpsKernelInfoStore() {} + ~HostAiCpuOpsKernelInfoStore() override = default; + + /** + * Initialize related resources of the host aicpu kernelinfo store + * @return status whether this operation success + */ + Status Initialize(const std::map &options) override; + + /** + * Release related resources of the host aicpu kernel info store + * @return status whether this operation success + */ + Status Finalize() override; + + /** + * Check to see if an operator is fully supported or partially supported. + * @param op_desc OpDesc information + * @param reason unsupported reason + * @return bool value indicate whether the operator is fully supported + */ + bool CheckSupported(const OpDescPtr &op_desc, std::string &reason) const override; + + /** + * Returns the full operator information. + * @param infos reference of a map, + * contain operator's name and detailed information + */ + void GetAllOpsKernelInfo(std::map &infos) const override; + + /** + * Calc the running size of Operator, + * then GE will alloc the mem size from runtime + * @param ge_node Node information + * @return status whether this operation success + */ + Status CalcOpRunningParam(ge::Node &ge_node) override; + + /** + * call the runtime's interface to generate the task + * @param node Node information + * @param context run context info + * @return status whether this operation success + */ + Status GenerateTask(const ge::Node &ge_node, ge::RunContext &context, std::vector &tasks) override; + + HostAiCpuOpsKernelInfoStore(const HostAiCpuOpsKernelInfoStore &ops_kernel_store) = delete; + HostAiCpuOpsKernelInfoStore(const HostAiCpuOpsKernelInfoStore &&ops_kernel_store) = delete; + HostAiCpuOpsKernelInfoStore &operator=(const HostAiCpuOpsKernelInfoStore &ops_kernel_store) = delete; + HostAiCpuOpsKernelInfoStore &operator=(HostAiCpuOpsKernelInfoStore &&ops_kernel_store) = delete; + + private: + // store op name and OpInfo key-value pair + std::map op_info_map_; +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_HOST_AICPU_OPS_KERNEL_INFO_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.cc b/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.cc new file mode 100644 index 00000000..32f8ec24 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.cc @@ -0,0 +1,51 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/op/assign_op.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "host_aicpu_engine/ops_kernel_store/op/op_factory.h" + +namespace { +const size_t kAssignInputNum = 2; +const size_t kAssignRefInputIndex = 0; +const size_t kAssignValueInputIndex = 1; +const size_t kAssignRefOutputIndex = 0; +} // namespace + +namespace ge { +namespace host_aicpu { +Status AssignOp::Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) { + GELOGI("AssignOp [%s, %s] compute begin.", node_.GetName().c_str(), node_.GetType().c_str()); + if (inputs.size() != kAssignInputNum) { + GELOGE(PARAM_INVALID, "Number of input for AssignOp must be %zu.", kAssignInputNum); + return PARAM_INVALID; + } + auto &ref_input = inputs[kAssignRefInputIndex]; + const auto &value_input = inputs[kAssignValueInputIndex]; + ref_input->SetData(value_input->GetData().GetData(), value_input->GetData().GetSize()); + GeTensorPtr output_ptr = MakeShared(op_desc_ptr->GetOutputDesc(kAssignRefOutputIndex), + value_input->GetData().GetData(), value_input->GetData().GetSize()); + GE_CHECK_NOTNULL(output_ptr); + outputs.push_back(output_ptr); + GELOGI("AssignOp [%s, %s] compute success.", node_.GetName().c_str(), node_.GetType().c_str()); + return SUCCESS; +} + +REGISTER_OP_CREATOR(Assign, AssignOp); +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.h new file mode 100644 index 00000000..caf9d4c9 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/assign_op.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_ASSIGN_OP_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_ASSIGN_OP_H_ + +#include "host_aicpu_engine/ops_kernel_store/op/op.h" + +namespace ge { +namespace host_aicpu { +class AssignOp : public Op { + public: + AssignOp(const Node &node, RunContext &run_context) : Op(node, run_context) {} + ~AssignOp() override = default; + AssignOp &operator=(const AssignOp &op) = delete; + AssignOp(const AssignOp &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) override; +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_ASSIGN_OP_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.cc b/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.cc new file mode 100644 index 00000000..9dbd80e0 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.cc @@ -0,0 +1,34 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/op/host_op.h" +#include "framework/common/util.h" +#include "host_aicpu_engine/ops_kernel_store/op/op_factory.h" + +namespace ge { +namespace host_aicpu { +Status HostOp::Run() { + // no need to generate device task + return SUCCESS; +} + +REGISTER_OP_CREATOR(NoOp, HostOp); +REGISTER_OP_CREATOR(Variable, HostOp); +REGISTER_OP_CREATOR(Constant, HostOp); +REGISTER_OP_CREATOR(Assign, HostOp); +REGISTER_OP_CREATOR(RandomUniform, HostOp); +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.h new file mode 100644 index 00000000..6655e620 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/host_op.h @@ -0,0 +1,36 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_HOST_OP_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_HOST_OP_H_ + +#include "host_aicpu_engine/ops_kernel_store/op/op.h" + +namespace ge { +namespace host_aicpu { +class HostOp : public Op { + public: + HostOp(const Node &node, RunContext &run_context) : Op(node, run_context) {} + ~HostOp() override = default; + HostOp &operator=(const HostOp &op) = delete; + HostOp(const HostOp &op) = delete; + + Status Run() override; +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_HOST_OP_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/op.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/op.h new file mode 100644 index 00000000..87c7993e --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/op.h @@ -0,0 +1,45 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_H_ + +#include +#include +#include +#include "common/ge_inner_error_codes.h" +#include "common/opskernel/ops_kernel_info_types.h" +#include "graph/node.h" + +namespace ge { +namespace host_aicpu { +/** + * The base class for all op. + */ +class Op { + public: + Op(const Node &node, RunContext &run_context) : run_context_(run_context), node_(node) {} + virtual ~Op() = default; + virtual Status Run() = 0; + + protected: + const RunContext &run_context_; + const Node &node_; +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.cc b/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.cc new file mode 100644 index 00000000..ec376d8a --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.cc @@ -0,0 +1,55 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/op/op_factory.h" +#include "framework/common/debug/ge_log.h" +#include "common/ge_inner_error_codes.h" +#include "graph/op_desc.h" + +namespace ge { +namespace host_aicpu { +OpFactory &OpFactory::Instance() { + static OpFactory instance; + return instance; +} + +std::shared_ptr OpFactory::CreateOp(const Node &node, RunContext &run_context) { + auto iter = op_creator_map_.find(node.GetType()); + if (iter != op_creator_map_.end()) { + return iter->second(node, run_context); + } + + GELOGE(FAILED, "Not supported OP, type = %s, name = %s", node.GetType().c_str(), node.GetName().c_str()); + return nullptr; +} + +void OpFactory::RegisterCreator(const std::string &type, const OP_CREATOR_FUNC &func) { + if (func == nullptr) { + GELOGW("Func is NULL."); + return; + } + + auto iter = op_creator_map_.find(type); + if (iter != op_creator_map_.end()) { + GELOGW("%s creator already exist", type.c_str()); + return; + } + + op_creator_map_[type] = func; + all_ops_.emplace_back(type); +} +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.h new file mode 100644 index 00000000..007bceaa --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/op_factory.h @@ -0,0 +1,94 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_FACTORY_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_FACTORY_H_ + +#include +#include +#include +#include +#include +#include "common/ge/ge_util.h" +#include "host_aicpu_engine/ops_kernel_store/op/op.h" + +namespace ge { +namespace host_aicpu { +using OP_CREATOR_FUNC = std::function(const Node &, RunContext &)>; + +/** + * manage all the op, support create op. + */ +class OpFactory { + public: + static OpFactory &Instance(); + + /** + * @brief create Op. + * @param [in] node share ptr of node + * @param [in] run_context run context + * @return not nullptr success + * @return nullptr fail + */ + std::shared_ptr CreateOp(const Node &node, RunContext &run_context); + + /** + * @brief Register Op create function. + * @param [in] type Op type + * @param [in] func Op create func + */ + void RegisterCreator(const std::string &type, const OP_CREATOR_FUNC &func); + + const std::vector &GetAllOps() const { return all_ops_; } + + bool CheckSupported(const std::string &type) { return op_creator_map_.find(type) != op_creator_map_.end(); } + + OpFactory(const OpFactory &) = delete; + OpFactory &operator=(const OpFactory &) = delete; + OpFactory(OpFactory &&) = delete; + OpFactory &operator=(OpFactory &&) = delete; + + private: + OpFactory() = default; + ~OpFactory() = default; + + // the op creator function map + std::map op_creator_map_; + std::vector all_ops_; +}; + +class OpRegistrar { + public: + OpRegistrar(const std::string &type, const OP_CREATOR_FUNC &func) { + OpFactory::Instance().RegisterCreator(type, func); + } + ~OpRegistrar() = default; + + OpRegistrar(const OpRegistrar &) = delete; + OpRegistrar &operator=(const OpRegistrar &) = delete; + OpRegistrar(OpRegistrar &&) = delete; + OpRegistrar &operator=(OpRegistrar &&) = delete; +}; + +#define REGISTER_OP_CREATOR(type, clazz) \ + std::shared_ptr Creator_##type##Op(const Node &node, RunContext &run_context) { \ + return MakeShared(node, run_context); \ + } \ + OpRegistrar g_##type##Op_creator(#type, Creator_##type##Op) +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_OP_FACTORY_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.cc b/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.cc new file mode 100644 index 00000000..81768f7a --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.cc @@ -0,0 +1,104 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/op/random_uniform_op.h" +#include +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/utils/type_utils.h" +#include "host_aicpu_engine/ops_kernel_store/op/op_factory.h" + +namespace ge { +namespace host_aicpu { +Status RandomUniformOp::Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) { + GELOGI("RandomUniformOp [%s, %s] compute begin.", node_.GetName().c_str(), node_.GetType().c_str()); + int64_t seed = 0; + int64_t seed2 = 0; + (void)AttrUtils::GetInt(op_desc_ptr, "seed", seed); + (void)AttrUtils::GetInt(op_desc_ptr, "seed2", seed2); + DataType data_type = DT_UNDEFINED; + if (AttrUtils::GetDataType(op_desc_ptr, VAR_ATTR_DTYPE, data_type) != GRAPH_SUCCESS) { + GELOGE(PARAM_INVALID, "get attr VAR_ATTR_DTYPE failed"); + return PARAM_INVALID; + } + + switch (data_type) { + case DT_FLOAT16: + break; + case DT_FLOAT: + if (Generate(op_desc_ptr, seed, seed2, outputs) != SUCCESS) { + GELOGE(FAILED, "Generate random_distribution for RandomUniformOp failed, data_type=DT_FLOAT"); + return FAILED; + } + break; + case DT_DOUBLE: + if (Generate(op_desc_ptr, seed, seed2, outputs) != SUCCESS) { + GELOGE(FAILED, "Generate random_distribution for RandomUniformOp failed, data_type=DT_DOUBLE"); + return FAILED; + } + break; + default: + GELOGE(UNSUPPORTED, "Supported DataType for RandomUniformOp is DT_FLOAT16 / DT_FLOAT / DT_DOUBLE, but dtype=%s", + TypeUtils::DataTypeToSerialString(data_type).c_str()); + return UNSUPPORTED; + } + + GELOGI("RandomUniformOp [%s, %s] compute success.", node_.GetName().c_str(), node_.GetType().c_str()); + return SUCCESS; +} + +template +Status RandomUniformOp::Generate(const ge::OpDescPtr &op_desc_ptr, int64_t seed, int64_t seed2, + std::vector &outputs) { + GE_CHECK_NOTNULL(op_desc_ptr); + // RandomUniformOp has and only has one output + int64_t data_num = op_desc_ptr->GetOutputDesc(0).GetShape().GetShapeSize(); + std::unique_ptr buf(new (std::nothrow) T[data_num]()); + if (buf == nullptr) { + GELOGE(MEMALLOC_FAILED, "New sizeof(T) * data_num(%zu) memory failed", static_cast(sizeof(T) * data_num)); + return MEMALLOC_FAILED; + } + + int64_t final_seed; + if (seed == 0) { + if (seed2 == 0) { + std::random_device rd; + final_seed = rd(); + } else { + final_seed = seed2; + } + } else { + final_seed = seed; + } + std::mt19937_64 gen(final_seed); + std::uniform_real_distribution distribution(0, 1); + for (int64_t i = 0; i < data_num; i++) { + *(buf.get() + i) = distribution(gen); + } + + GeTensorPtr output = + MakeShared(op_desc_ptr->GetOutputDesc(0), reinterpret_cast(buf.get()), data_num * sizeof(T)); + GE_CHECK_NOTNULL(output); + outputs.emplace_back(output); + + return SUCCESS; +} + +REGISTER_OP_CREATOR(RandomUniform, RandomUniformOp); +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.h new file mode 100644 index 00000000..dfb2485f --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/random_uniform_op.h @@ -0,0 +1,45 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_RANDOM_UNIFORM_OP_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_RANDOM_UNIFORM_OP_H_ + +#include "host_aicpu_engine/ops_kernel_store/op/op.h" + +namespace ge { +namespace host_aicpu { +class RandomUniformOp : public Op { + public: + RandomUniformOp(const Node &node, RunContext &run_context) : Op(node, run_context) {} + ~RandomUniformOp() override = default; + RandomUniformOp &operator=(const RandomUniformOp &op) = delete; + RandomUniformOp(const RandomUniformOp &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) override; + + private: + template + Status Generate(const ge::OpDescPtr &op_desc_ptr, int64_t seed, int64_t seed2, std::vector &outputs); +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_RANDOM_UNIFORM_OP_H_ diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.cc b/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.cc new file mode 100644 index 00000000..effa346b --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.cc @@ -0,0 +1,46 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "host_aicpu_engine/ops_kernel_store/op/variable_op.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "host_aicpu_engine/ops_kernel_store/op/op_factory.h" + +namespace { +const size_t kInputSize = 1; +} + +namespace ge { +namespace host_aicpu { +Status VariableOp::Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) { + GELOGI("VariableOp [%s, %s] compute begin.", node_.GetName().c_str(), node_.GetType().c_str()); + if (inputs.size() != kInputSize) { + GELOGE(PARAM_INVALID, "Number of input for VariableOp must be %zu.", kInputSize); + return PARAM_INVALID; + } + GeTensorPtr output_ptr = + MakeShared(op_desc_ptr->GetOutputDesc(0), inputs[0]->GetData().GetData(), inputs[0]->GetData().GetSize()); + GE_CHECK_NOTNULL(output_ptr); + outputs.push_back(output_ptr); + GELOGI("VariableOp [%s, %s] compute success.", node_.GetName().c_str(), node_.GetType().c_str()); + return SUCCESS; +} + +REGISTER_OP_CREATOR(Variable, VariableOp); +REGISTER_OP_CREATOR(Constant, VariableOp); +} // namespace host_aicpu +} // namespace ge diff --git a/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.h b/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.h new file mode 100644 index 00000000..b6570557 --- /dev/null +++ b/src/ge/host_aicpu_engine/ops_kernel_store/op/variable_op.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_VARIABLE_OP_H_ +#define GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_VARIABLE_OP_H_ + +#include "host_aicpu_engine/ops_kernel_store/op/op.h" + +namespace ge { +namespace host_aicpu { +class VariableOp : public Op { + public: + VariableOp(const Node &node, RunContext &run_context) : Op(node, run_context) {} + ~VariableOp() override = default; + VariableOp &operator=(const VariableOp &op) = delete; + VariableOp(const VariableOp &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(const ge::OpDescPtr &op_desc_ptr, const std::vector &inputs, + std::vector &outputs) override; +}; +} // namespace host_aicpu +} // namespace ge + +#endif // GE_HOST_AICPU_ENGINE_OPS_KERNEL_STORE_OP_VARIABLE_OP_H_ diff --git a/src/ge/host_kernels/add_kernel.cc b/src/ge/host_kernels/add_kernel.cc index 6d6a049c..afef1c37 100644 --- a/src/ge/host_kernels/add_kernel.cc +++ b/src/ge/host_kernels/add_kernel.cc @@ -133,25 +133,24 @@ Status AddKernel::BCastAdd(const OpDescPtr &op_desc_ptr, const std::vector &input) { if (op_desc_ptr == nullptr) { - GELOGE(PARAM_INVALID, "Op_desc_ptr must not be null."); + GELOGW("Op_desc_ptr must not be null."); return PARAM_INVALID; } // check how many inputs if ((input.size() != kAddInputSize) || (op_desc_ptr->GetOutputsSize() != kAddOutputSize)) { - GELOGE(PARAM_INVALID, "The number of input for add must be %zu, output number must be %zu.", kAddInputSize, - kAddOutputSize); + GELOGW("The number of input for add must be %zu, output number must be %zu.", kAddInputSize, kAddOutputSize); return PARAM_INVALID; } // input vector elements must not be null if ((input[kAddFirstInput] == nullptr) || (input[kAddSecondInput] == nullptr)) { - GELOGE(PARAM_INVALID, "Input vector elements must not be null."); + GELOGW("Input vector elements must not be null."); return PARAM_INVALID; } // Inputs must have the same datatype. DataType data_type_0 = input[kAddFirstInput]->GetTensorDesc().GetDataType(); DataType data_type_1 = input[kAddSecondInput]->GetTensorDesc().GetDataType(); if (data_type_0 != data_type_1) { - GELOGE(PARAM_INVALID, "Data type of inputs for add not matched, data_type_0:%s, data_type_1:%s", + GELOGW("Data type of inputs for add not matched, data_type_0:%s, data_type_1:%s", TypeUtils::DataTypeToSerialString(data_type_0).c_str(), TypeUtils::DataTypeToSerialString(data_type_1).c_str()); return PARAM_INVALID; @@ -192,7 +191,7 @@ Status AddKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector x2_dims; const auto &op_in_desc = op_desc_ptr->MutableInputDesc(0); GE_CHECK_NOTNULL(op_in_desc); - ; DataType data_type = op_in_desc->GetDataType(); bool result = (OpUtils::GetShapeDataFromConstTensor(input[0], data_type, x1_dims) == SUCCESS) && (OpUtils::GetShapeDataFromConstTensor(input[1], data_type, x2_dims) == SUCCESS); diff --git a/src/ge/host_kernels/concat_offset_kernel.cc b/src/ge/host_kernels/concat_offset_kernel.cc index 2e609d68..0a870949 100644 --- a/src/ge/host_kernels/concat_offset_kernel.cc +++ b/src/ge/host_kernels/concat_offset_kernel.cc @@ -41,7 +41,7 @@ Status ConcatOffsetKernel::Compute(const OpDescPtr op_desc_ptr, const vector(reinterpret_cast(input_0->GetData().data()))); // validate inputs if (static_cast(input.size()) != (N + kNumOne) || input.size() <= kConcatOffsetInputIndexOne) { - GELOGE(PARAM_INVALID, "The number of input for concat offset must be equal with %d, and must be more than one.", - (N + kNumOne)); + GELOGW("The number of input for concat offset must be equal with %d, and must be more than one.", (N + kNumOne)); return NOT_CHANGED; } @@ -59,7 +58,7 @@ Status ConcatOffsetKernel::Compute(const OpDescPtr op_desc_ptr, const vectorGetTensorDesc().GetShape(); int64_t output_size = output_shape.GetShapeSize(); if (concat_dim >= output_size) { - GELOGE(PARAM_INVALID, "Concat dim is biger than the size of output_shape."); + GELOGW("Concat dim is biger than the size of output_shape."); return NOT_CHANGED; } GELOGI("Output shape size is %ld", output_size); @@ -79,7 +78,7 @@ Status ConcatOffsetKernel::Compute(const OpDescPtr op_desc_ptr, const vectorGetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to fold node %s, out of memeory", op_desc_ptr->GetName().c_str()); + GELOGW("Failed to fold node %s, out of memeory", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } @@ -87,7 +86,7 @@ Status ConcatOffsetKernel::Compute(const OpDescPtr op_desc_ptr, const vectorMutableTensorDesc().SetShape(output_shape); GE_IF_BOOL_EXEC(output_ptr->SetData(reinterpret_cast(buf.get()), static_cast(sizeof(DT_INT32) * output_size)) != GRAPH_SUCCESS, - GELOGE(INTERNAL_ERROR, "set data failed"); + GELOGW("set data failed"); return NOT_CHANGED); v_output.push_back(output_ptr); // caculate offset diff --git a/src/ge/host_kernels/dynamic_stitch_kernel.cc b/src/ge/host_kernels/dynamic_stitch_kernel.cc index c8a19e44..c1245535 100644 --- a/src/ge/host_kernels/dynamic_stitch_kernel.cc +++ b/src/ge/host_kernels/dynamic_stitch_kernel.cc @@ -63,11 +63,11 @@ Status DynamicStitchKernel::Compute(const OpDescPtr op_desc_ptr, const vector &input) { if (op_desc_ptr == nullptr) { - GELOGE(PARAM_INVALID, "Input op_desc is nullptr."); + GELOGW("Input op_desc is nullptr."); return PARAM_INVALID; } if (op_desc_ptr->GetOutputsSize() == 0) { - GELOGE(PARAM_INVALID, "Current output_desc is empty."); + GELOGW("Current output_desc is empty."); return PARAM_INVALID; } // validate input @@ -78,7 +78,7 @@ Status DynamicStitchKernel::ValidateParams(const OpDescPtr &op_desc_ptr, const s } for (const auto &in : input) { if (in == nullptr) { - GELOGE(PARAM_INVALID, "input is nullptr."); + GELOGW("input is nullptr."); return PARAM_INVALID; } } @@ -150,7 +150,7 @@ Status DynamicStitchKernel::GenData(const vector &input, GeTen // 2.allocate memery for output std::unique_ptr buf(new (std::nothrow) uint8_t[allowance]); if (buf == nullptr) { - GELOGE(MEMALLOC_FAILED, "new buffer failed"); + GELOGW("new buffer failed"); return INTERNAL_ERROR; } // 3.copy data from input_data along with the sequence of input_indices @@ -164,7 +164,7 @@ Status DynamicStitchKernel::GenData(const vector &input, GeTen output_ptr->MutableTensorDesc().SetShape(merged_shape); Status ret = output_ptr->SetData(buf.get(), allowance); if (ret != GRAPH_SUCCESS) { - GELOGE(INTERNAL_ERROR, "set data failed"); + GELOGW("set data failed"); return NOT_CHANGED; } return SUCCESS; diff --git a/src/ge/host_kernels/empty_kernel.cc b/src/ge/host_kernels/empty_kernel.cc index 856caf50..a5e5fbcf 100644 --- a/src/ge/host_kernels/empty_kernel.cc +++ b/src/ge/host_kernels/empty_kernel.cc @@ -38,7 +38,7 @@ const size_t kShapeMaxDims = 1; } // namespace Status EmptyKernel::EmptyCheck(const OpDescPtr &op_desc_ptr, const std::vector &input) { if (op_desc_ptr == nullptr) { - GELOGE(PARAM_INVALID, "Parameter's invalid, Input opDescPtr is nullptr."); + GELOGW("Parameter's invalid, Input opDescPtr is nullptr."); return PARAM_INVALID; } // check input size @@ -46,20 +46,19 @@ Status EmptyKernel::EmptyCheck(const OpDescPtr &op_desc_ptr, const std::vectorGetAllInputsDesc().size() != kEmptyInputsSize) || (input.size() != kEmptyInputsSize) || (op_desc_ptr->GetAllOutputsDesc().size() != kEmptyOutputsSize)); if (size_check) { - GELOGE(PARAM_INVALID, "Input/Output size error. InDesc size:%zu, OutDesc size:%zu, in size:%zu ", + GELOGW("Input/Output size error. InDesc size:%zu, OutDesc size:%zu, in size:%zu ", op_desc_ptr->GetAllInputsDesc().size(), op_desc_ptr->GetAllOutputsDesc().size(), input.size()); return PARAM_INVALID; } if (input.at(kEmptyFirstInput) == nullptr) { - GELOGE(PARAM_INVALID, "Parameter's invalid, first input is nullptr."); + GELOGW("Parameter's invalid, first input is nullptr."); return PARAM_INVALID; } ConstGeTensorPtr shape = input.at(kEmptyFirstInput); // Check if the dimension is 1-D if (shape->GetTensorDesc().GetShape().GetDimNum() > kShapeMaxDims) { - GELOGE(PARAM_INVALID, "Check if the dimension is 1-D failed, dims:%zu", - shape->GetTensorDesc().GetShape().GetDimNum()); + GELOGW("Check if the dimension is 1-D failed, dims:%zu", shape->GetTensorDesc().GetShape().GetDimNum()); return PARAM_INVALID; } return SUCCESS; @@ -84,7 +83,7 @@ Status EmptyKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector(shape, shape_vec, total_data_size); } else { - GELOGE(PARAM_INVALID, "shape type must be DT_INT32 or DT_INT64."); + GELOGW("shape type must be DT_INT32 or DT_INT64."); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/expanddims_kernel.cc b/src/ge/host_kernels/expanddims_kernel.cc index 1d17ad48..15648573 100644 --- a/src/ge/host_kernels/expanddims_kernel.cc +++ b/src/ge/host_kernels/expanddims_kernel.cc @@ -66,7 +66,7 @@ Status ExpanddimsKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vec auto output_tensor_desc = op_desc_ptr->GetOutputDesc(kExpandDimsIndexZero); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); + GELOGW("Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/floordiv_kernel.cc b/src/ge/host_kernels/floordiv_kernel.cc index 4175df92..05eded80 100644 --- a/src/ge/host_kernels/floordiv_kernel.cc +++ b/src/ge/host_kernels/floordiv_kernel.cc @@ -260,7 +260,7 @@ Status FloorDivKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/floormod_kernel.cc b/src/ge/host_kernels/floormod_kernel.cc index a8c16c9d..7ad746de 100644 --- a/src/ge/host_kernels/floormod_kernel.cc +++ b/src/ge/host_kernels/floormod_kernel.cc @@ -122,7 +122,7 @@ Status FloorModKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector(op_desc_ptr->GetOutputDesc(kFloorModFirstOutput)); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/gather_v2_kernel.cc b/src/ge/host_kernels/gather_v2_kernel.cc index c8cc3006..7413395a 100644 --- a/src/ge/host_kernels/gather_v2_kernel.cc +++ b/src/ge/host_kernels/gather_v2_kernel.cc @@ -274,7 +274,7 @@ Status GatherV2Kernel::SaveIndicesByDataType(ConstGeTensorPtr indices_tensor_ptr auto indices_ptr = const_cast(reinterpret_cast(indices_tensor_ptr->GetData().data())); for (int64_t i = 0; i < indices_shape.GetShapeSize(); i++) { if (*(indices_ptr + i) < 0 || *(indices_ptr + i) >= x_shape.GetDim(axis)) { - GELOGE(NOT_CHANGED, "indices %ld value is not in range [0, %ld)", i, x_shape.GetDim(axis)); + GELOGW("indices %ld value is not in range [0, %ld)", i, x_shape.GetDim(axis)); return NOT_CHANGED; } indicates_.push_back(*(indices_ptr + i)); @@ -284,7 +284,7 @@ Status GatherV2Kernel::SaveIndicesByDataType(ConstGeTensorPtr indices_tensor_ptr auto indices_ptr = const_cast(reinterpret_cast(indices_tensor_ptr->GetData().data())); for (int64_t i = 0; i < indices_shape.GetShapeSize(); i++) { if (*(indices_ptr + i) < 0 || *(indices_ptr + i) >= x_shape.GetDim(axis)) { - GELOGE(NOT_CHANGED, "indices %ld value is not in range [0, %ld)", i, x_shape.GetDim(axis)); + GELOGW("indices %ld value is not in range [0, %ld)", i, x_shape.GetDim(axis)); return NOT_CHANGED; } indicates_.push_back(*(indices_ptr + i)); @@ -296,19 +296,19 @@ Status GatherV2Kernel::SaveIndicesByDataType(ConstGeTensorPtr indices_tensor_ptr Status GatherV2Kernel::Check(const OpDescPtr &op_desc_ptr, const vector &input, vector &v_output) const { if (op_desc_ptr == nullptr) { - GELOGE(NOT_CHANGED, "input opdesc is nullptr."); + GELOGW("input opdesc is nullptr."); return NOT_CHANGED; } if (input.size() != kGatherV2InpotNum) { - GELOGE(NOT_CHANGED, "The number of input for GatherV2 must be %zu.", kGatherV2InpotNum); + GELOGW("The number of input for GatherV2 must be %zu.", kGatherV2InpotNum); return NOT_CHANGED; } bool is_null = (input[kGatherV2InputIndexZero] == nullptr || input[kGatherV2InputIndexOne] == nullptr || input[kGatherV2InputIndexTwo] == nullptr); if (is_null) { - GELOGE(NOT_CHANGED, "some input is nullptr."); + GELOGW("some input is nullptr."); return NOT_CHANGED; } ConstGeTensorPtr tensor0 = input.at(kGatherV2InputIndexZero); @@ -318,7 +318,7 @@ Status GatherV2Kernel::Check(const OpDescPtr &op_desc_ptr, const vectorGetData().size() == 0) || (tensor1->GetData().size() == 0) || (tensor2->GetData().size() == 0)); if (size_is_zero) { - GELOGE(NOT_CHANGED, "some input size is zero."); + GELOGW("some input size is zero."); return NOT_CHANGED; } @@ -326,13 +326,13 @@ Status GatherV2Kernel::Check(const OpDescPtr &op_desc_ptr, const vectorGetTensorDesc().GetShape(); // axis must be scalar if (axis_shape.GetDimNum() != 0) { - GELOGE(NOT_CHANGED, "axis must be scalar but its shape is %zu", axis_shape.GetDimNum()); + GELOGW("axis must be scalar but its shape is %zu", axis_shape.GetDimNum()); return NOT_CHANGED; } auto axis_data_type = tensor2->GetTensorDesc().GetDataType(); bool is_valid_axis_data_type = axis_data_type == DT_INT32 || axis_data_type == DT_INT64; if (!is_valid_axis_data_type) { - GELOGE(NOT_CHANGED, "axis datatype must be DT_INT32 or DT_INT64"); + GELOGW("axis datatype must be DT_INT32 or DT_INT64"); return NOT_CHANGED; } @@ -340,11 +340,11 @@ Status GatherV2Kernel::Check(const OpDescPtr &op_desc_ptr, const vectorGetTensorDesc().GetDataType(); bool is_valid_indices_data_type = indices_data_type == DT_INT32 || indices_data_type == DT_INT64; if (!is_valid_indices_data_type) { - GELOGE(NOT_CHANGED, "indices datatype must be DT_INT32 or DT_INT64"); + GELOGW("indices datatype must be DT_INT32 or DT_INT64"); return NOT_CHANGED; } if (indices_shape.GetDimNum() > kMaxIndicatesDims) { - GELOGE(NOT_CHANGED, "indices input only support 0 or 1 dims"); + GELOGW("indices input only support 0 or 1 dims"); return NOT_CHANGED; } return SUCCESS; @@ -372,7 +372,7 @@ Status GatherV2Kernel::Compute(const OpDescPtr op_desc_ptr, const vectorGetName().c_str()); @@ -390,13 +390,13 @@ Status GatherV2Kernel::Compute(const OpDescPtr op_desc_ptr, const vector= 0 ? axis : axis + x_shape.GetDimNum(); // check axis value if (axis < 0 || (axis + 1) > static_cast(x_shape.GetDimNum())) { - GELOGE(NOT_CHANGED, "axis is invalid"); + GELOGW("axis is invalid"); return NOT_CHANGED; } auto indices_data_type = tensor1->GetTensorDesc().GetDataType(); ret = SaveIndicesByDataType(tensor1, x_shape, indices_shape, indices_data_type, static_cast(axis)); if (ret != SUCCESS) { - GELOGE(NOT_CHANGED, "Save indeices by data type failed!"); + GELOGW("Save indeices by data type failed!"); return ret; } @@ -420,7 +420,7 @@ Status GatherV2Kernel::Compute(const OpDescPtr op_desc_ptr, const vector(op_desc_ptr->GetOutputDesc(0)); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } output_ptr->MutableTensorDesc().SetShape(GeShape(y_shape)); diff --git a/src/ge/host_kernels/identity_kernel.cc b/src/ge/host_kernels/identity_kernel.cc new file mode 100644 index 00000000..16bd3138 --- /dev/null +++ b/src/ge/host_kernels/identity_kernel.cc @@ -0,0 +1,63 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "identity_kernel.h" +#include "inc/kernel_factory.h" + +namespace { +constexpr uint32_t kInputDescIndex = 0; +constexpr uint32_t kOutputDescIndex = 0; +} // namespace + +namespace ge { +Status IdentityKernel::Compute(const ge::OpDescPtr op_desc, const std::vector &input, + std::vector &v_output) { + if (op_desc == nullptr) { + GELOGE(PARAM_INVALID, "IdentityKernel op_desc is null."); + return NOT_CHANGED; + } + if (input.empty()) { + GELOGE(PARAM_INVALID, "Node [%s] inputs is empty.", op_desc->GetName().c_str()); + return NOT_CHANGED; + } + if (op_desc->GetOutputsSize() < 1) { + GELOGE(PARAM_INVALID, "Node [%s] output is empty.", op_desc->GetName().c_str()); + return NOT_CHANGED; + } + GELOGD("IdentityKernel in: node[%s]", op_desc->GetName().c_str()); + + auto out_tensor_desc = op_desc->GetOutputDesc(kOutputDescIndex); + GeTensorPtr output_ptr = MakeShared(out_tensor_desc); + if (output_ptr == nullptr) { + GELOGE(OUT_OF_MEMORY, "Node [%s] make shared failed.", op_desc->GetName().c_str()); + return OUT_OF_MEMORY; + } + auto input_tensor_ptr = input.at(kInputDescIndex); + if (input_tensor_ptr == nullptr) { + GELOGE(PARAM_INVALID, "Node [%s] get input failed.", op_desc->GetName().c_str()); + return NOT_CHANGED; + } + if (output_ptr->SetData(input_tensor_ptr->GetData()) != GRAPH_SUCCESS) { + GELOGW("Compute: SetData failed"); + return NOT_CHANGED; + } + v_output.emplace_back(output_ptr); + GELOGD("IdentityKernel success: node[%s]", op_desc->GetName().c_str()); + + return SUCCESS; +} +REGISTER_KERNEL(IDENTITY, IdentityKernel); +} // namespace ge diff --git a/src/ge/host_kernels/identity_kernel.h b/src/ge/host_kernels/identity_kernel.h new file mode 100644 index 00000000..2164d880 --- /dev/null +++ b/src/ge/host_kernels/identity_kernel.h @@ -0,0 +1,31 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_GRAPH_PASSES_FOLDING_KERNEL_IDENTITY_KERNEL_H_ +#define GE_GRAPH_PASSES_FOLDING_KERNEL_IDENTITY_KERNEL_H_ + +#include "inc/kernel.h" +#include + +namespace ge { +class IdentityKernel : public Kernel { + public: + Status Compute(const ge::OpDescPtr op_desc_ptr, const std::vector &input, + std::vector &v_output) override; +}; +} // namespace ge + +#endif // GE_GRAPH_PASSES_FOLDING_KERNEL_IDENTITY_KERNEL_H_ diff --git a/src/ge/host_kernels/pack_kernel.cc b/src/ge/host_kernels/pack_kernel.cc index f3f64a6c..9b62a582 100644 --- a/src/ge/host_kernels/pack_kernel.cc +++ b/src/ge/host_kernels/pack_kernel.cc @@ -63,7 +63,7 @@ Status PackKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vector &input) { if (op_desc_ptr == nullptr) { - GELOGE(PARAM_INVALID, "input opdesc is nullptr."); + GELOGW("input opdesc is nullptr."); return PARAM_INVALID; } if (!(AttrUtils::GetInt(op_desc_ptr, PACK_ATTR_NAME_NUM, n_))) { @@ -71,16 +71,15 @@ Status PackKernel::ValidateKernelParams(const ge::OpDescPtr &op_desc_ptr, GELOGD("Attr %s is not set, default value %ld is used.", PACK_ATTR_NAME_NUM.c_str(), n_); } if (!(AttrUtils::GetInt(op_desc_ptr, ATTR_NAME_AXIS, axis_))) { - GELOGE(PARAM_INVALID, "Attr %s is not exist.", ATTR_NAME_AXIS.c_str()); + GELOGW("Attr %s is not exist.", ATTR_NAME_AXIS.c_str()); return PARAM_INVALID; } if (input.empty()) { - GELOGE(PARAM_INVALID, "The number of input for Pack should be %ld, in fact it is %zu ", n_, input.size()); + GELOGW("The number of input for Pack should be %ld, in fact it is %zu ", n_, input.size()); return NOT_CHANGED; } if (input.size() != static_cast(n_)) { - GELOGE(PARAM_INVALID, "The number of input for Pack should be %d, in fact it is %ld ", static_cast(n_), - input.size()); + GELOGW("The number of input for Pack should be %d, in fact it is %ld ", static_cast(n_), input.size()); return PARAM_INVALID; } data_type_ = op_desc_ptr->GetInputDesc(0).GetDataType(); diff --git a/src/ge/host_kernels/permute_kernel.cc b/src/ge/host_kernels/permute_kernel.cc index 8263d19f..24bed54d 100644 --- a/src/ge/host_kernels/permute_kernel.cc +++ b/src/ge/host_kernels/permute_kernel.cc @@ -110,14 +110,14 @@ Status PermuteKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetData().data(); formats::TransResult trans_result; auto ret = formats::TransposeWithShapeCheck(src_data, src_shape, data_shape, src_data_type, perm_list, trans_result); if (ret != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Failed to Transpose from %s to %s, shape %s to %s, perm_list %s, data type %s", + GELOGW("Failed to Transpose from %s to %s, shape %s to %s, perm_list %s, data type %s", TypeUtils::FormatToSerialString(src_format).c_str(), TypeUtils::FormatToSerialString(data_format).c_str(), formats::ShapeToString(src_shape).c_str(), formats::ShapeToString(data_shape).c_str(), formats::ShapeToString(perm_list).c_str(), TypeUtils::DataTypeToSerialString(src_data_type).c_str()); diff --git a/src/ge/host_kernels/rank_kernel.cc b/src/ge/host_kernels/rank_kernel.cc index faaf16b8..7fb92039 100644 --- a/src/ge/host_kernels/rank_kernel.cc +++ b/src/ge/host_kernels/rank_kernel.cc @@ -19,6 +19,7 @@ #include #include +#include "graph/types.h" #include "common/ge_inner_error_codes.h" #include "common/op/ge_op_utils.h" #include "framework/common/debug/ge_log.h" @@ -46,10 +47,13 @@ Status RankKernel::Compute(const NodePtr &node, std::vector &v_outp const auto &input_shape = op_desc->MutableInputDesc(kRankDataInputIndex); GE_CHECK_NOTNULL(input_shape); + if (input_shape->GetShape().GetDims() == UNKNOWN_RANK) { + return NOT_CHANGED; + } auto ndims = input_shape->GetShape().GetDimNum(); GeTensorDesc tensor_desc(op_desc->GetOutputDesc(0)); GeTensorPtr output_ptr; - output_ptr = MakeShared(tensor_desc, reinterpret_cast(&ndims), sizeof(ndims)); + output_ptr = MakeShared(tensor_desc, reinterpret_cast(&ndims), GetSizeByDataType(DT_INT32)); if (output_ptr == nullptr) { GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed"); return MEMALLOC_FAILED; diff --git a/src/ge/host_kernels/reduce_prod_kernel.cc b/src/ge/host_kernels/reduce_prod_kernel.cc index 479b50ab..739d4b9f 100644 --- a/src/ge/host_kernels/reduce_prod_kernel.cc +++ b/src/ge/host_kernels/reduce_prod_kernel.cc @@ -51,7 +51,7 @@ Status ReduceProdKernel::ReduceProdCheck(const ge::OpDescPtr &op_desc_ptr, op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } - GELOGE(PARAM_INVALID, "Unexpected ReduceProd node, node input size: %zu, node name: %s", input.size(), + GELOGW("Unexpected ReduceProd node, node input size: %zu, node name: %s", input.size(), op_desc_ptr->GetName().c_str()); return PARAM_INVALID; } @@ -60,13 +60,13 @@ Status ReduceProdKernel::ReduceProdCheck(const ge::OpDescPtr &op_desc_ptr, GE_CHECK_NOTNULL(data_tensor); GE_CHECK_NOTNULL(axis_tensor); if (axis_tensor->GetTensorDesc().GetShape().GetDimNum() > kReduceProdMaxAxisRank) { - GELOGE(PARAM_INVALID, "Axis must be at most rank 1, node node: %s", op_desc_ptr->GetName().c_str()); + GELOGW("Axis must be at most rank 1, node node: %s", op_desc_ptr->GetName().c_str()); return PARAM_INVALID; } DataType data_type = data_tensor->GetTensorDesc().GetDataType(); if (kReduceProdSupportedType.find(data_type) == kReduceProdSupportedType.end()) { - GELOGE(PARAM_INVALID, "ReduceProdKernel data type %s not support, node name: %s", + GELOGW("ReduceProdKernel data type %s not support, node name: %s", TypeUtils::DataTypeToSerialString(data_type).c_str(), op_desc_ptr->GetName().c_str()); return PARAM_INVALID; } @@ -83,7 +83,7 @@ Status ReduceProdKernel::AxisCal(const std::vector &input) int32_t *axis = const_cast(reinterpret_cast(axis_tensor->GetData().GetData())); GE_CHECK_NOTNULL(axis); if (static_cast(*axis) >= data_dim_size) { - GELOGE(PARAM_INVALID, "axis is out of rank of data_dims, axis is %d.", *axis); + GELOGW("axis is out of rank of data_dims, axis is %d.", *axis); return PARAM_INVALID; } axis_dim_ = data_dims[static_cast(*axis)]; @@ -98,13 +98,13 @@ Status ReduceProdKernel::AxisCal(const std::vector &input) // data_dims is the vector of dims, element in data_dims isn't negative. if (axis_appear) { if (data_dims[i] != 0 && end_dim_ > (INT64_MAX / data_dims[i])) { - GELOGE(INTERNAL_ERROR, "Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", end_dim_, data_dims[i]); + GELOGW("Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", end_dim_, data_dims[i]); return INTERNAL_ERROR; } end_dim_ *= data_dims[i]; } else { if (data_dims[i] != 0 && head_dim_ > (INT64_MAX / data_dims[i])) { - GELOGE(INTERNAL_ERROR, "Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", head_dim_, data_dims[i]); + GELOGW("Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", head_dim_, data_dims[i]); return INTERNAL_ERROR; } head_dim_ *= data_dims[i]; @@ -122,7 +122,7 @@ Status ReduceProdKernel::DataCal(const std::vector &input, size_t data_num = data_tensor->GetData().size() / sizeof(int32_t); unique_ptr buf(new (std::nothrow) int32_t[data_num]()); if (buf == nullptr) { - GELOGE(MEMALLOC_FAILED, "new buf failed"); + GELOGW("new buf failed"); return INTERNAL_ERROR; } @@ -190,12 +190,12 @@ Status ReduceProdKernel::ComputeNoAxis(const ge::OpDescPtr &op_desc_ptr, const s ConstGeTensorPtr data_tensor = input.at(kReduceProdDataIndex); GE_CHECK_NOTNULL(data_tensor); if (data_tensor->GetData().size() == 0) { - GELOGE(PARAM_INVALID, "ReduceProdKernel data size of inputs is 0, node node: %s", op_desc_ptr->GetName().c_str()); + GELOGW("ReduceProdKernel data size of inputs is 0, node node: %s", op_desc_ptr->GetName().c_str()); return PARAM_INVALID; } DataType data_type = data_tensor->GetTensorDesc().GetDataType(); if (kReduceProdSupportedType.find(data_type) == kReduceProdSupportedType.end()) { - GELOGE(PARAM_INVALID, "ReduceProdKernel data type %s not support, node name: %s", + GELOGW("ReduceProdKernel data type %s not support, node name: %s", TypeUtils::DataTypeToSerialString(data_type).c_str(), op_desc_ptr->GetName().c_str()); return PARAM_INVALID; } @@ -206,7 +206,7 @@ Status ReduceProdKernel::ComputeNoAxis(const ge::OpDescPtr &op_desc_ptr, const s size_t data_num = data_tensor->GetData().size() / sizeof(int32_t); unique_ptr buf(new (std::nothrow) int32_t[data_num]()); if (buf == nullptr) { - GELOGE(MEMALLOC_FAILED, "new buf failed"); + GELOGW("new buf failed"); return INTERNAL_ERROR; } @@ -235,7 +235,7 @@ Status ReduceProdKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vec GELOGI("ReduceProdKernel in."); Status ret = ReduceProdCheck(op_desc_ptr, input); if (ret != SUCCESS && ret != NOT_CHANGED) { - GELOGE(PARAM_INVALID, "ReduceProdKernel input is invalid, failed to fold node."); + GELOGW("ReduceProdKernel input is invalid, failed to fold node."); return NOT_CHANGED; } @@ -243,7 +243,7 @@ Status ReduceProdKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vec auto output_tensor_desc = op_desc_ptr->GetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/reformat_kernel.cc b/src/ge/host_kernels/reformat_kernel.cc index 33a13599..c2dd1e17 100644 --- a/src/ge/host_kernels/reformat_kernel.cc +++ b/src/ge/host_kernels/reformat_kernel.cc @@ -56,7 +56,7 @@ Status ReFormatKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetTensorDesc().GetShape()).c_str()); return NOT_CHANGED; } GeTensorPtr output_ptr = MakeShared(op_desc_ptr->GetOutputDesc(kReformatFirstOutput)); if (output_ptr == nullptr) { - GELOGE(INTERNAL_ERROR, "Create shared ptr for GeTensor failed"); + GELOGW("Create shared ptr for GeTensor failed"); return NOT_CHANGED; } - GE_IF_BOOL_EXEC(output_ptr->SetData(input.at(0)->GetData()) != GRAPH_SUCCESS, - GELOGE(INTERNAL_ERROR, "set data failed"); + GE_IF_BOOL_EXEC(output_ptr->SetData(input.at(0)->GetData()) != GRAPH_SUCCESS, GELOGW("set data failed"); return NOT_CHANGED); v_output.emplace_back(output_ptr); GELOGD("ReFormatKernel success."); diff --git a/src/ge/host_kernels/reshape_kernel.cc b/src/ge/host_kernels/reshape_kernel.cc index 906624d2..dc7e4bb8 100644 --- a/src/ge/host_kernels/reshape_kernel.cc +++ b/src/ge/host_kernels/reshape_kernel.cc @@ -67,7 +67,7 @@ Status ReshapeKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vector auto output_tensor_desc = op_desc_ptr->GetOutputDesc(kOutputDescFirstIndex); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); + GELOGW("Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/rsqrt_kernel.cc b/src/ge/host_kernels/rsqrt_kernel.cc index 3e14fd5f..56972d23 100644 --- a/src/ge/host_kernels/rsqrt_kernel.cc +++ b/src/ge/host_kernels/rsqrt_kernel.cc @@ -64,7 +64,7 @@ Status RsqrtKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector 0) { unique_ptr buf(new (std::nothrow) float[data_count]()); if (buf == nullptr) { - GELOGE(MEMALLOC_FAILED, "new buf failed"); + GELOGW("new buf failed"); return NOT_CHANGED; } @@ -81,13 +81,13 @@ Status RsqrtKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "MakeShared GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("MakeShared GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } output_ptr->MutableTensorDesc().SetDataType(DT_FLOAT); GE_IF_BOOL_EXEC(output_ptr->SetData(reinterpret_cast(buf.get()), data_size) != GRAPH_SUCCESS, - GELOGE(INTERNAL_ERROR, "set data failed"); + GELOGW("set data failed"); return NOT_CHANGED); output_ptr->MutableTensorDesc().SetShape(x_shape); v_output.push_back(output_ptr); diff --git a/src/ge/host_kernels/slice_d_kernel.cc b/src/ge/host_kernels/slice_d_kernel.cc index ad0a1675..3b8fd0a0 100644 --- a/src/ge/host_kernels/slice_d_kernel.cc +++ b/src/ge/host_kernels/slice_d_kernel.cc @@ -129,7 +129,7 @@ Status SliceDKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); + GELOGW("Failed to fold node %s, out of memory", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } @@ -143,8 +143,14 @@ Status SliceDKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector(const_cast(x_tensor->GetData().data())); int64_t x_data_size = x_tensor->GetTensorDesc().GetShape().GetShapeSize(); - Status ret = OpUtils::SetOutputSliceData(data, x_data_size, x_data_type, x_dims, begin_list, size_list, - output_ptr.get(), stride_list); + + Status ret = CheckOutputDims(size_list, op_desc_ptr); + if (ret != SUCCESS) { + return ret; + } + + ret = OpUtils::SetOutputSliceData(data, x_data_size, x_data_type, x_dims, begin_list, size_list, output_ptr.get(), + stride_list); if (ret != SUCCESS) { GELOGW("Set output data of SliceD failed."); return NOT_CHANGED; @@ -155,5 +161,16 @@ Status SliceDKernel::Compute(const OpDescPtr op_desc_ptr, const std::vector &output_dims, const OpDescPtr attr) { + // check dim not all less than 0 + for (auto dim : output_dims) { + if (dim > 0) { + return SUCCESS; + } + } + GELOGW("all output dim <=0, can't be processed. op_name : %s", attr->GetName().c_str()); + return NOT_CHANGED; +} + REGISTER_KERNEL(SLICED, SliceDKernel); } // namespace ge diff --git a/src/ge/host_kernels/slice_d_kernel.h b/src/ge/host_kernels/slice_d_kernel.h index 9fe35352..90ef9b8b 100644 --- a/src/ge/host_kernels/slice_d_kernel.h +++ b/src/ge/host_kernels/slice_d_kernel.h @@ -29,6 +29,7 @@ class SliceDKernel : public Kernel { private: Status SliceDCheck(const OpDescPtr &op_desc_ptr, const std::vector &input, std::vector &begin_list, std::vector &size_list); + Status CheckOutputDims(const std::vector &output_dims, const OpDescPtr attr); }; } // namespace ge diff --git a/src/ge/host_kernels/slice_kernel.cc b/src/ge/host_kernels/slice_kernel.cc index 1d7d90c2..5f72fc49 100644 --- a/src/ge/host_kernels/slice_kernel.cc +++ b/src/ge/host_kernels/slice_kernel.cc @@ -21,8 +21,8 @@ #include "common/types.h" #include "common/util.h" #include "framework/common/debug/ge_log.h" -#include "host_kernels/kernel_utils.h" #include "graph/utils/type_utils.h" +#include "host_kernels/kernel_utils.h" #include "inc/kernel_factory.h" namespace ge { diff --git a/src/ge/host_kernels/ssd_prior_box_kernel.cc b/src/ge/host_kernels/ssd_prior_box_kernel.cc index c874d732..9de5a08d 100644 --- a/src/ge/host_kernels/ssd_prior_box_kernel.cc +++ b/src/ge/host_kernels/ssd_prior_box_kernel.cc @@ -365,7 +365,7 @@ Status SsdPriorboxKernel::Compute(const NodePtr &node, std::vector // make TensorDesc GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(INTERNAL_ERROR, "Create shared ptr for GeTensor failed"); + GELOGW("Create shared ptr for GeTensor failed"); return NOT_CHANGED; } GE_IF_BOOL_EXEC(output_ptr->SetData(reinterpret_cast(output_data.get()), diff --git a/src/ge/host_kernels/strided_slice_kernel.cc b/src/ge/host_kernels/strided_slice_kernel.cc index 0d70a36a..6a9a558c 100644 --- a/src/ge/host_kernels/strided_slice_kernel.cc +++ b/src/ge/host_kernels/strided_slice_kernel.cc @@ -46,31 +46,31 @@ Status StridedSliceKernel::CheckAndGetAttr(const OpDescPtr &attr, const std::vec int64_t shrink_axis_mask = 0; if (attr == nullptr) { - GELOGE(PARAM_INVALID, "input opdescptr is nullptr."); + GELOGW("input opdescptr is nullptr."); return PARAM_INVALID; } if (input.size() != kStridedSliceInputSize) { - GELOGE(PARAM_INVALID, "The number of input for strided slice must be %zu.", kStridedSliceInputSize); + GELOGW("The number of input for strided slice must be %zu.", kStridedSliceInputSize); return PARAM_INVALID; } if (!AttrUtils::GetInt(attr, STRIDE_SLICE_ATTR_BEGIN_MASK, begin_mask)) { - GELOGE(PARAM_INVALID, "get begin_mask attr failed."); + GELOGW("get begin_mask attr failed."); return PARAM_INVALID; } if (!AttrUtils::GetInt(attr, STRIDE_SLICE_ATTR_END_MASK, end_mask)) { - GELOGE(PARAM_INVALID, "get end_mask attr failed."); + GELOGW("get end_mask attr failed."); return PARAM_INVALID; } if (!AttrUtils::GetInt(attr, STRIDE_SLICE_ATTR_ELLIPSIS_MASK, ellipsis_mask)) { - GELOGE(PARAM_INVALID, "get ellipsis_mask attr failed."); + GELOGW("get ellipsis_mask attr failed."); return PARAM_INVALID; } if (!AttrUtils::GetInt(attr, STRIDE_SLICE_ATTR_NEW_AXIS_MASK, new_axis_mask)) { - GELOGE(PARAM_INVALID, "get new_axis_mask attr failed."); + GELOGW("get new_axis_mask attr failed."); return PARAM_INVALID; } if (!AttrUtils::GetInt(attr, STRIDE_SLICE_ATTR_SHRINK_AXIS_MASK, shrink_axis_mask)) { - GELOGE(PARAM_INVALID, "get shrink_axis_mask attr failed."); + GELOGW("get shrink_axis_mask attr failed."); return PARAM_INVALID; } if ((ellipsis_mask != 0) || (new_axis_mask != 0)) { @@ -98,7 +98,7 @@ Status StridedSliceKernel::CheckAndGetAttr(const OpDescPtr &attr, const std::vec ConstGeTensorPtr weight2 = input[kStridedSliceInputIndex2]; ConstGeTensorPtr weight3 = input[kStridedSliceInputIndex3]; if (CheckWeight(weight0, weight1, weight2, weight3) != SUCCESS) { - GELOGE(PARAM_INVALID, "Check And Get Attr failed."); + GELOGW("Check And Get Attr failed."); return PARAM_INVALID; } @@ -168,6 +168,17 @@ void StridedSliceKernel::GetOutputDims(uint32_t dims_size, const std::vector &output_dims, const OpDescPtr attr) { + // check dim not all less than 0 + for (auto dim : output_dims) { + if (dim > 0) { + return SUCCESS; + } + } + GELOGW("all output dim <=0, can't be processed. op_name : %s", attr->GetName().c_str()); + return NOT_CHANGED; +} + Status StridedSliceKernel::Compute(const ge::OpDescPtr attr, const std::vector &input, vector &v_output) { GELOGI("StridedSliceKernel in."); @@ -191,7 +202,7 @@ Status StridedSliceKernel::Compute(const ge::OpDescPtr attr, const std::vector(weight2->GetData().data()); const int32_t *stride = reinterpret_cast(weight3->GetData().data()); if ((begin == nullptr) || (end == nullptr) || (stride == nullptr)) { - GELOGE(PARAM_INVALID, "input weight tensor is nullptr."); + GELOGW("input weight tensor is nullptr."); return NOT_CHANGED; } @@ -237,16 +248,22 @@ Status StridedSliceKernel::Compute(const ge::OpDescPtr attr, const std::vectorGetOutputDesc(0); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "MakeShared GeTensor failed, node name %s.", attr->GetName().c_str()); + GELOGW("MakeShared GeTensor failed, node name %s.", attr->GetName().c_str()); return NOT_CHANGED; } void *data = reinterpret_cast(const_cast(weight0->GetData().data())); GE_CHECK_NOTNULL(data); + + ret = CheckOutputDims(output_dims, attr); + if (ret != SUCCESS) { + return ret; + } + ret = OpUtils::SetOutputSliceData(data, static_cast(data_size), args.data_type, input_dims, begin_vec, output_dims, output_ptr.get(), stride_vec); if (ret != SUCCESS) { - GELOGE(INTERNAL_ERROR, "SetOutputSliceData failed."); + GELOGW("SetOutputSliceData failed."); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/strided_slice_kernel.h b/src/ge/host_kernels/strided_slice_kernel.h index e569b2d0..0ba3afbd 100644 --- a/src/ge/host_kernels/strided_slice_kernel.h +++ b/src/ge/host_kernels/strided_slice_kernel.h @@ -44,6 +44,7 @@ class StridedSliceKernel : public Kernel { int32_t &end_i, int32_t &dim_i) const; void GetOutputDims(uint32_t dims_size, const std::vector &output_dims, const Attr &args, vector &v_dims); + Status CheckOutputDims(const std::vector &output_dims, const OpDescPtr attr); }; } // namespace ge #endif // GE_GRAPH_PASSES_FOLDING_KERNEL_STRIDED_SLICE_KERNEL_H_ diff --git a/src/ge/host_kernels/sub_kernel.cc b/src/ge/host_kernels/sub_kernel.cc index ed1e5808..70a14c9f 100644 --- a/src/ge/host_kernels/sub_kernel.cc +++ b/src/ge/host_kernels/sub_kernel.cc @@ -162,7 +162,7 @@ Status SubKernel::Compute(const ge::OpDescPtr op_desc_ptr, const std::vectorGetOutputDesc(kSubFirstOutput); GeTensorPtr output_ptr = MakeShared(output_tensor_desc); if (output_ptr == nullptr) { - GELOGE(MEMALLOC_FAILED, "make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); + GELOGW("make_shared ge::GeTensor failed, node name %s.", op_desc_ptr->GetName().c_str()); return NOT_CHANGED; } diff --git a/src/ge/host_kernels/transdata_kernel.cc b/src/ge/host_kernels/transdata_kernel.cc index 5fe44fe4..c5c9da6e 100644 --- a/src/ge/host_kernels/transdata_kernel.cc +++ b/src/ge/host_kernels/transdata_kernel.cc @@ -113,7 +113,7 @@ Status TransdataKernel::Compute(const OpDescPtr op_desc_ptr, const std::vectorGetData().data(); formats::TransResult trans_result; auto ret = formats::TransposeWithShapeCheck(src_data, src_shape, data_shape, src_data_type, perm_list, trans_result); if (ret != SUCCESS) { - GELOGE(INTERNAL_ERROR, "Failed to Transpose from %s to %s, shape %s to %s, perm_list %s, data type %s", + GELOGW("Failed to Transpose from %s to %s, shape %s to %s, perm_list %s, data type %s", TypeUtils::FormatToSerialString(src_format).c_str(), TypeUtils::FormatToSerialString(data_format).c_str(), formats::ShapeToString(src_shape).c_str(), formats::ShapeToString(data_shape).c_str(), formats::ShapeToString(perm_list).c_str(), TypeUtils::DataTypeToSerialString(src_data_type).c_str()); diff --git a/src/ge/hybrid/common/npu_memory_allocator.cc b/src/ge/hybrid/common/npu_memory_allocator.cc index f432318b..1908725f 100644 --- a/src/ge/hybrid/common/npu_memory_allocator.cc +++ b/src/ge/hybrid/common/npu_memory_allocator.cc @@ -25,6 +25,11 @@ namespace hybrid { std::map> NpuMemoryAllocator::allocators_; std::mutex NpuMemoryAllocator::mu_; +AllocationAttr::AllocationAttr(int padding, void *try_reuse_addr) + : padding_(padding), try_reuse_addr_(try_reuse_addr) {} +AllocationAttr::AllocationAttr(int padding) : AllocationAttr(padding, nullptr) {} +AllocationAttr::AllocationAttr(void *try_reuse_addr) : AllocationAttr(0, try_reuse_addr) {} + NpuMemoryAllocator *NpuMemoryAllocator::GetAllocator() { int32_t device_id = 0; if (rtGetDevice(&device_id) != RT_ERROR_NONE) { @@ -38,15 +43,26 @@ NpuMemoryAllocator *NpuMemoryAllocator::GetAllocator() { NpuMemoryAllocator::NpuMemoryAllocator(uint32_t device_id) : device_id_(device_id) {} -void *NpuMemoryAllocator::Allocate(std::size_t size, void *try_reuse_addr) { - void *buffer = - MemManager::CachingInstance(RT_MEMORY_HBM).Malloc(size, reinterpret_cast(try_reuse_addr), device_id_); +void *NpuMemoryAllocator::Allocate(std::size_t size, AllocationAttr *attr) { + void *try_reuse_addr = nullptr; + size_t allocate_size = size; + if (attr != nullptr) { + try_reuse_addr = attr->try_reuse_addr_; + if (attr->padding_ != 0) { + // padding up to multiple of attr->padding, and add extra attr->padding_ + allocate_size = (size + 2 * attr->padding_ - 1) / attr->padding_ * attr->padding_; + GELOGD("Padding size %ld by %d. final size = %zu.", size, attr->padding_, allocate_size); + } + } + + void *buffer = MemManager::CachingInstance(RT_MEMORY_HBM) + .Malloc(allocate_size, reinterpret_cast(try_reuse_addr), device_id_); if (buffer == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to malloc memory, device_id = %u, size = %zu", device_id_, size); + GELOGE(MEMALLOC_FAILED, "Failed to malloc memory, device_id = %u, size = %zu", device_id_, allocate_size); return nullptr; } - GELOGI("Allocating buffer of size %u successfully. device_id = %u, address = %p", size, device_id_, buffer); + GELOGI("Allocating buffer of size %zu successfully. device_id = %u, address = %p", allocate_size, device_id_, buffer); return buffer; } diff --git a/src/ge/hybrid/common/npu_memory_allocator.h b/src/ge/hybrid/common/npu_memory_allocator.h index 8cfeafa6..a9744540 100644 --- a/src/ge/hybrid/common/npu_memory_allocator.h +++ b/src/ge/hybrid/common/npu_memory_allocator.h @@ -26,16 +26,35 @@ namespace ge { namespace hybrid { +class AllocationAttr { + public: + explicit AllocationAttr(int padding); + explicit AllocationAttr(void *try_reuse_addr); + AllocationAttr(int padding, void *try_reuse_addr); + ~AllocationAttr() = default; + + private: + friend class NpuMemoryAllocator; + int padding_ = 0; + void *try_reuse_addr_ = nullptr; +}; + class NpuMemoryAllocator { public: ~NpuMemoryAllocator() = default; static NpuMemoryAllocator *GetAllocator(uint32_t device_id); static NpuMemoryAllocator *GetAllocator(); static void DestroyAllocator(); + static AllocationAttr *AttrWithDefaultPadding() { + static AllocationAttr attr(kDefaultPadding, nullptr); + return &attr; + } - void *Allocate(std::size_t size, void *try_reuse_addr = nullptr); + void *Allocate(std::size_t size, AllocationAttr *attr = nullptr); void Deallocate(void *data); + static constexpr int kDefaultPadding = 32; + private: explicit NpuMemoryAllocator(uint32_t device_id); uint32_t device_id_; diff --git a/src/ge/hybrid/common/tensor_value.cc b/src/ge/hybrid/common/tensor_value.cc index 9544e03a..929d3c87 100644 --- a/src/ge/hybrid/common/tensor_value.cc +++ b/src/ge/hybrid/common/tensor_value.cc @@ -24,7 +24,7 @@ namespace hybrid { TensorBuffer::TensorBuffer(NpuMemoryAllocator *allocator, void *buffer, size_t size) : allocator_(allocator), buffer_(buffer), size_(size) {} -std::unique_ptr TensorBuffer::Create(NpuMemoryAllocator *allocator, size_t size) { +std::unique_ptr TensorBuffer::Create(NpuMemoryAllocator *allocator, size_t size, AllocationAttr *attr) { void *buffer = nullptr; if (size == 0) { GELOGD("size is 0"); @@ -36,7 +36,7 @@ std::unique_ptr TensorBuffer::Create(NpuMemoryAllocator *allocator return nullptr; } - buffer = allocator->Allocate(size); + buffer = allocator->Allocate(size, attr); if (buffer == nullptr) { GELOGE(MEMALLOC_FAILED, "Failed to allocate memory. size = %zu", size); return nullptr; diff --git a/src/ge/hybrid/common/tensor_value.h b/src/ge/hybrid/common/tensor_value.h index 18e67534..db8df9e5 100644 --- a/src/ge/hybrid/common/tensor_value.h +++ b/src/ge/hybrid/common/tensor_value.h @@ -24,10 +24,12 @@ namespace ge { namespace hybrid { class NpuMemoryAllocator; +class AllocationAttr; class TensorBuffer { public: - static std::unique_ptr Create(NpuMemoryAllocator *allocator, size_t size); + static std::unique_ptr Create(NpuMemoryAllocator *allocator, size_t size, + AllocationAttr *attr = nullptr); static std::unique_ptr Create(void *buffer, size_t size); diff --git a/src/ge/hybrid/executor/hybrid_execution_context.cc b/src/ge/hybrid/executor/hybrid_execution_context.cc index bb8e0195..8144ba52 100644 --- a/src/ge/hybrid/executor/hybrid_execution_context.cc +++ b/src/ge/hybrid/executor/hybrid_execution_context.cc @@ -17,34 +17,5 @@ #include "hybrid_execution_context.h" namespace ge { -namespace hybrid { -NodeStatePtr GraphExecutionContext::GetOrCreateNodeState(const NodePtr &node) { - auto &node_state = node_states[node]; - if (node_state == nullptr) { - const NodeItem *node_item = model->GetNodeItem(node); - if (node_item == nullptr) { - return nullptr; - } - node_state.reset(new (std::nothrow) NodeState(*node_item)); - } - - return node_state; -} - -void GraphExecutionContext::OnError(Status error_code) { - GELOGE(error_code, "Error occurred while executing model"); - { - std::lock_guard lk(mu_); - this->status = error_code; - } - - compile_queue.Stop(); - execution_queue.Stop(); -} - -Status GraphExecutionContext::GetStatus() { - std::lock_guard lk(mu_); - return status; -} -} // namespace hybrid +namespace hybrid {} // namespace hybrid } // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/executor/hybrid_execution_context.h b/src/ge/hybrid/executor/hybrid_execution_context.h index 07a6fabf..96722fa9 100644 --- a/src/ge/hybrid/executor/hybrid_execution_context.h +++ b/src/ge/hybrid/executor/hybrid_execution_context.h @@ -20,6 +20,7 @@ #include #include #include "common/blocking_queue.h" +#include "framework/common/debug/ge_log.h" #include "hybrid/common/npu_memory_allocator.h" #include "hybrid/common/tensor_value.h" #include "hybrid/executor/hybrid_profiler.h" @@ -33,34 +34,26 @@ namespace hybrid { struct GraphExecutionContext { uint64_t session_id = 0; const HybridModel *model = nullptr; - NodeDoneManager cv_manager; - BlockingQueue compile_queue; - BlockingQueue execution_queue; - std::vector all_inputs; - std::vector all_outputs; - std::unordered_map node_states; rtStream_t stream = nullptr; + rtContext_t rt_context = nullptr; + rtContext_t rt_gen_context = nullptr; std::unique_ptr callback_manager; NpuMemoryAllocator *allocator = nullptr; mutable std::unique_ptr profiler; bool trace_enabled = false; - int profiling_level = 0; + long profiling_level = 0; bool dump_enabled = false; - Status status = SUCCESS; - std::mutex mu_; - - NodeStatePtr GetOrCreateNodeState(const NodePtr &node); - void OnError(Status status); - Status GetStatus(); + long iteration = 0; }; -#define RECORD_PROFILING_EVENT(context, event_type, fmt, category, node_name, ...) \ +#define RECORD_PROFILING_EVENT(context, evt_type, fmt, category, node_name, ...) \ do { \ if ((context)->profiler != nullptr) { \ if (node_name != nullptr) { \ - context->profiler->RecordEvent(event_type, "[%s] [%s] " fmt, node_name, category, ##__VA_ARGS__); \ + context->profiler->RecordEvent(evt_type, "tid:%lu [%s] [%s] " fmt, GetTid(), node_name, category, \ + ##__VA_ARGS__); \ } else { \ - context->profiler->RecordEvent(event_type, "[%s] " fmt, category, ##__VA_ARGS__); \ + context->profiler->RecordEvent(evt_type, "tid:%lu [%s] " fmt, GetTid(), category, ##__VA_ARGS__); \ } \ } \ } while (0) @@ -79,7 +72,6 @@ struct GraphExecutionContext { #define RECORD_CALLBACK_EVENT(context, name, fmt, ...) \ RECORD_PROFILING_EVENT((context), HybridProfiler::CALLBACK, fmt, "Callback", name, ##__VA_ARGS__) - } // namespace hybrid } // namespace ge #endif // GE_HYBRID_EXECUTOR_HYBRID_EXECUTION_CONTEXT_H_ diff --git a/src/ge/hybrid/executor/hybrid_model_async_executor.cc b/src/ge/hybrid/executor/hybrid_model_async_executor.cc index bd5d77f7..7f650017 100644 --- a/src/ge/hybrid/executor/hybrid_model_async_executor.cc +++ b/src/ge/hybrid/executor/hybrid_model_async_executor.cc @@ -77,19 +77,18 @@ Status HybridModelAsyncExecutor::Init() { GE_CHECK_NOTNULL(data_inputer_); GE_CHK_RT_RET(rtStreamCreate(&stream_, RT_STREAM_PRIORITY_DEFAULT)); - engine_ = std::unique_ptr(new (std::nothrow) HybridModelExecutor(model_, device_id_, stream_)); - GE_CHECK_NOTNULL(engine_); - GE_CHK_STATUS_RET(engine_->Init(), "Failed to init hybrid engine"); - + executor_ = std::unique_ptr(new (std::nothrow) HybridModelExecutor(model_, device_id_, stream_)); + GE_CHECK_NOTNULL(executor_); + GE_CHK_STATUS_RET(executor_->Init(), "Failed to init hybrid engine"); GE_CHK_STATUS_RET(InitInputTensors(), "Failed to init input tensors"); return SUCCESS; } Status HybridModelAsyncExecutor::PreRun(InputData ¤t_data) { GE_CHK_STATUS_RET(SyncVarData(), "Failed to sync var data"); - RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[SyncVarData] End"); + RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[SyncVarData] End"); GE_CHK_STATUS_RET(CopyInputData(current_data), "Failed to copy input data to model"); - RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[CopyInputData] End"); + RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[CopyInputData] End"); return SUCCESS; } @@ -119,21 +118,21 @@ Status HybridModelAsyncExecutor::RunInternal() { args.inputs[it.first] = it.second; } - RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[RunInternal] [iteration = %d] Start", iterator_count_); + RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[RunInternal] [iteration = %d] Start", iterator_count_); ret = PreRun(current_data); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( - ret != SUCCESS, (void)HandleResult(ret, current_data.index, args.outputs, data_wrapper->GetOutput()); + ret != SUCCESS, (void)HandleResult(ret, current_data.index, args, data_wrapper->GetOutput()); CsaInteract::GetInstance().StoreInternalErrorCode(ret, ERROR_MODULE_FMK, JOBSUBSTATE_GRAPH_EXEC); continue, "PreRun failed."); // [No need to check value] - ret = engine_->Execute(args); - ret = HandleResult(ret, current_data.index, args.outputs, data_wrapper->GetOutput()); + ret = executor_->Execute(args); + ret = HandleResult(ret, current_data.index, args, data_wrapper->GetOutput()); if (ret != SUCCESS) { CsaInteract::GetInstance().StoreInternalErrorCode(ret, ERROR_MODULE_RUNTIME, JOBSUBSTATE_GRAPH_EXEC); continue; } - RECORD_MODEL_EXECUTION_EVENT(engine_->GetContext(), "[RunInternal] [iteration = %d] End", iterator_count_); + RECORD_MODEL_EXECUTION_EVENT(executor_->GetContext(), "[RunInternal] [iteration = %d] End", iterator_count_); iterator_count_++; GELOGI("run iterator count is %lu", iterator_count_); } @@ -143,8 +142,8 @@ Status HybridModelAsyncExecutor::RunInternal() { return SUCCESS; } -Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, - const std::vector &output_tensors, OutputData *output_data) { +Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, HybridModelExecutor::ExecuteArgs &args, + OutputData *output_data) { GELOGD("Start to handle result. model id = %u, data index = %u, execution ret = %u", model_id_, data_id, exec_ret); std::vector output_tensor_info_list; if (exec_ret == END_OF_SEQUENCE) { @@ -158,7 +157,7 @@ Status HybridModelAsyncExecutor::HandleResult(Status exec_ret, uint32_t data_id, } GE_CHECK_NOTNULL(output_data); - auto ret = CopyOutputs(output_tensors, output_data, output_tensor_info_list); + auto ret = CopyOutputs(args, output_data, output_tensor_info_list); if (ret != SUCCESS) { OnComputeDone(data_id, INTERNAL_ERROR, output_tensor_info_list); return INTERNAL_ERROR; @@ -215,9 +214,8 @@ Status HybridModelAsyncExecutor::CopyInputData(const InputData ¤t_data) { Status HybridModelAsyncExecutor::InitInputTensors() { auto allocator = NpuMemoryAllocator::GetAllocator(device_id_); GE_CHECK_NOTNULL(allocator); - for (const auto &it : model_->input_nodes_) { - auto input_index = it.first; - auto input_node = it.second; + int input_index = 0; + for (const auto &input_node : model_->GetRootGraphItem()->GetInputNodes()) { GELOGD("Init input[%u], node = %s", input_index, input_node->NodeName().c_str()); auto output_desc = input_node->op_desc->GetOutputDescPtr(kDataOutputIndex); GE_CHECK_NOTNULL(output_desc); @@ -235,6 +233,7 @@ Status HybridModelAsyncExecutor::InitInputTensors() { TensorValue tensor(shared_ptr(buffer.release())); tensor.SetName("Input_" + input_node->NodeName()); input_tensors_.emplace(input_index, tensor); + input_index += 1; } return SUCCESS; @@ -250,35 +249,33 @@ Status HybridModelAsyncExecutor::OnComputeDone(uint32_t data_index, uint32_t res return result_code; } -Status HybridModelAsyncExecutor::CopyOutputs(const std::vector &output_tensors, OutputData *output_data, +Status HybridModelAsyncExecutor::CopyOutputs(HybridModelExecutor::ExecuteArgs &args, OutputData *output_data, std::vector &outputs) { // copy output data from op to designated position - NodeItem *net_output_node = model_->net_output_node_; - GE_CHECK_NOTNULL(net_output_node); - auto all_input_desc = net_output_node->op_desc->GetAllInputsDescPtr(); - - if (all_input_desc.size() != output_tensors.size()) { + std::vector &output_tensor_desc_list = args.output_desc; + std::vector &output_tensors = args.outputs; + if (output_tensor_desc_list.size() != output_tensors.size()) { GELOGE(INTERNAL_ERROR, "Output sizes mismatch. From op_desc = %zu, and from output tensors = %zu", - all_input_desc.size(), output_tensors.size()); + output_tensor_desc_list.size(), output_tensors.size()); return INTERNAL_ERROR; } - GELOGD("Number of outputs = %zu", all_input_desc.size()); + GELOGD("Number of outputs = %zu", output_tensor_desc_list.size()); for (size_t i = 0; i < output_tensors.size(); ++i) { GELOGD("Start to process output[%zu]", i); auto &output_tensor = output_tensors[i]; - auto &tensor_desc = all_input_desc.at(i); + auto &tensor_desc = output_tensor_desc_list.at(i); GE_CHECK_NOTNULL(tensor_desc); int64_t output_size = -1; - GE_CHK_GRAPH_STATUS_RET(TensorUtils::CalcTensorMemSize(tensor_desc->MutableShape(), tensor_desc->GetFormat(), + GE_CHK_GRAPH_STATUS_RET(TensorUtils::CalcTensorMemSize(tensor_desc->GetShape(), tensor_desc->GetFormat(), tensor_desc->GetDataType(), output_size), "Failed to calc tensor size for output[%zu]. shape = [%s], type = %s, format = %s", i, - tensor_desc->MutableShape().ToString().c_str(), + tensor_desc->GetShape().ToString().c_str(), TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), TypeUtils::FormatToSerialString(tensor_desc->GetFormat()).c_str()); GELOGD("Got tensor size for output[%zu] successfully. shape = [%s], type = %s, format = %s, size = %ld", i, - tensor_desc->MutableShape().ToString().c_str(), + tensor_desc->GetShape().ToString().c_str(), TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), TypeUtils::FormatToSerialString(tensor_desc->GetFormat()).c_str(), output_size); @@ -286,7 +283,7 @@ Status HybridModelAsyncExecutor::CopyOutputs(const std::vector &out GE_CHECK_LE(output_size, UINT32_MAX); if (output_tensor.GetSize() < static_cast(output_size)) { GELOGE(INTERNAL_ERROR, "output[%zu] tensor size(%zu) is not enough for output shape [%s]", i, - output_tensor.GetSize(), tensor_desc->MutableShape().ToString().c_str()); + output_tensor.GetSize(), tensor_desc->GetShape().ToString().c_str()); return INTERNAL_ERROR; } @@ -302,7 +299,7 @@ Status HybridModelAsyncExecutor::CopyOutputs(const std::vector &out output.data = std::move(data_buf); output_data->blobs.emplace_back(data_buf.get(), static_cast(output_size), false); } else { - GELOGW("Output[%zu] is empty. shape = [%s]", i, tensor_desc->MutableShape().ToString().c_str()); + GELOGW("Output[%zu] is empty. shape = [%s]", i, tensor_desc->GetShape().ToString().c_str()); output.data = nullptr; output_data->blobs.emplace_back(nullptr, 0U, false); } @@ -310,7 +307,53 @@ Status HybridModelAsyncExecutor::CopyOutputs(const std::vector &out outputs.emplace_back(std::move(output)); GELOGD("Output[%zu] added, type = %s, shape = [%s], size = %ld", i, TypeUtils::DataTypeToSerialString(tensor_desc->GetDataType()).c_str(), - tensor_desc->MutableShape().ToString().c_str(), output_size); + tensor_desc->GetShape().ToString().c_str(), output_size); + } + + return SUCCESS; +} + +Status HybridModelAsyncExecutor::Execute(const vector &inputs, vector &outputs) { + GELOGD("Start to execute model."); + // prepare inputs + InputData input_data; + for (auto &tensor : inputs) { + DataBuffer buffer; + buffer.data = const_cast(tensor.GetData().GetData()); + buffer.length = tensor.GetData().size(); + input_data.blobs.emplace_back(buffer); + } + GE_CHK_STATUS_RET(CopyInputData(input_data), "Failed to copy input data to model"); + GELOGD("Done copying input data successfully."); + + HybridModelExecutor::ExecuteArgs args; + args.inputs.resize(input_tensors_.size()); + args.input_desc.resize(input_tensors_.size()); + for (auto &it : input_tensors_) { + args.inputs[it.first] = it.second; + args.input_desc[it.first] = MakeShared(inputs[it.first].GetTensorDesc()); + } + + GE_CHK_STATUS_RET(executor_->Execute(args), "Failed to execute model."); + + std::vector output_tensor_info_list; + OutputData output_data; + GE_CHK_STATUS_RET(CopyOutputs(args, &output_data, output_tensor_info_list), "Failed to copy outputs."); + GELOGD("Done copying output data successfully. output count = %zu", output_tensor_info_list.size()); + + int out_index = 0; + outputs.resize(output_tensor_info_list.size()); + for (auto &out_tensor_info : output_tensor_info_list) { + auto &ge_tensor = outputs[out_index]; + if (out_tensor_info.length > 0) { + GE_CHK_GRAPH_STATUS_RET(ge_tensor.SetData(out_tensor_info.data.get(), out_tensor_info.length), + "Failed to set output[%d].", out_index); + } + + ge_tensor.MutableTensorDesc() = *args.output_desc[out_index]; + GELOGD("Set output[%d], tensor size = %ld, shape = [%s]", out_index, out_tensor_info.length, + ge_tensor.MutableTensorDesc().MutableShape().ToString().c_str()); + ++out_index; } return SUCCESS; diff --git a/src/ge/hybrid/executor/hybrid_model_async_executor.h b/src/ge/hybrid/executor/hybrid_model_async_executor.h index cb440ba7..195f79a9 100644 --- a/src/ge/hybrid/executor/hybrid_model_async_executor.h +++ b/src/ge/hybrid/executor/hybrid_model_async_executor.h @@ -35,6 +35,8 @@ class HybridModelAsyncExecutor { Status Init(); + Status Execute(const vector &inputs, vector &outputs); + Status Start(const std::shared_ptr &listener); void SetDeviceId(uint32_t device_id); @@ -52,10 +54,10 @@ class HybridModelAsyncExecutor { Status SyncVarData(); - Status HandleResult(Status exec_ret, uint32_t data_id, const std::vector &output_tensors, + Status HandleResult(Status exec_ret, uint32_t data_id, HybridModelExecutor::ExecuteArgs &args, OutputData *output_data); - Status CopyOutputs(const std::vector &output_tensors, OutputData *output_data, + Status CopyOutputs(HybridModelExecutor::ExecuteArgs &args, OutputData *output_data, std::vector &outputs); Status OnComputeDone(uint32_t data_index, uint32_t result_code, std::vector &outputs); @@ -70,7 +72,7 @@ class HybridModelAsyncExecutor { uint32_t model_id_ = 0U; std::atomic_bool run_flag_; std::unique_ptr data_inputer_; - std::unique_ptr engine_; + std::unique_ptr executor_; std::future future_; uint64_t iterator_count_ = 0; diff --git a/src/ge/hybrid/executor/hybrid_model_executor.cc b/src/ge/hybrid/executor/hybrid_model_executor.cc index 856b4483..d62d7be3 100644 --- a/src/ge/hybrid/executor/hybrid_model_executor.cc +++ b/src/ge/hybrid/executor/hybrid_model_executor.cc @@ -26,17 +26,17 @@ HybridModelExecutor::HybridModelExecutor(HybridModel *model, uint32_t device_id, Status HybridModelExecutor::Init() { GELOGD("Start to init HybridGraphEngine."); GE_CHK_STATUS_RET_NOLOG(InitExecutionContext()); - infer_shape_engine_.reset(new (std::nothrow) ShapeInferenceEngine(&context_)); - compile_engine_.reset(new (std::nothrow) TaskCompileEngine(&context_)); - execute_engine_.reset(new (std::nothrow) ExecutionEngine(&context_, context_.callback_manager.get())); - GE_CHK_STATUS_RET_NOLOG(compile_engine_->Init()); GELOGD("HybridGraphEngine initialized successfully."); return SUCCESS; } Status HybridModelExecutor::Execute(HybridModelExecutor::ExecuteArgs &args) { GELOGD("Start to execute model."); - auto ret = ExecuteGraphInternal(args); + auto root_graph_item = model_->GetRootGraphItem(); + GE_CHECK_NOTNULL(root_graph_item); + + SubgraphExecutor executor(model_->GetRootGraphItem(), &context_); + auto ret = ExecuteGraphInternal(executor, args); Cleanup(); RECORD_MODEL_EXECUTION_EVENT(&context_, "[Cleanup] End"); GE_CHK_STATUS_RET(ret, "Failed to execute model"); @@ -46,24 +46,22 @@ Status HybridModelExecutor::Execute(HybridModelExecutor::ExecuteArgs &args) { context_.profiler->Reset(); } + context_.iteration += 1; return SUCCESS; } -Status HybridModelExecutor::ExecuteGraphInternal(HybridModelExecutor::ExecuteArgs &args) { +Status HybridModelExecutor::ExecuteGraphInternal(SubgraphExecutor &executor, HybridModelExecutor::ExecuteArgs &args) { RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitContext] Start"); GE_CHK_STATUS_RET_NOLOG(ResetExecutionContext(context_)); RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitContext] End"); - GE_CHK_STATUS_RET_NOLOG(InitInputsAndOutputs(args, context_)); - RECORD_MODEL_EXECUTION_EVENT(&context_, "[InitInputsAndOutputs] End"); - GE_CHK_STATUS_RET_NOLOG(compile_engine_->Start(pool_)); - RECORD_MODEL_EXECUTION_EVENT(&context_, "[CompileProcess] Started"); - GE_CHK_STATUS_RET_NOLOG(infer_shape_engine_->Start(pool_)); - RECORD_MODEL_EXECUTION_EVENT(&context_, "[InferShapeProcess] Started"); - GE_CHK_STATUS_RET(execute_engine_->Start(), "Run execution engine failed."); - RECORD_MODEL_EXECUTION_EVENT(&context_, "[ExecutionProcess] End"); - GE_CHK_STATUS_RET_NOLOG(Synchronize()); + + GE_CHK_STATUS_RET(executor.ExecuteAsync(args.inputs, args.input_desc), "Failed to execute partitioned call."); + RECORD_MODEL_EXECUTION_EVENT(&context_, "[ExecuteAsync] End"); + + GE_CHK_STATUS_RET(executor.Synchronize(), "Failed to sync root graph."); RECORD_MODEL_EXECUTION_EVENT(&context_, "[Synchronize] End"); - GE_CHK_STATUS_RET_NOLOG(GetOutput(args)); + + GE_CHK_STATUS_RET(executor.GetOutputs(args.outputs, args.output_desc), "Failed to get outputs"); RECORD_MODEL_EXECUTION_EVENT(&context_, "[GetOutput] End"); return SUCCESS; } @@ -71,18 +69,16 @@ Status HybridModelExecutor::ExecuteGraphInternal(HybridModelExecutor::ExecuteArg Status HybridModelExecutor::Cleanup() { GELOGD("Start to cleanup."); context_.callback_manager->Destroy(); - context_.cv_manager.Reset(); - context_.node_states.clear(); - context_.all_inputs.clear(); - context_.all_outputs.clear(); - context_.compile_queue.Clear(); - context_.execution_queue.Clear(); RuntimeInferenceContext::DestroyContext(to_string(context_.session_id)); GELOGD("Cleanup successfully."); return SUCCESS; } Status HybridModelExecutor::InitExecutionContext() { + GE_CHK_RT_RET(rtCtxGetCurrent(&context_.rt_context)); + GE_CHK_RT_RET(rtCtxCreate(&context_.rt_gen_context, RT_CTX_GEN_MODE, 0)); + GE_CHK_RT_RET(rtCtxSetCurrent(context_.rt_context)); + context_.stream = stream_; context_.model = model_; context_.session_id = ::ge::GetContext().SessionId(); @@ -94,78 +90,15 @@ Status HybridModelExecutor::InitExecutionContext() { if (IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) { context_.trace_enabled = true; } - return SUCCESS; } Status HybridModelExecutor::ResetExecutionContext(GraphExecutionContext &context) { - auto &model = *context.model; - context.all_inputs.resize(model.TotalInputs()); - context.all_outputs.resize(model.TotalOutputs()); - context.compile_queue.Restart(); - context.execution_queue.Restart(); GE_CHK_STATUS_RET_NOLOG(context.callback_manager->Init()); - - for (auto const_node : model.GetConstNodes()) { - auto weight_tensor = model.GetWeight(const_node); - GE_CHECK_NOTNULL(weight_tensor); - for (auto &dst_aid_and_nid : const_node->outputs[0]) { - auto *dst_node_item = dst_aid_and_nid.second; - auto input_offset = dst_node_item->input_start + dst_aid_and_nid.first; - context.all_inputs[input_offset] = *weight_tensor; - } - } - string ctx_id = std::to_string(context.session_id); RuntimeInferenceContext::DestroyContext(ctx_id); GE_CHK_GRAPH_STATUS_RET(RuntimeInferenceContext::CreateContext(ctx_id), "Failed to Destroy RuntimeInferenceContext"); return SUCCESS; } - -Status HybridModelExecutor::InitInputsAndOutputs(HybridModelExecutor::ExecuteArgs &args, - GraphExecutionContext &context) { - for (const auto &it : model_->GetInputNodes()) { - uint32_t input_index = it.first; - if (input_index >= args.inputs.size()) { - GELOGE(PARAM_INVALID, "Not enough inputs. NumInputs = %zu, but input index = %u", args.inputs.size(), - input_index); - return PARAM_INVALID; - } - - auto node_item = it.second; - auto &input_tensor = args.inputs[input_index]; - GELOGD("Set input tensor[%u] to inputs with index = %d, addr = %p, size = %zu", input_index, node_item->input_start, - input_tensor.GetData(), input_tensor.GetSize()); - context.all_inputs[node_item->input_start] = input_tensor; - } - - for (size_t i = 0; i < model_->GetOutputOffsets().size(); ++i) { - auto offset = model_->GetOutputOffsets()[i]; - if (i < args.outputs.size() && args.outputs[i].GetData() != nullptr) { - GELOGD("Use user allocated output memory. output index = %zu, output offset = %d", i, offset); - context.all_outputs[offset] = args.outputs[i]; - } - } - - return SUCCESS; -} - -Status HybridModelExecutor::Synchronize() { - GE_CHK_RT_RET(rtStreamSynchronize(stream_)); - return SUCCESS; -} - -Status HybridModelExecutor::GetOutput(HybridModelExecutor::ExecuteArgs &args) { - auto &net_output_input_offsets = model_->GetNetOutputInputOffsets(); - auto num_outputs = net_output_input_offsets.size(); - args.outputs.resize(num_outputs); - for (size_t i = 0; i < num_outputs; ++i) { - auto offset = net_output_input_offsets[i]; - GELOGI("Get output[%zu] from offset %d", i, offset); - args.outputs[i] = context_.all_inputs[offset]; - } - - return SUCCESS; -} } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/executor/hybrid_model_executor.h b/src/ge/hybrid/executor/hybrid_model_executor.h index 2bda6331..9996dbe0 100644 --- a/src/ge/hybrid/executor/hybrid_model_executor.h +++ b/src/ge/hybrid/executor/hybrid_model_executor.h @@ -20,9 +20,7 @@ #include "graph/load/new_model_manager/data_inputer.h" #include "hybrid/executor/hybrid_execution_context.h" #include "hybrid/executor/rt_callback_manager.h" -#include "hybrid/executor/worker/execution_engine.h" -#include "hybrid/executor/worker/shape_inference_engine.h" -#include "hybrid/executor/worker/task_compile_engine.h" +#include "hybrid/executor/subgraph_executor.h" namespace ge { namespace hybrid { @@ -30,7 +28,9 @@ class HybridModelExecutor { public: struct ExecuteArgs { std::vector inputs; + std::vector input_desc; std::vector outputs; + std::vector output_desc; }; HybridModelExecutor(HybridModel *model, uint32_t device_id, rtStream_t stream); @@ -44,24 +44,15 @@ class HybridModelExecutor { Status Execute(ExecuteArgs &args); private: - Status ExecuteGraphInternal(ExecuteArgs &args); + Status ExecuteGraphInternal(SubgraphExecutor &executor, ExecuteArgs &args); Status Cleanup(); Status InitExecutionContext(); static Status ResetExecutionContext(GraphExecutionContext &context); - Status InitInputsAndOutputs(ExecuteArgs &args, GraphExecutionContext &context); - Status GetOutput(ExecuteArgs &args); - - Status Synchronize(); - - ThreadPool pool_; HybridModel *model_; uint32_t device_id_; rtStream_t stream_; GraphExecutionContext context_; - std::unique_ptr infer_shape_engine_; - std::unique_ptr compile_engine_; - std::unique_ptr execute_engine_; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/executor/hybrid_profiler.cc b/src/ge/hybrid/executor/hybrid_profiler.cc index 1081a144..4c70e043 100644 --- a/src/ge/hybrid/executor/hybrid_profiler.cc +++ b/src/ge/hybrid/executor/hybrid_profiler.cc @@ -59,11 +59,10 @@ void HybridProfiler::Dump(std::ostream &output_stream) { auto first_evt = events_[0]; auto start = first_evt.timestamp; - output_stream << "Start " << first_evt.desc << std::endl; std::vector prev_timestamps; prev_timestamps.resize(kMaxEventTypes, start); - for (int i = 1; i < counter_; ++i) { + for (int i = 0; i < counter_; ++i) { auto &evt = events_[i]; auto elapsed = std::chrono::duration_cast(evt.timestamp - start).count(); auto &prev_ts = prev_timestamps[evt.event_type]; diff --git a/src/ge/hybrid/executor/node_done_manager.cc b/src/ge/hybrid/executor/node_done_manager.cc index dfeddb5b..3ec45339 100644 --- a/src/ge/hybrid/executor/node_done_manager.cc +++ b/src/ge/hybrid/executor/node_done_manager.cc @@ -15,35 +15,49 @@ */ #include "hybrid/executor/node_done_manager.h" +#include #include "framework/common/debug/ge_log.h" namespace ge { namespace hybrid { +namespace { +constexpr int kDefaultWaitTimeoutInSec = 10; +} bool NodeDoneManager::Cond::Await() { - std::unique_lock lk(mu_); - cv_.wait(lk, [&]() { return is_released_ || is_cancelled_; }); + std::unique_lock lk(cond_mu_); + if (!cv_.wait_for(lk, std::chrono::seconds(kDefaultWaitTimeoutInSec), + [&]() { return is_released_ || is_cancelled_; })) { + GELOGE(INTERNAL_ERROR, "Wait timed out."); + return false; + } + return is_released_; } void NodeDoneManager::Cond::Release() { - std::unique_lock lk(mu_); + std::unique_lock lk(cond_mu_); is_released_ = true; cv_.notify_all(); } void NodeDoneManager::Cond::Cancel() { - std::unique_lock lk(mu_); + std::unique_lock lk(cond_mu_); is_cancelled_ = true; cv_.notify_all(); } bool NodeDoneManager::Cond::IsRelease() { - std::unique_lock lk(mu_); + std::unique_lock lk(cond_mu_); return is_released_; } NodeDoneManager::Cond *NodeDoneManager::GetSubject(const NodePtr &node) { std::lock_guard lk(mu_); + if (destroyed_) { + GELOGD("Already destroyed."); + return nullptr; + } + auto it = subjects_.find(node); if (it == subjects_.end()) { return &subjects_[node]; @@ -52,8 +66,10 @@ NodeDoneManager::Cond *NodeDoneManager::GetSubject(const NodePtr &node) { return &it->second; } -void NodeDoneManager::Reset() { +void NodeDoneManager::Destroy() { + GELOGD("Start to reset NodeDoneManager."); std::lock_guard lk(mu_); + GELOGD("Cond size = %zu.", subjects_.size()); for (auto &sub : subjects_) { if (!sub.second.IsRelease()) { sub.second.Cancel(); @@ -62,15 +78,24 @@ void NodeDoneManager::Reset() { } subjects_.clear(); + destroyed_ = true; + GELOGD("Done resetting NodeDoneManager successfully."); } void NodeDoneManager::NodeDone(const NodePtr &node) { - GetSubject(node)->Release(); - GELOGD("[%s] Node released.", node->GetName().c_str()); + auto sub = GetSubject(node); + if (sub != nullptr) { + sub->Release(); + GELOGD("[%s] Node released.", node->GetName().c_str()); + } } bool NodeDoneManager::Await(const NodePtr &node) { auto sub = GetSubject(node); + if (sub == nullptr) { + return false; + } + GELOGD("[%s] Await start. is_released = %s", node->GetName().c_str(), sub->IsRelease() ? "true" : "false"); bool ret = sub->Await(); GELOGD("[%s] Await ended. is_released = %s", node->GetName().c_str(), sub->IsRelease() ? "true" : "false"); diff --git a/src/ge/hybrid/executor/node_done_manager.h b/src/ge/hybrid/executor/node_done_manager.h index ccf263d1..f1fdfbec 100644 --- a/src/ge/hybrid/executor/node_done_manager.h +++ b/src/ge/hybrid/executor/node_done_manager.h @@ -31,7 +31,7 @@ class NodeDoneManager { bool Await(const NodePtr &node); - void Reset(); + void Destroy(); private: class Cond { @@ -42,7 +42,7 @@ class NodeDoneManager { bool Await(); private: - std::mutex mu_; + std::mutex cond_mu_; std::condition_variable cv_; bool is_released_ = false; bool is_cancelled_ = false; @@ -51,6 +51,7 @@ class NodeDoneManager { Cond *GetSubject(const NodePtr &node); std::mutex mu_; std::unordered_map subjects_; + bool destroyed_ = false; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/executor/node_state.cc b/src/ge/hybrid/executor/node_state.cc index 6895f158..c78dd725 100644 --- a/src/ge/hybrid/executor/node_state.cc +++ b/src/ge/hybrid/executor/node_state.cc @@ -15,13 +15,136 @@ */ #include "hybrid/executor/node_state.h" +#include +#include "framework/common/debug/log.h" #include "graph/compute_graph.h" +#include "hybrid_execution_context.h" +#include "subgraph_context.h" namespace ge { namespace hybrid { -NodeState::NodeState(const NodeItem &node_item) { - this->node_item = &node_item; - this->op_desc = node_item.node->GetOpDesc(); +namespace { +constexpr auto kMaxWaitTimeInSec = 10; +} +ShapeInferenceState::ShapeInferenceState(const NodeItem &node_item) : node_item(node_item) { + this->num_pending_shapes_ = node_item.num_inputs - node_item.num_static_input_shapes; + GELOGD("[%s] ShapeInferenceState created, pending shape count = %d", node_item.NodeName().c_str(), + this->num_pending_shapes_); +} + +void ShapeInferenceState::UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape) { + if (!node_item.is_dynamic || node_item.is_input_shape_static[idx]) { + GELOGD("[%s] Trying to update static shape, idx = %u. old shape = [%s], new shape = [%s]", + node_item.NodeName().c_str(), idx, node_item.op_desc->MutableInputDesc(idx)->GetShape().ToString().c_str(), + shape.ToString().c_str()); + return; + } + + GELOGD("[%s] Update input shape [%u] with Shape: [%s] and OriginalShape: [%s]", node_item.NodeName().c_str(), idx, + shape.ToString().c_str(), ori_shape.ToString().c_str()); + + std::lock_guard lk(mu_); + node_item.op_desc->MutableInputDesc(idx)->SetShape(shape); + node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); + if (--num_pending_shapes_ == 0) { + ready_cv_.notify_all(); + } +} + +void ShapeInferenceState::UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future) { + if (!node_item.is_dynamic || node_item.is_input_shape_static[idx]) { + GELOGD("[%s] Trying to update constant shape, idx = %u", node_item.NodeName().c_str(), idx); + return; + } + + GELOGD("[%s] Update input shape [%u] with ShapeFuture.", node_item.NodeName().c_str(), idx); + std::lock_guard lk(mu_); + shape_futures.emplace_back(idx, std::move(future)); + if (--num_pending_shapes_ == 0) { + ready_cv_.notify_all(); + } +} + +Status ShapeInferenceState::AwaitShapesReady(const GraphExecutionContext &context) { + if (!node_item.is_dynamic) { + return SUCCESS; + } + std::unique_lock lk(mu_); + if (num_pending_shapes_ > 0) { + GELOGD("[%s] Await pending shape or shape future start.", node_item.NodeName().c_str()); + if (!ready_cv_.wait_for(lk, std::chrono::seconds(kMaxWaitTimeInSec), [&]() { return num_pending_shapes_ == 0; })) { + GELOGE(INTERNAL_ERROR, "[%s] Wait for shape timeout.", node_item.NodeName().c_str()); + return INTERNAL_ERROR; + } + GELOGD("[%s] Await pending shape or shape future end.", node_item.NodeName().c_str()); + } + + for (auto &p : shape_futures) { + auto idx = p.first; + auto &future = p.second; + GeShape shape; + GeShape ori_shape; + RECORD_SHAPE_INFERENCE_EVENT(&context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] Start", idx); + GE_CHK_STATUS_RET(future.Get(ori_shape, shape), "[%s] Get shape failed. index = %u", node_item.NodeName().c_str(), + idx); + RECORD_SHAPE_INFERENCE_EVENT(&context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] End", idx); + + GELOGD("[%s] Update input shape [%u] with shape: [%s] and ori_shape: [%s]", node_item.NodeName().c_str(), idx, + shape.ToString().c_str(), ori_shape.ToString().c_str()); + node_item.op_desc->MutableInputDesc(idx)->SetShape(std::move(shape)); + node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); + } + + return SUCCESS; +} + +ShapeFuture::ShapeFuture(NodePtr src_node, uint32_t src_index, SubgraphContext *subgraph_context) + : src_node_(std::move(src_node)), src_index_(src_index), subgraph_context_(subgraph_context) {} + +NodeState::NodeState(const NodeItem &node_item, SubgraphContext *subgraph_context) + : node_item_(&node_item), shape_inference_state_(node_item), subgraph_context_(subgraph_context) { + this->op_desc_ = node_item.node->GetOpDesc(); +} + +Status NodeState::AwaitInputTensors(GraphExecutionContext &context) const { + for (auto &src_node : node_item_->dependents_for_execution) { + GELOGI("[%s] Start to wait for data dependent node: [%s]", node_item_->NodeName().c_str(), + src_node->GetName().c_str()); + RECORD_EXECUTION_EVENT(&context, node_item_->NodeName().c_str(), "[AwaitNodeDone] [%s] Start", + src_node->GetName().c_str()); + if (!subgraph_context_->Await(src_node)) { + GELOGE(INTERNAL_ERROR, "[%s] Await node [%s] failed.", GetName().c_str(), src_node->GetName().c_str()); + return INTERNAL_ERROR; + } + + RECORD_EXECUTION_EVENT(&context, node_item_->NodeName().c_str(), "[AwaitNodeDone] [%s] End", + src_node->GetName().c_str()); + GELOGI("[%s] Done waiting node.", src_node->GetName().c_str()); + } + + return SUCCESS; +} + +Status NodeState::WaitForPrepareDone() { + if (prepare_future_.valid()) { + GELOGD("[%s] Start to wait for prepare future.", GetName().c_str()); + GE_CHK_STATUS_RET(prepare_future_.get(), "[%s] PreRun failed.", GetName().c_str()); + } + + return SUCCESS; +} + +Status ShapeFuture::Get(GeShape &ori_shape, GeShape &shape) { + GELOGI("Start to wait node: %s for getting shape", src_node_->GetName().c_str()); + if (!subgraph_context_->Await(src_node_)) { + GELOGE(INTERNAL_ERROR, "cancelled"); + return INTERNAL_ERROR; + } + + shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->MutableShape(); + ori_shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->GetOriginShape(); + GELOGI("Get shape from %s:%u. shape = [%s]", src_node_->GetName().c_str(), src_index_, shape.ToString().c_str()); + return SUCCESS; } } // namespace hybrid -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/hybrid/executor/node_state.h b/src/ge/hybrid/executor/node_state.h index b2811bcb..73e0f75c 100644 --- a/src/ge/hybrid/executor/node_state.h +++ b/src/ge/hybrid/executor/node_state.h @@ -17,38 +17,83 @@ #ifndef GE_HYBRID_EXECUTOR_NODE_STATE_H_ #define GE_HYBRID_EXECUTOR_NODE_STATE_H_ +#include +#include +#include +#include "external/ge/ge_api_error_codes.h" #include "hybrid/model/node_item.h" +#include "node_done_manager.h" namespace ge { namespace hybrid { - class NodeTask; +class GraphExecutionContext; +class SubgraphContext; -// ĺ­ć”ľä¸€äş›äĽšĺŹĺŚ–çš„äżˇćŻ... -class NodeState { +class ShapeFuture { public: - NodeState() = default; - explicit NodeState(const NodeItem &node_item); + ShapeFuture(NodePtr src_node, uint32_t src_index, SubgraphContext *subgraph_context); + ~ShapeFuture() = default; + Status Get(GeShape &ori_shape, GeShape &shape); + + private: + NodePtr src_node_; + uint32_t src_index_; + SubgraphContext *subgraph_context_; +}; + +struct ShapeInferenceState { + explicit ShapeInferenceState(const NodeItem &node_item); + + void UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape); + + void UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future); + + Status AwaitShapesReady(const GraphExecutionContext &context); + + const NodeItem &node_item; + + private: + std::vector> shape_futures; + int num_pending_shapes_ = 0; + std::condition_variable ready_cv_; + std::mutex mu_; +}; + +// saving sth. dynamic during execution +struct NodeState { + public: + NodeState(const NodeItem &node_item, SubgraphContext *subgraph_context); ~NodeState() = default; - inline int NodeId() const { return node_item->node_id; } + OpDesc *GetOpDesc() const { return op_desc_.get(); } + + inline const NodeItem *GetNodeItem() const { return node_item_; } + + inline const string &GetName() const { return node_item_->NodeName(); } + + inline const string &GetType() const { return node_item_->NodeType(); } - inline Node *GetNode() const { return node_item->node.get(); } + ShapeInferenceState &GetShapeInferenceState() { return shape_inference_state_; } - OpDesc *GetOpDesc() const { return op_desc.get(); } + const shared_ptr &GetKernelTask() const { return kernel_task_; } - inline const NodeItem *GetNodeItem() const { return node_item; } + void SetKernelTask(const shared_ptr &kernel_task) { kernel_task_ = kernel_task; } - inline const string &GetName() const { return node_item->NodeName(); } + Status WaitForPrepareDone(); - inline const string &GetType() const { return node_item->NodeType(); } + void SetPrepareFuture(std::future &&prepare_future) { this->prepare_future_ = std::move(prepare_future); } - // private: - const NodeItem *node_item = nullptr; - std::shared_ptr kernel_task = nullptr; + Status AwaitInputTensors(GraphExecutionContext &context) const; - bool is_compiled = false; - OpDescPtr op_desc; + private: + const NodeItem *node_item_ = nullptr; + std::shared_ptr kernel_task_ = nullptr; + std::future prepare_future_; + OpDescPtr op_desc_; + ShapeInferenceState shape_inference_state_; + SubgraphContext *subgraph_context_; + std::mutex mu_; }; using NodeStatePtr = std::shared_ptr; diff --git a/src/ge/hybrid/executor/rt_callback_manager.cc b/src/ge/hybrid/executor/rt_callback_manager.cc index 6be8da31..c1c98f73 100644 --- a/src/ge/hybrid/executor/rt_callback_manager.cc +++ b/src/ge/hybrid/executor/rt_callback_manager.cc @@ -42,7 +42,6 @@ Status CallbackManager::Init() { rtContext_t ctx = nullptr; GE_CHK_RT_RET(rtCtxGetCurrent(&ctx)); ret_future_ = std::async([&](rtContext_t context) -> Status { return CallbackProcess(context); }, ctx); - if (!ret_future_.valid()) { GELOGE(INTERNAL_ERROR, "Failed to init callback manager."); return INTERNAL_ERROR; diff --git a/src/ge/hybrid/executor/subgraph_context.cc b/src/ge/hybrid/executor/subgraph_context.cc new file mode 100644 index 00000000..395e75de --- /dev/null +++ b/src/ge/hybrid/executor/subgraph_context.cc @@ -0,0 +1,113 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "subgraph_context.h" + +#include "common/debug/log.h" + +namespace ge { +namespace hybrid { +SubgraphContext::SubgraphContext(const GraphItem *graph_item) : graph_item_(graph_item) {} + +Status SubgraphContext::Init() { + GE_CHECK_NOTNULL(graph_item_); + GELOGD("[%s] Start to init subgraph context. total inputs = %d, total outputs = %d", graph_item_->GetName().c_str(), + graph_item_->TotalInputs(), graph_item_->TotalOutputs()); + all_inputs_.resize(graph_item_->TotalInputs()); + all_outputs_.resize(graph_item_->TotalOutputs()); + + return SUCCESS; +} + +NodeStatePtr SubgraphContext::GetOrCreateNodeState(const NodeItem *node_item) { + std::lock_guard lk(mu_); + auto &node_state = node_states_[node_item]; + if (node_state == nullptr) { + node_state.reset(new (std::nothrow) NodeState(*node_item, this)); + } + + return node_state; +} + +Status SubgraphContext::SetInput(int index, const TensorValue &tensor) { + if (static_cast(index) >= all_inputs_.size()) { + GELOGE(INTERNAL_ERROR, "output index output range. all input num = %zu, input index = %d", all_inputs_.size(), + index); + return INTERNAL_ERROR; + } + + all_inputs_[index] = tensor; + return SUCCESS; +} + +Status SubgraphContext::SetInput(const NodeItem &node_item, int input_index, const TensorValue &tensor) { + auto index = node_item.input_start + input_index; + return SetInput(index, tensor); +} + +Status SubgraphContext::SetOutput(const NodeItem &node_item, int output_index, const TensorValue &tensor) { + auto index = node_item.output_start + output_index; + if (output_index >= node_item.num_outputs || static_cast(index) >= all_outputs_.size()) { + GELOGE(INTERNAL_ERROR, "output index output range. all output num = %zu, node_item = %s, output index = %d", + all_outputs_.size(), node_item.DebugString().c_str(), output_index); + return INTERNAL_ERROR; + } + + all_outputs_[index] = tensor; + return SUCCESS; +} + +Status SubgraphContext::GetInput(int index, TensorValue &tensor) { + GE_CHECK_GE(all_inputs_.size(), index + 1U); + tensor = all_inputs_[index]; + return SUCCESS; +} + +Status SubgraphContext::GetOutputs(std::vector &outputs) { + if (graph_item_->IsDynamic()) { + GELOGD("[%s] graph is dynamic, get outputs from net output input tensors", graph_item_->GetName().c_str()); + // get from net output inputs + auto output_node = graph_item_->GetOutputNode(); + if (output_node != nullptr) { + for (int i = 0; i < output_node->num_inputs; ++i) { + TensorValue tensor; + GE_CHK_STATUS_RET_NOLOG(GetInput(output_node->input_start + i, tensor)); + GELOGD("[%s] Adding output tensor by input index [%d], tensor = %s", graph_item_->GetName().c_str(), + output_node->input_start + i, tensor.DebugString().c_str()); + outputs.emplace_back(std::move(tensor)); + } + } + } else { + GELOGD("[%s] graph is non-dynamic, get outputs from subgraph outputs", graph_item_->GetName().c_str()); + for (auto &tensor : all_outputs_) { + GELOGD("[%s] Adding output tensor: %s", graph_item_->GetName().c_str(), tensor.DebugString().c_str()); + outputs.emplace_back(tensor); + } + } + + return SUCCESS; +} + +bool SubgraphContext::Await(const NodePtr &node) { return node_done_manager_.Await(node); } + +void SubgraphContext::OnError(Status error) { + GELOGE(error, "[%s] Error occurred while executing graph.", graph_item_->GetName().c_str()); + node_done_manager_.Destroy(); +} + +void SubgraphContext::NodeDone(const NodePtr &node) { node_done_manager_.NodeDone(node); } +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/executor/subgraph_context.h b/src/ge/hybrid/executor/subgraph_context.h new file mode 100644 index 00000000..fd934d80 --- /dev/null +++ b/src/ge/hybrid/executor/subgraph_context.h @@ -0,0 +1,61 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ +#define GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ + +#include + +#include "hybrid/common/tensor_value.h" +#include "hybrid/executor/node_state.h" +#include "hybrid/executor/node_done_manager.h" +#include "hybrid/model/graph_item.h" +#include "hybrid/model/node_item.h" + +namespace ge { +namespace hybrid { +class SubgraphContext { + public: + explicit SubgraphContext(const GraphItem *graph_item); + ~SubgraphContext() = default; + + Status Init(); + NodeStatePtr GetOrCreateNodeState(const NodeItem *node_item); + + void OnError(Status error); + + Status SetInput(const NodeItem &node_item, int input_index, const TensorValue &tensor); + Status SetOutput(const NodeItem &node_item, int output_index, const TensorValue &tensor); + Status SetInput(int index, const TensorValue &tensor); + Status GetInput(int index, TensorValue &tensor); + Status GetOutputs(std::vector &outputs); + + bool Await(const NodePtr &node); + void NodeDone(const NodePtr &node); + + private: + friend class TaskContext; + const GraphItem *graph_item_; + std::mutex mu_; + std::vector all_inputs_; + std::vector all_outputs_; + NodeDoneManager node_done_manager_; + std::unordered_map node_states_; +}; +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_EXECUTOR_ITERATION_CONTEXT_H_ diff --git a/src/ge/hybrid/executor/subgraph_executor.cc b/src/ge/hybrid/executor/subgraph_executor.cc new file mode 100644 index 00000000..7664e90d --- /dev/null +++ b/src/ge/hybrid/executor/subgraph_executor.cc @@ -0,0 +1,373 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/executor/subgraph_executor.h" +#include "hybrid/executor/worker/task_compile_engine.h" +#include "hybrid/executor/worker/execution_engine.h" +#include "hybrid/node_executor/node_executor.h" + +namespace ge { +namespace hybrid { +namespace { +constexpr int kDefaultThreadNum = 4; +constexpr int kDataInputIndex = 0; +} // namespace + +SubgraphExecutor::SubgraphExecutor(const GraphItem *graph_item, GraphExecutionContext *context, bool force_infer_shape) + : graph_item_(graph_item), + context_(context), + force_infer_shape_(force_infer_shape), + pre_run_pool_(kDefaultThreadNum) {} + +SubgraphExecutor::~SubgraphExecutor() { GELOGD("[%s] SubgraphExecutor destroyed.", graph_item_->GetName().c_str()); } + +Status SubgraphExecutor::Init(const std::vector &inputs, + const std::vector &input_desc) { + subgraph_context_.reset(new (std::nothrow) SubgraphContext(graph_item_)); + GE_CHECK_NOTNULL(subgraph_context_); + GE_CHK_STATUS_RET(subgraph_context_->Init(), "[%s] Failed to init subgraph context.", graph_item_->GetName().c_str()); + + shape_inference_engine_.reset(new (std::nothrow) ShapeInferenceEngine(context_, subgraph_context_.get())); + GE_CHECK_NOTNULL(shape_inference_engine_); + + if (graph_item_->IsDynamic()) { + GE_CHK_STATUS_RET(InitInputsForUnknownShape(inputs, input_desc), "[%s] Failed to set inputs.", + graph_item_->GetName().c_str()); + } else { + GE_CHK_STATUS_RET(InitInputsForKnownShape(inputs), + "[%s] Failed to init subgraph executor for known shape subgraph.", + graph_item_->GetName().c_str()); + } + + return SUCCESS; +} + +Status SubgraphExecutor::InitInputsForUnknownShape(const std::vector &inputs, + const std::vector &input_desc) { + // Number of inputs of parent node should be greater or equal than that of subgraph + auto input_nodes = graph_item_->GetInputNodes(); + if (inputs.size() < input_nodes.size()) { + GELOGE(INTERNAL_ERROR, "[%s] Number of inputs [%zu] is not sufficient for subgraph which needs [%zu] inputs.", + graph_item_->GetName().c_str(), inputs.size(), input_nodes.size()); + return INTERNAL_ERROR; + } + + for (size_t i = 0; i < input_nodes.size(); ++i) { + auto &input_node = input_nodes[i]; + if (input_node == nullptr) { + GELOGD("[%s] Input[%zu] is not needed by subgraph, skip it.", graph_item_->GetName().c_str(), i); + continue; + } + + auto &input_tensor = inputs[i]; + GELOGD("[%s] Set input tensor[%zu] to inputs with index = %d, tensor = %s", graph_item_->GetName().c_str(), i, + input_node->input_start, input_tensor.DebugString().c_str()); + + GE_CHK_STATUS_RET(subgraph_context_->SetInput(*input_node, kDataInputIndex, input_tensor), + "[%s] Failed to set input tensor[%zu]", graph_item_->GetName().c_str(), i); + + if (force_infer_shape_ || input_node->is_dynamic) { + GELOGD("[%s] Start to update input[%zu] for subgraph data node.", graph_item_->GetName().c_str(), i); + GE_CHECK_LE(i + 1, input_desc.size()); + const auto &tensor_desc = input_desc[i]; + auto node_state = subgraph_context_->GetOrCreateNodeState(input_node); + GE_CHECK_NOTNULL(node_state); + node_state->GetShapeInferenceState().UpdateInputShape(0, tensor_desc->GetOriginShape(), tensor_desc->GetShape()); + } + } + + GELOGD("[%s] Done setting inputs.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::InitInputsForKnownShape(const std::vector &inputs) { + auto &input_index_mapping = graph_item_->GetInputIndexMapping(); + for (size_t i = 0; i < input_index_mapping.size(); ++i) { + auto &parent_input_index = input_index_mapping[i]; + if (static_cast(parent_input_index) >= inputs.size()) { + GELOGE(INTERNAL_ERROR, + "[%s] Number of inputs [%zu] is not sufficient for subgraph which needs at lease [%d] inputs", + graph_item_->GetName().c_str(), inputs.size(), parent_input_index + 1); + + return INTERNAL_ERROR; + } + + auto &input_tensor = inputs[parent_input_index]; + subgraph_context_->SetInput(i, input_tensor); + GELOGD("[%s] Set input tensor[%zu] with inputs with index = %d, tensor = %s", graph_item_->GetName().c_str(), i, + parent_input_index, input_tensor.DebugString().c_str()); + } + + return SUCCESS; +} + +Status SubgraphExecutor::ExecuteAsync(const std::vector &inputs, + const std::vector &input_desc) { + GELOGD("[%s] is dynamic = %s", graph_item_->GetName().c_str(), graph_item_->IsDynamic() ? "true" : "false"); + GE_CHK_STATUS_RET(Init(inputs, input_desc), "[%s] Failed to init executor.", graph_item_->GetName().c_str()); + + if (!graph_item_->IsDynamic()) { + return ExecuteAsyncForKnownShape(inputs); + } + + GE_CHK_STATUS_RET(ScheduleTasks(), "[%s] Failed to execute tasks.", graph_item_->GetName().c_str()); + GELOGD("[%s] Done executing subgraph successfully.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::ExecuteAsyncForKnownShape(const std::vector &inputs) { + GELOGD("[%s] subgraph is not dynamic.", graph_item_->GetName().c_str()); + if (graph_item_->GetAllNodes().size() != 1) { + GELOGE(INTERNAL_ERROR, "[%s] Invalid known shape subgraph. node size = %zu", graph_item_->GetName().c_str(), + graph_item_->GetAllNodes().size()); + return INTERNAL_ERROR; + } + + auto node_item = graph_item_->GetAllNodes()[0]; + GE_CHECK_NOTNULL(node_item); + auto node_state = subgraph_context_->GetOrCreateNodeState(node_item); + GE_CHECK_NOTNULL(node_state); + node_state->SetKernelTask(node_item->kernel_task); + + known_shape_task_context_ = TaskContext::Create(*node_item, context_, subgraph_context_.get()); + GE_CHECK_NOTNULL(known_shape_task_context_); + + GE_CHK_STATUS_RET(ExecutionEngine::ExecuteAsync(*node_state, known_shape_task_context_, *context_), + "[%s] Failed to execute node [%s] for known subgraph.", graph_item_->GetName().c_str(), + known_shape_task_context_->GetNodeName()); + + GELOGD("[%s] Done execute non-dynamic subgraph successfully.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::ExecuteAsync(TaskContext &task_context) { + std::vector inputs; + std::vector input_desc; + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto tensor = task_context.GetInput(i); + GE_CHECK_NOTNULL(tensor); + inputs.emplace_back(*tensor); + input_desc.emplace_back(task_context.GetInputDesc(i)); + } + + GE_CHK_STATUS_RET(ExecuteAsync(inputs, input_desc), "[%s] Failed to execute subgraph.", + graph_item_->GetName().c_str()); + + GE_CHK_STATUS_RET(SetOutputsToParentNode(task_context), "[%s] Failed to set output shapes to parent node.", + graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::PrepareNodes() { + GELOGD("[%s] Start to prepare nodes. force infer shape = %s.", graph_item_->GetName().c_str(), + force_infer_shape_ ? "true" : "false"); + auto &all_nodes = graph_item_->GetAllNodes(); + for (size_t i = 0; i < all_nodes.size(); ++i) { + auto &node_item = *all_nodes[i]; + // for while op + if (force_infer_shape_ && !node_item.is_dynamic) { + GELOGD("[%s] Force infer shape is set, updating node to dynamic.", node_item.NodeName().c_str()); + auto &mutable_node_item = const_cast(node_item); + mutable_node_item.SetToDynamic(); + } + + GELOGD("[%s] Start to prepare node [%s].", graph_item_->GetName().c_str(), node_item.NodeName().c_str()); + auto node_state = subgraph_context_->GetOrCreateNodeState(&node_item); + GE_CHECK_NOTNULL(node_state); + auto p_node_state = node_state.get(); + + if (node_item.node_type == NETOUTPUT) { + // Wait for all inputs become valid + // after PrepareNodes returned. all output tensors and shapes are valid + GE_CHK_STATUS_RET_NOLOG(p_node_state->GetShapeInferenceState().AwaitShapesReady(*context_)); + GE_CHK_STATUS_RET_NOLOG(p_node_state->AwaitInputTensors(*context_)); + continue; + } + + // only do shape inference and compilation for nodes with dynamic shapes. + if (node_item.is_dynamic) { + auto prepare_future = pre_run_pool_.commit([this, p_node_state]() -> Status { + GE_CHK_STATUS_RET_NOLOG(InferShape(shape_inference_engine_.get(), *p_node_state)); + return PrepareForExecution(context_, *p_node_state); + }); + + p_node_state->SetPrepareFuture(std::move(prepare_future)); + } else { + GELOGD("[%s] Skipping shape inference and compilation for node with static shape.", node_item.NodeName().c_str()); + if (node_item.kernel_task == nullptr) { + GELOGW("[%s] Node of static shape got no task.", node_item.NodeName().c_str()); + GE_CHK_STATUS_RET(TaskCompileEngine::Compile(*p_node_state, context_), "[%s] Failed to create task.", + p_node_state->GetName().c_str()); + } else { + node_state->SetKernelTask(node_item.kernel_task); + } + } + + if (!ready_queue_.Push(p_node_state)) { + GELOGE(INTERNAL_ERROR, "[%s] Error occurs while launching tasks. quit from preparing nodes.", + graph_item_->GetName().c_str()); + return INTERNAL_ERROR; + } + + GELOGD("[%s] Push node [%s] to queue.", graph_item_->GetName().c_str(), node_item.NodeName().c_str()); + } + + return SUCCESS; +} + +Status SubgraphExecutor::InferShape(ShapeInferenceEngine *shape_inference_engine, NodeState &node_state) { + const auto &node_item = *node_state.GetNodeItem(); + GE_CHK_STATUS_RET(shape_inference_engine->InferShape(node_state), "[%s] Failed to InferShape.", + node_state.GetName().c_str()); + GE_CHK_STATUS_RET(shape_inference_engine->PropagateOutputShapes(node_item), "[%s] Failed to PropagateOutputShapes.", + node_state.GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::PrepareForExecution(GraphExecutionContext *ctx, NodeState &node_state) { + auto &node_item = *node_state.GetNodeItem(); + if (node_item.kernel_task == nullptr) { + GE_CHK_STATUS_RET(TaskCompileEngine::Compile(node_state, ctx), "Failed to create task for node[%s]", + node_state.GetName().c_str()); + } else { + node_state.SetKernelTask(node_item.kernel_task); + } + + GELOGD("[%s] Start to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); + RECORD_COMPILE_EVENT(ctx, node_item.NodeName().c_str(), "[CalcOpRunningParam] Start"); + GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().CalcOpRunningParam(*node_item.node), + "[%s] Failed to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); + RECORD_COMPILE_EVENT(ctx, node_item.NodeName().c_str(), "[CalcOpRunningParam] End"); + GELOGD("[%s] Done invoking CalcOpRunningParam successfully.", node_item.NodeName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::LaunchTasks() { + while (true) { + NodeState *node_state = nullptr; + if (!ready_queue_.Pop(node_state)) { + GELOGE(INTERNAL_ERROR, "[%s] Failed to pop node.", graph_item_->GetName().c_str()); + return INTERNAL_ERROR; + } + + if (node_state == nullptr) { + GELOGD("[%s] Got EOF from queue.", graph_item_->GetName().c_str()); + return SUCCESS; + } + + GE_CHK_STATUS_RET_NOLOG(node_state->WaitForPrepareDone()); + + GELOGD("[%s] Start to execute.", node_state->GetName().c_str()); + auto task_context = TaskContext::Create(*node_state->GetNodeItem(), context_, subgraph_context_.get()); + GE_CHECK_NOTNULL(task_context); + task_context->SetForceInferShape(force_infer_shape_); + auto shared_task_context = std::shared_ptr(task_context.release()); + GE_CHK_STATUS_RET(ExecutionEngine::ExecuteAsync(*node_state, shared_task_context, *context_), + "[%s] Execute node failed.", node_state->GetName().c_str()); + + GELOGD("[%s] Done executing node successfully.", node_state->GetName().c_str()); + } +} + +Status SubgraphExecutor::ScheduleTasks() { + GELOGD("[%s] Start to schedule prepare workers.", graph_item_->GetName().c_str()); + auto prepare_future = std::async([&]() -> Status { + auto ret = PrepareNodes(); + ready_queue_.Push(nullptr); + return ret; + }); + + GELOGD("[%s] Start to execute subgraph.", graph_item_->GetName().c_str()); + auto ret = LaunchTasks(); + if (ret != SUCCESS) { + GELOGE(ret, "[%s] Failed to execute subgraph.", graph_item_->GetName().c_str()); + subgraph_context_->OnError(ret); + ready_queue_.Stop(); + prepare_future.wait(); + return ret; + } + + GE_CHK_STATUS_RET(prepare_future.get(), "[%s] Error occurred in task preparation.", graph_item_->GetName().c_str()); + + GELOGD("[%s] Done launching all tasks successfully.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::GetOutputs(vector &outputs) { return subgraph_context_->GetOutputs(outputs); } + +Status SubgraphExecutor::GetOutputs(vector &outputs, std::vector &output_desc) { + GE_CHK_STATUS_RET(GetOutputs(outputs), "[%s] Failed to get output tensors.", graph_item_->GetName().c_str()); + + // copy output data from op to designated position + std::vector output_tensor_desc_list; + GE_CHK_STATUS_RET(graph_item_->GetOutputDescList(output_desc), "[%s] Failed to get output tensor desc.", + graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::Synchronize() { + GELOGD("[%s] Synchronize start.", graph_item_->GetName().c_str()); + GE_CHK_RT_RET(rtStreamSynchronize(context_->stream)); + GELOGD("[%s] Done synchronizing successfully.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status SubgraphExecutor::SetOutputsToParentNode(TaskContext &task_context) { + // get output tensors and tensor desc list + std::vector outputs; + std::vector output_desc_list; + GE_CHK_STATUS_RET(subgraph_context_->GetOutputs(outputs), "[%s] Failed to get output tensors.", + graph_item_->GetName().c_str()); + GE_CHK_STATUS_RET(graph_item_->GetOutputDescList(output_desc_list), "[%s] Failed to get output tensor desc.", + graph_item_->GetName().c_str()); + + if (outputs.size() != output_desc_list.size()) { + GELOGE(INTERNAL_ERROR, "[%s] num output tensors = %zu, num output tensor desc = %zu", + graph_item_->GetName().c_str(), outputs.size(), output_desc_list.size()); + return INTERNAL_ERROR; + } + + // mapping to parent task context + for (size_t i = 0; i < outputs.size(); ++i) { + int parent_output_index = graph_item_->GetParentOutputIndex(i); + GE_CHECK_GE(parent_output_index, 0); + // update tensor + GELOGD("[%s] Updating output[%zu] to parent output[%d]", graph_item_->GetName().c_str(), i, parent_output_index); + + GELOGD("[%s] Updating output tensor, index = %d, tensor = %s", graph_item_->GetName().c_str(), parent_output_index, + outputs[i].DebugString().c_str()); + GE_CHK_STATUS_RET(task_context.SetOutput(parent_output_index, outputs[i])); + + // updating shapes. dynamic format/dtype is not supported. + // It should be noted that even the subgraph is of known shape, it is also necessary to update parent output desc, + // for instance, IfOp may have two known-shaped subgraphs of different output shapes + const auto &output_desc = output_desc_list[i]; + auto parent_output_desc = task_context.MutableOutputDesc(parent_output_index); + GE_CHECK_NOTNULL(parent_output_desc); + GELOGD("[%s] Updating output shape[%d] from [%s] to [%s]", graph_item_->GetName().c_str(), parent_output_index, + parent_output_desc->MutableShape().ToString().c_str(), output_desc->GetShape().ToString().c_str()); + parent_output_desc->SetShape(output_desc->GetShape()); + + GELOGD("[%s] Updating output original shape[%d] from [%s] to [%s]", graph_item_->GetName().c_str(), + parent_output_index, parent_output_desc->GetOriginShape().ToString().c_str(), + output_desc->GetOriginShape().ToString().c_str()); + parent_output_desc->SetOriginShape(output_desc->GetOriginShape()); + } + + return SUCCESS; +} +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/executor/subgraph_executor.h b/src/ge/hybrid/executor/subgraph_executor.h new file mode 100644 index 00000000..7cdb2070 --- /dev/null +++ b/src/ge/hybrid/executor/subgraph_executor.h @@ -0,0 +1,101 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ +#define GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ + +#include + +#include "common/blocking_queue.h" +#include "common/thread_pool.h" +#include "hybrid/executor/subgraph_context.h" +#include "hybrid/executor/node_state.h" +#include "hybrid/executor/hybrid_execution_context.h" +#include "hybrid/executor/worker/shape_inference_engine.h" +#include "hybrid/model/graph_item.h" +#include "hybrid/node_executor/task_context.h" + +namespace ge { +namespace hybrid { +// Executor for executing a subgraph +class SubgraphExecutor { + public: + SubgraphExecutor(const GraphItem *graph_item, GraphExecutionContext *context, bool force_infer_shape = false); + ~SubgraphExecutor(); + + /** + * Execute subgraph async, output tensor address(not data) and output tensor descriptions are + * valid after this method returned + * @param inputs input tensors + * @param input_desc input tensor descriptions + * @return SUCCESS on success, error code otherwise + */ + Status ExecuteAsync(const std::vector &inputs, const std::vector &input_desc); + + /** + * Execute subgraph async, output tensor address(not data) and output tensor descriptions are + * valid after this method returned + * @param task_context instance of TaskContext + * @return SUCCESS on success, error code otherwise + */ + Status ExecuteAsync(TaskContext &task_context); + + /** + * Synchronize all tasks in the subgraph. output tensor data are valid after this method returned + * @return SUCCESS on success, error code otherwise + */ + Status Synchronize(); + + /** + * Get output tensors + * @param outputs output tensors + * @return SUCCESS on success, error code otherwise + */ + Status GetOutputs(std::vector &outputs); + + /** + * Get output tensors and output tensor descriptions + * @param outputs output tensors + * @param output_desc output tensor descriptions + * @return SUCCESS on success, error code otherwise + */ + Status GetOutputs(std::vector &outputs, std::vector &output_desc); + + private: + static Status PrepareForExecution(GraphExecutionContext *ctx, NodeState &node_state); + static Status InferShape(ShapeInferenceEngine *shape_inference_engine, NodeState &node_state); + Status Init(const std::vector &inputs, const std::vector &input_desc); + Status InitInputsForUnknownShape(const std::vector &inputs, + const std::vector &input_desc); + Status InitInputsForKnownShape(const std::vector &inputs); + Status ExecuteAsyncForKnownShape(const std::vector &inputs); + Status ScheduleTasks(); + Status PrepareNodes(); + Status LaunchTasks(); + Status SetOutputsToParentNode(TaskContext &task_context); + + const GraphItem *graph_item_; + GraphExecutionContext *context_; + std::unique_ptr subgraph_context_; + bool force_infer_shape_; + ThreadPool pre_run_pool_; + BlockingQueue ready_queue_; + std::unique_ptr shape_inference_engine_; + std::shared_ptr known_shape_task_context_; +}; +} // namespace hybrid +} // namespace ge +#endif // GE_HYBRID_EXECUTOR_EXECUTOR_SUBGRAPH_EXECUTOR_H_ diff --git a/src/ge/hybrid/executor/worker/execution_engine.cc b/src/ge/hybrid/executor/worker/execution_engine.cc index 9e656139..20da6378 100644 --- a/src/ge/hybrid/executor/worker/execution_engine.cc +++ b/src/ge/hybrid/executor/worker/execution_engine.cc @@ -15,7 +15,6 @@ */ #include "hybrid/executor/worker/execution_engine.h" -#include #include "graph/runtime_inference_context.h" #include "graph/utils/tensor_utils.h" #include "graph/utils/tensor_adapter.h" @@ -23,9 +22,38 @@ namespace ge { namespace hybrid { +namespace { +constexpr int64_t kMaxPadding = 63; + +Status LogInputs(const NodeItem &node_item, const TaskContext &task_context) { + for (auto i = 0; i < task_context.NumInputs(); ++i) { + const auto &input_tensor = task_context.GetInput(i); + GE_CHECK_NOTNULL(input_tensor); + const auto &tensor_desc = node_item.op_desc->MutableInputDesc(i); + GE_CHECK_NOTNULL(tensor_desc); + GELOGD("[%s] Print task args. input[%d] = %s, shape = [%s]", node_item.NodeName().c_str(), i, + input_tensor->DebugString().c_str(), tensor_desc->MutableShape().ToString().c_str()); + } + + return SUCCESS; +} + +Status LogOutputs(const NodeItem &node_item, const TaskContext &task_context) { + for (auto i = 0; i < task_context.NumOutputs(); ++i) { + const auto &output_tensor = task_context.GetOutput(i); + GE_CHECK_NOTNULL(output_tensor); + const auto &tensor_desc = node_item.op_desc->MutableOutputDesc(i); + GE_CHECK_NOTNULL(tensor_desc); + GELOGD("[%s] Print task args. output[%d] = %s, shape = [%s]", node_item.NodeName().c_str(), i, + output_tensor->DebugString().c_str(), tensor_desc->MutableShape().ToString().c_str()); + } + + return SUCCESS; +} +} // namespace class NodeDoneCallback { public: - NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr &task_context); + NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr task_context); ~NodeDoneCallback() = default; Status OnNodeDone(); @@ -35,8 +63,8 @@ class NodeDoneCallback { std::shared_ptr context_; }; -NodeDoneCallback::NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr &task_context) - : graph_context_(graph_context), context_(task_context) {} +NodeDoneCallback::NodeDoneCallback(GraphExecutionContext *graph_context, std::shared_ptr task_context) + : graph_context_(graph_context), context_(std::move(task_context)) {} Status NodeDoneCallback::PrepareConstInputs(const NodeItem &node_item) { for (auto output_idx : node_item.to_const_output_id_list) { @@ -46,17 +74,28 @@ Status NodeDoneCallback::PrepareConstInputs(const NodeItem &node_item) { auto output_tensor = context_->GetOutput(output_idx); GE_CHECK_NOTNULL(output_tensor); - vector host_buffer(output_tensor->GetSize()); - GELOGD("[%s] To cache output[%d] to host, size = %zu", node_item.NodeName().c_str(), output_idx, - output_tensor->GetSize()); - GE_CHK_RT_RET(rtMemcpy(host_buffer.data(), host_buffer.size(), output_tensor->GetData(), output_tensor->GetSize(), - RT_MEMCPY_HOST_TO_DEVICE)); Tensor tensor; - tensor.SetData(host_buffer); auto ge_tensor_desc = node_item.op_desc->MutableOutputDesc(output_idx); GE_CHECK_NOTNULL(ge_tensor_desc); tensor.SetTensorDesc(TensorAdapter::GeTensorDesc2TensorDesc(*ge_tensor_desc)); + int64_t tensor_size; + GE_CHK_GRAPH_STATUS_RET(TensorUtils::GetTensorSizeInBytes(*ge_tensor_desc, tensor_size), + "Failed to invoke GetTensorSizeInBytes"); + + if (output_tensor->GetSize() < static_cast(tensor_size)) { + GELOGE(INTERNAL_ERROR, "[%s] Tensor size is not enough. output index = %d, required size = %zu, tensor = %s", + node_item.NodeName().c_str(), output_idx, tensor_size, output_tensor->DebugString().c_str()); + return INTERNAL_ERROR; + } + + vector host_buffer(tensor_size); + GELOGD("[%s] To cache output[%d] to host, size = %zu", node_item.NodeName().c_str(), output_idx, + output_tensor->GetSize()); + GE_CHK_RT_RET( + rtMemcpy(host_buffer.data(), tensor_size, output_tensor->GetData(), tensor_size, RT_MEMCPY_DEVICE_TO_HOST)); + tensor.SetData(host_buffer); + string session_id = std::to_string(context_->GetSessionId()); RuntimeInferenceContext *runtime_infer_ctx = nullptr; GE_CHK_GRAPH_STATUS_RET(RuntimeInferenceContext::GetContext(session_id, &runtime_infer_ctx), @@ -87,115 +126,118 @@ Status NodeDoneCallback::OnNodeDone() { GE_CHK_STATUS_RET_NOLOG(PrepareConstInputs(node_item)); // PropagateOutputs for type == DEPEND_COMPUTE if (node_item.shape_inference_type == DEPEND_COMPUTE) { + if (graph_context_->trace_enabled) { + (void)LogOutputs(node_item, *context_); + } + GE_CHK_STATUS_RET(context_->PropagateOutputs(), "[%s] Failed to propagate outputs failed", node_item.NodeName().c_str()); RECORD_CALLBACK_EVENT(graph_context_, context_->GetNodeName(), "[PropagateOutputs] End"); } - // release + // release condition variable if (node_item.has_observer) { GELOGI("[%s] Notify observer. node_id = %d", node_item.NodeName().c_str(), node_item.node_id); - graph_context_->cv_manager.NodeDone(node_item.node); + context_->NodeDone(); } RECORD_CALLBACK_EVENT(graph_context_, context_->GetNodeName(), "[Callback] End"); return SUCCESS; } -ExecutionEngine::ExecutionEngine(GraphExecutionContext *context, CallbackManager *callback_manager) - : context_(context), callback_manager_(callback_manager) {} - -Status ExecutionEngine::Start() { - GE_CHK_STATUS_RET_NOLOG(ExecutionProcess()); - return SUCCESS; -} - -Status ExecutionEngine::ExecutionProcess() { - GELOGI("ExecutorEngine worker started"); - auto &ready_queue = context_->execution_queue; - while (true) { - NodeStatePtr node_state = nullptr; - if (!ready_queue.Pop(node_state)) { - GELOGE(FAILED, "Pop task failed"); - return FAILED; - } - - // EOF - if (node_state == nullptr) { - break; +Status ExecutionEngine::ExecuteAsync(NodeState &node_state, const std::shared_ptr &task_context, + GraphExecutionContext &execution_context) { + GELOGI("[%s] Node is ready for execution", task_context->GetNodeName()); + RECORD_EXECUTION_EVENT(&execution_context, task_context->GetNodeName(), "Start"); + auto cb = std::shared_ptr(new (std::nothrow) NodeDoneCallback(&execution_context, task_context)); + GE_CHECK_NOTNULL(cb); + auto callback = [&, cb]() { + auto ret = cb->OnNodeDone(); + if (ret != SUCCESS) { + task_context->OnError(ret); } + }; - RECORD_EXECUTION_EVENT(context_, node_state->GetName().c_str(), "Start"); - GELOGI("[%s] Node is ready for execution", node_state->GetName().c_str()); - auto *node_item = node_state->node_item; - auto task_context = TaskContext::Create(*node_item, context_); - GE_CHECK_NOTNULL(task_context); - auto shared_task_context = shared_ptr(task_context.release()); - - auto cb = std::shared_ptr(new (std::nothrow) NodeDoneCallback(context_, shared_task_context)); - GE_CHECK_NOTNULL(cb); - auto callback = [&, cb]() { - auto ret = cb->OnNodeDone(); - if (ret != SUCCESS) { - context_->OnError(ret); - } - }; - - GE_CHK_STATUS_RET_NOLOG(ExecuteAsync(*node_state, *shared_task_context, callback)); - GE_CHK_STATUS_RET_NOLOG(PropagateOutputs(*node_item, *shared_task_context)); - } - - GELOGI("ExecutorEngine worker ended."); + GE_CHK_STATUS_RET_NOLOG(DoExecuteAsync(node_state, *task_context, execution_context, callback)); + GE_CHK_STATUS_RET_NOLOG(PropagateOutputs(*node_state.GetNodeItem(), *task_context, execution_context)); return SUCCESS; } -Status ExecutionEngine::ExecuteAsync(NodeState &node_state, TaskContext &task_context, - const std::function &callback) { - const auto &task = node_state.kernel_task; +Status ExecutionEngine::DoExecuteAsync(NodeState &node_state, TaskContext &task_context, GraphExecutionContext &context, + const std::function &callback) { + const auto &task = node_state.GetKernelTask(); if (task == nullptr) { GELOGE(INTERNAL_ERROR, "[%s] NodeTask is null.", node_state.GetName().c_str()); return INTERNAL_ERROR; } - RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PrepareTask] Start"); - auto executor = node_state.node_item->node_executor; + // Wait for dependent nodes(DEPEND_COMPUTE), so that the input tensors are valid. + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[AwaitDependents] Start"); + GE_CHK_STATUS_RET(node_state.AwaitInputTensors(context), "[%s] Failed to wait for dependent nodes.", + node_state.GetName().c_str()); + + const auto &node_item = *node_state.GetNodeItem(); + auto executor = node_item.node_executor; + GE_CHECK_NOTNULL(executor); + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PrepareTask] Start"); GE_CHK_STATUS_RET(executor->PrepareTask(*task, task_context), "[%s] Failed to prepare task", node_state.GetName().c_str()); - RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PrepareTask] End"); + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PrepareTask] End"); GELOGD("[%s] Done task preparation successfully.", node_state.GetName().c_str()); - if (context_->trace_enabled) { - for (auto i = 0; i < task_context.NumInputs(); ++i) { - const auto &input_tensor = task_context.GetInput(i); - GE_CHECK_NOTNULL(input_tensor); - GELOGD("[%s] Tensor of input[%d] = %s", node_state.GetName().c_str(), i, input_tensor->DebugString().c_str()); - } - - for (auto i = 0; i < task_context.NumOutputs(); ++i) { - const auto &output_tensor = task_context.GetOutput(i); - GE_CHECK_NOTNULL(output_tensor); - GELOGD("[%s] Tensor of output[%d] = %s", node_state.GetName().c_str(), i, output_tensor->DebugString().c_str()); + if (context.trace_enabled) { + LogInputs(node_item, task_context); + if (node_item.shape_inference_type != DEPEND_COMPUTE) { + LogOutputs(node_item, task_context); } } - RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[ExecuteTask] Start"); + GE_CHK_STATUS_RET(ValidateInputTensors(node_state, task_context), "Failed to validate input tensors."); + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[ValidateInputTensors] End"); + GE_CHK_STATUS_RET(executor->ExecuteTask(*task, task_context, callback), "[%s] Failed to execute task", node_state.GetName().c_str()); - RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[ExecuteTask] End"); + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[ExecuteTask] End"); GELOGD("[%s] Done task launch successfully.", node_state.GetName().c_str()); return SUCCESS; } -Status ExecutionEngine::PropagateOutputs(const NodeItem &node_item, TaskContext &task_context) { +Status ExecutionEngine::ValidateInputTensors(const NodeState &node_state, const TaskContext &task_context) { + for (auto i = 0; i < task_context.NumInputs(); ++i) { + const auto &input_tensor = task_context.GetInput(i); + GE_CHECK_NOTNULL(input_tensor); + const auto &tensor_desc = node_state.GetOpDesc()->MutableInputDesc(i); + GE_CHECK_NOTNULL(tensor_desc); + int64_t expected_size; + GE_CHK_GRAPH_STATUS_RET(TensorUtils::GetTensorMemorySizeInBytes(*tensor_desc, expected_size)); + GELOGD("[%s] Input[%d] expects [%ld] bytes.", task_context.GetNodeName(), i, expected_size); + auto size_diff = expected_size - static_cast(input_tensor->GetSize()); + if (size_diff > 0) { + if (size_diff <= kMaxPadding) { + GELOGW("[%s] Input[%d]: tensor size mismatches. expected: %ld, but given %zu", task_context.GetNodeName(), i, + expected_size, input_tensor->GetSize()); + } else { + GELOGE(INTERNAL_ERROR, "[%s] Input[%d]: tensor size mismatches. expected: %ld, but given %zu", + task_context.GetNodeName(), i, expected_size, input_tensor->GetSize()); + return INTERNAL_ERROR; + } + } + } + + return SUCCESS; +} + +Status ExecutionEngine::PropagateOutputs(const NodeItem &node_item, TaskContext &task_context, + GraphExecutionContext &context) { if (node_item.shape_inference_type != DEPEND_COMPUTE) { GE_CHK_STATUS_RET(task_context.PropagateOutputs(), "[%s] Failed to propagate outputs.", node_item.NodeName().c_str()); - RECORD_EXECUTION_EVENT(context_, task_context.GetNodeName(), "[PropagateOutputs] End"); + RECORD_EXECUTION_EVENT(&context, task_context.GetNodeName(), "[PropagateOutputs] End"); + GELOGD("[%s] Done propagating outputs successfully.", node_item.NodeName().c_str()); } - GELOGD("[%s] Done propagating outputs successfully.", node_item.NodeName().c_str()); return SUCCESS; } } // namespace hybrid diff --git a/src/ge/hybrid/executor/worker/execution_engine.h b/src/ge/hybrid/executor/worker/execution_engine.h index f5f317af..56f1557d 100644 --- a/src/ge/hybrid/executor/worker/execution_engine.h +++ b/src/ge/hybrid/executor/worker/execution_engine.h @@ -17,30 +17,21 @@ #ifndef GE_HYBRID_EXECUTOR_EXECUTOR_EXECUTION_ENGINE_H_ #define GE_HYBRID_EXECUTOR_EXECUTOR_EXECUTION_ENGINE_H_ -#include "common/thread_pool.h" -#include "hybrid/common/npu_memory_allocator.h" #include "hybrid/executor/hybrid_execution_context.h" -#include "hybrid/executor/rt_callback_manager.h" #include "hybrid/node_executor/task_context.h" namespace ge { namespace hybrid { class ExecutionEngine { public: - explicit ExecutionEngine(GraphExecutionContext *context, CallbackManager *callback_manager); - ~ExecutionEngine() = default; - - Status Start(); + static Status ExecuteAsync(NodeState &node_state, const std::shared_ptr &task_context, + GraphExecutionContext &execution_context); private: - Status PropagateOutputs(const NodeItem &node_item, TaskContext &task_context); - - Status ExecutionProcess(); - - Status ExecuteAsync(NodeState &node_state, TaskContext &task_context, const std::function &callback); - - GraphExecutionContext *context_; - CallbackManager *callback_manager_; + static Status ValidateInputTensors(const NodeState &node_state, const TaskContext &task_context); + static Status PropagateOutputs(const NodeItem &node_item, TaskContext &task_context, GraphExecutionContext &context); + static Status DoExecuteAsync(NodeState &node_state, TaskContext &task_context, GraphExecutionContext &context, + const std::function &callback); }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/executor/worker/shape_inference_engine.cc b/src/ge/hybrid/executor/worker/shape_inference_engine.cc index 90082fff..650bcc54 100644 --- a/src/ge/hybrid/executor/worker/shape_inference_engine.cc +++ b/src/ge/hybrid/executor/worker/shape_inference_engine.cc @@ -15,117 +15,30 @@ */ #include "hybrid/executor/worker/shape_inference_engine.h" - #include "graph/shape_refiner.h" -#include "graph/runtime_inference_context.h" #include "graph/utils/node_utils.h" #include "hybrid/node_executor/node_executor.h" namespace ge { namespace hybrid { +ShapeInferenceEngine::ShapeInferenceEngine(GraphExecutionContext *execution_context, SubgraphContext *subgraph_context) + : execution_context_(execution_context), subgraph_context_(subgraph_context) {} -ShapeInferenceEngine::ShapeInferenceEngine(GraphExecutionContext *context) : context_(context) {} - -Status ShapeInferenceEngine::Start(ThreadPool &pool) { - GELOGI("RuntimeShapeInferenceEngine start."); - pool.commit([&]() { - auto ret = this->InferShapeProcess(); - InferenceDone(ret); - }); - - return SUCCESS; -} - -Status ShapeInferenceEngine::InferShapeProcess() { - GELOGI("RuntimeShapeInferenceEngine worker start."); - const auto &root_nodes = context_->model->RootNodes(); - auto &complete_queue = context_->compile_queue; - std::queue ready_nodes; - for (auto &node_item : root_nodes) { - auto infer_state = GetOrCreateEntry(*node_item); - GE_CHECK_NOTNULL(infer_state); - ready_nodes.emplace(infer_state); - } - - while (!ready_nodes.empty()) { - InferenceState *infer_state = ready_nodes.front(); - ready_nodes.pop(); - auto node_item = infer_state->node_item; - // even for non-dynamic shape node, it is still necessary to wait for pending shapes if got any. - // which indicates that the parent node is of type 4, in which case the inputs will be valid only - // when computing is done. - GE_CHK_STATUS_RET(infer_state->AwaitShapeFutures(context_), "Await shape failed."); - GELOGI("[%s] Node is ready for shape inference.", node_item.NodeName().c_str()); - if (node_item.is_dynamic) { - // may block - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "Start"); - GELOGI("[%s] Start to invoke InferShape", node_item.NodeName().c_str()); - auto ret = InferShape(*infer_state); - if (ret != SUCCESS) { - return ret; - } - - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[CalcOpRunningParam] Start"); - GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().CalcOpRunningParam(*node_item.node), - "[%s] Failed to invoke CalcOpRunningParam.", node_item.NodeName().c_str()); - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[CalcOpRunningParam] End"); - } else { - GELOGD("[%s] Skip static shape node", node_item.NodeName().c_str()); - } - - if (node_item.node_type != NETOUTPUT) { - GELOGI("[%s] Push to compile queue", node_item.NodeName().c_str()); - // may block if full - auto node_state = context_->GetOrCreateNodeState(node_item.node); - complete_queue.Push(node_state); - } - - // Propagate - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[PropagateOutputShapes] Start"); - PropagateOutputShapes(*infer_state, ready_nodes); - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[PropagateOutputShapes] End"); - } - - return SUCCESS; -} - -void ShapeInferenceEngine::InferenceDone(Status status) { - if (status != SUCCESS) { - GELOGE(status, "Error occurred while shape inference"); - context_->OnError(status); - } else { - context_->compile_queue.Push(nullptr); - } - inference_states_.clear(); - GELOGI("RuntimeShapeInferenceEngine worker END"); -} - -Status ShapeInferenceEngine::InferShape(InferenceState &entry) { - // input shapes are ready, wait for dependent data if has any - const auto &node_item = entry.node_item; - if (!node_item.dependent_node_list.empty()) { - for (auto &src_node : node_item.dependent_node_list) { - auto *src_node_item = context_->model->GetNodeItem(src_node); - GELOGI("[%s] Start to wait for data dependent node: %s", node_item.NodeName().c_str(), - src_node_item->NodeName().c_str()); - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] Start", - src_node->GetName().c_str()); - if (!context_->cv_manager.Await(src_node)) { - GELOGE(INTERNAL_ERROR, "[%s] Await node failed.", src_node_item->NodeName().c_str()); - return INTERNAL_ERROR; - } +Status ShapeInferenceEngine::InferShape(NodeState &node_state) { + // Wait for all input shape become valid + GE_CHK_STATUS_RET_NOLOG(node_state.GetShapeInferenceState().AwaitShapesReady(*execution_context_)); - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] End", - src_node->GetName().c_str()); - GELOGI("[%s] Done waiting node.", src_node_item->NodeName().c_str()); - } + auto &node_item = *node_state.GetNodeItem(); + if (node_item.is_output_shape_static) { + return SUCCESS; } - + // Skip shape inference for node of type DEPEND_COMPUTE if (node_item.shape_inference_type == DEPEND_COMPUTE) { - GELOGD("[%s] Skip node with unknown shape type DEPEND_COMPUTE", node_item.NodeName().c_str()); + GELOGD("[%s] Skipping node with unknown shape type DEPEND_COMPUTE", node_item.NodeName().c_str()); return SUCCESS; } + // Clear shape range in case shape inference func forgot to do it if (node_item.shape_inference_type == DEPEND_SHAPE_RANGE) { // in case InferFunc forgot to reset output shape for (auto &output_desc : node_item.op_desc->GetAllOutputsDescPtr()) { @@ -133,13 +46,18 @@ Status ShapeInferenceEngine::InferShape(InferenceState &entry) { } } - // do shape inference - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[InferShape] Start"); - GELOGD("[%s] Start to invoke InferShapeAndType", node_item.NodeName().c_str()); - GE_CHK_STATUS_RET(ShapeRefiner::InferShapeAndType(node_item.node), "Invoke InferShapeAndType failed."); - RECORD_SHAPE_INFERENCE_EVENT(context_, node_item.NodeName().c_str(), "[InferShape] End"); + // Wait for "const input nodes" if node's shape inference function requires any. + GE_CHK_STATUS_RET_NOLOG(AwaitDependentNodes(node_state)); - // Check shape + // Do shape inference + GELOGD("[%s] Start to invoke InferShapeAndType", node_item.NodeName().c_str()); + { + std::lock_guard lk(mu_); + RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[InferShapeAndType] Start"); + GE_CHK_STATUS_RET(ShapeRefiner::InferShapeAndType(node_item.node), "Invoke InferShapeAndType failed."); + RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[InferShapeAndType] End"); + } + // Check again to make sure shape is valid after shape inference if (node_item.shape_inference_type != DEPEND_SHAPE_RANGE) { bool is_unknown_shape = false; GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node_item.node, is_unknown_shape), @@ -149,12 +67,37 @@ Status ShapeInferenceEngine::InferShape(InferenceState &entry) { node_item.NodeName().c_str()); } + GELOGD("[%s] [HybridTrace] After shape inference. Node = %s", node_item.NodeName().c_str(), + node_item.DebugString().c_str()); + GELOGD("[%s] InferShapeAndType finished successfully.", node_item.NodeName().c_str()); return SUCCESS; } -void ShapeInferenceEngine::PropagateOutputShapes(InferenceState &entry, std::queue &queue) { - auto &node_item = entry.node_item; +Status ShapeInferenceEngine::AwaitDependentNodes(NodeState &node_state) { + auto &node_item = *node_state.GetNodeItem(); + for (auto &src_node : node_item.dependents_for_shape_inference) { + GELOGI("[%s] Start to wait for data dependent node: %s", node_item.NodeName().c_str(), src_node->GetName().c_str()); + RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] Start", + src_node->GetName().c_str()); + if (!subgraph_context_->Await(src_node)) { + GELOGE(INTERNAL_ERROR, "[%s] Await node failed.", src_node->GetName().c_str()); + return INTERNAL_ERROR; + } + + RECORD_SHAPE_INFERENCE_EVENT(execution_context_, node_item.NodeName().c_str(), "[AwaitNodeDone] [%s] End", + src_node->GetName().c_str()); + GELOGI("[%s] Done waiting node.", src_node->GetName().c_str()); + } + + return SUCCESS; +} + +Status ShapeInferenceEngine::PropagateOutputShapes(const NodeItem &node_item) { + if (node_item.is_output_shape_static) { + return SUCCESS; + } + // output shape will not be valid until compute is done. bool shape_is_future = node_item.shape_inference_type == DEPEND_SHAPE_RANGE || node_item.shape_inference_type == DEPEND_COMPUTE; @@ -171,88 +114,25 @@ void ShapeInferenceEngine::PropagateOutputShapes(InferenceState &entry, std::que // propagate output to all sub-inputs for (auto &dst_input_index_and_node : output_nodes) { auto &dst_node_item = dst_input_index_and_node.second; - auto inference_state = GetOrCreateEntry(*dst_node_item); + auto dst_node_state = subgraph_context_->GetOrCreateNodeState(dst_node_item); + GE_CHECK_NOTNULL(dst_node_state); + GELOGI("[%s] Update dst node [%s], input index = %d", node_item.NodeName().c_str(), dst_node_item->NodeName().c_str(), dst_input_index_and_node.first); - // in case type 3/4, shape will be valid after computing is done + // in case type 3 and 4, shape will be valid after computing is done if (shape_is_future) { - ShapeFuture future(node_item.node, i, &context_->cv_manager); - inference_state->UpdateInputShapeFuture(dst_input_index_and_node.first, std::move(future)); + ShapeFuture future(node_item.node, i, subgraph_context_); + dst_node_state->GetShapeInferenceState().UpdateInputShapeFuture(dst_input_index_and_node.first, + std::move(future)); } else { - inference_state->UpdateInputShape(dst_input_index_and_node.first, ori_shape, shape); - } - - if (inference_state->IsInputShapesReady()) { - GELOGI("[%s] Node input shape is ready, add to queue.", inference_state->node_item.NodeName().c_str()); - queue.emplace(inference_state); + dst_node_state->GetShapeInferenceState().UpdateInputShape(dst_input_index_and_node.first, ori_shape, shape); } } } GELOGD("[%s] Propagating output shapes finished successfully.", node_item.NodeName().c_str()); -} - -ShapeInferenceEngine::InferenceState *ShapeInferenceEngine::GetOrCreateEntry(const NodeItem &node_item) { - auto &node_state = inference_states_[node_item.node_id]; - if (node_state == nullptr) { - node_state.reset(new (std::nothrow) InferenceState(node_item)); - } - - return node_state.get(); -} - -ShapeInferenceEngine::InferenceState::InferenceState(const NodeItem &node_item) : node_item(node_item) { - this->num_pending_shapes = node_item.num_inputs; -} - -void ShapeInferenceEngine::InferenceState::UpdateInputShape(uint32_t idx, const GeShape &ori_shape, - const GeShape &shape) { - if (node_item.const_input_shapes.count(idx) != 0) { - GELOGD("[%s] Trying to update constant shape, idx = %u. old shape = [%s], new shape = [%s]", - node_item.NodeName().c_str(), idx, node_item.op_desc->MutableInputDesc(idx)->GetShape().ToString().c_str(), - shape.ToString().c_str()); - } - - GELOGD("[%s] Update input shape [%u] with Shape: [%s] and OriginalShape: [%s]", node_item.NodeName().c_str(), idx, - shape.ToString().c_str(), ori_shape.ToString().c_str()); - num_pending_shapes -= 1; - node_item.op_desc->MutableInputDesc(idx)->SetShape(shape); - node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); -} - -void ShapeInferenceEngine::InferenceState::UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future) { - if (node_item.const_input_shapes.count(idx) != 0) { - GELOGE(INTERNAL_ERROR, "[%s] Trying to update constant shape, idx = %u", node_item.NodeName().c_str(), idx); - return; - } - - GELOGD("[%s] Update input shape [%u] with ShapeFuture.", node_item.NodeName().c_str(), idx); - num_pending_shapes -= 1; - shape_futures.emplace_back(idx, std::move(future)); -} - -Status ShapeInferenceEngine::InferenceState::AwaitShapeFutures(GraphExecutionContext *context) { - for (auto &p : shape_futures) { - auto idx = p.first; - auto &future = p.second; - GeShape shape; - GeShape ori_shape; - RECORD_SHAPE_INFERENCE_EVENT(context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] Start", idx); - GE_CHK_STATUS_RET(future.Get(ori_shape, shape), "[%s] Get shape failed. index = %u", node_item.NodeName().c_str(), - idx); - RECORD_SHAPE_INFERENCE_EVENT(context, node_item.NodeName().c_str(), "[AwaitShape] [idx = %u] End", idx); - - GELOGD("[%s] Update input shape [%u] with shape: [%s] and ori_shape: [%s]", node_item.NodeName().c_str(), idx, - shape.ToString().c_str(), ori_shape.ToString().c_str()); - node_item.op_desc->MutableInputDesc(idx)->SetShape(std::move(shape)); - node_item.op_desc->MutableInputDesc(idx)->SetOriginShape(ori_shape); - } - return SUCCESS; } - -ShapeInferenceEngine::ShapeFuture::ShapeFuture(NodePtr src_node, uint32_t src_index, NodeDoneManager *node_done_manager) - : src_node_(std::move(src_node)), src_index_(src_index), node_done_manager_(node_done_manager) {} } // namespace hybrid -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/hybrid/executor/worker/shape_inference_engine.h b/src/ge/hybrid/executor/worker/shape_inference_engine.h index b1e1c879..65878818 100644 --- a/src/ge/hybrid/executor/worker/shape_inference_engine.h +++ b/src/ge/hybrid/executor/worker/shape_inference_engine.h @@ -17,75 +17,27 @@ #ifndef GE_HYBRID_EXECUTOR_INFERSHAPE_SHAPE_INFERENCE_ENGINE_H_ #define GE_HYBRID_EXECUTOR_INFERSHAPE_SHAPE_INFERENCE_ENGINE_H_ -#include -#include -#include -#include "common/thread_pool.h" #include "hybrid/executor/hybrid_execution_context.h" +#include "hybrid/executor/subgraph_context.h" +#include namespace ge { namespace hybrid { class ShapeInferenceEngine { public: - explicit ShapeInferenceEngine(GraphExecutionContext *context); - + ShapeInferenceEngine(GraphExecutionContext *execution_context, SubgraphContext *subgraph_context); ~ShapeInferenceEngine() = default; - Status Start(ThreadPool &pool); - - private: - class ShapeFuture { - public: - ShapeFuture(NodePtr src_node, uint32_t src_index, NodeDoneManager *node_done_manager); - ~ShapeFuture() = default; - Status Get(GeShape &ori_shape, GeShape &shape) { - GELOGI("Start to wait node: %s for getting shape", src_node_->GetName().c_str()); - if (!node_done_manager_->Await(src_node_)) { - GELOGE(INTERNAL_ERROR, "cancelled"); - return INTERNAL_ERROR; - } - - shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->MutableShape(); - ori_shape = src_node_->GetOpDesc()->MutableOutputDesc(src_index_)->GetOriginShape(); - GELOGI("Get shape from %s:%u. shape = [%s]", src_node_->GetName().c_str(), src_index_, shape.ToString().c_str()); - return SUCCESS; - } - - private: - NodePtr src_node_; - uint32_t src_index_; - NodeDoneManager *node_done_manager_; - }; - - struct InferenceState { - explicit InferenceState(const NodeItem &node_item); - inline bool IsInputShapesReady() const { return num_pending_shapes == 0; } - - void UpdateInputShape(uint32_t idx, const GeShape &ori_shape, const GeShape &shape); - - Status AwaitShapeFutures(GraphExecutionContext *context); + Status InferShape(NodeState &node_state); - void UpdateInputShapeFuture(uint32_t idx, ShapeFuture &&future); + Status PropagateOutputShapes(const NodeItem &node_item); - const NodeItem &node_item; - - private: - std::vector> shape_futures; - int num_pending_shapes = 0; - }; - - InferenceState *GetOrCreateEntry(const NodeItem &node_item); - - Status InferShapeProcess(); - - void InferenceDone(Status status); - - Status InferShape(InferenceState &entry); - - void PropagateOutputShapes(InferenceState &entry, std::queue &queue); + private: + Status AwaitDependentNodes(NodeState &node_state); - GraphExecutionContext *context_; - std::unordered_map> inference_states_; + GraphExecutionContext *execution_context_; + SubgraphContext *subgraph_context_; + std::mutex mu_; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/executor/worker/task_compile_engine.cc b/src/ge/hybrid/executor/worker/task_compile_engine.cc index f6434ffa..57b19f5f 100644 --- a/src/ge/hybrid/executor/worker/task_compile_engine.cc +++ b/src/ge/hybrid/executor/worker/task_compile_engine.cc @@ -16,172 +16,22 @@ #include "hybrid/executor/worker/task_compile_engine.h" #include "init/gelib.h" -#include "framework/common/debug/log.h" #include "hybrid/node_executor/node_executor.h" namespace ge { namespace hybrid { -namespace { -uint32_t kDefaultWorkerCnt = 4; -uint32_t kDefaultDeviceId = 0; -} // namespace -TaskCompileEngine::TaskCompileEngine(GraphExecutionContext *context) : context_(context), pool_(kDefaultWorkerCnt) {} - -TaskCompileEngine::~TaskCompileEngine() { - if (rt_context_ != nullptr) { - GELOGD("To destroy compile context: %p.", rt_context_); - GE_CHK_RT(rtCtxDestroy(rt_context_)); - } -} - -Status TaskCompileEngine::Init() { - GELOGD("Start to init CompileEngine"); - rtContext_t current_ctx = nullptr; - GE_CHK_RT(rtCtxGetCurrent(¤t_ctx)); - GE_CHK_RT_RET(rtCtxCreate(&rt_context_, RT_CTX_GEN_MODE, kDefaultDeviceId)); - GELOGD("Context created for compiling. ctx = %p", rt_context_); - GE_CHK_RT_RET(rtCtxSetCurrent(current_ctx)); - return SUCCESS; -} - -void TaskCompileEngine::Reset() { - complete_queue_.Push(nullptr); // ensure iteration can stop - unique_ptr entry; - while (true) { - complete_queue_.Pop(entry); - if (entry == nullptr) { - break; - } - - if (entry->future != nullptr) { - entry->future->wait(); - } - } - - complete_queue_.Clear(); -} - -Status TaskCompileEngine::Start(ThreadPool &pool) { - pool.commit([&]() { (void)this->CompileProcess(); }); - - worker_future_ = pool_.commit([&]() -> Status { return this->DistributeCompiledTasks(); }); - - if (!worker_future_.valid()) { - GELOGE(INTERNAL_ERROR, "Failed to start worker thread"); - return INTERNAL_ERROR; - } - - return SUCCESS; -} - -Status TaskCompileEngine::CompileProcess() { - auto &compile_queue = context_->compile_queue; - while (true) { - NodeStatePtr node_state; - // Stop() will not be invoked, Pop won't failed - (void)compile_queue.Pop(node_state); - - // EOF - if (node_state == nullptr) { - GELOGD("Got EOF"); - complete_queue_.Push(unique_ptr()); - break; - } - - auto entry = unique_ptr(new (std::nothrow) ResultQueueEntry()); - GE_CHECK_NOTNULL(entry); - entry->node_state = node_state; - - auto node_item = *node_state->node_item; - if (node_item.kernel_task != nullptr) { - GELOGD("use precompiled task. node name = %s", node_item.NodeName().c_str()); - node_state->kernel_task = node_item.kernel_task; - complete_queue_.Push(std::move(entry)); - continue; - } - - auto ret = CompileAsync(*node_state->node_item, *entry); - if (ret == SUCCESS) { - complete_queue_.Push(std::move(entry)); - continue; - } - - // On Error - worker_future_.wait(); - Reset(); - return CompileDone(ret); - } - - Status ret = worker_future_.get(); - Reset(); - return CompileDone(ret); -} - -Status TaskCompileEngine::CompileDone(Status status) { - if (status != SUCCESS) { - GELOGE(status, "Error occurred while compiling node."); - context_->OnError(status); - } else { - context_->execution_queue.Push(nullptr); - } - GELOGI("CompileEngine worker END. ret = %u", status); - return status; -} - -Status TaskCompileEngine::DoCompile(const NodeItem &node_item, NodeState &node_state) { - RECORD_COMPILE_EVENT(context_, node_state.GetName().c_str(), "Start"); - GE_CHK_RT_RET(rtCtxSetCurrent(rt_context_)); - auto ret = node_item.node_executor->CompileTask(*context_->model, node_item.node, node_state.kernel_task); - RECORD_COMPILE_EVENT(context_, node_state.GetName().c_str(), "End"); +Status TaskCompileEngine::Compile(NodeState &node_state, GraphExecutionContext *context) { + const auto &node_item = *node_state.GetNodeItem(); + RECORD_COMPILE_EVENT(context, node_item.NodeName().c_str(), "Start"); + GE_CHK_RT_RET(rtCtxSetCurrent(context->rt_gen_context)); + + shared_ptr kernel_task; + auto ret = node_item.node_executor->CompileTask(*context->model, node_item.node, kernel_task); + RECORD_COMPILE_EVENT(context, node_state.GetName().c_str(), "End"); GE_CHK_STATUS_RET(ret, "Failed to create task for node: %s", node_item.NodeName().c_str()); + node_state.SetKernelTask(kernel_task); GELOGI("Compiling node %s successfully", node_state.GetName().c_str()); return SUCCESS; } - -Status TaskCompileEngine::CompileAsync(const NodeItem &node_item, ResultQueueEntry &entry) { - auto node_state = entry.node_state; - auto f = pool_.commit([this, node_item, node_state]() -> Status { return DoCompile(node_item, *node_state); }); - - if (!f.valid()) { - GELOGE(INTERNAL_ERROR, "Failed to commit compile task"); - return INTERNAL_ERROR; - } - - entry.future = unique_ptr>(new (std::nothrow) std::future(std::move(f))); - GE_CHECK_NOTNULL(entry.future); - return SUCCESS; -} - -Status TaskCompileEngine::DistributeCompiledTasks() { - GELOGD("DistributeCompiledTasks start."); - auto &execute_queue = context_->execution_queue; - unique_ptr entry; - bool ret = SUCCESS; - while (true) { - if (!complete_queue_.Pop(entry)) { - GELOGE(INTERNAL_ERROR, "Failed to pop item from queue"); - ret = INTERNAL_ERROR; - break; - } - - // EOF - if (entry == nullptr) { - break; - } - - // if has compile future - if (entry->future != nullptr) { - ret = entry->future->get(); - if (ret != SUCCESS) { - break; - } - } - - execute_queue.Push(entry->node_state); - } - - GELOGD("DistributeCompiledTasks out. ret = %u.", ret); - return ret; -} } // namespace hybrid -} // namespace ge +} // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/executor/worker/task_compile_engine.h b/src/ge/hybrid/executor/worker/task_compile_engine.h index 828a1d8c..a677cb2e 100644 --- a/src/ge/hybrid/executor/worker/task_compile_engine.h +++ b/src/ge/hybrid/executor/worker/task_compile_engine.h @@ -17,44 +17,13 @@ #ifndef GE_HYBRID_EXECUTOR_COMPILE_TASK_COMPILE_ENGINE_H_ #define GE_HYBRID_EXECUTOR_COMPILE_TASK_COMPILE_ENGINE_H_ -#include -#include -#include "common/thread_pool.h" #include "hybrid/executor/hybrid_execution_context.h" namespace ge { namespace hybrid { class TaskCompileEngine { public: - explicit TaskCompileEngine(GraphExecutionContext *context); - - ~TaskCompileEngine(); - - Status Init(); - - Status Start(ThreadPool &pool); - - private: - struct ResultQueueEntry { - NodeStatePtr node_state; - std::unique_ptr> future; - }; - - Status CompileProcess(); - - Status CompileDone(Status status); - - private: - Status DoCompile(const NodeItem &node_item, NodeState &node_state); - Status CompileAsync(const NodeItem &node_item, ResultQueueEntry &entry); - Status DistributeCompiledTasks(); - void Reset(); - - rtContext_t rt_context_ = nullptr; - GraphExecutionContext *context_; - BlockingQueue> complete_queue_; - ThreadPool pool_; - std::future worker_future_; + static Status Compile(NodeState &node_state, GraphExecutionContext *context); }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/hybrid_davinci_model.cc b/src/ge/hybrid/hybrid_davinci_model.cc index 58c7d0e3..0454fa72 100644 --- a/src/ge/hybrid/hybrid_davinci_model.cc +++ b/src/ge/hybrid/hybrid_davinci_model.cc @@ -18,6 +18,7 @@ #include "hybrid_davinci_model.h" #include "hybrid/model/hybrid_model.h" #include "hybrid/executor/hybrid_model_async_executor.h" +#include "hybrid/node_executor/node_executor.h" namespace ge { namespace hybrid { @@ -25,14 +26,19 @@ class HybridDavinciModel::Impl { public: explicit Impl(GeRootModelPtr ge_model) : model_(std::move(ge_model)), executor_(&model_) {} - ~Impl() = default; + ~Impl() { NodeExecutorManager::GetInstance().FinalizeExecutors(); } Status Init() { + GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().EnsureInitialized(), "Failed to initialize executors"); GE_CHK_STATUS_RET(model_.Init(), "Failed to init model.") GE_CHK_STATUS_RET(executor_.Init(), "Failed to init model executor.") return SUCCESS; } + Status Execute(const vector &inputs, vector &outputs) { + return executor_.Execute(inputs, outputs); + } + Status ModelRunStart() { return executor_.Start(listener_); } Status ModelRunStop() { return executor_.Stop(); } @@ -76,6 +82,11 @@ Status HybridDavinciModel::Init() { return impl_->Init(); } +Status HybridDavinciModel::Execute(const vector &inputs, vector &outputs) { + GE_CHECK_NOTNULL(impl_); + return impl_->Execute(inputs, outputs); +} + Status HybridDavinciModel::ModelRunStart() { GE_CHECK_NOTNULL(impl_); return impl_->ModelRunStart(); diff --git a/src/ge/hybrid/hybrid_davinci_model.h b/src/ge/hybrid/hybrid_davinci_model.h index 866b756b..c286a222 100644 --- a/src/ge/hybrid/hybrid_davinci_model.h +++ b/src/ge/hybrid/hybrid_davinci_model.h @@ -37,6 +37,8 @@ class HybridDavinciModel { Status Init(); + Status Execute(const vector &inputs, vector &outputs); + Status ModelRunStart(); Status ModelRunStop(); diff --git a/src/ge/hybrid/hybrid_davinci_model_stub.cc b/src/ge/hybrid/hybrid_davinci_model_stub.cc index bca118f8..7bde98a3 100644 --- a/src/ge/hybrid/hybrid_davinci_model_stub.cc +++ b/src/ge/hybrid/hybrid_davinci_model_stub.cc @@ -26,6 +26,8 @@ std::unique_ptr HybridDavinciModel::Create(const GeRootModel Status HybridDavinciModel::Init() { return UNSUPPORTED; } +Status HybridDavinciModel::Execute(const vector &inputs, vector &outputs) { return UNSUPPORTED; } + Status HybridDavinciModel::ModelRunStart() { return UNSUPPORTED; } Status HybridDavinciModel::ModelRunStop() { return UNSUPPORTED; } diff --git a/src/ge/hybrid/model/graph_item.cc b/src/ge/hybrid/model/graph_item.cc new file mode 100644 index 00000000..120865ce --- /dev/null +++ b/src/ge/hybrid/model/graph_item.cc @@ -0,0 +1,63 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "framework/common/util.h" +#include "graph_item.h" + +namespace ge { +namespace hybrid { +namespace { +constexpr int kInvalidIndex = -1; +} // namespace +GraphItem::~GraphItem() { GELOGD("[%s] GraphItem destroyed.", name_.c_str()); } + +const vector &hybrid::GraphItem::GetAllNodes() const { return node_items_; } + +const vector &GraphItem::GetInputNodes() const { return input_nodes_; } + +Status GraphItem::GetOutputDescList(vector &output_desc_list) const { + if (output_node_ == nullptr) { + return SUCCESS; + } + + if (is_dynamic_) { + for (auto &tensor_desc : output_node_->op_desc->GetAllInputsDescPtr()) { + output_desc_list.emplace_back(tensor_desc); + } + } else { + for (auto &tensor_desc : output_node_->op_desc->GetAllOutputsDescPtr()) { + output_desc_list.emplace_back(tensor_desc); + } + } + + return SUCCESS; +} + +bool GraphItem::IsDynamic() const { return is_dynamic_; } + +const vector &GraphItem::GetInputIndexMapping() const { return input_index_mapping_; } + +int GraphItem::GetParentOutputIndex(size_t index) const { + if (index >= output_index_mapping_.size()) { + return kInvalidIndex; + } + + return output_index_mapping_[index]; +} + +const NodeItem *GraphItem::GetOutputNode() const { return output_node_; } +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/model/graph_item.h b/src/ge/hybrid/model/graph_item.h new file mode 100644 index 00000000..cb0fbbed --- /dev/null +++ b/src/ge/hybrid/model/graph_item.h @@ -0,0 +1,64 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ +#define GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ + +#include "external/ge/ge_api_error_codes.h" +#include "hybrid/model/node_item.h" + +namespace ge { +namespace hybrid { +class GraphItem { + public: + GraphItem() = default; + ~GraphItem(); + const vector &GetAllNodes() const; + const vector &GetInputNodes() const; + Status GetOutputDescList(std::vector &output_desc_list) const; + + int TotalInputs() const { return total_inputs_; } + + int TotalOutputs() const { return total_outputs_; } + + const std::string &GetName() const { return name_; } + + void SetName(const string &name) { name_ = name; } + + const NodeItem *GetOutputNode() const; + + bool IsDynamic() const; + int GetParentOutputIndex(size_t index) const; + const vector &GetInputIndexMapping() const; + + private: + friend class HybridModelBuilder; + std::string name_; + std::vector node_items_; + std::vector input_nodes_; + const NodeItem *output_node_ = nullptr; + // + std::vector> output_edges_; + int total_inputs_ = 0; + int total_outputs_ = 0; + + bool is_dynamic_ = true; + std::vector input_index_mapping_; + std::vector output_index_mapping_; +}; +} // namespace hybrid +} // namespace ge +#endif // GE_HYBRID_MODEL_SUBGRAPH_ITEM_H_ diff --git a/src/ge/hybrid/model/hybrid_model.cc b/src/ge/hybrid/model/hybrid_model.cc index e3726aec..0cb81aa3 100644 --- a/src/ge/hybrid/model/hybrid_model.cc +++ b/src/ge/hybrid/model/hybrid_model.cc @@ -29,6 +29,8 @@ namespace ge { namespace hybrid { HybridModel::HybridModel(GeRootModelPtr ge_model) : ge_root_model_(std::move(ge_model)) {} +HybridModel::~HybridModel() { GELOGD("[%s] HybridModel destroyed.", model_name_.c_str()); } + Status HybridModel::Init() { GELOGD("Start to init hybrid model."); GE_CHK_STATUS_RET(HybridModelBuilder(*this).Build(), "Failed to build hybrid model."); @@ -36,22 +38,6 @@ Status HybridModel::Init() { return SUCCESS; } -void HybridModel::Print() const { - for (const auto &node : node_items_) { - GELOGD("%s", node->DebugString().c_str()); - } -} - -TensorValue *HybridModel::GetWeight(const NodeItem *const_node) const { - auto it = weights_.find(const_node->node_id); - if (it == weights_.end() || it->second == nullptr) { - GELOGE(INTERNAL_ERROR, "[%s] Failed to get weight", const_node->NodeName().c_str()); - return nullptr; - } - - return it->second.get(); -} - TensorValue *HybridModel::GetVariable(const string &name) const { auto it = variable_tensors_.find(name); if (it == variable_tensors_.end()) { @@ -83,26 +69,26 @@ const std::vector *HybridModel::GetTaskDefs(const NodePtr &node) } NodeItem *HybridModel::MutableNodeItem(const NodePtr &node) { - auto node_id = node->GetOpDesc()->GetId(); - if (node_id < 0 || static_cast(node_id) > node_items_.size()) { - GELOGE(INTERNAL_ERROR, "index out of range. node_id = %ld, num_nodes = %zu", node_id, node_items_.size()); + auto it = node_items_.find(node); + if (it == node_items_.end()) { return nullptr; } - return node_items_[node_id].get(); + + return it->second.get(); } const NodeItem *HybridModel::GetNodeItem(const NodePtr &node) const { - auto node_id = node->GetOpDesc()->GetId(); - if (node_id < 0 || static_cast(node_id) > node_items_.size()) { - GELOGE(INTERNAL_ERROR, "Index out of range. node_id = %ld, num_nodes = %zu.", node_id, node_items_.size()); + auto it = node_items_.find(node); + if (it == node_items_.end()) { return nullptr; } - return node_items_[node_id].get(); + + return it->second.get(); } GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const { - auto it = known_shape_sub_graphs_.find(node); - if (it == known_shape_sub_graphs_.end()) { + auto it = known_shape_sub_models_.find(node); + if (it == known_shape_sub_models_.end()) { GELOGE(INTERNAL_ERROR, "[%s] Failed to get GeModel for subgraph node.", node->GetName().c_str()); return nullptr; } @@ -110,8 +96,27 @@ GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const { return it->second; } -const vector &HybridModel::GetNetOutputInputOffsets() const { return net_output_input_offsets_; } +const GraphItem *HybridModel::GetRootGraphItem() const { return root_graph_item_.get(); } + +const GraphItem *HybridModel::GetSubgraphItem(const std::string &graph_name) const { + GELOGD("To find subgraph item by name = %s", graph_name.c_str()); + auto it = subgraph_items_.find(graph_name); + if (it == subgraph_items_.end()) { + GELOGD("Subgraph item not found by node = %s", graph_name.c_str()); + return nullptr; + } + + return it->second.get(); +} + +const GraphItem *HybridModel::GetSubgraphItem(const ComputeGraphPtr &subgraph) const { + if (subgraph == nullptr) { + GELOGE(PARAM_INVALID, "subgraph is nullptr"); + return nullptr; + } -void HybridModel::SetDeviceId(uint32_t device_id) { device_id_ = device_id; } + auto subgraph_name = subgraph->GetName(); + return GetSubgraphItem(subgraph_name); +} } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/model/hybrid_model.h b/src/ge/hybrid/model/hybrid_model.h index 007f76c6..f554752e 100644 --- a/src/ge/hybrid/model/hybrid_model.h +++ b/src/ge/hybrid/model/hybrid_model.h @@ -26,39 +26,23 @@ #include "graph/node.h" #include "hybrid/common/tensor_value.h" #include "hybrid/model/node_item.h" +#include "hybrid/model/graph_item.h" #include "model/ge_root_model.h" namespace ge { namespace hybrid { -class HybridModelAsyncExecutor; class HybridModel { public: explicit HybridModel(GeRootModelPtr ge_model); - ~HybridModel() = default; + ~HybridModel(); Status Init(); - const std::vector &RootNodes() const { return root_nodes_; } - const NodeItem *GetNodeItem(const NodePtr &node) const; - size_t NumNodes() const { return node_items_.size(); } - uint64_t GetSessionId() const { return root_runtime_param_.session_id; } - int TotalInputs() const { return total_inputs_; } - - const map &GetInputNodes() const { return input_nodes_; } - - const std::map> &GetInputOffsets() const { return input_offsets_; } - - const vector &GetNetOutputInputOffsets() const; - - const std::vector &GetOutputOffsets() const { return output_offsets_; } - - const std::vector &GetConstNodes() const { return const_nodes_; } - GeModelPtr GetGeModel(const NodePtr &node) const; NodeItem *MutableNodeItem(const NodePtr &node); @@ -67,46 +51,40 @@ class HybridModel { const uint8_t *GetVarMemBase() const { return var_mem_base_; } - void SetDeviceId(uint32_t device_id); + void SetDeviceId(uint32_t device_id) { device_id_ = device_id; } void SetModelId(uint32_t model_id) { model_id_ = model_id; } uint32_t GetModelId() const { return model_id_; } - TensorValue *GetWeight(const NodeItem *const_node) const; - TensorValue *GetVariable(const string &name) const; NodePtr GetVariableNode(const string &name) const; const std::vector *GetTaskDefs(const NodePtr &node) const; - int TotalOutputs() const { return total_outputs_; } + const GraphItem *GetRootGraphItem() const; - GeRootModelPtr GetGeRootModel() const { return ge_root_model_; } - void Print() const; + const GraphItem *GetSubgraphItem(const std::string &graph_name) const; + + const GraphItem *GetSubgraphItem(const ComputeGraphPtr &subgraph) const; private: friend class HybridModelBuilder; friend class HybridModelAsyncExecutor; + std::string model_name_; GeRootModelPtr ge_root_model_; - std::vector root_nodes_; std::map input_nodes_; - std::map> input_offsets_; - std::vector output_offsets_; - std::vector net_output_input_offsets_; - NodeItem *net_output_node_ = nullptr; - std::vector> node_items_; - std::vector const_nodes_; std::map constant_op_nodes_; std::map variable_nodes_; std::map> variable_tensors_; - std::map> weights_; std::map> task_defs_; - std::map known_shape_sub_graphs_; - int total_inputs_ = 0; - int total_outputs_ = 0; + std::map known_shape_sub_models_; + + std::unique_ptr root_graph_item_; + std::map> subgraph_items_; + std::map> node_items_; // runtime fields uint32_t device_id_ = 0; diff --git a/src/ge/hybrid/model/hybrid_model_builder.cc b/src/ge/hybrid/model/hybrid_model_builder.cc index 190890b7..436beada 100644 --- a/src/ge/hybrid/model/hybrid_model_builder.cc +++ b/src/ge/hybrid/model/hybrid_model_builder.cc @@ -23,7 +23,6 @@ #include "graph/manager/trans_var_data_utils.h" #include "graph/utils/graph_utils.h" #include "graph/utils/type_utils.h" -#include "framework/common/debug/log.h" #include "hybrid/common/npu_memory_allocator.h" #include "hybrid/node_executor/node_executor.h" @@ -32,6 +31,7 @@ namespace hybrid { namespace { const uint32_t kSubgraphIndex = 0U; const uint32_t kVarOutputIndex = 0U; +const uint32_t kAlignment = 32; const int kBytes = 8; int64_t CalcVarSizeInBytes(const GeTensorDesc &desc) { @@ -46,6 +46,9 @@ int64_t CalcVarSizeInBytes(const GeTensorDesc &desc) { for (size_t dim_index = 0; dim_index < dim_num; ++dim_index) { var_size *= shape.GetDim(dim_index); } + + // padding up to multiple of kAlignment, and add extra kAlignment + var_size = (var_size + kAlignment * 2 - 1) / kAlignment * kAlignment; return var_size; } } // namespace @@ -56,20 +59,19 @@ HybridModelBuilder::HybridModelBuilder(HybridModel &hybrid_model) Status HybridModelBuilder::Build() { GE_CHK_STATUS_RET(ValidateParams(), "Failed to validate GeRootModel"); - graph_name_ = ge_root_model_->GetRootGraph()->GetName(); + hybrid_model_.model_name_ = ge_root_model_->GetRootGraph()->GetName(); GELOGI("[%s] Start to build hybrid model.", GetGraphName()); GE_CHK_STATUS_RET(InitRuntimeParams(), "[%s] Failed to InitRuntimeParams", GetGraphName()); - GE_CHK_STATUS_RET(NodeExecutorManager::GetInstance().EnsureInitialized(), "Failed to initialize executors"); GE_CHK_STATUS_RET(IndexSpecialNodes(), "[%s] Failed to index nodes", GetGraphName()); GE_CHK_STATUS_RET(IndexTaskDefs(), "[%s] Failed to index task defs", GetGraphName()); GE_CHK_STATUS_RET(LoadGraph(), "[%s] Failed to load graph", GetGraphName()); + GE_CHK_STATUS_RET(AssignUninitializedConstantOps(), "[%s] Failed to assign uninitialized constants", GetGraphName()); GE_CHK_STATUS_RET(TransAllVarData(), "[%s] Failed to trans all var data", GetGraphName()); GE_CHK_STATUS_RET(CopyVarData(), "[%s] Failed to copy var data", GetGraphName()); GE_CHK_STATUS_RET(InitModelMem(), "[%s] Failed to init memory", GetGraphName()); GE_CHK_STATUS_RET(InitWeights(), "[%s] Failed to init weights", GetGraphName()); GE_CHK_STATUS_RET(InitConstantOps(), "[%s] Failed to init constant op", GetGraphName()); GE_CHK_STATUS_RET(InitVariableTensors(), "[%s] Failed to init variables", GetGraphName()); - GE_CHK_STATUS_RET(ResolveRootNodes(), "[%s] Failed to resolve root nodes", GetGraphName()); GE_CHK_STATUS_RET(LoadTasks(), "[%s] Failed to load tasks", GetGraphName()); GELOGI("[%s] Done building hybrid model successfully.", GetGraphName()); return SUCCESS; @@ -81,45 +83,17 @@ Status HybridModelBuilder::ValidateParams() { return SUCCESS; } -Status HybridModelBuilder::ResolveRootNodes() { - for (auto &node : hybrid_model_.node_items_) { - if (node->node->GetInDataNodes().empty()) { - hybrid_model_.root_nodes_.emplace_back(node.get()); - GELOGI("[%s] Root node added. node name = %s", GetGraphName(), node->NodeName().c_str()); - } - } - - if (hybrid_model_.root_nodes_.empty()) { - GELOGE(PARAM_INVALID, "[%s] Root nodes is empty.", GetGraphName()); - return PARAM_INVALID; - } - - return SUCCESS; -} - -Status HybridModelBuilder::BuildNoteItem(const NodePtr &node, NodeItem &node_item) { - GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node, node_item.is_dynamic), - "[%s] Failed to get shape status.", node->GetName().c_str()); - +Status HybridModelBuilder::BuildNodeItem(const NodePtr &node, NodeItem &node_item) { auto op_desc = node->GetOpDesc(); vector dependencies = node->GetOpDesc()->GetOpInferDepends(); GE_CHK_STATUS_RET(ParseDependentInputNodes(node_item, dependencies), "[%s] Failed to parse node dependencies.", node_item.NodeName().c_str()); - auto it = node_ref_inputs_.find(node); - if (it != node_ref_inputs_.end()) { - for (auto &idx_and_node : it->second) { - // var and constant only have one output - node_item.const_input_shapes[idx_and_node.first] = - idx_and_node.second->GetOpDesc()->MutableOutputDesc(kVarOutputIndex); - } - } - node_item.outputs.resize(node_item.num_outputs); for (int i = 0; i < node_item.num_outputs; ++i) { auto out_data_anchor = node->GetOutDataAnchor(i); if (out_data_anchor == nullptr) { - GELOGE(INTERNAL_ERROR, "out anchor[%zu] of node %s is nullptr", i, node->GetName().c_str()); + GELOGE(INTERNAL_ERROR, "out anchor[%d] of node %s is nullptr", i, node->GetName().c_str()); return INTERNAL_ERROR; } @@ -137,27 +111,46 @@ Status HybridModelBuilder::BuildNoteItem(const NodePtr &node, NodeItem &node_ite } } + GE_CHK_STATUS_RET_NOLOG(ResolveRefIo(node_item)); return SUCCESS; } -Status HybridModelBuilder::GetOrCreateNodeItem(const NodePtr &node, NodeItem **node_item) { - auto &node_items = hybrid_model_.node_items_; - auto node_id = node->GetOpDesc()->GetId(); - if (node_id < 0 || static_cast(node_id) > node_items.size()) { - GELOGE(INTERNAL_ERROR, "[%s] Index out of range. node_id = %ld, num_nodes = %zu", node->GetName().c_str(), node_id, - node_items.size()); - return INTERNAL_ERROR; +Status HybridModelBuilder::ResolveRefIo(NodeItem &node_item) { + bool is_ref = false; + auto &op_desc = *node_item.op_desc; + (void)AttrUtils::GetBool(op_desc, ATTR_NAME_REFERENCE, is_ref); + if (!is_ref) { + return SUCCESS; } - auto &node_ptr = node_items[node_id]; - if (node_ptr != nullptr) { - *node_item = node_ptr.get(); + auto inputs = op_desc.GetAllInputName(); + auto outputs = op_desc.GetAllOutputName(); + for (auto &output : outputs) { + for (auto &input : inputs) { + if (input.first == output.first) { + auto input_idx = static_cast(input.second); + auto output_idx = static_cast(output.second); + node_item.reuse_inputs[output_idx] = input_idx; + GELOGD("[%s] Output[%d] reuse input[%d]", node_item.NodeName().c_str(), output_idx, input_idx); + } + } + } + + return SUCCESS; +} + +Status HybridModelBuilder::GetOrCreateNodeItem(const NodePtr &node, NodeItem **node_item) { + auto &node_items = hybrid_model_.node_items_; + auto it = node_items.find(node); + if (it != node_items.end()) { + *node_item = it->second.get(); return SUCCESS; } auto new_node = std::unique_ptr(new (std::nothrow) NodeItem(node)); GE_CHECK_NOTNULL(new_node); GE_CHECK_NOTNULL(new_node->op_desc); + GE_CHK_STATUS_RET(new_node->Init(), "Failed to init NodeItem [%s] .", node->GetName().c_str()); GE_CHK_STATUS_RET_NOLOG(NodeExecutorManager::GetInstance().GetExecutor(*node, &new_node->node_executor)); // we do not need L2 Buffer @@ -166,21 +159,54 @@ Status HybridModelBuilder::GetOrCreateNodeItem(const NodePtr &node, NodeItem **n (void)AttrUtils::SetBool(new_node->op_desc, kIsFirstNode, false); (void)AttrUtils::SetBool(new_node->op_desc, kIsLastNode, false); - int32_t unknown_shape_type_val = 0; - (void)AttrUtils::GetInt(new_node->op_desc, ::ge::ATTR_NAME_UNKNOWN_SHAPE_TYPE, unknown_shape_type_val); - new_node->shape_inference_type = static_cast(unknown_shape_type_val); - if (new_node->shape_inference_type == DEPEND_SHAPE_RANGE || new_node->shape_inference_type == DEPEND_COMPUTE) { - new_node->has_observer = true; + if (new_node->is_dynamic && (new_node->IsControlOp() || new_node->NodeType() == PARTITIONEDCALL)) { + new_node->shape_inference_type = DEPEND_COMPUTE; } + new_node->node_id = node_index; + new_node->op_desc->SetId(node_index); + node_index += 1; + *node_item = new_node.get(); - node_items[node_id] = std::move(new_node); + node_items[node] = std::move(new_node); return SUCCESS; } Status HybridModelBuilder::ParseDependentInputNodes(NodeItem &node_item, const std::vector &dependencies) { std::set dependent_input_nodes; auto &ge_node = node_item.node; + + // The input tensors become valid after computation is done for parent nodes of type DEPEND_COMPUTE. + // Wait for these parent nodes before execution. + for (const auto &in_anchor : ge_node->GetAllInDataAnchors()) { + const auto &peer_anchor = in_anchor->GetPeerOutAnchor(); + if (peer_anchor == nullptr) { + GELOGD("[%s] Input[%d] do not have peer anchor", node_item.NodeName().c_str(), in_anchor->GetIdx()); + continue; + } + + auto src_node = peer_anchor->GetOwnerNode(); + GE_CHECK_NOTNULL(src_node); + + auto src_node_item = MutableNodeItem(src_node); + GE_CHECK_NOTNULL(src_node_item); + + if (src_node_item->shape_inference_type == DEPEND_COMPUTE) { + GELOGD("[%s] Add input data dependent node [%s] due to inference type = DEPEND_COMPUTE", + node_item.NodeName().c_str(), src_node_item->NodeName().c_str()); + + src_node_item->has_observer = true; + node_item.dependents_for_execution.emplace_back(src_node); + } + + if (src_node_item->shape_inference_type == DEPEND_SHAPE_RANGE) { + GELOGD("[%s] Add input shape dependent node [%s] due to inference type = DEPEND_SHAPE_RANGE", + node_item.NodeName().c_str(), src_node_item->NodeName().c_str()); + src_node_item->has_observer = true; + dependent_input_nodes.emplace(src_node); + } + } + for (const auto &input_name : dependencies) { int input_index = node_item.op_desc->GetInputIndexByName(input_name); if (input_index < 0) { @@ -205,7 +231,7 @@ Status HybridModelBuilder::ParseDependentInputNodes(NodeItem &node_item, const s } for (const auto &dep_node : dependent_input_nodes) { - node_item.dependent_node_list.emplace_back(dep_node); + node_item.dependents_for_shape_inference.emplace_back(dep_node); } return SUCCESS; @@ -262,9 +288,14 @@ Status HybridModelBuilder::DoLinkDataAnchors(OutDataAnchorPtr &out_data_anchor, Status HybridModelBuilder::MergeInputNodes(ComputeGraph &graph) { const auto &wrapped_node = graph.GetParentNode(); + std::set root_nodes; for (const auto &node : graph.GetDirectNode()) { GE_CHECK_NOTNULL(node); if (node->GetType() != DATA_TYPE) { + if (node->GetInDataNodes().empty()) { + root_nodes.emplace(node); + } + continue; } @@ -291,12 +322,28 @@ Status HybridModelBuilder::MergeInputNodes(ComputeGraph &graph) { for (auto &out_data_anchor : node->GetAllOutDataAnchors()) { GE_CHECK_NOTNULL(out_data_anchor); for (auto &peer_in_data_anchor : out_data_anchor->GetPeerInDataAnchors()) { + auto dst_node = peer_in_data_anchor->GetOwnerNode(); + root_nodes.emplace(dst_node); GE_CHK_STATUS_RET_NOLOG(DoUnlinkDataAnchors(out_data_anchor, peer_in_data_anchor)); GE_CHK_STATUS_RET_NOLOG(DoLinkDataAnchors(src_out_anchor, peer_in_data_anchor)); } } } + // transfer in control edges to all root nodes + for (auto &root_node : root_nodes) { + auto in_nodes = root_node->GetInAllNodes(); + std::set in_node_set(in_nodes.begin(), in_nodes.end()); + for (auto &in_control_node : wrapped_node->GetInControlNodes()) { + if (in_node_set.count(in_control_node) == 0) { + GELOGD("[%s] Restore control edge to [%s]", in_control_node->GetName().c_str(), root_node->GetName().c_str()); + GE_CHECK_NOTNULL(in_control_node->GetOutControlAnchor()); + (void)in_control_node->GetOutControlAnchor()->LinkTo(root_node->GetInControlAnchor()); + } + } + } + + wrapped_node->GetInControlAnchor()->UnlinkAll(); return SUCCESS; } @@ -307,6 +354,11 @@ Status HybridModelBuilder::MergeNetOutputNode(ComputeGraph &graph) { const auto &net_output_desc = net_output_node->GetOpDesc(); GE_CHECK_NOTNULL(net_output_desc); + auto all_in_nodes = net_output_node->GetInAllNodes(); + auto all_out_nodes = parent_node->GetOutAllNodes(); + net_output_node->GetInControlAnchor()->UnlinkAll(); + parent_node->GetOutControlAnchor()->UnlinkAll(); + for (const auto &in_data_anchor : net_output_node->GetAllInDataAnchors()) { auto src_out_anchor = in_data_anchor->GetPeerOutAnchor(); GE_CHECK_NOTNULL(src_out_anchor); @@ -338,10 +390,25 @@ Status HybridModelBuilder::MergeNetOutputNode(ComputeGraph &graph) { } } + // transfer out control edges + std::set in_node_set(all_in_nodes.begin(), all_in_nodes.end()); + std::set out_node_set(all_out_nodes.begin(), all_out_nodes.end()); + for (auto &src_node : in_node_set) { + GELOGD("[%s] process in node.", src_node->GetName().c_str()); + auto out_nodes = src_node->GetOutAllNodes(); + std::set node_set(out_nodes.begin(), out_nodes.end()); + for (auto &dst_node : out_node_set) { + if (node_set.count(dst_node) == 0) { + src_node->GetOutControlAnchor()->LinkTo(dst_node->GetInControlAnchor()); + GELOGD("[%s] Restore control edge to [%s]", src_node->GetName().c_str(), dst_node->GetName().c_str()); + } + } + } + return SUCCESS; } -Status HybridModelBuilder::MergeSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph) { +Status HybridModelBuilder::UnfoldSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph) { merged_graph = MakeShared("MergedGraph"); for (const auto &node : root_graph.GetDirectNode()) { GE_CHECK_NOTNULL(node); @@ -371,32 +438,74 @@ Status HybridModelBuilder::MergeSubgraphs(ComputeGraph &root_graph, ComputeGraph } auto subgraph = NodeUtils::GetSubgraph(*node, kSubgraphIndex); - GE_CHK_STATUS_RET(MergeInputNodes(*subgraph), "Failed to merge data nodes for subgraph: %s", - subgraph->GetName().c_str()); - GE_CHK_STATUS_RET(MergeNetOutputNode(*subgraph), "Failed to merge net output nodes for subgraph: %s", - subgraph->GetName().c_str()); - GELOGD("Merging subgraph %s successfully.", subgraph->GetName().c_str()); - for (auto &sub_node : subgraph->GetAllNodes()) { - auto sub_op_type = sub_node->GetType(); - if (sub_op_type == DATA_TYPE || sub_op_type == NETOUTPUT) { - continue; - } + GE_CHECK_NOTNULL(subgraph); + GE_CHK_GRAPH_STATUS_RET(UnfoldSubgraph(root_graph, *merged_graph, *subgraph), "[%s] Failed to merge subgraph.", + subgraph->GetName().c_str()); + } - if (sub_op_type == CONSTANT || sub_op_type == CONSTANTOP || sub_op_type == VARIABLE) { - GELOGE(INTERNAL_ERROR, "Unexpected node in unknown subgraph. type = %s, node = %s::%s", sub_op_type.c_str(), - subgraph->GetName().c_str(), sub_node->GetName().c_str()); - return INTERNAL_ERROR; - } + // invoke before adding subgraphs. in case modify node id in known-shaped subgraphs. + GE_CHK_GRAPH_STATUS_RET(merged_graph->TopologicalSorting(), "Failed to invoke TopologicalSorting on merged graph."); + + for (auto &remained_subgraph : root_graph.GetAllSubgraphs()) { + GELOGD("Adding subgraph [%s] to merged-graph.", remained_subgraph->GetName().c_str()); + GE_CHK_GRAPH_STATUS_RET(merged_graph->AddSubgraph(remained_subgraph), "Failed to add subgraph [%s]", + remained_subgraph->GetName().c_str()); + } + + return SUCCESS; +} - merged_graph->AddNode(sub_node); - GELOGD("%s::%s added to merged graph.", subgraph->GetName().c_str(), sub_node->GetName().c_str()); +Status HybridModelBuilder::UnfoldSubgraph(ComputeGraph &root_graph, ComputeGraph &parent_graph, + ComputeGraph &sub_graph) { + auto parent_node = sub_graph.GetParentNode(); + GE_CHECK_NOTNULL(parent_node); + + GE_CHK_STATUS_RET(MergeInputNodes(sub_graph), "[%s] Failed to merge data nodes for subgraph", + sub_graph.GetName().c_str()); + GE_CHK_STATUS_RET(MergeNetOutputNode(sub_graph), "[%s] Failed to merge net output nodes for subgraph", + sub_graph.GetName().c_str()); + GELOGD("[%s] Done merging subgraph inputs and outputs successfully.", sub_graph.GetName().c_str()); + + for (auto &sub_node : sub_graph.GetDirectNode()) { + auto sub_op_type = sub_node->GetType(); + if (sub_op_type == DATA_TYPE || sub_op_type == NETOUTPUT) { + continue; + } + + if (sub_op_type == CONSTANT || sub_op_type == VARIABLE) { + GELOGE(INTERNAL_ERROR, "Unexpected node in unknown subgraph. type = %s, node = %s::%s", sub_op_type.c_str(), + sub_graph.GetName().c_str(), sub_node->GetName().c_str()); + return INTERNAL_ERROR; } + + if (sub_op_type == PARTITIONEDCALL) { + bool is_unknown_shape = false; + GE_CHK_GRAPH_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*sub_node, is_unknown_shape), + "[%s] Failed to invoke GetNodeUnknownShapeStatus.", sub_node->GetName().c_str()); + if (is_unknown_shape) { + auto sub_sub_graph = NodeUtils::GetSubgraph(*sub_node, kSubgraphIndex); + GE_CHECK_NOTNULL(sub_sub_graph); + GE_CHK_STATUS_RET(UnfoldSubgraph(root_graph, parent_graph, *sub_sub_graph), "[%s] Failed to merge subgraph", + sub_sub_graph->GetName().c_str()); + continue; + } + } + + parent_graph.AddNode(sub_node); + GELOGD("[%s::%s] added to parent graph: [%s].", sub_graph.GetName().c_str(), sub_node->GetName().c_str(), + parent_graph.GetName().c_str()); } + GELOGD("[%s] Done merging subgraph. remove it from root graph.", sub_graph.GetName().c_str()); + root_graph.RemoveSubgraph(sub_graph.GetName()); return SUCCESS; } -Status HybridModelBuilder::ParseNetOutput(const NodeItem &node_item) { +Status HybridModelBuilder::BuildOutputMapping(GraphItem &graph_item, const NodeItem &node_item, bool is_root_graph) { + auto output_size = node_item.op_desc->GetAllInputsSize(); + GE_CHECK_LE(output_size, UINT32_MAX); + graph_item.output_edges_.resize(output_size); + for (auto &in_data_anchor : node_item.node->GetAllInDataAnchors()) { auto peer_out_anchor = in_data_anchor->GetPeerOutAnchor(); GE_CHECK_NOTNULL(peer_out_anchor); @@ -408,11 +517,20 @@ Status HybridModelBuilder::ParseNetOutput(const NodeItem &node_item) { auto output_offset = src_node_item->output_start + peer_out_anchor->GetIdx(); GELOGI("Output[%d], node = %s, output_index = %d, output_offset = %d ", in_data_anchor->GetIdx(), src_node_item->NodeName().c_str(), peer_out_anchor->GetIdx(), output_offset); - hybrid_model_.output_offsets_.emplace_back(output_offset); + + graph_item.output_edges_[in_data_anchor->GetIdx()] = {src_node_item, peer_out_anchor->GetIdx()}; } - for (int i = 0; i < node_item.num_inputs; ++i) { - hybrid_model_.net_output_input_offsets_.emplace_back(node_item.input_start + i); + if (!is_root_graph) { + for (uint32_t i = 0; i < static_cast(output_size); ++i) { + uint32_t p_index = i; + // Net output of Subgraph of while do not have parent index + if (AttrUtils::GetInt(node_item.op_desc->GetInputDesc(i), ATTR_NAME_PARENT_NODE_INDEX, p_index)) { + GELOGD("[%s] Parent index not set for input[%u].", node_item.NodeName().c_str(), i); + } + + graph_item.output_index_mapping_.emplace_back(p_index); + } } return SUCCESS; @@ -420,82 +538,46 @@ Status HybridModelBuilder::ParseNetOutput(const NodeItem &node_item) { Status HybridModelBuilder::LoadGraph() { auto root_graph = ge_root_model_->GetRootGraph(); - GELOGI("Before merge subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", root_graph->GetDirectNodesSize(), + std::shared_ptr merged_graph; + GELOGI("Before merging subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", root_graph->GetDirectNodesSize(), root_graph->GetAllNodesSize()); - ComputeGraphPtr merged_graph; - GE_CHK_STATUS_RET_NOLOG(MergeSubgraphs(*root_graph, merged_graph)); - GELOGI("After merge subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", merged_graph->GetDirectNodesSize(), - merged_graph->GetAllNodesSize()); - - merged_graph->SetGraphID(runtime_param_.graph_id); - GE_DUMP(merged_graph, "hybrid_merged_graph"); - int input_start = 0; - int output_start = 0; - uint32_t data_op_index = 0; - hybrid_model_.node_items_.resize(merged_graph->GetDirectNodesSize()); - - int64_t node_index = 0; - for (auto &node : merged_graph->GetDirectNode()) { - OpDescPtr op_desc = node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - op_desc->SetId(node_index++); - } - - for (const auto &node : merged_graph->GetDirectNode()) { - GE_CHECK_NOTNULL(node); - GE_CHECK_NOTNULL(node->GetOpDesc()); - const auto &op_type = node->GetType(); - - NodeItem *node_item = nullptr; - GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(node, &node_item)); - GE_CHK_STATUS_RET_NOLOG(BuildNoteItem(node, *node_item)); - GE_CHK_STATUS_RET_NOLOG(UpdateAnchorStatus(node)); // needed by FE generate task - - node_item->input_start = input_start; - node_item->output_start = output_start; - input_start += node_item->num_inputs; - output_start += node_item->num_outputs; - - if (op_type == DATA_TYPE || op_type == AIPP_DATA_TYPE) { - auto data_index = data_op_index; - if (AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_INDEX, data_index)) { - GELOGI("ge_train: get new index %u, old %u", data_index, data_op_index); - } - hybrid_model_.input_nodes_.emplace(data_index, node_item); - data_op_index++; - } else if (op_type == NETOUTPUT) { - hybrid_model_.net_output_node_ = node_item; - GE_CHK_STATUS_RET_NOLOG(ParseNetOutput(*node_item)); - } else if (op_type == PARTITIONEDCALL) { // known graph - GE_CHK_STATUS_RET_NOLOG(ParsePartitionedCall(*node_item)); + GE_CHK_GRAPH_STATUS_RET(UnfoldSubgraphs(*root_graph, merged_graph), "Failed to unfold subgraphs."); + root_graph = std::move(merged_graph); + GELOGI("After merging subgraphs DirectNodesSize = %zu, GetAllNodesSize = %zu", root_graph->GetDirectNodesSize(), + root_graph->GetAllNodesSize()); + GE_DUMP(root_graph, "hybrid_merged_graph"); + + GE_CHK_STATUS_RET(LoadDynamicSubgraph(*root_graph, true), "Failed to load root graph."); + GELOGD("Done loading root graph successfully."); + + for (auto &sub_graph : root_graph->GetAllSubgraphs()) { + GE_CHECK_NOTNULL(sub_graph); + GELOGD("Start to load subgraph [%s]", sub_graph->GetName().c_str()); + auto parent_node = sub_graph->GetParentNode(); + GE_CHECK_NOTNULL(parent_node); + auto parent_node_item = MutableNodeItem(parent_node); + // parent node is in another known subgraph + if (parent_node_item == nullptr) { + GELOGD("[%s] Subgraph is in another known shaped subgraph, skip it.", sub_graph->GetName().c_str()); + continue; } - GELOGI("NodeItem created: %s", node_item->DebugString().c_str()); - } - - for (auto &it : hybrid_model_.input_nodes_) { - auto input_index = it.first; - auto input_node = it.second; - - if (input_node->outputs.empty()) { - GELOGE(INTERNAL_ERROR, "data output anchor is empty"); - return INTERNAL_ERROR; - } + if (sub_graph->GetGraphUnknownFlag()) { + GE_CHK_STATUS_RET(LoadDynamicSubgraph(*sub_graph, false), "Failed to load subgraph: [%s]", + sub_graph->GetName().c_str()); + } else { + GE_CHK_STATUS_RET(IdentifyVariableOutputs(*parent_node_item), "[%s] Failed to identify ref outputs.", + parent_node_item->NodeName().c_str()); - for (auto &out : input_node->outputs) { - std::vector offsets; - for (auto &dst_anchor_and_node : out) { - auto dst_node_item = dst_anchor_and_node.second; - offsets.emplace_back(dst_node_item->input_start + dst_anchor_and_node.first); + // if parent is function control op. need add a virtual partitioned call + if (parent_node_item->IsControlOp()) { + GE_CHK_STATUS_RET(LoadKnownShapedSubgraph(*sub_graph, parent_node_item), + "Failed to load function control op subgraph [%s]", sub_graph->GetName().c_str()); } - - hybrid_model_.input_offsets_.emplace(input_index, std::move(offsets)); } } - hybrid_model_.total_inputs_ = input_start; - hybrid_model_.total_outputs_ = output_start; - GELOGI("HybridGraph::LoadGraph OUT"); + GELOGI("Done loading all subgraphs successfully."); return SUCCESS; } @@ -507,7 +589,6 @@ Status HybridModelBuilder::VarNodeToTensor(const NodePtr &var_node, std::unique_ string var_name = var_node->GetName(); auto tensor_desc = var_node->GetOpDesc()->MutableOutputDesc(0); uint8_t *var_logic = nullptr; - GE_CHK_STATUS_RET(var_manager_->GetVarAddr(var_name, *tensor_desc, &var_logic), "Failed to get var addr. var_name = %s, session_id = %ld", var_name.c_str(), hybrid_model_.GetSessionId()); @@ -559,10 +640,26 @@ Status HybridModelBuilder::HandleDtString(const GeTensor &tensor, void *var_addr return SUCCESS; } +Status HybridModelBuilder::AssignUninitializedConstantOps() { + for (auto &it : hybrid_model_.constant_op_nodes_) { + const string &var_name = it.first; + const NodePtr &var_node = it.second; + auto tensor_desc = var_node->GetOpDesc()->MutableOutputDesc(0); + if (!var_manager_->IsVarExist(var_name, *tensor_desc)) { + // allocate constant + GELOGD("[%s] Constant not allocated during graph building. now allocate it.", var_name.c_str()); + GE_CHK_STATUS_RET(var_manager_->AssignVarMem(var_name, *tensor_desc, RT_MEMORY_HBM)); + GE_CHK_STATUS_RET(var_manager_->SetAllocatedGraphId(var_name, runtime_param_.graph_id)); + } + } + + return SUCCESS; +} + Status HybridModelBuilder::InitConstantOps() { for (auto &it : hybrid_model_.constant_op_nodes_) { - string var_name = it.first; - NodePtr &var_node = it.second; + const string &var_name = it.first; + const NodePtr &var_node = it.second; std::unique_ptr var_tensor; GE_CHK_STATUS_RET_NOLOG(VarNodeToTensor(var_node, var_tensor)); @@ -578,7 +675,7 @@ Status HybridModelBuilder::InitConstantOps() { if (ge_tensor->GetData().size() > 0) { GE_CHK_STATUS_RET_NOLOG(HandleDtString(*ge_tensor, v_output_addr)); - GELOGI("[IMAS]InitConstant memcpy graph_%u type[V] name[%s] output[%d] memaddr[%p] mem_size[%u] datasize[%zu]", + GELOGI("[IMAS]InitConstant memcpy graph_%u type[V] name[%s] output[%d] memaddr[%p] mem_size[%zu] datasize[%zu]", runtime_param_.graph_id, op_desc->GetName().c_str(), 0, v_output_addr, v_output_size, ge_tensor->GetData().size()); GE_CHK_RT_RET(rtMemcpy(v_output_addr, v_output_size, ge_tensor->GetData().data(), ge_tensor->GetData().size(), @@ -614,7 +711,8 @@ Status HybridModelBuilder::InitWeights() { } Status HybridModelBuilder::LoadTasks() { - for (auto &node_item : hybrid_model_.node_items_) { + for (auto &it : hybrid_model_.node_items_) { + auto &node_item = it.second; auto &node_ptr = node_item->node; if (node_item->node_type == NETOUTPUT) { continue; @@ -622,7 +720,6 @@ Status HybridModelBuilder::LoadTasks() { GELOGD("[%s] Start to build kernel task", node_ptr->GetName().c_str()); auto load_ret = node_item->node_executor->LoadTask(hybrid_model_, node_ptr, node_item->kernel_task); - if (load_ret != UNSUPPORTED && load_ret != SUCCESS) { GELOGE(load_ret, "[%s] Failed to load task", node_ptr->GetName().c_str()); return load_ret; @@ -634,6 +731,23 @@ Status HybridModelBuilder::LoadTasks() { return SUCCESS; } +Status HybridModelBuilder::LoadGeModel(ComputeGraph &sub_graph, const GeModelPtr &ge_model) { + auto parent_node = sub_graph.GetParentNode(); + GE_CHECK_NOTNULL(parent_node); + auto op_type = parent_node->GetType(); + if (op_type == IF || op_type == CASE || op_type == WHILE) { + GELOGD("Set ge_model for control op subgraph: [%s], task_size = %d", sub_graph.GetName().c_str(), + ge_model->GetModelTaskDefPtr()->task_size()); + subgraph_models_.emplace(sub_graph.GetName(), ge_model); + } else { + GELOGD("Set ge_model for subgraph: [%s], task_size = %d", sub_graph.GetName().c_str(), + ge_model->GetModelTaskDefPtr()->task_size()); + hybrid_model_.known_shape_sub_models_.emplace(sub_graph.GetParentNode(), ge_model); + } + + return SUCCESS; +} + Status HybridModelBuilder::IndexTaskDefs() { const auto &root_graph = ge_root_model_->GetRootGraph(); for (auto &it : ge_root_model_->GetSubgraphInstanceNameToModel()) { @@ -646,12 +760,9 @@ Status HybridModelBuilder::IndexTaskDefs() { continue; } - bool is_unknown_shape = false; - GE_CHK_GRAPH_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*sub_graph->GetParentNode(), is_unknown_shape), - "Failed to invoke GetNodeUnknownShapeStatus."); + bool is_unknown_shape = sub_graph->GetGraphUnknownFlag(); if (!is_unknown_shape) { - GELOGD("Set ge_model for subgraph: %s", sub_graph->GetName().c_str()); - hybrid_model_.known_shape_sub_graphs_.emplace(sub_graph->GetParentNode(), ge_model); + GE_CHK_STATUS_RET_NOLOG(LoadGeModel(*sub_graph, ge_model)); continue; } @@ -676,6 +787,8 @@ Status HybridModelBuilder::IndexTaskDefs() { op_index = task_def.kernel().context().op_index(); } else if (task_type == RT_MODEL_TASK_KERNEL_EX) { op_index = task_def.kernel_ex().op_index(); + } else if (task_type == RT_MODEL_TASK_HCCL) { + op_index = task_def.kernel_hccl().op_index(); } else { GELOGD("Skip task type: %d", static_cast(task_type)); continue; @@ -790,12 +903,12 @@ Status HybridModelBuilder::GetPeerNodeAcrossSubGraphs(const NodePtr &data_node, for (uint32_t i = 0; i < static_cast(input_size); ++i) { uint32_t p_index = 0; if (!AttrUtils::GetInt(net_output_desc->GetInputDesc(i), ATTR_NAME_PARENT_NODE_INDEX, p_index)) { - GELOGW("SubGraph: %s input tensor %zu attr %s not found.", src_graph->GetName().c_str(), i, + GELOGW("SubGraph: %s input tensor %u attr %s not found.", src_graph->GetName().c_str(), i, ATTR_NAME_PARENT_NODE_INDEX.c_str()); continue; } - GELOGD("NetOutput's input[%zu], parent_node_index = %u", i, p_index); + GELOGD("NetOutput's input[%u], parent_node_index = %u", i, p_index); if (p_index == out_index) { auto in_anchor = src_net_output_node->GetInDataAnchor(i); GE_CHECK_NOTNULL(in_anchor); @@ -830,7 +943,7 @@ Status HybridModelBuilder::InitRuntimeParams() { ret = ge::AttrUtils::GetInt(first_model, ATTR_MODEL_VAR_SIZE, value); runtime_param_.var_size = ret ? (uint64_t)value : 0; runtime_param_.graph_id = ge_root_model_->GetRootGraph()->GetGraphID(); - GELOGI("InitRuntimeParams(), session_id:%u, var_size:%lu. graph_id = %u", runtime_param_.session_id, + GELOGI("InitRuntimeParams(), session_id:%lu, var_size:%lu. graph_id = %u", runtime_param_.session_id, runtime_param_.var_size, runtime_param_.graph_id); var_manager_ = VarManager::Instance(runtime_param_.session_id); @@ -838,15 +951,19 @@ Status HybridModelBuilder::InitRuntimeParams() { return SUCCESS; } -Status HybridModelBuilder::ParsePartitionedCall(NodeItem &node_item) { +Status HybridModelBuilder::IdentifyVariableOutputs(NodeItem &node_item) { GELOGD("Start to parse outputs of node: %s", node_item.NodeName().c_str()); auto subgraph = NodeUtils::GetSubgraph(*node_item.node, kSubgraphIndex); GE_CHECK_NOTNULL(subgraph); auto net_output_node = subgraph->FindFirstNodeMatchType(NETOUTPUT); - GE_CHECK_NOTNULL(net_output_node); + if (net_output_node == nullptr) { + GELOGD("[%s] Subgraph do not got net output", subgraph->GetName().c_str()); + return SUCCESS; + } auto net_output_desc = net_output_node->GetOpDesc(); GE_CHECK_NOTNULL(net_output_desc); + // constant/variable connected to net output for (const auto &in_data_anchor : net_output_node->GetAllInDataAnchors()) { auto src_node = GetPeerNode(in_data_anchor); GE_CHECK_NOTNULL(src_node); @@ -864,6 +981,8 @@ Status HybridModelBuilder::ParsePartitionedCall(NodeItem &node_item) { node_item.ref_outputs.emplace(parent_index, src_node); } + // Data nodes marked with REF_VAR_SRC_VAR_NAME + // Using variable tensor as data's output for (auto &node : subgraph->GetDirectNode()) { if (node->GetType() != DATA) { continue; @@ -912,6 +1031,11 @@ Status HybridModelBuilder::GetParentNodeOutputIndex(const OpDesc &op_desc, int i Status HybridModelBuilder::InitModelMem() { hybrid_model_.var_mem_base_ = var_manager_->GetVarMemoryBase(RT_MEMORY_HBM); auto total_var_size = hybrid_model_.TotalVarMemSize(); + if (total_var_size == 0 && !hybrid_model_.constant_op_nodes_.empty()) { + total_var_size = var_manager_->GetVarMemSize(RT_MEMORY_HBM) > 0 ? var_manager_->GetVarMemMaxSize() : 0; + GELOGD("Model var size = 0. but got uninitialized constant. set var size to %zu.", total_var_size); + } + if (total_var_size > 0 && hybrid_model_.var_mem_base_ == nullptr) { GE_CHK_STATUS_RET(var_manager_->MallocVarMemory(total_var_size), "Malloc Var Memory Fail."); hybrid_model_.var_mem_base_ = var_manager_->GetVarMemoryBase(RT_MEMORY_HBM); @@ -951,5 +1075,154 @@ Status HybridModelBuilder::CopyVarData() { GELOGI("CopyVarData success."); return SUCCESS; } + +Status HybridModelBuilder::LoadKnownShapedSubgraph(ComputeGraph &graph, NodeItem *parent_node_item) { + GELOGD("Start to load known shaped subgraph [%s]", graph.GetName().c_str()); + auto graph_item = std::unique_ptr(new (std::nothrow) GraphItem()); + GE_CHECK_NOTNULL(graph_item); + graph_item->is_dynamic_ = false; + auto subgraph_name = graph.GetName(); + auto wrapper_op_desc = MakeShared(subgraph_name + "_partitioned_call", PARTITIONEDCALL); + GE_CHECK_NOTNULL(wrapper_op_desc); + + for (auto &node : graph.GetDirectNode()) { + GE_CHECK_NOTNULL(node); + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + const auto &op_type = node->GetType(); + + if (op_type == DATA) { + int32_t data_index = 0; + if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, data_index)) { + GELOGE(FAILED, "[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); + return FAILED; + } + + (void)wrapper_op_desc->AddInputDesc(op_desc->GetInputDesc(0)); + graph_item->input_index_mapping_.emplace_back(data_index); + } else if (op_type == NETOUTPUT) { + int output_index = 0; + for (const auto &output_desc : op_desc->GetAllInputsDescPtr()) { + int32_t data_index = output_index++; + if (!AttrUtils::GetInt(output_desc, ATTR_NAME_PARENT_NODE_INDEX, data_index)) { + GELOGI("[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); + } + + GE_CHK_GRAPH_STATUS_RET(wrapper_op_desc->AddOutputDesc(*output_desc), + "[%s] Failed to add output desc. output index = %d", graph.GetName().c_str(), + output_index); + + graph_item->output_index_mapping_.emplace_back(data_index); + } + } + } + + auto temp_graph = MakeShared("temp"); + GE_CHECK_NOTNULL(temp_graph); + auto wrapper_node = temp_graph->AddNode(wrapper_op_desc); + GeModelPtr ge_model = subgraph_models_[subgraph_name]; + GE_CHECK_NOTNULL(ge_model); + hybrid_model_.known_shape_sub_models_.emplace(wrapper_node, ge_model); + + NodeItem *node_item = nullptr; + GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(wrapper_node, &node_item)); + node_item->input_start = 0; + node_item->output_start = 0; + node_item->outputs.resize(node_item->num_outputs); + graph_item->node_items_.emplace_back(node_item); + graph_item->output_node_ = node_item; + graph_item->total_inputs_ = node_item->num_inputs; + graph_item->total_outputs_ = node_item->num_outputs; + + GELOGD("NodeItem create for known shape subgraph [%s], NodeItem = %s", graph.GetName().c_str(), + node_item->DebugString().c_str()); + + GELOGD("Done parse known shape subgraph successfully. graph = [%s]", graph.GetName().c_str()); + graph_item->SetName(graph.GetName()); + GELOGD("Done loading known shape subgraph: [%s]", graph_item->GetName().c_str()); + hybrid_model_.subgraph_items_.emplace(graph.GetName(), std::move(graph_item)); + return SUCCESS; +} + +Status HybridModelBuilder::LoadDynamicSubgraph(ComputeGraph &graph, bool is_root_graph) { + GELOGD("Start to load subgraph [%s]", graph.GetName().c_str()); + // for known partitioned call, load all nodes + auto graph_item = std::unique_ptr(new (std::nothrow) GraphItem()); + GE_CHECK_NOTNULL(graph_item); + + graph_item->is_dynamic_ = true; + graph_item->node_items_.reserve(graph.GetDirectNodesSize()); + int input_start = 0; + int output_start = 0; + std::vector data_nodes; + for (auto &node : graph.GetDirectNode()) { + GE_CHECK_NOTNULL(node); + GE_CHECK_NOTNULL(node->GetOpDesc()); + const auto &op_type = node->GetType(); + + NodeItem *node_item = nullptr; + GE_CHK_STATUS_RET_NOLOG(GetOrCreateNodeItem(node, &node_item)); + GE_CHK_STATUS_RET_NOLOG(BuildNodeItem(node, *node_item)); + GE_CHK_STATUS_RET_NOLOG(UpdateAnchorStatus(node)); // needed by FE generate task + + node_item->input_start = input_start; + node_item->output_start = output_start; + input_start += node_item->num_inputs; + output_start += node_item->num_outputs; + + if (op_type == DATA_TYPE || op_type == AIPP_DATA_TYPE) { + data_nodes.emplace_back(node_item); + } else if (op_type == NETOUTPUT) { + graph_item->output_node_ = node_item; + GE_CHK_STATUS_RET_NOLOG(BuildOutputMapping(*graph_item, *node_item, is_root_graph)); + } + + graph_item->node_items_.emplace_back(node_item); + GELOGD("NodeItem created: %s", node_item->DebugString().c_str()); + } + + graph_item->total_inputs_ = input_start; + graph_item->total_outputs_ = output_start; + GE_CHK_STATUS_RET_NOLOG(BuildInputMapping(*graph_item, data_nodes, is_root_graph)); + if (is_root_graph) { + graph_item->SetName("Root-Graph"); + GELOGD("Done loading dynamic subgraph: [%s]", graph_item->GetName().c_str()); + hybrid_model_.root_graph_item_ = std::move(graph_item); + } else { + graph_item->SetName(graph.GetName()); + GELOGD("Done loading dynamic subgraph: [%s]", graph_item->GetName().c_str()); + hybrid_model_.subgraph_items_.emplace(graph.GetName(), std::move(graph_item)); + } + + return SUCCESS; +} + +Status HybridModelBuilder::BuildInputMapping(GraphItem &graph_item, vector &data_nodes, + bool is_root_graph) { + uint32_t data_op_index = 0; + for (auto &node_item : data_nodes) { + auto node = node_item->node; + int data_index = data_op_index; + if (is_root_graph) { + if (AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_INDEX, data_index)) { + GELOGI("ge_train: get new index %u, old %u", data_index, data_op_index); + } + data_op_index++; + } else { + if (!AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, data_index)) { + GELOGE(FAILED, "[%s] Failed to get attr [%s]", node->GetName().c_str(), ATTR_NAME_PARENT_NODE_INDEX.c_str()); + return FAILED; + } + } + + if (graph_item.input_nodes_.size() <= static_cast(data_index)) { + graph_item.input_nodes_.resize(data_index + 1); + } + + graph_item.input_nodes_[data_index] = node_item; + } + + return SUCCESS; +} } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/model/hybrid_model_builder.h b/src/ge/hybrid/model/hybrid_model_builder.h index 33cd1f03..1103aa1c 100644 --- a/src/ge/hybrid/model/hybrid_model_builder.h +++ b/src/ge/hybrid/model/hybrid_model_builder.h @@ -46,18 +46,20 @@ class HybridModelBuilder { static Status HandleDtString(const GeTensor &tensor, void *var_addr); static Status MergeInputNodes(ComputeGraph &compute_graph); static Status MergeNetOutputNode(ComputeGraph &compute_graph); - static Status MergeSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph); + static Status UnfoldSubgraphs(ComputeGraph &root_graph, ComputeGraphPtr &merged_graph); + static Status UnfoldSubgraph(ComputeGraph &root_graph, ComputeGraph &parent_graph, ComputeGraph &sub_graph); static Status InitWeights(); - + static Status BuildInputMapping(GraphItem &graph_item, std::vector &data_nodes, bool is_root_graph); + static Status ResolveRefIo(NodeItem &node_item); + Status BuildOutputMapping(GraphItem &partitioned_call, const NodeItem &node_item, bool is_root_graph); Status ValidateParams(); Status LoadGraph(); + Status LoadGeModel(ComputeGraph &graph, const GeModelPtr &ge_model); Status LoadTasks(); - Status ParsePartitionedCall(NodeItem &node_item); - Status ParseNetOutput(const NodeItem &node_item); - Status BuildNoteItem(const NodePtr &node, NodeItem &node_item); + Status IdentifyVariableOutputs(NodeItem &node_item); + Status BuildNodeItem(const NodePtr &node, NodeItem &node_item); Status GetOrCreateNodeItem(const NodePtr &node, NodeItem **node_item); Status ParseDependentInputNodes(NodeItem &node_item, const std::vector &dependencies); - Status ResolveRootNodes(); Status IndexTaskDefs(); Status IndexSpecialNodes(); Status InitRuntimeParams(); @@ -65,19 +67,23 @@ class HybridModelBuilder { Status TransAllVarData(); Status CopyVarData(); Status VarNodeToTensor(const NodePtr &var_node, std::unique_ptr &tensor); + Status AssignUninitializedConstantOps(); Status InitConstantOps(); Status InitVariableTensors(); + Status LoadDynamicSubgraph(ComputeGraph &graph, bool is_root_graph); + Status LoadKnownShapedSubgraph(ComputeGraph &graph, NodeItem *parent_node_item); - const char *GetGraphName() const { return graph_name_.c_str(); } + const char *GetGraphName() const { return hybrid_model_.model_name_.c_str(); } const NodeItem *GetNodeItem(const NodePtr &node) const; NodeItem *MutableNodeItem(const NodePtr &node); GeRootModelPtr ge_root_model_; - std::string graph_name_; std::map> weights_; + std::map subgraph_models_; HybridModel &hybrid_model_; std::map>> node_ref_inputs_; + int node_index = 0; RuntimeParam &runtime_param_; VarManager *var_manager_ = nullptr; diff --git a/src/ge/hybrid/model/node_item.cc b/src/ge/hybrid/model/node_item.cc index b5d4fbda..bfc29c84 100644 --- a/src/ge/hybrid/model/node_item.cc +++ b/src/ge/hybrid/model/node_item.cc @@ -16,6 +16,10 @@ #include "node_item.h" #include +#include "common/debug/log.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/utils/node_utils.h" +#include "hybrid/node_executor/node_executor.h" namespace ge { namespace hybrid { @@ -28,20 +32,61 @@ NodeItem::NodeItem(NodePtr node) : node(std::move(node)) { this->node_type = this->node->GetType(); } +Status NodeItem::Init() { + int32_t unknown_shape_type_val = 0; + (void)AttrUtils::GetInt(op_desc, ::ge::ATTR_NAME_UNKNOWN_SHAPE_TYPE, unknown_shape_type_val); + shape_inference_type = static_cast(unknown_shape_type_val); + + GE_CHK_STATUS_RET(NodeUtils::GetNodeUnknownShapeStatus(*node, is_dynamic), "[%s] Failed to get shape status.", + node->GetName().c_str()); + + if (is_dynamic) { + for (int i = 0; i < num_inputs; ++i) { + const auto &input_desc = op_desc->MutableInputDesc(i); + GE_CHECK_NOTNULL(input_desc); + if (input_desc->MutableShape().IsUnknownShape()) { + is_input_shape_static.push_back(false); + } else { + num_static_input_shapes++; + is_input_shape_static.push_back(true); + GELOGD("[%s] The shape of input[%d] is static. shape = [%s]", NodeName().c_str(), i, + input_desc->MutableShape().ToString().c_str()); + } + } + + for (int i = 0; i < num_outputs; ++i) { + const auto &output_desc = op_desc->MutableOutputDesc(i); + GE_CHECK_NOTNULL(output_desc); + if (output_desc->MutableShape().IsUnknownShape()) { + is_output_shape_static = false; + break; + } + } + } + + return SUCCESS; +} + +bool NodeItem::IsControlOp() const { + auto op_type = op_desc->GetType(); + return op_type == IF || op_type == CASE || op_type == WHILE || op_type == FOR; +} + std::string NodeItem::DebugString() const { std::stringstream ss; ss << "Node: "; ss << "id = " << node_id; - ss << ", name = " << node->GetName(); - ss << ", type = " << node->GetType(); + ss << ", name = [" << node->GetName(); + ss << "], type = " << node->GetType(); ss << ", is_dynamic = " << (is_dynamic ? "True" : "False"); + ss << ", is_output_static = " << (is_output_shape_static ? "True" : "False"); ss << ", unknown_shape_op_type = " << shape_inference_type; ss << ", input_start = " << input_start; ss << ", num_inputs = " << num_inputs; ss << ", output_start = " << output_start; ss << ", num_outputs = " << num_outputs; ss << ", dependent_nodes = ["; - for (const auto &dep_node : dependent_node_list) { + for (const auto &dep_node : dependents_for_shape_inference) { ss << dep_node->GetName() << ", "; } ss << "]"; @@ -55,5 +100,17 @@ std::string NodeItem::DebugString() const { return ss.str(); } + +void NodeItem::SetToDynamic() { + num_static_input_shapes = 0; + is_dynamic = true; + for (size_t i = 0; i < is_input_shape_static.size(); ++i) { + is_input_shape_static[i] = false; + } + if (kernel_task != nullptr && !kernel_task->IsSupportDynamicShape()) { + GELOGD("[%s] Dynamic shape is not supported, clear node task.", node_name.c_str()); + kernel_task = nullptr; + } +} } // namespace hybrid -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/hybrid/model/node_item.h b/src/ge/hybrid/model/node_item.h index b12d100b..ff024b36 100644 --- a/src/ge/hybrid/model/node_item.h +++ b/src/ge/hybrid/model/node_item.h @@ -18,6 +18,7 @@ #define GE_HYBRID_MODEL_NODE_ITEM_H_ #include +#include "external/ge/ge_api_error_codes.h" #include "graph/node.h" #include "graph/op_desc.h" #include "framework/common/types.h" @@ -33,10 +34,18 @@ struct NodeItem { explicit NodeItem(NodePtr node); ~NodeItem() = default; + Status Init(); + const std::string &NodeName() const { return node_name; } const std::string &NodeType() const { return node_type; } + bool IsControlOp() const; + + bool NeedInfershape() const; + + void SetToDynamic(); + std::string DebugString() const; NodePtr node; @@ -52,17 +61,22 @@ struct NodeItem { UnknowShapeOpType shape_inference_type = DEPEND_IN_SHAPE; std::string node_name; std::string node_type; - std::vector dependent_node_list; + std::vector dependents_for_shape_inference; + std::vector dependents_for_execution; std::set to_const_output_id_list; - // src_output_id, dst_anchor_id, dst_node vector inputs; + // src_output_id, dst_anchor_id, dst_node vector>> outputs; std::shared_ptr kernel_task; const NodeExecutor *node_executor = nullptr; - std::map const_input_shapes; std::map ref_outputs; + std::map reuse_inputs; + + std::vector is_input_shape_static; + bool is_output_shape_static = true; + int num_static_input_shapes = 0; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/aicore/aicore_node_executor.cc b/src/ge/hybrid/node_executor/aicore/aicore_node_executor.cc index 3f198bba..71280649 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_node_executor.cc +++ b/src/ge/hybrid/node_executor/aicore/aicore_node_executor.cc @@ -16,10 +16,8 @@ #include "aicore_node_executor.h" #include "cce/taskdown_common.hpp" -#include "graph/debug/ge_attr_define.h" -#include "hybrid/model/hybrid_model.h" +#include "hybrid/executor/hybrid_execution_context.h" #include "init/gelib.h" -#include "framework/common/debug/log.h" namespace ge { namespace hybrid { @@ -27,16 +25,47 @@ REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::AICORE, AiCore AiCoreNodeTask::AiCoreNodeTask(std::vector> &&tasks) : tasks_(std::move(tasks)) {} +Status AiCoreNodeExecutor::Initialize() { + auto ge_lib = GELib::GetInstance(); + GE_CHECK_NOTNULL(ge_lib); + if (!ge_lib->InitFlag()) { + GELOGE(GE_CLI_GE_NOT_INITIALIZED, "Ge_lib is uninitialized, failed."); + return GE_CLI_GE_NOT_INITIALIZED; + } + + auto &kernel_manager = ge_lib->OpsKernelManagerObj(); + auto aic_ops_store = kernel_manager.GetOpsKernelInfoStore("AIcoreEngine"); + GE_CHECK_NOTNULL(aic_ops_store); + + compiler_.reset(new (std::nothrow) AiCoreTaskCompiler(aic_ops_store)); + GE_CHECK_NOTNULL(compiler_); + return SUCCESS; +} + Status AiCoreNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const { GE_CHECK_NOTNULL(node); - GELOGI("AiCoreNodeExecutor[%s] LoadTask Start.", node->GetName().c_str()); + GELOGI("AiCoreNodeExecutor(%s) LoadTask Start.", node->GetName().c_str()); auto *task_defs = model.GetTaskDefs(node); - Status ret = SUCCESS; - GE_IF_BOOL_EXEC(task_defs != nullptr && !task_defs->empty(), ret = CreateTask(model, *task_defs, node, task)); + if (task_defs == nullptr || task_defs->empty()) { + bool dynamic_flag = false; + if (!AttrUtils::GetBool(node->GetOpDesc(), "support_dynamicshape", dynamic_flag) || !dynamic_flag) { + GELOGD("Skip create task of node (%s) as 'support_dynamicshape' is false and cann't get task_defs.", + node->GetName().c_str()); + return SUCCESS; + } else { + GELOGE(FAILED, "Task_defs is empty for node (%s) which 'support_dynamicshape' is true, failed.", + node->GetName().c_str()); + return FAILED; + } + } - GELOGI("AiCoreNodeExecutor[%s] LoadTask End, ret[%u].", node->GetName().c_str(), ret); - return ret; + AiCoreTaskBuilder builder(node->GetOpDesc(), *task_defs); + std::unique_ptr node_task; + GE_CHK_STATUS_RET(builder.BuildTask(node_task, true), "[%s] Failed to build op tasks.", node->GetName().c_str()); + task = std::move(node_task); + GELOGI("AiCoreNodeExecutor(%s) LoadTask End.", node->GetName().c_str()); + return SUCCESS; } Status AiCoreNodeExecutor::GenNodeKey(const NodePtr &node, std::string &node_key) { @@ -45,18 +74,21 @@ Status AiCoreNodeExecutor::GenNodeKey(const NodePtr &node, std::string &node_key GE_CHECK_NOTNULL(op_desc); // make sure unique, (op_id + input_shape) is unique - node_key = std::to_string(op_desc->GetId()) + "/"; + node_key = std::to_string(op_desc->GetId()) + "-"; node_key.append(std::to_string(op_desc->GetInputsSize())); - auto input_descs = op_desc->GetAllInputsDesc(); - for (auto input_desc : input_descs) { - node_key.push_back('/'); - std::vector dims = input_desc.GetShape().GetDims(); - GE_IF_BOOL_EXEC(dims.size() == 0, continue); // scalar - for (std::size_t i = 0; i < dims.size() - 1; i++) { - node_key.append(std::to_string(dims[i])); - node_key.push_back(','); + auto input_descs = op_desc->GetAllInputsDescPtr(); + for (auto &input_desc : input_descs) { + node_key.push_back('-'); + auto &shape = input_desc->MutableShape(); + auto num_dims = shape.GetDimNum(); + if (num_dims == 0) { + continue; + } // scalar + for (std::size_t i = 0; i < num_dims - 1; i++) { + node_key.append(std::to_string(shape.GetDim(i))); + node_key.push_back('_'); } - node_key.append(std::to_string(dims[dims.size() - 1])); + node_key.append(std::to_string(shape.GetDim(num_dims - 1))); } return SUCCESS; } @@ -65,8 +97,10 @@ bool AiCoreNodeTaskRegistry::AddTask(const std::string &node_key, const std::sha GE_CHECK_NOTNULL(task); std::lock_guard lock(mutex_); auto iter = reg_node_tasks_.find(node_key); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(iter != reg_node_tasks_.end(), return false, - "AiCoreNodeTaskRegistry[%s] AddTask failed, key already exist.", node_key.c_str()); + if (iter != reg_node_tasks_.end()) { + GELOGE(FAILED, "AiCoreNodeTaskRegistry(%s) AddTask failed, key already exist.", node_key.c_str()); + return false; + } auto ret = reg_node_tasks_.emplace(node_key, task); return ret.second; } @@ -80,231 +114,89 @@ std::shared_ptr AiCoreNodeTaskRegistry::GetTask(const std::string &nod Status AiCoreNodeExecutor::CompileTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const { GE_CHECK_NOTNULL(node); - GELOGI("AiCoreNodeExecutor[%s] CompileTask Start.", node->GetName().c_str()); + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + GELOGI("AiCoreNodeExecutor(%s) CompileTask Start.", node->GetName().c_str()); AiCoreNodeTaskRegistry ®istry = AiCoreNodeTaskRegistry::GetInstance(); - std::string node_key; - GE_CHK_STATUS_RET(GenNodeKey(node, node_key), "GenNodeKey failed. op name = %s", node->GetName().c_str()); + std::string shape_key; + GE_CHK_STATUS_RET(GenNodeKey(node, shape_key), "GenNodeKey failed, op name = %s.", node->GetName().c_str()); + auto node_key = std::to_string(model.GetModelId()) + "/" + shape_key; GELOGD("NodeKey for %s = %s", node->GetName().c_str(), node_key.c_str()); task = registry.GetTask(node_key); - GE_CHK_TRUE_EXEC_INFO(task != nullptr, return SUCCESS, "AiCoreNodeExecutor[%s] CompileTask Skip.", - node->GetName().c_str()); + if (task != nullptr) { + GELOGI("AiCoreNodeExecutor(%s) CompileTask Skip.", node->GetName().c_str()); + return SUCCESS; + } std::vector task_defs; - GE_CHK_STATUS_RET_NOLOG(compiler_->CompileOp(node, task_defs)); + auto ori_node_name = node->GetName(); + op_desc->SetName(ori_node_name + "_" + shape_key); + GE_CHK_STATUS_RET(compiler_->CompileOp(node, task_defs), "Compile op(%s) failed.", ori_node_name.c_str()); + op_desc->SetName(ori_node_name); GELOGD("successfully generated task_defs: %s", node->GetName().c_str()); - GE_CHK_STATUS_RET_NOLOG(CreateTask(model, task_defs, node, task)); + AiCoreTaskBuilder builder(node->GetOpDesc(), task_defs); + std::unique_ptr node_task; + GE_CHK_STATUS_RET(builder.BuildTask(node_task, false), "[%s] Failed to build op tasks.", node->GetName().c_str()); + task = std::move(node_task); GELOGD("successfully created node task: %s", node->GetName().c_str()); - GE_CHK_BOOL_EXEC(registry.AddTask(node_key, task), return INTERNAL_ERROR, "Add NodeTask failed. op name = %s", - node->GetName().c_str()); // should not happen. - GELOGI("AiCoreNodeExecutor[%s] CompileTask End.", node->GetName().c_str()); - return SUCCESS; -} - -Status AiCoreNodeExecutor::BuildAiCoreTask(const domi::KernelDef &kernel_def, const OpDescPtr &op_desc, - AiCoreOpTask **task) { - GE_CHECK_NOTNULL(op_desc); - GE_CHECK_NOTNULL(task); - - const auto &context = kernel_def.context(); - auto kernel_type = static_cast(context.kernel_type()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(kernel_type != cce::ccKernelType::TE, return UNSUPPORTED, - "Only TBE kernel is supported, but [%s] got %u", op_desc->GetName().c_str(), - context.kernel_type()); - - auto *aicore_task = new (std::nothrow) AiCoreOpTask(); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aicore_task == nullptr, return MEMALLOC_FAILED, "Create AiCore op task failed."); - - auto builder = AiCoreTaskBuilder(op_desc, kernel_def); - auto ret = builder.BuildTask(*aicore_task); - GE_IF_BOOL_EXEC(ret != SUCCESS, delete aicore_task; aicore_task = nullptr; return ret); - - *task = aicore_task; - return SUCCESS; -} - -Status AiCoreNodeExecutor::CreateTask(const HybridModel &model, const std::vector &task_defs, - const NodePtr &node, std::shared_ptr &task) { - GE_CHECK_NOTNULL(node); - GELOGD("To CreateTask, task def size = %zu", task_defs.size()); - std::vector> aicore_op_tasks; - aicore_op_tasks.reserve(task_defs.size()); - for (size_t i = 0; i < task_defs.size(); ++i) { - const domi::TaskDef &task_def = task_defs[i]; - GELOGD("Op[%s] Task[%d], type = %u, DebugString = %s", node->GetName().c_str(), i, task_def.type(), - task_def.DebugString().c_str()); - auto task_type = static_cast(task_def.type()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(task_type == RT_MODEL_TASK_KERNEL_EX, return UNSUPPORTED, - "BuildKernelExTask is not supported"); - GE_CHK_BOOL_TRUE_EXEC_INFO(task_type != RT_MODEL_TASK_KERNEL, continue, "Skip task type %d", - static_cast(task_type)); - - const domi::KernelDef &kernel_def = task_def.kernel(); - AiCoreOpTask *aicore_op_task = nullptr; - // not use hybrid model now - GE_CHK_STATUS_RET_NOLOG(BuildAiCoreTask(kernel_def, node->GetOpDesc(), &aicore_op_task)); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aicore_op_task == nullptr, return FAILED, "BuildAiCoreTask[%s] failed.", - node->GetName().c_str()); - - aicore_op_tasks.emplace_back(std::unique_ptr(aicore_op_task)); + if (!registry.AddTask(node_key, task)) { + GELOGE(INTERNAL_ERROR, "Add NodeTask failed, op name = %s.", node->GetName().c_str()); + return INTERNAL_ERROR; } - if (!aicore_op_tasks.empty()) { - auto aic_task = std::shared_ptr(new AiCoreNodeTask(std::move(aicore_op_tasks))); - task = std::move(aic_task); - GELOGD("Generate AiCoreOpTask success"); - return SUCCESS; - } - - GELOGE(INTERNAL_ERROR, "Failed to build task. node = %s", node->GetName().c_str()); - return INTERNAL_ERROR; -} - -Status AiCoreNodeExecutor::Initialize() { - std::shared_ptr ge_lib = GELib::GetInstance(); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG((ge_lib == nullptr) || !ge_lib->InitFlag(), return GE_CLI_GE_NOT_INITIALIZED, - "Get ge_lib failed."); - - auto &kernel_manager = ge_lib->OpsKernelManagerObj(); - auto aic_ops_store = kernel_manager.GetOpsKernelInfoStore("AIcoreEngine"); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aic_ops_store == nullptr, return GE_CLI_GE_NOT_INITIALIZED, - "Failed to get kernel info store for AIcoreEngine."); - - compiler_.reset(new (std::nothrow) AiCoreTaskCompiler(aic_ops_store)); - GE_CHECK_NOTNULL(compiler_); + GELOGI("AiCoreNodeExecutor(%s) CompileTask End.", node->GetName().c_str()); return SUCCESS; } -Status AiCoreNodeExecutor::Finalize() { return NodeExecutor::Finalize(); } - Status AiCoreNodeTask::ExecuteAsync(TaskContext &context, std::function done_callback) { auto op_desc = context.GetNodeItem().op_desc; GE_CHECK_NOTNULL(op_desc); - GELOGI("AiCoreNodeTask[%s] ExecuteAsync Start.", op_desc->GetName().c_str()); - for (size_t i = 0; i < tasks_.size(); i++) { - GE_CHECK_NOTNULL(tasks_[i]); - GE_CHK_STATUS_RET_NOLOG(tasks_[i]->LaunchKernel(context.GetStream())); + GELOGI("[%s] ExecuteAsync Start.", op_desc->GetName().c_str()); + for (auto &task : tasks_) { + GE_CHK_STATUS_RET_NOLOG(task->LaunchKernel(context.GetStream())); } if (done_callback != nullptr) { GE_CHK_STATUS_RET_NOLOG(context.RegisterCallback(done_callback)); } - GELOGI("AiCoreNodeTask[%s] ExecuteAsync End.", op_desc->GetName().c_str()); + GELOGD("[%s] ExecuteAsync End.", op_desc->GetName().c_str()); return SUCCESS; } -Status AiCoreNodeTask::UpdateAtomicArgs(TaskContext &context, std::unique_ptr &task) { - GE_CHECK_NOTNULL(task); +Status AiCoreNodeTask::UpdateArgs(TaskContext &context) { auto op_desc = context.GetNodeItem().op_desc; GE_CHECK_NOTNULL(op_desc); - - // refresh atomic output addr - std::vector atomic_output_indexes; // here atomic just clean output - (void)ge::AttrUtils::GetListInt(op_desc, ge::ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indexes); - GE_RETURN_WITH_LOG_IF_TRUE(atomic_output_indexes.size() > static_cast(context.NumOutputs()), - "AtomicAddrClean op's arg_size error."); - auto *arg_off = reinterpret_cast(task->args_.get()) + task->offset_; - auto *arg_base = reinterpret_cast(arg_off); - int index = 0; - for (size_t i = 0; i < atomic_output_indexes.size(); ++i) { - const auto output = context.GetOutput(atomic_output_indexes[i]); - GE_CHECK_NOTNULL(output); - arg_base[index++] = reinterpret_cast(output->GetData()); + GELOGI("[%s] AiCoreNodeTask UpdateArgs Start.", op_desc->GetName().c_str()); + for (auto &task : tasks_) { + GE_CHK_STATUS_RET_NOLOG(task->UpdateArgs(context)); } - - // refresh atomic workspace addr - auto workspace_sizes = op_desc->GetWorkspaceBytes(); - uint64_t ops_workspace_num = static_cast(workspace_sizes.size()); - uint64_t workspace_num = static_cast(context.NumWorkspaces()); - GE_CHK_BOOL_EXEC(ops_workspace_num == workspace_num, return PARAM_INVALID, - "The workspace_num in op_desc %lu is not equal to it %lu in context.", ops_workspace_num, - workspace_num); - GE_IF_BOOL_EXEC(workspace_num == 0, return SUCCESS); - - map> workspace_info; - workspace_info = op_desc->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); - if (!workspace_info.empty()) { - bool is_fusion_node = false; - (void)ge::AttrUtils::GetBool(op_desc, ATOMIC_ATTR_IS_FUSION_NODE, is_fusion_node); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(is_fusion_node, return PARAM_INVALID, - "Atomic desc[%s] shouldn't be fusion_node in AiCoreNodeTask", - op_desc->GetName().c_str()); - - for (auto iter = workspace_info.begin(); iter != workspace_info.end(); ++iter) { - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(op_desc->GetName() != iter->first, return PARAM_INVALID, - "The node name %s and the node name %s in workspace info are inconsistent.", - op_desc->GetName().c_str(), iter->first.c_str()); - GE_IF_BOOL_EXEC(iter->second.empty(), continue); - - for (auto &info_iter : iter->second) { - auto workspace_index = static_cast(info_iter.first); - - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(workspace_index >= workspace_num, return PARAM_INVALID, - "The workspace index %lu is more than the size %lu of workspace vector.", - workspace_index, workspace_num); - - const auto workspace = context.MutableWorkspace(workspace_index); - arg_base[index++] = reinterpret_cast(workspace); - } - } - } - + GELOGI("[%s] AiCoreNodeTask UpdateArgs End.", op_desc->GetName().c_str()); return SUCCESS; } -Status AiCoreNodeTask::UpdateAllArgs(TaskContext &context, std::unique_ptr &task) { - GE_CHECK_NOTNULL(task); - auto *arg_off = reinterpret_cast(task->args_.get()) + task->offset_; - auto *arg_base = reinterpret_cast(arg_off); - int index = 0; - for (int i = 0; i < context.NumInputs(); ++i) { - const auto input = context.GetInput(i); - GE_CHECK_NOTNULL(input); - arg_base[index++] = reinterpret_cast(input->GetData()); - } - - for (int i = 0; i < context.NumOutputs(); ++i) { - const auto output = context.GetOutput(i); - GE_CHECK_NOTNULL(output); - arg_base[index++] = reinterpret_cast(output->GetData()); - } - - auto op_desc = context.GetNodeItem().op_desc; - GE_CHECK_NOTNULL(op_desc); - auto workspace_sizes = op_desc->GetWorkspaceBytes(); - int ops_workspace_num = static_cast(workspace_sizes.size()); - int workspace_num = static_cast(context.NumWorkspaces()); - GE_CHK_BOOL_EXEC(ops_workspace_num == workspace_num, return PARAM_INVALID, - "The workspace_num in op_desc %lu is not equal to it %lu in context.", ops_workspace_num, - workspace_num); - for (int i = 0; i < workspace_num; ++i) { - const auto workspace = context.MutableWorkspace(i); - arg_base[index++] = reinterpret_cast(workspace); +Status AiCoreNodeTask::UpdateTilingData(TaskContext &context) { + GELOGD("[%s] PrepareWithShape started", context.GetNodeName()); + for (auto &task : tasks_) { + GE_CHK_STATUS_RET_NOLOG(task->PrepareWithShape(context)); } - + GELOGD("[%s] Done PrepareWithShape successfully.", context.GetNodeName()); return SUCCESS; } -Status AiCoreNodeTask::UpdateArgs(TaskContext &context) { - auto op_desc = context.GetNodeItem().op_desc; - GE_CHECK_NOTNULL(op_desc); - GELOGI("AiCoreNodeTask[%s] UpdateArgs Start.", op_desc->GetName().c_str()); - GE_IF_BOOL_EXEC(tasks_.size() == 1, return UpdateAllArgs(context, tasks_[0])); - - std::vector atomic_output_indexes; // here atomic just clean output - (void)ge::AttrUtils::GetListInt(op_desc, ge::ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indexes); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(atomic_output_indexes.empty(), return FAILED, "ATOMIC_ATTR_OUTPUT_INDEX is empty."); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(tasks_.size() != 2, return FAILED, "AtomicAddrClean op task num != 2."); - - GE_CHK_STATUS_RET_NOLOG(UpdateAtomicArgs(context, tasks_[0])); - GE_CHK_STATUS_RET_NOLOG(UpdateAllArgs(context, tasks_[1])); +bool AiCoreNodeTask::IsSupportDynamicShape() { + for (size_t i = 0; i < tasks_.size(); ++i) { + if (!tasks_[i]->IsDynamicShapeSupported()) { + GELOGD("[%s] Task does not support dynamic shape.", tasks_[i]->GetName().c_str()); + return false; + } + } - GELOGI("AiCoreNodeTask[%s] UpdateArgs End.", op_desc->GetName().c_str()); - return SUCCESS; + return true; } } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/aicore/aicore_node_executor.h b/src/ge/hybrid/node_executor/aicore/aicore_node_executor.h index a8b24e68..506202fa 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_node_executor.h +++ b/src/ge/hybrid/node_executor/aicore/aicore_node_executor.h @@ -25,7 +25,6 @@ namespace ge { namespace hybrid { - class AiCoreNodeTaskRegistry { public: ~AiCoreNodeTaskRegistry() = default; @@ -47,32 +46,27 @@ class AiCoreNodeTaskRegistry { class AiCoreNodeTask : public NodeTask { public: explicit AiCoreNodeTask(std::vector> &&tasks); - ~AiCoreNodeTask() = default; - Status ExecuteAsync(TaskContext &context, std::function done_callback) override; + ~AiCoreNodeTask() override = default; + bool IsSupportDynamicShape() override; + Status UpdateTilingData(TaskContext &context) override; + Status UpdateArgs(TaskContext &context) override; + Status ExecuteAsync(TaskContext &context, std::function done_callback) override; private: - static Status UpdateAllArgs(TaskContext &context, std::unique_ptr &task); - static Status UpdateAtomicArgs(TaskContext &context, std::unique_ptr &task); std::vector> tasks_; }; class AiCoreNodeExecutor : public NodeExecutor { public: Status Initialize() override; - Status Finalize() override; - Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const override; Status CompileTask(const HybridModel &model, const NodePtr &node, std::shared_ptr &task) const override; private: - static Status CreateTask(const HybridModel &model, const std::vector &task_defs, const NodePtr &node, - std::shared_ptr &task); - static Status BuildAiCoreTask(const domi::KernelDef &kernel_def, const OpDescPtr &op_desc, AiCoreOpTask **task); static Status GenNodeKey(const NodePtr &node, std::string &node_key); std::unique_ptr compiler_; }; - } // namespace hybrid } // namespace ge #endif // GE_HYBRID_KERNEL_AICORE_NODE_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/aicore/aicore_op_task.cc b/src/ge/hybrid/node_executor/aicore/aicore_op_task.cc index 27256e9a..9ec0cc22 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_op_task.cc +++ b/src/ge/hybrid/node_executor/aicore/aicore_op_task.cc @@ -14,19 +14,313 @@ * limitations under the License. */ -#include "aicore_op_task.h" +#include "hybrid/node_executor/aicore/aicore_op_task.h" +#include "cce/taskdown_common.hpp" #include "framework/common/debug/log.h" +#include "hybrid/executor/hybrid_execution_context.h" +#include "hybrid/node_executor/aicore/aicore_task_builder.h" + +using optiling::OpRunInfo; namespace ge { namespace hybrid { +namespace { +constexpr char const *kAttrSupportDynamicShape = "support_dynamicshape"; +constexpr char const *kAttrOpParamSize = "op_para_size"; +constexpr char const *kAttrAtomicOpParamSize = "atomic_op_para_size"; +} // namespace -Status AiCoreOpTask::LaunchKernel(rtStream_t stream) { - GELOGI("AiCoreOpTask LaunchKernel Start (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); +Status AiCoreOpTask::Init(const OpDesc &op_desc, const domi::TaskDef &task_def) { + GE_CHK_STATUS_RET_NOLOG(InitWithTaskDef(op_desc, task_def)); + GE_CHK_STATUS_RET_NOLOG(InitTilingInfo(op_desc)); + return SUCCESS; +} + +Status AiCoreOpTask::InitWithTaskDef(const OpDesc &op_desc, const domi::TaskDef &task_def) { + GE_CHK_STATUS_RET(ValidateTaskDef(task_def), "[%s] Failed to validate task def: [%s]", op_desc.GetName().c_str(), + task_def.DebugString().c_str()); + + const domi::KernelDef &kernel_def = task_def.kernel(); + const domi::KernelContext &context = kernel_def.context(); + stub_name_ = kernel_def.stub_func(); + GE_CHK_RT_RET(rtGetFunctionByName(stub_name_.c_str(), &stub_func_)); + args_size_ = kernel_def.args_size(); + block_dim_ = kernel_def.block_dim(); + + // malloc args memory + args_.reset(new (std::nothrow) uint8_t[args_size_]); + GE_CHECK_NOTNULL(args_); + errno_t err = memcpy_s(args_.get(), args_size_, kernel_def.args().data(), args_size_); + if (err != EOK) { + GELOGE(INTERNAL_ERROR, "AiCoreTask memcpy args failed."); + return INTERNAL_ERROR; + } + + if (context.args_offset().size() < sizeof(uint16_t)) { + GELOGE(INTERNAL_ERROR, "Invalid args_offset, size = %zu.", context.args_offset().size()); + return INTERNAL_ERROR; + } + + const auto *args_offset_buffer = reinterpret_cast(context.args_offset().data()); + uint32_t offset = *args_offset_buffer; + if (offset > args_size_) { + GELOGE(INTERNAL_ERROR, "[%s] Arg offset out of range. offset = %u, arg size = %u", GetName().c_str(), offset, + args_size_); + return INTERNAL_ERROR; + } + + arg_base_ = reinterpret_cast(args_.get() + offset); + max_arg_count_ = (args_size_ - offset) / sizeof(void *); + GELOGD("[%s] Done setting kernel args successfully. stub_func = %s, block_dim = %d, arg base = %p, arg size = %u", + op_desc.GetName().c_str(), stub_name_.c_str(), block_dim_, arg_base_, args_size_); + + return SUCCESS; +} + +Status AiCoreOpTask::ValidateTaskDef(const domi::TaskDef &task_def) { + auto task_type = static_cast(task_def.type()); + if (task_type != RT_MODEL_TASK_KERNEL) { + GELOGE(INTERNAL_ERROR, "Invalid task type (%d) in AiCore CreateTask.", static_cast(task_type)); + return INTERNAL_ERROR; + } + + const domi::KernelDef &kernel_def = task_def.kernel(); + const domi::KernelContext &context = kernel_def.context(); + auto kernel_type = static_cast(context.kernel_type()); + if (kernel_type != cce::ccKernelType::TE) { + GELOGE(INTERNAL_ERROR, "Invalid kernel type(%d) in AiCore TaskDef.", static_cast(kernel_type)); + return INTERNAL_ERROR; + } + + return SUCCESS; +} + +Status AiCoreOpTask::PrepareWithShape(TaskContext &context) { + if (tiling_buffer_ != nullptr) { + return UpdateTilingInfo(context); + } + + return SUCCESS; +} + +Status AiCoreOpTask::UpdateTilingInfo(TaskContext &context) { + auto node = context.GetNodeItem().node; + GE_CHECK_NOTNULL(node); + auto op_desc = node->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + + GELOGD("[%s] Start to update tiling info for task: [%s]", node->GetName().c_str(), stub_name_.c_str()); + OpRunInfo tiling_info; + tiling_info.block_dim = -1; // codex: Using uninitialized value + + auto execution_context = context.GetExecutionContext(); + RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CalcTilingInfo] Start"); + GE_CHK_STATUS_RET(CalcTilingInfo(node, tiling_info)); + RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CalcTilingInfo] End"); + + // update op args by tiling info + block_dim_ = static_cast(tiling_info.block_dim); + op_desc->SetWorkspaceBytes(tiling_info.workspaces); + + tiling_data_ = tiling_info.tiling_data.str(); + if (tiling_data_.empty()) { + GELOGE(INTERNAL_ERROR, "[%s] Tiling data is empty.", stub_name_.c_str()); + return INTERNAL_ERROR; + } + + if (tiling_data_.size() > tiling_buffer_->GetSize()) { + GELOGE(INTERNAL_ERROR, "[%s] Tiling data size now (%zu) shouldn't larger than we alloc before (%zu).", + stub_name_.c_str(), tiling_data_.size(), tiling_buffer_->GetSize()); + return INTERNAL_ERROR; + } + + RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CopyTilingInfo] Start"); + GE_CHK_RT_RET(rtMemcpy(tiling_buffer_->GetData(), tiling_buffer_->GetSize(), tiling_data_.c_str(), + tiling_data_.size(), RT_MEMCPY_HOST_TO_DEVICE)); + RECORD_EXECUTION_EVENT(execution_context, context.GetNodeName(), "[CopyTilingInfo] End"); + + GELOGD("[%s] Done updating tiling info for task: [%s]", node->GetName().c_str(), stub_name_.c_str()); + return SUCCESS; +} + +Status AiCoreOpTask::CalcTilingInfo(const NodePtr &node, OpRunInfo &tiling_info) { + GELOGD("[%s] Start to invoke OpParaCalculate.", node->GetName().c_str()); + GE_CHK_STATUS_RET(OpParaCalculate(*node, tiling_info), "Failed calc tiling data of node %s.", + node->GetName().c_str()); + GELOGD("[%s] Done invoking OpParaCalculate successfully.", node->GetName().c_str()); + return SUCCESS; +} + +Status AiCoreOpTask::UpdateArgs(TaskContext &task_context) { + size_t expected_arg_count = task_context.NumInputs() + task_context.NumOutputs() + task_context.NumWorkspaces(); + if (tiling_buffer_ != nullptr) { + ++expected_arg_count; + } + if (expected_arg_count > max_arg_count_) { + GELOGE(INTERNAL_ERROR, "[%s] Invalid arg memory, max arg count = %u, but expect = %zu", GetName().c_str(), + max_arg_count_, expected_arg_count); + return INTERNAL_ERROR; + } + + int index = 0; + for (int i = 0; i < task_context.NumInputs(); ++i) { + const auto input = task_context.GetInput(i); + GE_CHECK_NOTNULL(input); + arg_base_[index++] = reinterpret_cast(input->GetData()); + } + for (int i = 0; i < task_context.NumOutputs(); ++i) { + const auto output = task_context.GetOutput(i); + GE_CHECK_NOTNULL(output); + arg_base_[index++] = reinterpret_cast(output->GetData()); + } + + int workspace_num = static_cast(task_context.NumWorkspaces()); + for (int i = 0; i < workspace_num; ++i) { + const auto workspace = task_context.MutableWorkspace(i); + GE_CHECK_NOTNULL(workspace); + arg_base_[index++] = reinterpret_cast(workspace); + } + + if (tiling_buffer_ != nullptr) { + arg_base_[index++] = reinterpret_cast(tiling_buffer_->GetData()); + } + + if (task_context.IsTraceEnabled()) { + for (int i = 0; i < index; ++i) { + GELOGD("[%s] Arg[%d] = %lu", stub_name_.c_str(), i, arg_base_[i]); + } + } + + return SUCCESS; +} + +Status AiCoreOpTask::LaunchKernel(rtStream_t stream) { + GELOGD("AiCoreOpTask LaunchKernel Start (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); GE_CHK_RT_RET(rtKernelLaunch(stub_func_, block_dim_, args_.get(), args_size_, nullptr, stream)); - GELOGI("AiCoreOpTask LaunchKernel End (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); + GELOGD("AiCoreOpTask LaunchKernel End (task = %s, block_dim = %u).", stub_name_.c_str(), block_dim_); return SUCCESS; } +Status AiCoreOpTask::InitTilingInfo(const OpDesc &op_desc) { + bool dynamic_supported = false; + (void)AttrUtils::GetBool(op_desc, kAttrSupportDynamicShape, dynamic_supported); + if (!dynamic_supported) { + GELOGD("[%s] Dynamic shape is not supported.", op_desc.GetName().c_str()); + return SUCCESS; + } + + GELOGD("Start alloc tiling data of node %s.", op_desc.GetName().c_str()); + int64_t max_size = -1; + (void)AttrUtils::GetInt(op_desc, GetKeyForOpParamSize(), max_size); + GELOGD("Got op param size by key: %s, ret = %ld", GetKeyForOpParamSize().c_str(), max_size); + if (max_size <= 0) { + GELOGE(PARAM_INVALID, "[%s] Invalid op_param_size: %ld.", op_desc.GetName().c_str(), max_size); + return PARAM_INVALID; + } + + auto allocator = NpuMemoryAllocator::GetAllocator(); + GE_CHECK_NOTNULL(allocator); + tiling_buffer_ = TensorBuffer::Create(allocator, static_cast(max_size)); + GE_CHECK_NOTNULL(tiling_buffer_); + + GELOGD("[%s] Done allocating tiling buffer, size=%ld.", op_desc.GetName().c_str(), max_size); + return SUCCESS; +} + +bool AiCoreOpTask::IsDynamicShapeSupported() { return tiling_buffer_ != nullptr; } + +const std::string &AiCoreOpTask::GetName() const { return stub_name_; } + +std::string AiCoreOpTask::GetKeyForOpParamSize() const { return kAttrOpParamSize; } + +Status AtomicAddrCleanOpTask::Init(const OpDesc &op_desc, const domi::TaskDef &task_def) { + GE_CHK_STATUS_RET_NOLOG(AiCoreOpTask::Init(op_desc, task_def)); + return InitAtomicAddrCleanIndices(op_desc); +} + +Status AtomicAddrCleanOpTask::InitAtomicAddrCleanIndices(const OpDesc &op_desc) { + GELOGD("[%s] Start to setup AtomicAddrClean task.", op_desc.GetName().c_str()); + std::vector atomic_output_indices; + (void)ge::AttrUtils::GetListInt(op_desc, ATOMIC_ATTR_OUTPUT_INDEX, atomic_output_indices); + map> workspace_info; // op_name, ws_index, ws_offset + workspace_info = op_desc.TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); + if (atomic_output_indices.empty() && workspace_info.empty()) { + GELOGE(INTERNAL_ERROR, "[%s] Neither ATOMIC_ATTR_OUTPUT_INDEX nor EXT_ATTR_ATOMIC_WORKSPACE_INFO is empty.", + op_desc.GetName().c_str()); + return INTERNAL_ERROR; + } + + for (auto output_index : atomic_output_indices) { + GELOGD("[%s] Adding output index [%ld]", op_desc.GetName().c_str(), output_index); + GE_CHECK_GE(output_index, 0); + GE_CHECK_LE(output_index, INT32_MAX); + atomic_output_indices_.emplace_back(static_cast(output_index)); + } + + for (auto &iter : workspace_info) { + for (auto &info_iter : iter.second) { + auto workspace_index = info_iter.first; + GELOGD("[%s] Adding workspace index [%ld]", op_desc.GetName().c_str(), workspace_index); + GE_CHECK_GE(workspace_index, 0); + GE_CHECK_LE(workspace_index, INT32_MAX); + atomic_workspace_indices_.emplace_back(static_cast(workspace_index)); + } + } + + size_t arg_count = atomic_workspace_indices_.size() + atomic_output_indices_.size(); + if (tiling_buffer_ != nullptr) { + arg_count += 1; + } + + if (arg_count > max_arg_count_) { + GELOGE(INTERNAL_ERROR, "[%s] Invalid arg memory, max arg count = %u, but expect = %zu", GetName().c_str(), + max_arg_count_, arg_count); + return INTERNAL_ERROR; + } + + return SUCCESS; +} + +std::string AtomicAddrCleanOpTask::GetKeyForOpParamSize() const { return kAttrAtomicOpParamSize; } + +Status AtomicAddrCleanOpTask::CalcTilingInfo(const NodePtr &node, OpRunInfo &tiling_info) { + GELOGD("[%s] Start to invoke OpAtomicCalculate.", node->GetName().c_str()); + GE_CHK_STATUS_RET(OpAtomicCalculate(*node, tiling_info), "Failed calc tiling data of node %s.", + node->GetName().c_str()); + GELOGD("[%s] Done invoking OpAtomicCalculate successfully.", node->GetName().c_str()); + return SUCCESS; +} + +Status AtomicAddrCleanOpTask::UpdateArgs(TaskContext &task_context) { + // refresh atomic output addr + int index = 0; + for (auto atomic_output_index : atomic_output_indices_) { + const auto output_tensor = task_context.GetOutput(atomic_output_index); + GE_CHECK_NOTNULL(output_tensor); + arg_base_[index++] = reinterpret_cast(output_tensor->GetData()); + } + + // refresh atomic workspace addr + for (auto atomic_ws_index : atomic_workspace_indices_) { + const auto workspace_tensor = task_context.GetOutput(atomic_ws_index); + GE_CHECK_NOTNULL(workspace_tensor); + arg_base_[index++] = reinterpret_cast(workspace_tensor->GetData()); + } + + if (tiling_buffer_ != nullptr) { + arg_base_[index++] = reinterpret_cast(tiling_buffer_->GetData()); + } else { + GELOGD("[%s] Not a dynamic op", GetName().c_str()); + } + + if (task_context.IsTraceEnabled()) { + for (int i = 0; i < index; ++i) { + GELOGD("[%s] Arg[%d] = %lu", GetName().c_str(), i, arg_base_[i]); + } + } + + return SUCCESS; +} } // namespace hybrid -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/hybrid/node_executor/aicore/aicore_op_task.h b/src/ge/hybrid/node_executor/aicore/aicore_op_task.h index d23688a5..41ab0d79 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_op_task.h +++ b/src/ge/hybrid/node_executor/aicore/aicore_op_task.h @@ -18,27 +18,70 @@ #define GE_HYBRID_KERNEL_AICORE_OP_TASK_H_ #include +#include #include "common/ge_inner_error_codes.h" #include "runtime/stream.h" +#include "hybrid/common/tensor_value.h" +#include "hybrid/node_executor/task_context.h" +#include "proto/task.pb.h" +#include "register/op_tiling.h" + namespace ge { namespace hybrid { class AiCoreOpTask { public: AiCoreOpTask() = default; - ~AiCoreOpTask() = default; + virtual ~AiCoreOpTask() = default; + + virtual Status Init(const OpDesc &op_desc, const domi::TaskDef &task_def); + + bool IsDynamicShapeSupported(); + + // do preparation with shape(without actual io memory) + Status PrepareWithShape(TaskContext &context); + + virtual Status UpdateArgs(TaskContext &task_context); + Status LaunchKernel(rtStream_t stream); + const std::string &GetName() const; + + protected: + Status UpdateTilingInfo(TaskContext &context); + virtual std::string GetKeyForOpParamSize() const; + virtual Status CalcTilingInfo(const NodePtr &node, optiling::OpRunInfo &tiling_info); + + std::unique_ptr tiling_buffer_ = nullptr; + std::string tiling_data_; + uintptr_t *arg_base_ = nullptr; + uint32_t max_arg_count_ = 0; + private: - friend class AiCoreTaskBuilder; - friend class AiCoreNodeTask; + static Status ValidateTaskDef(const domi::TaskDef &task_def); + Status InitWithTaskDef(const OpDesc &node, const domi::TaskDef &task_def); + Status InitTilingInfo(const OpDesc &op_desc); + std::string stub_name_; void *stub_func_ = nullptr; std::unique_ptr args_ = nullptr; uint32_t args_size_ = 0; uint32_t block_dim_ = 1; - uint16_t offset_ = 0; }; +class AtomicAddrCleanOpTask : public AiCoreOpTask { + public: + Status Init(const OpDesc &op_desc, const domi::TaskDef &task_def) override; + Status UpdateArgs(TaskContext &task_context) override; + + protected: + std::string GetKeyForOpParamSize() const override; + Status CalcTilingInfo(const NodePtr &node, optiling::OpRunInfo &tiling_info) override; + + private: + Status InitAtomicAddrCleanIndices(const OpDesc &op_desc); + std::vector atomic_output_indices_; + std::vector atomic_workspace_indices_; +}; } // namespace hybrid } // namespace ge #endif // GE_HYBRID_KERNEL_AICORE_OP_TASK_H_ diff --git a/src/ge/hybrid/node_executor/aicore/aicore_task_builder.cc b/src/ge/hybrid/node_executor/aicore/aicore_task_builder.cc index 5b263007..bad91806 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_task_builder.cc +++ b/src/ge/hybrid/node_executor/aicore/aicore_task_builder.cc @@ -15,76 +15,78 @@ */ #include "aicore_task_builder.h" -#include -#include "graph/op_desc.h" -#include "cce/taskdown_common.hpp" -#include "framework/common/debug/log.h" -#include "graph/debug/ge_attr_define.h" +#include "common/debug/log.h" +#include "aicore_node_executor.h" namespace ge { namespace hybrid { -std::mutex g_reg_mutex; - -AiCoreTaskBuilder::AiCoreTaskBuilder(const OpDescPtr &op_desc, const domi::KernelDef &kernel_def) - : op_desc_(op_desc), kernel_def_(kernel_def) { - std::string session_graph_id; - GE_IF_BOOL_EXEC(AttrUtils::GetStr(*op_desc_, ATTR_NAME_SESSION_GRAPH_ID, session_graph_id), - GELOGD("Get original type of session_graph_id.")); - // get bin_file_key - stub_name_ = (session_graph_id.empty()) ? op_desc_->GetName() : session_graph_id + "_" + op_desc_->GetName(); -} - -Status AiCoreTaskBuilder::SetKernelArgs(AiCoreOpTask &task) { - const domi::KernelContext &context = kernel_def_.context(); - // get kernel_type - auto kernel_type = static_cast(context.kernel_type()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(kernel_type != cce::ccKernelType::TE, return UNSUPPORTED, - "Invalid kernel type[%d] in AiCore TaskDef.", static_cast(kernel_type)); - - task.args_size_ = kernel_def_.args_size(); - task.block_dim_ = kernel_def_.block_dim(); - - // malloc args memory - task.args_.reset(new (std::nothrow) uint8_t[task.args_size_]); - // task.args_ = std::make_unique(task.args_size_); - GE_CHECK_NOTNULL(task.args_); - errno_t err = memcpy_s(task.args_.get(), task.args_size_, kernel_def_.args().data(), task.args_size_); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(err != EOK, return INTERNAL_ERROR, "AiCoreTask memcpy failed."); - - const auto *args_offset_tmp = reinterpret_cast(const_cast(context.args_offset().data())); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(context.args_offset().size() / sizeof(uint16_t) < 1, return FAILED, - "context.args_offset().size() / sizeof(uint16_t) less than 1"); - task.offset_ = *args_offset_tmp; - return SUCCESS; +namespace { +const size_t kNumTaskWithAtomicAddrCleanTask = 2; } - const char *AiCoreKernelRegistry::GetUnique(const string &stub_key) { std::lock_guard lock(mutex_); auto it = unique_stubs_.find(stub_key); - GE_IF_BOOL_EXEC(it != unique_stubs_.end(), return it->c_str()); + if (it != unique_stubs_.end()) { + return it->c_str(); + } it = unique_stubs_.insert(unique_stubs_.end(), stub_key); return it->c_str(); } -Status AiCoreTaskBuilder::SetStub(AiCoreOpTask &task) { - AiCoreKernelRegistry ®istry = AiCoreKernelRegistry::GetInstance(); - std::lock_guard lock(g_reg_mutex); - const char *unique_key = registry.GetUnique(stub_name_); +AiCoreTaskBuilder::AiCoreTaskBuilder(const OpDescPtr &op_desc, const std::vector &task_defs) + : op_desc_(op_desc), task_defs_(task_defs) {} - GE_CHK_RT_RET(rtGetFunctionByName(unique_key, &(task.stub_func_))); - task.stub_name_ = stub_name_; +Status AiCoreTaskBuilder::BuildTask(std::unique_ptr &node_task, bool ignore_failure_on_atomic) { + GE_CHECK_NOTNULL(op_desc_); + if (task_defs_.size() > kNumTaskWithAtomicAddrCleanTask) { + GELOGE(INTERNAL_ERROR, "[%s] At most 2 task was supported, but got %zu", op_desc_->GetName().c_str(), + task_defs_.size()); + return INTERNAL_ERROR; + } - return SUCCESS; -} + std::vector> op_tasks; + if (ExpectAtomicAddrCleanTask()) { + if (task_defs_.size() != kNumTaskWithAtomicAddrCleanTask) { + if (ignore_failure_on_atomic) { + GELOGI("[%s] AtomicAddrClean task was expected, but got %zu task_defs", op_desc_->GetName().c_str(), + task_defs_.size()); + return SUCCESS; + } else { + GELOGE(INTERNAL_ERROR, "[%s] AtomicAddrClean task was expected, but got %zu task_defs", + op_desc_->GetName().c_str(), task_defs_.size()); + return INTERNAL_ERROR; + } + } -Status AiCoreTaskBuilder::BuildTask(AiCoreOpTask &task) { - GE_CHECK_NOTNULL(op_desc_); - GELOGI("AiCoreTaskBuilder[%s] BuildTask Start.", op_desc_->GetName().c_str()); - GE_CHK_STATUS_RET_NOLOG(SetKernelArgs(task)); - GE_CHK_STATUS_RET_NOLOG(SetStub(task)); - GELOGI("AiCoreTaskBuilder[%s] BuildTask End.", op_desc_->GetName().c_str()); + GELOGD("[%s] Build AtomicAddrClean task.", op_desc_->GetName().c_str()); + auto atomic_task = std::unique_ptr(new (std::nothrow) AtomicAddrCleanOpTask()); + GE_CHECK_NOTNULL(atomic_task); + GE_CHK_STATUS_RET(atomic_task->Init(*op_desc_, task_defs_.front()), "[%s] Failed to init task for AtomicAddrClean", + op_desc_->GetName().c_str()); + op_tasks.emplace_back(std::move(atomic_task)); + } + + // build aicore task + auto aicore_task = std::unique_ptr(new (std::nothrow) AiCoreOpTask()); + GE_CHECK_NOTNULL(aicore_task); + GE_CHK_STATUS_RET(aicore_task->Init(*op_desc_, task_defs_.back()), "[%s] Failed to init task for AtomicAddrClean", + op_desc_->GetName().c_str()); + op_tasks.emplace_back(std::move(aicore_task)); + + node_task.reset(new (std::nothrow) AiCoreNodeTask(std::move(op_tasks))); + GE_CHECK_NOTNULL(node_task); return SUCCESS; } +bool AiCoreTaskBuilder::ExpectAtomicAddrCleanTask() { + if (op_desc_->HasAttr(ATOMIC_ATTR_OUTPUT_INDEX)) { + GELOGD("[%s] Node has ATOMIC_ATTR_OUTPUT_INDEX", op_desc_->GetName().c_str()); + return true; + } + map> workspace_info; + workspace_info = op_desc_->TryGetExtAttr(EXT_ATTR_ATOMIC_WORKSPACE_INFO, workspace_info); + + return !workspace_info.empty(); +} } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/aicore/aicore_task_builder.h b/src/ge/hybrid/node_executor/aicore/aicore_task_builder.h index 18cb309c..4610e57a 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_task_builder.h +++ b/src/ge/hybrid/node_executor/aicore/aicore_task_builder.h @@ -17,14 +17,13 @@ #ifndef GE_HYBRID_KERNEL_AICORE_TASK_BUILDER_H_ #define GE_HYBRID_KERNEL_AICORE_TASK_BUILDER_H_ -#include +#include #include -#include -#include #include "aicore_op_task.h" -#include "proto/task.pb.h" +#include "framework/common/debug/ge_log.h" #include "graph/utils/attr_utils.h" #include "graph/op_kernel_bin.h" +#include "proto/task.pb.h" namespace ge { namespace hybrid { @@ -45,16 +44,16 @@ class AiCoreKernelRegistry { class AiCoreTaskBuilder { public: - AiCoreTaskBuilder(const OpDescPtr &op_desc, const domi::KernelDef &kernel_def); + AiCoreTaskBuilder(const OpDescPtr &op_desc, const std::vector &task_defs); ~AiCoreTaskBuilder() = default; - Status BuildTask(AiCoreOpTask &task); + + Status BuildTask(std::unique_ptr &node_task, bool ignore_failure_on_atomic); private: - Status SetKernelArgs(AiCoreOpTask &task); - Status SetStub(AiCoreOpTask &task); - const OpDescPtr &op_desc_; - const domi::KernelDef &kernel_def_; - std::string stub_name_; + bool ExpectAtomicAddrCleanTask(); + + OpDescPtr op_desc_; + const std::vector &task_defs_; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/aicore/aicore_task_compiler.cc b/src/ge/hybrid/node_executor/aicore/aicore_task_compiler.cc index ac89afbd..588f179d 100644 --- a/src/ge/hybrid/node_executor/aicore/aicore_task_compiler.cc +++ b/src/ge/hybrid/node_executor/aicore/aicore_task_compiler.cc @@ -34,7 +34,6 @@ Status AiCoreTaskCompiler::DoCompileOp(OpsKernelInfoStore &ops_store, const Node GE_CHECK_NOTNULL(node); vector node_vec; node_vec.emplace_back(node); - std::lock_guard lk(mu_); GE_CHK_STATUS_RET(ops_store.CompileOpRun(node_vec), "Failed to execute CompileOp, node = %s", node->GetName().c_str()); GE_CHK_STATUS_RET(ops_store.CalcOpRunningParam(*node), "Failed to execute CalcOpRunningParam, node = %s", @@ -44,9 +43,8 @@ Status AiCoreTaskCompiler::DoCompileOp(OpsKernelInfoStore &ops_store, const Node Status AiCoreTaskCompiler::CompileOp(const NodePtr &node, std::vector &tasks) const { GE_CHECK_NOTNULL(node); - GELOGI("AiCoreTaskCompiler[%s] CompileOp Start.", node->GetName().c_str()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(aic_kernel_store_ == nullptr, return FAILED, - "Failed to get AiCore kernel store, node = %s", node->GetName().c_str()); + GELOGI("AiCoreTaskCompiler(%s) CompileOp Start.", node->GetName().c_str()); + GE_CHECK_NOTNULL(aic_kernel_store_); GE_CHK_STATUS_RET_NOLOG(DoCompileOp(*aic_kernel_store_, node)); GELOGD("successfully compiled op: %s", node->GetName().c_str()); @@ -56,9 +54,11 @@ Status AiCoreTaskCompiler::CompileOp(const NodePtr &node, std::vector output_offsets(op_desc->GetOutputsSize(), kMemBase); op_desc->SetInputOffset(input_offsets); op_desc->SetOutputOffset(output_offsets); + std::vector workspaces(op_desc->GetWorkspaceBytes().size(), kMemBase); + op_desc->SetWorkspace(std::move(workspaces)); GE_CHK_STATUS_RET_NOLOG(DoGenerateTask(*aic_kernel_store_, *node, tasks)); GELOGD("successfully generated task: %s", node->GetName().c_str()); - GELOGI("AiCoreTaskCompiler[%s] CompileOp End.", node->GetName().c_str()); + GELOGI("AiCoreTaskCompiler(%s) CompileOp End.", node->GetName().c_str()); return SUCCESS; } @@ -91,6 +91,5 @@ Status AiCoreTaskCompiler::DoGenerateTask(OpsKernelInfoStore &store, const Node GE_CHK_RT(rtModelDestroy(rt_model_)); return ret; } - } // namespace hybrid -} // namespace ge \ No newline at end of file +} // namespace ge diff --git a/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.cc b/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.cc index d5c3c03c..332675bf 100644 --- a/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.cc +++ b/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.cc @@ -199,6 +199,5 @@ void AicpuExtInfoHandler::GetShapeAndType(const AicpuShapeAndType *shape_and_typ data_type = static_cast(shape_and_type->type); shape = std::move(GeShape(dims)); } - } // namespace hybrid } // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.h b/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.h index e96d794c..a42678b1 100644 --- a/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.h +++ b/src/ge/hybrid/node_executor/aicpu/aicpu_ext_info.h @@ -24,7 +24,6 @@ namespace ge { namespace hybrid { - using AicpuShapeAndType = aicpu::FWKAdapter::ShapeAndType; using AicpuExtInfo = aicpu::FWKAdapter::ExtInfo; diff --git a/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.cc b/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.cc index 372f35f5..46d9a0aa 100644 --- a/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.cc +++ b/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.cc @@ -40,19 +40,28 @@ Status AicpuNodeTaskBase::AllocTensorBuffer(size_t size, std::unique_ptris_dynamic) { + // dynamic node must have ext info + GE_CHK_STATUS_RET(aicpu_ext_handle_.Parse(kernel_ext_info), + "Node[%s] parse kernel ext info failed, kernel_ext_info_size=%zu.", node_name_.c_str(), + kernel_ext_info.size()); + } + + // if no ext info no need copy to device. + if (kernel_ext_info.empty()) { + GELOGI("Node[%s] kernel_ext_info is empty, no need copy to device, is_dynamic=%s.", node_name_.c_str(), + node_item_->is_dynamic ? "true" : "false"); + return SUCCESS; + } // copy task args buf GE_CHK_STATUS_RET(AllocTensorBuffer(kernel_ext_info.size(), ext_info_addr_dev_), "Node[%s] alloc kernel_ext_info buf failed, size=%zu", node_name_.c_str(), kernel_ext_info.size()); - // if no input and no output(DEPEND_COMPUTE equal no output), copy once, or else copy when update args. - if (node_item_->num_inputs == 0 && ((unknown_type_ == DEPEND_COMPUTE) || (node_item_->num_outputs == 0))) { - GE_CHK_RT_RET(rtMemcpy(ext_info_addr_dev_->GetData(), ext_info_addr_dev_->GetSize(), kernel_ext_info.data(), - kernel_ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE)); - } + // copy default ext info to device + GE_CHK_RT_RET(rtMemcpy(ext_info_addr_dev_->GetData(), ext_info_addr_dev_->GetSize(), kernel_ext_info.data(), + kernel_ext_info.size(), RT_MEMCPY_HOST_TO_DEVICE)); + return SUCCESS; } @@ -139,16 +148,18 @@ Status AicpuNodeTaskBase::UpdateExtInfo() { } Status AicpuNodeTaskBase::UpdateArgs(TaskContext &context) { - GELOGI("Node[%s] update args begin. unknown_type=%d", node_name_.c_str(), unknown_type_); + GELOGI("Node[%s] update args begin. is_dynamic=%s, unknown_type=%d", node_name_.c_str(), + node_item_->is_dynamic ? "true" : "false", unknown_type_); if (node_item_->num_inputs == 0 && node_item_->num_outputs == 0) { GELOGI("Node[%s] has no input and output, no need update args.", node_name_.c_str()); return SUCCESS; } GE_CHK_STATUS_RET(UpdateIoAddr(context), "Node[%s] update io addr failed.", node_name_.c_str()); - - GE_CHK_STATUS_RET(UpdateExtInfo(), "Node[%s] update ext info failed.", node_name_.c_str()); - + if (node_item_->is_dynamic) { + // dynamic node need update ext info. + GE_CHK_STATUS_RET(UpdateExtInfo(), "Node[%s] update ext info failed.", node_name_.c_str()); + } GELOGI("Node[%s] update args end.", node_name_.c_str()); return SUCCESS; } @@ -275,9 +286,12 @@ Status AicpuTfNodeTask::Init(const HybridModel &model) { fwk_op_kernel.fwkKernelBase.fwk_kernel.workspaceBaseAddr = reinterpret_cast(kernel_workspace_->GetData()); fwk_op_kernel.fwkKernelBase.fwk_kernel.inputOutputAddr = reinterpret_cast(input_output_addr_->GetData()); - // set ext info addr and ext info num - fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast(ext_info_addr_dev_->GetData()); - fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoLen = ext_info_addr_dev_->GetSize(); + + if (ext_info_addr_dev_ != nullptr) { + // set ext info addr and ext info num + fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoAddr = reinterpret_cast(ext_info_addr_dev_->GetData()); + fwk_op_kernel.fwkKernelBase.fwk_kernel.extInfoLen = ext_info_addr_dev_->GetSize(); + } fwk_op_kernel.fwkKernelBase.fwk_kernel.stepIDAddr = GetStepIdAddr(model); @@ -506,7 +520,8 @@ Status AicpuTfNodeTask::UpdateIoAddr(TaskContext &context) { io_addrs.emplace_back(reinterpret_cast(inputData->GetData())); } - if (unknown_type_ != DEPEND_COMPUTE) { + // known shape or not depend compute + if (!node_item_->is_dynamic || unknown_type_ != DEPEND_COMPUTE) { // unknown type 4 do this in call back. GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); for (auto j = 0; j < node_item_->num_outputs; ++j) { @@ -548,14 +563,17 @@ Status AicpuTfNodeTask::LaunchTask(TaskContext &context) { } Status AicpuTfNodeTask::TaskCallback(TaskContext &context) { - GELOGI("Node[%s] task callback start. unknown_type=%d.", node_name_.c_str(), unknown_type_); + GELOGI("Node[%s] task callback start. is_dynamic=%s, unknown_type=%d.", node_name_.c_str(), + node_item_->is_dynamic ? "true" : "false", unknown_type_); Status callback_ret = SUCCESS; - // check need update shape, call update shape. - if (unknown_type_ == DEPEND_SHAPE_RANGE) { - // check result - callback_ret = UpdateOutputShapeFromExtInfo(); - } else if (unknown_type_ == DEPEND_COMPUTE) { - callback_ret = UpdateShapeAndDataByResultSummary(context); + if (node_item_->is_dynamic) { + // check need update shape, call update shape. + if (unknown_type_ == DEPEND_SHAPE_RANGE) { + // check result + callback_ret = UpdateOutputShapeFromExtInfo(); + } else if (unknown_type_ == DEPEND_COMPUTE) { + callback_ret = UpdateShapeAndDataByResultSummary(context); + } } GELOGI("Node[%s] task callback end.", node_name_.c_str()); return callback_ret; @@ -612,8 +630,13 @@ Status AicpuNodeTask::Init(const HybridModel &model) { GE_CHK_STATUS_RET(InitExtInfo(kernel_ext_info), "Node[%s] init ext info failed.", node_name.c_str()); - aicpu_param_head->extInfoLength = ext_info_addr_dev_->GetSize(); - aicpu_param_head->extInfoAddr = reinterpret_cast(ext_info_addr_dev_->GetData()); + if (ext_info_addr_dev_ == nullptr) { + aicpu_param_head->extInfoLength = 0; + aicpu_param_head->extInfoAddr = 0; + } else { + aicpu_param_head->extInfoLength = ext_info_addr_dev_->GetSize(); + aicpu_param_head->extInfoAddr = reinterpret_cast(ext_info_addr_dev_->GetData()); + } GELOGI("Node[%s] init end.", node_name.c_str()); return SUCCESS; @@ -664,10 +687,12 @@ Status AicpuNodeTask::LaunchTask(TaskContext &context) { } Status AicpuNodeTask::TaskCallback(TaskContext &context) { - GELOGI("Node[%s] task callback start, unknown_type=%d.", node_name_.c_str(), unknown_type_); + GELOGI("Node[%s] task callback start, is_dynamic = %s, unknown_type=%d.", node_name_.c_str(), + node_item_->is_dynamic ? "true" : "false", unknown_type_); Status callback_ret = SUCCESS; + // check need update shape, call update shape. - if (unknown_type_ == DEPEND_SHAPE_RANGE) { + if (node_item_->is_dynamic && unknown_type_ == DEPEND_SHAPE_RANGE) { // check result callback_ret = UpdateOutputShapeFromExtInfo(); } else { diff --git a/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.h b/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.h index ce3f9707..8aca6ff7 100644 --- a/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.h +++ b/src/ge/hybrid/node_executor/aicpu/aicpu_node_executor.h @@ -24,7 +24,6 @@ namespace ge { namespace hybrid { - class AicpuNodeTaskBase : public NodeTask { public: AicpuNodeTaskBase(const NodeItem *node_item, const domi::TaskDef &task_def) @@ -70,8 +69,10 @@ class AicpuNodeTaskBase : public NodeTask { const std::string node_type_; + // valid when node_item_->is_dynamic is true UnknowShapeOpType unknown_type_ = DEPEND_IN_SHAPE; + // valid when node_item_->is_dynamic is true AicpuExtInfoHandler aicpu_ext_handle_; // ext info addr, device mem @@ -169,7 +170,6 @@ class AiCpuNodeExecutor : public NodeExecutor { Status PrepareTask(NodeTask &task, TaskContext &context) const override; }; - } // namespace hybrid } // namespace ge #endif // GE_HYBRID_KERNEL_AICPU_NODE_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/compiledsubgraph/known_node_executor.cc b/src/ge/hybrid/node_executor/compiledsubgraph/known_node_executor.cc index 81960c48..2e1893f2 100644 --- a/src/ge/hybrid/node_executor/compiledsubgraph/known_node_executor.cc +++ b/src/ge/hybrid/node_executor/compiledsubgraph/known_node_executor.cc @@ -26,7 +26,6 @@ namespace ge { namespace hybrid { - REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::COMPILED_SUBGRAPH, KnownNodeExecutor); Status KnownNodeTask::ExecuteAsync(TaskContext &context, std::function done_callback) { @@ -50,19 +49,12 @@ Status KnownNodeTask::ExecuteAsync(TaskContext &context, std::function d rtError_t rt_ret; GELOGI("rtModelExecute start."); - rt_ret = rtModelExecute(davinci_model_->GetRtModelHandle(), davinci_model_->GetRtModelStream(), 0); + rt_ret = rtModelExecute(davinci_model_->GetRtModelHandle(), context.GetStream(), 0); GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtModelExecute error, ret: Ox%X", rt_ret); return FAILED;); GELOGI("rtModelExecute end"); - GELOGI("rtStreamSynchronize start."); - rt_ret = rtStreamSynchronize(davinci_model_->GetRtModelStream()); - GE_IF_BOOL_EXEC(rt_ret != RT_ERROR_NONE, GELOGE(rt_ret, "rtStreamSynchronize error, ret: Ox%X", rt_ret); - return FAILED;); - GELOGI("rtStreamSynchronize end."); - context.RegisterCallback(done_callback); GELOGI("[%s] KnownNodeTask::ExecuteAsync success.", context.GetNodeName()); - return SUCCESS; } @@ -89,7 +81,8 @@ Status KnownNodeTask::UpdateArgs(TaskContext &context) { GE_CHK_STATUS_RET(davinci_model_->UpdateKnownNodeArgs(inputs, outputs), "known node task update known node args failed."); - GELOGI("[%s] KnownNodeExecutor::UpdateArgs success.", context.GetNodeName()); + GELOGI("[%s] KnownNodeExecutor::UpdateArgs success, task_size = %d:", context.GetNodeName(), + davinci_model_->GetTaskList().size()); return SUCCESS; } @@ -98,13 +91,22 @@ Status KnownNodeTask::Init(TaskContext &context) { GE_CHK_STATUS_RET(context.AllocateOutputs(), "known node task allocate output failed."); // init davinicmodel - davinci_model_->InitRuntimeParams(); - GE_CHK_STATUS_RET(davinci_model_->InitVariableMem(), "init variable mem failed."); + if (!load_flag_) { + davinci_model_->InitRuntimeParams(); + GE_CHK_STATUS_RET(davinci_model_->InitVariableMem(), "init variable mem failed."); + } + // allocate mem base void *buffer = nullptr; if (davinci_model_->TotalMemSize() != 0) { - GE_CHK_STATUS_RET(context.AllocateWorkspace(davinci_model_->TotalMemSize(), &buffer), - "known node task allocate workspace failed."); + GE_CHK_STATUS_RET( + context.AllocateWorkspace(davinci_model_->TotalMemSize(), &buffer, davinci_model_->GetRuntimeParam().mem_base), + "known node task allocate workspace failed."); + bool addr_not_changed = false; + if (davinci_model_->GetRuntimeParam().mem_base == buffer) { + addr_not_changed = true; + } + davinci_model_->SetKnownNodeAddrNotChanged(addr_not_changed); // update mem base davinci_model_->UpdateMemBase(static_cast(buffer)); GELOGI("KnownNodeTask::Init mem base is %p, size %u.", davinci_model_->GetRuntimeParam().mem_base, @@ -124,7 +126,6 @@ Status KnownNodeTask::Init(TaskContext &context) { Status KnownNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { GELOGI("[%s] KnownNodeExecutor::PrepareTask in.", context.GetNodeName()); - GE_CHK_STATUS_RET(task.Init(context), "known node init davinci model failed."); GE_CHK_STATUS_RET(task.UpdateArgs(context), "known node task update args failed."); @@ -161,6 +162,5 @@ Status KnownNodeExecutor::ExecuteTask(NodeTask &task, TaskContext &context, context.GetNodeItem().NodeName().c_str()); return SUCCESS; } - } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/controlop/control_op_executor.cc b/src/ge/hybrid/node_executor/controlop/control_op_executor.cc new file mode 100644 index 00000000..aee7fb77 --- /dev/null +++ b/src/ge/hybrid/node_executor/controlop/control_op_executor.cc @@ -0,0 +1,344 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "control_op_executor.h" +#include "graph/utils/node_utils.h" +#include "hybrid/executor/hybrid_execution_context.h" +#include "hybrid/executor/subgraph_executor.h" + +namespace ge { +namespace hybrid { +REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::CONTROL_OP, ControlOpNodeExecutor); + +Status ControlOpNodeTask::ExecuteSubgraph(const GraphItem *subgraph, TaskContext &task_context, + const std::function &done_callback) { + GELOGD("[%s] Start to execute subgraph.", subgraph->GetName().c_str()); + auto execution_context = const_cast(task_context.GetExecutionContext()); + auto executor = MakeShared(subgraph, execution_context); + GE_CHECK_NOTNULL(executor); + GE_CHK_STATUS_RET(executor->ExecuteAsync(task_context), "[%s] Failed to execute partitioned call.", + subgraph->GetName().c_str()); + + auto callback = [executor, done_callback]() mutable { + if (done_callback != nullptr) { + done_callback(); + } + // executor must outlive task context + executor.reset(); + }; + + GE_CHK_STATUS_RET_NOLOG(task_context.RegisterCallback(callback)); + GELOGD("[%s] Done executing subgraph successfully.", subgraph->GetName().c_str()); + return SUCCESS; +} + +Status ControlOpNodeTask::CopyTensorValueToHost(const TensorValue &tensor, int32_t &value) { + GE_CHECK_NOTNULL(tensor.GetData()); + GE_CHECK_GE(tensor.GetSize(), sizeof(value)); + GE_CHK_RT_RET(rtMemcpy(&value, sizeof(value), tensor.GetData(), sizeof(value), RT_MEMCPY_DEVICE_TO_HOST)); + return SUCCESS; +} + +Status ControlOpNodeTask::UpdateArgs(TaskContext &context) { + // do nothing + return SUCCESS; +} + +Status ControlOpNodeTask::ExecuteAsync(TaskContext &task_context, std::function done_callback) { + auto ret = DoExecuteAsync(task_context, done_callback); + task_context.SetStatus(ret); + + if (done_callback) { + done_callback(); + } + + return ret; +} + +Status IfOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { + GELOGD("[%s] Start to init IfOpNodeTask.", node->GetName().c_str()); + auto then_subgraph = NodeUtils::GetSubgraph(*node, kThenBranchIndex); + GE_CHECK_NOTNULL(then_subgraph); + GELOGD("[%s] Adding subgraph [%s] to then-subgraph.", node->GetName().c_str(), then_subgraph->GetName().c_str()); + then_ = model.GetSubgraphItem(then_subgraph); + GE_CHECK_NOTNULL(then_); + + auto else_subgraph = NodeUtils::GetSubgraph(*node, kElseBranchIndex); + GE_CHECK_NOTNULL(else_subgraph); + GELOGD("[%s] Adding subgraph [%s] to else-subgraph.", node->GetName().c_str(), else_subgraph->GetName().c_str()); + else_ = model.GetSubgraphItem(else_subgraph); + GE_CHECK_NOTNULL(else_); + + GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); + return SUCCESS; +} + +const GraphItem *IfOpNodeTask::SelectBranch(int32_t cond) const { return cond != 0 ? then_ : else_; } + +Status IfOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const { + auto cond_tensor = task_context.GetInput(kIfCondIndex); + GE_CHECK_NOTNULL(cond_tensor); + int32_t cond_val = 0; + GE_CHK_STATUS_RET(CopyTensorValueToHost(*cond_tensor, cond_val), "[%s] Failed to get cond value.", + task_context.GetNodeName()); + + auto subgraph = SelectBranch(cond_val); + GELOGD("[%s] Taking subgraph [%s] by cond = [%d]", task_context.GetNodeName(), subgraph->GetName().c_str(), cond_val); + GE_CHK_STATUS_RET(ExecuteSubgraph(subgraph, task_context, done_callback), + "[%s] Failed to execute subgraph. cond = %d", task_context.GetNodeName(), cond_val); + + GELOGD("[%s] Done executing with cond = %d successfully.", task_context.GetNodeName(), cond_val); + return SUCCESS; +} + +Status CaseOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { + size_t num_subgraphs = node->GetOpDesc()->GetSubgraphInstanceNames().size(); + GE_CHECK_LE(num_subgraphs, kMaxBranchNum); + GE_CHECK_GE(num_subgraphs, kMinBranchNum); + auto num_branches = static_cast(num_subgraphs); + GELOGD("[%s] Start to init CaseOpNodeTask with %u branches.", node->GetName().c_str(), num_branches); + + for (uint32_t i = 0; i < num_branches; ++i) { + auto sub_graph = NodeUtils::GetSubgraph(*node, i); + GE_CHECK_NOTNULL(sub_graph); + auto graph_item = model.GetSubgraphItem(sub_graph); + GE_CHECK_NOTNULL(graph_item); + GELOGD("[%s] Adding subgraph [%s] to branch %u.", node->GetName().c_str(), sub_graph->GetName().c_str(), i); + subgraphs_.emplace_back(graph_item); + } + + GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); + return SUCCESS; +} + +const GraphItem *CaseOpNodeTask::SelectBranch(int32_t branch_index) const { + // subgraphs_ is non-empty. checked int Init + if (branch_index < 0 || static_cast(branch_index) >= subgraphs_.size()) { + GELOGI("Branch index out of range. index = %d, num_subgraphs = %zu, will taking last branch.", branch_index, + subgraphs_.size()); + branch_index = subgraphs_.size() - 1; + } + + return subgraphs_[branch_index]; +} + +Status CaseOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const { + auto branch_tensor = task_context.GetInput(kCaseBranchIndex); + GE_CHECK_NOTNULL(branch_tensor); + int32_t branch_index = 0; + GE_CHK_STATUS_RET(CopyTensorValueToHost(*branch_tensor, branch_index), "[%s] Failed to get branch index.", + task_context.GetNodeName()); + + const GraphItem *subgraph = SelectBranch(branch_index); + GELOGI("[%s] Taking subgraph [%s] by branch = [%d]", task_context.GetNodeName(), subgraph->GetName().c_str(), + branch_index); + + std::vector inputs; + std::vector outputs; + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto input_tensor = task_context.GetInput(i); + GE_CHECK_NOTNULL(input_tensor); + inputs.emplace_back(*input_tensor); + } + + GE_CHK_STATUS_RET(ExecuteSubgraph(subgraph, task_context, done_callback), "[%s] Failed to execute else-subgraph.", + task_context.GetNodeName()); + + GELOGD("[%s] Done executing subgraph[%d] successfully.", task_context.GetNodeName(), branch_index); + return SUCCESS; +} + +Status WhileOpNodeTask::Init(const NodePtr &node, const HybridModel &model) { + GELOGD("[%s] Start to init WhileOpNodeTask.", node->GetName().c_str()); + auto cond_subgraph = NodeUtils::GetSubgraph(*node, kCondBranchIndex); + GE_CHECK_NOTNULL(cond_subgraph); + GELOGD("[%s] Adding subgraph [%s] to cond-subgraph.", node->GetName().c_str(), cond_subgraph->GetName().c_str()); + cond_ = model.GetSubgraphItem(cond_subgraph); + GE_CHECK_NOTNULL(cond_); + + auto body_subgraph = NodeUtils::GetSubgraph(*node, kBodyBranchIndex); + GE_CHECK_NOTNULL(body_subgraph); + GELOGD("[%s] Adding subgraph [%s] to body-subgraph.", node->GetName().c_str(), body_subgraph->GetName().c_str()); + body_ = model.GetSubgraphItem(body_subgraph); + GE_CHECK_NOTNULL(body_); + + GELOGD("[%s] Done initialization successfully.", node->GetName().c_str()); + return SUCCESS; +} + +Status WhileOpNodeTask::DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const { + if (task_context.NumInputs() != task_context.NumOutputs()) { + GELOGE(INTERNAL_ERROR, "[%s] Invalid while args. num_inputs = %d, num_outputs = %d", task_context.GetNodeName(), + task_context.NumInputs(), task_context.NumOutputs()); + return INTERNAL_ERROR; + } + + bool is_continue = false; + GE_CHK_STATUS_RET(ExecuteOneLoop(task_context, is_continue), "[%s] Failed to execute iteration 0.", + task_context.GetNodeName()); + if (!is_continue) { + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto input_tensor = task_context.GetInput(i); + auto input_tensor_desc = task_context.GetInputDesc(i); + auto output_tensor_desc = task_context.MutableOutputDesc(i); + GE_CHECK_NOTNULL(input_tensor); + GE_CHECK_NOTNULL(input_tensor_desc); + GE_CHECK_NOTNULL(output_tensor_desc); + GE_CHK_STATUS_RET_NOLOG(task_context.SetOutput(i, *input_tensor)); + *output_tensor_desc = *input_tensor_desc; + } + + return SUCCESS; + } + + // backup original input tensor desc + std::vector ori_input_desc; + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto tensor_desc = task_context.GetInputDesc(i); + GE_CHECK_NOTNULL(tensor_desc); + ori_input_desc.emplace_back(*tensor_desc); + } + + int iteration = 1; + while (true) { + GELOGD("[%s] Start to execute, iteration = %d", task_context.GetNodeName(), iteration); + GE_CHK_STATUS_RET(ExecuteOneLoop(task_context, is_continue), "[%s] Failed to execute iteration %d.", + task_context.GetNodeName(), iteration); + + if (!is_continue) { + GELOGD("[%s] Quit from loop. current iteration = %d", task_context.GetNodeName(), iteration); + break; + } + + ++iteration; + } + + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto input_tensor = task_context.GetInput(i); + auto tensor_desc = task_context.MutableInputDesc(i); + GE_CHECK_NOTNULL(input_tensor); + GE_CHECK_NOTNULL(tensor_desc); + // restore original input tensor desc + *tensor_desc = std::move(ori_input_desc[i]); + GE_CHK_STATUS_RET_NOLOG(task_context.SetOutput(i, *input_tensor)); + } + + return SUCCESS; +} + +Status WhileOpNodeTask::ExecuteCond(TaskContext &task_context, bool &is_continue) const { + std::vector inputs; + std::vector input_desc; + std::vector output_desc; + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto input_tensor = task_context.GetInput(i); + GE_CHECK_NOTNULL(input_tensor); + inputs.emplace_back(*input_tensor); + input_desc.emplace_back(task_context.GetInputDesc(i)); + } + + auto execution_context = const_cast(task_context.GetExecutionContext()); + auto executor = MakeShared(cond_, execution_context, task_context.IsForceInferShape()); + GE_CHECK_NOTNULL(executor); + GELOGD("[%s] Start to execute cond-subgraph.", task_context.GetNodeName()); + GE_CHK_STATUS_RET(executor->ExecuteAsync(inputs, input_desc), "Failed to execute partitioned call."); + GELOGD("[%s] Done executing cond-subgraph successfully.", cond_->GetName().c_str()); + GE_CHK_STATUS_RET_NOLOG(task_context.RegisterCallback([executor]() mutable { executor.reset(); })); + + // get cond output + GE_CHK_STATUS_RET(executor->Synchronize(), "[%s] Failed to sync cond-subgraph result.", cond_->GetName().c_str()); + std::vector cond_outputs; + GE_CHK_STATUS_RET(executor->GetOutputs(cond_outputs), "[%s] Failed to get cond-output.", cond_->GetName().c_str()); + if (cond_outputs.empty()) { + GELOGE(INTERNAL_ERROR, "[%s] Cond output is empty.", task_context.GetNodeName()); + return INTERNAL_ERROR; + } + + int cond_val = 0; + GE_CHK_STATUS_RET(CopyTensorValueToHost(cond_outputs[0], cond_val), "[%s] Failed to get cond result.", + task_context.GetNodeName()); + is_continue = cond_val != 0; + return SUCCESS; +} + +Status WhileOpNodeTask::MoveOutputs2Inputs(TaskContext &task_context) { + // set outputs to inputs for next iteration + for (int i = 0; i < task_context.NumInputs(); ++i) { + auto input_tensor = task_context.MutableInput(i); + auto output_tensor = task_context.MutableOutput(i); + GE_CHECK_NOTNULL(input_tensor); + GE_CHECK_NOTNULL(output_tensor); + *input_tensor = *output_tensor; + output_tensor->Destroy(); + + auto output_tensor_desc = task_context.MutableOutputDesc(i); + GE_CHECK_NOTNULL(output_tensor_desc); + GELOGD("[%s] To update input shape[%d] by output shape. from [%s] to [%s]", task_context.GetNodeName(), i, + task_context.MutableInputDesc(i)->GetShape().ToString().c_str(), + output_tensor_desc->GetShape().ToString().c_str()); + *task_context.MutableInputDesc(i) = *output_tensor_desc; + } + + return SUCCESS; +} + +Status WhileOpNodeTask::ExecuteOneLoop(TaskContext &task_context, bool &is_continue) const { + GE_CHK_STATUS_RET(ExecuteCond(task_context, is_continue), "[%s] Failed to execute cond-subgraph", + task_context.GetNodeName()); + if (!is_continue) { + return SUCCESS; + } + + GELOGD("[%s] Start to execute body-subgraph.", task_context.GetNodeName()); + GE_CHK_STATUS_RET(ExecuteSubgraph(body_, task_context, nullptr), "[%s] Failed to execute cond-subgraph", + task_context.GetNodeName()); + GELOGD("[%s] Done executing body-subgraph successfully.", task_context.GetNodeName()); + + // set outputs to inputs for next iteration + GE_CHK_STATUS_RET(MoveOutputs2Inputs(task_context), "[%s] Failed to move outputs to inputs", + task_context.GetNodeName()); + + return SUCCESS; +} + +Status ControlOpNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, + shared_ptr &task) const { + auto node_item = model.GetNodeItem(node); + GE_CHECK_NOTNULL(node_item); + + unique_ptr node_task; + auto node_type = node->GetType(); + if (node_type == IF) { + node_task.reset(new (std::nothrow) IfOpNodeTask()); + } else if (node_type == CASE) { + node_task.reset(new (std::nothrow) CaseOpNodeTask()); + } else if (node_type == WHILE) { + node_task.reset(new (std::nothrow) WhileOpNodeTask()); + } else { + GELOGE(PARAM_INVALID, "[%s] Unsupported type: %s", node->GetName().c_str(), node_type.c_str()); + return PARAM_INVALID; + } + + GE_CHECK_NOTNULL(node_task); + GE_CHK_STATUS_RET(node_task->Init(node, model), "[%s] Failed to init ControlOpNodeTask.", node->GetName().c_str()); + + task = std::move(node_task); + return SUCCESS; +} + +Status ControlOpNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { return SUCCESS; } +} // namespace hybrid +} // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/node_executor/controlop/control_op_executor.h b/src/ge/hybrid/node_executor/controlop/control_op_executor.h new file mode 100644 index 00000000..0619c6a0 --- /dev/null +++ b/src/ge/hybrid/node_executor/controlop/control_op_executor.h @@ -0,0 +1,100 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ +#define GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ + +#include +#include "hybrid/node_executor/node_executor.h" +#include "hybrid/model/graph_item.h" + +namespace ge { +namespace hybrid { +class ControlOpNodeTask : public NodeTask { + public: + virtual Status Init(const NodePtr &node, const HybridModel &model) = 0; + Status UpdateArgs(TaskContext &context) override; + + Status ExecuteAsync(TaskContext &task_context, std::function done_callback) override; + + protected: + virtual Status DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const = 0; + static Status CopyTensorValueToHost(const TensorValue &tensor_value, int32_t &value); + static Status ExecuteSubgraph(const GraphItem *subgraph, TaskContext &task_context, + const std::function &done_callback); +}; + +class IfOpNodeTask : public ControlOpNodeTask { + public: + Status Init(const NodePtr &node, const HybridModel &model) override; + + protected: + const GraphItem *SelectBranch(int32_t cond) const; + Status DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const override; + + private: + static constexpr int kIfCondIndex = 0; + static constexpr int kThenBranchIndex = 0; + static constexpr int kElseBranchIndex = 1; + + const GraphItem *then_ = nullptr; + const GraphItem *else_ = nullptr; +}; + +class CaseOpNodeTask : public ControlOpNodeTask { + public: + Status Init(const NodePtr &node, const HybridModel &model) override; + + protected: + const GraphItem *SelectBranch(int32_t branch_index) const; + Status DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const override; + + private: + static constexpr int kCaseBranchIndex = 0; + static constexpr size_t kMaxBranchNum = INT32_MAX; + static constexpr size_t kMinBranchNum = 1; + + std::vector subgraphs_; +}; + +class WhileOpNodeTask : public ControlOpNodeTask { + public: + Status Init(const NodePtr &node, const HybridModel &model) override; + + protected: + Status DoExecuteAsync(TaskContext &task_context, const std::function &done_callback) const override; + Status ExecuteCond(TaskContext &task_context, bool &is_continue) const; + + static Status MoveOutputs2Inputs(TaskContext &task_context); + + Status ExecuteOneLoop(TaskContext &task_context, bool &is_continue) const; + + private: + static constexpr int kCondBranchIndex = 0; + static constexpr int kBodyBranchIndex = 1; + + const GraphItem *cond_ = nullptr; + const GraphItem *body_ = nullptr; +}; + +class ControlOpNodeExecutor : public NodeExecutor { + public: + Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const override; + Status PrepareTask(NodeTask &task, TaskContext &context) const override; +}; +} // namespace hybrid +} // namespace ge +#endif // GE_HYBRID_CONTROLOP_CONTROL_OP_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/hccl/hccl_node_executor.cc b/src/ge/hybrid/node_executor/hccl/hccl_node_executor.cc new file mode 100644 index 00000000..f4fb7530 --- /dev/null +++ b/src/ge/hybrid/node_executor/hccl/hccl_node_executor.cc @@ -0,0 +1,207 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hccl/hccl_node_executor.h" +#include "graph/manager/util/hcom_util.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/fmk_error_codes.h" +#include "common/ge/ge_util.h" +#include "common/ge/plugin_manager.h" +#include "graph/attr_value.h" +#include "graph/debug/ge_attr_define.h" +#include "hccl/hcom.h" + +namespace ge { +namespace hybrid { + +REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::HCCL, HcclNodeExecutor); + +Status HcclNodeTask::ExecuteAsync(TaskContext &context, std::function done_callback) { + GELOGI("[%s] HcclNodeTask::ExecuteAsync in.", context.GetNodeName()); + if (context.handle_ == nullptr) { + GELOGE(FAILED, "hccl handle is nullptr! "); + return FAILED; + } + auto EnqueueHcomOpertion = (hcclResult_t(*)(HcomOpertion, std::function))dlsym( + context.handle_, "EnqueueHcomOpertion"); + if (EnqueueHcomOpertion == nullptr) { + GELOGE(FAILED, "Failed to invoke EnqueueHcomOpertion hcom unknown node function."); + if (dlclose(context.handle_) != 0) { + GELOGW("Failed to close handle %s", dlerror()); + } + return FAILED; + } + + vector inputs; + for (int i = 0; i < context.NumInputs(); ++i) { + TensorValue *tv = context.MutableInput(i); + GE_CHECK_NOTNULL(tv); + inputs.emplace_back(tv->MutableData()); + } + + vector outputs; + for (int i = 0; i < context.NumOutputs(); ++i) { + TensorValue *tv = context.MutableOutput(i); + GE_CHECK_NOTNULL(tv); + outputs.emplace_back(tv->MutableData()); + } + + const NodeItem &node_item = context.GetNodeItem(); + const OpDescPtr op_desc = MakeShared(*(node_item.op_desc)); + GE_CHECK_NOTNULL(op_desc); + + HcomOpertion op_info; + op_info.hcclType = op_desc->GetType(); + op_info.inputPtr = inputs.empty() ? nullptr : inputs[0]; + op_info.outputPtr = outputs.empty() ? nullptr : outputs[0]; + ge::DataType src_data_type = op_desc->GetInputDescPtr(0)->GetDataType(); + auto iter = kConstOpHcclDataType.find(static_cast(src_data_type)); + if (iter == kConstOpHcclDataType.end()) { + GELOGE(PARAM_INVALID, "kConstOpHcclDataType find failed."); + return PARAM_INVALID; + } + op_info.dataType = iter->second; + hcclRedOp_t op_type = HCCL_REP_OP_SUM; + if (op_desc->GetType() == HCOMALLREDUCE || op_desc->GetType() == HCOMREDUCESCATTER || + op_desc->GetType() == HVDCALLBACKALLREDUCE) { + GE_CHK_STATUS_RET(HcomOmeUtil::GetHcclOperationType(op_desc, op_type), "GetHcclOperationType failed"); + op_info.opType = op_type; + } + int64_t root_id = 0; + if (op_desc->GetType() == HCOMBROADCAST) { + GE_CHK_STATUS_RET(HcomOmeUtil::GetHcclRootId(op_desc, root_id), "GetHcclRootId failed"); + } + op_info.root = root_id; + auto callback = [this](hcclResult_t status) { + if (status != HCCL_SUCCESS) { + GELOGE(HCCL_E_INTERNAL, "Call HcomExcutorInitialize failed, ret: 0x%X", status); + } + std::lock_guard lock(this->hccl_mutex_); + this->cond_.notify_all(); + GELOGI("hccl callback success."); + }; + int32_t count = 0; + GE_CHK_STATUS_RET(HcomOmeUtil::GetHcomCount(op_desc, static_cast(op_info.dataType), false, count), + "GetHcomCount failed"); + GELOGI("[%s] HcclNodeTask::ExecuteAsync hccl_type %s, count %d, data_type %d, op_type %d, root %d.", + context.GetNodeName(), op_info.hcclType.c_str(), count, op_info.dataType, op_info.opType, op_info.root); + op_info.count = count; + + hcclResult_t hccl_ret = EnqueueHcomOpertion(op_info, callback); + if (hccl_ret != HCCL_SUCCESS) { + GELOGE(HCCL_E_INTERNAL, "Call HcomExcutorInitialize failed, ret: 0x%X", hccl_ret); + return HCCL_E_INTERNAL; + } + + // pending until hccl finished + std::unique_lock ulock(hccl_mutex_); + cond_.wait(ulock); + + context.RegisterCallback(done_callback); + GELOGI("[%s] HcclNodeTask::ExecuteAsync success.", context.GetNodeName()); + return SUCCESS; +} + +Status HcclNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } + +Status HcclNodeTask::Init(TaskContext &context) { + GELOGI("[%s] HcclNodeExecutor::Init success.", context.GetNodeName()); + return SUCCESS; +} + +Status HcclNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { + GELOGI("[%s] HcclNodeExecutor::PrepareTask in.", context.GetNodeName()); + + GE_CHK_STATUS_RET(task.Init(context), "hccl node load hccl so failed."); + // allocate output mem + GE_CHK_STATUS_RET(context.AllocateOutputs(), "hccl node task allocate output failed."); + + GE_CHK_STATUS_RET(task.UpdateArgs(context), "hccl node task update args failed."); + GELOGI("[%s] HcclNodeExecutor::PrepareTask success.", context.GetNodeName()); + return SUCCESS; +} + +Status HcclNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const { + GELOGI("[%s] HcclNodeExecutor::LoadTask in.", node->GetName().c_str()); + GE_CHECK_NOTNULL(node); + + task = MakeShared(); + GE_CHECK_NOTNULL(task); + GELOGI("[%s] HcclNodeExecutor::LoadTask success.", node->GetName().c_str()); + return SUCCESS; +} + +Status HcclNodeExecutor::ExecuteTask(NodeTask &task, TaskContext &context, + const std::function &callback) const { + context.handle_ = handle_; + GE_CHK_STATUS_RET(task.ExecuteAsync(context, callback), "Failed to execute task. node = %s", + context.GetNodeItem().NodeName().c_str()); + return SUCCESS; +} + +Status HcclNodeExecutor::Initialize() { + std::string file_name = "libhcom_graph_adaptor.so"; + std::string path = PluginManager::GetPath(); + path.append(file_name); + string canonical_path = RealPath(path.c_str()); + if (canonical_path.empty()) { + GELOGW("failed to get realpath of %s", path.c_str()); + return FAILED; + } + + GELOGI("FileName:%s, Path:%s.", file_name.c_str(), canonical_path.c_str()); + handle_ = dlopen(canonical_path.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (handle_ == nullptr) { + GELOGE(GE_PLGMGR_SO_NOT_EXIST, "Failed in dlopen %s! ", dlerror()); + return FAILED; + } + auto HcomExcutorInitialize = (hcclResult_t(*)())dlsym(handle_, "HcomExcutorInitialize"); + if (HcomExcutorInitialize == nullptr) { + GELOGE(FAILED, "Failed to invoke HcomExcutorInitialize hcom unknown node function."); + return FAILED; + } + hcclResult_t hccl_ret = HcomExcutorInitialize(); + if (hccl_ret == HCCL_E_PTR) { + GELOGI("Hccl comm is null, hcom executor initialize is not required."); + } else if (hccl_ret == HCCL_SUCCESS) { + GELOGI("Hcom executor initialize success."); + } else { + GELOGE(FAILED, "Call HcomExcutorInitialize failed, ret: 0x%X", hccl_ret); + return FAILED; + } + return SUCCESS; +} + +Status HcclNodeExecutor::Finalize() { + auto HcomExcutorFinalize = (hcclResult_t(*)())dlsym(handle_, "HcomExcutorFinalize"); + if (HcomExcutorFinalize == nullptr) { + GELOGE(FAILED, "Failed to invoke HcomExcutorFinalize hcom unknown node function."); + return FAILED; + } + hcclResult_t hccl_ret = HcomExcutorFinalize(); + if (hccl_ret != HCCL_SUCCESS) { + GELOGE(FAILED, "Call HcomExcutorFinalize failed, ret: 0x%X", hccl_ret); + return FAILED; + } + // dlclose file handle + if (dlclose(handle_) != 0) { + GELOGW("Failed to close handle %s", dlerror()); + } + GELOGI("Hcom executor finalize success."); + return SUCCESS; +} +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hccl/hccl_node_executor.h b/src/ge/hybrid/node_executor/hccl/hccl_node_executor.h new file mode 100644 index 00000000..8791c4e3 --- /dev/null +++ b/src/ge/hybrid/node_executor/hccl/hccl_node_executor.h @@ -0,0 +1,59 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef HYBRID_HCCL_NODE_EXECUTOR_H_ +#define HYBRID_HCCL_NODE_EXECUTOR_H_ +#include "hybrid/node_executor/node_executor.h" +#include "hybrid/model/hybrid_model.h" +#include "graph/op_desc.h" + +namespace ge { +namespace hybrid { +class HybridModel; + +class HcclNodeTask : public NodeTask { + public: + HcclNodeTask() {} + + ~HcclNodeTask() {} + + Status UpdateArgs(TaskContext &context) override; + Status ExecuteAsync(TaskContext &context, std::function done_callback) override; + Status Init(TaskContext &context) override; + + private: + std::shared_ptr davinci_model_ = nullptr; + bool load_flag_ = false; + std::mutex hccl_mutex_; + std::condition_variable cond_; +}; + +class HcclNodeExecutor : public NodeExecutor { + public: + Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const; + Status PrepareTask(NodeTask &task, TaskContext &context) const; + Status ExecuteTask(NodeTask &task, TaskContext &context, const std::function &callback) const; + Status Initialize() override; + Status Finalize() override; + ~HcclNodeExecutor() {} + + private: + void *handle_; +}; +} // namespace hybrid +} // namespace ge + +#endif // HYBRID_HCCL_NODE_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.cc b/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.cc new file mode 100644 index 00000000..4798b87e --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.cc @@ -0,0 +1,191 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/host_aicpu_node_executor.h" +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" +#include "graph/passes/folding_pass.h" +#include "hybrid/model/hybrid_model.h" +#include "inc/kernel_factory.h" +#include "ge_local_engine/engine/host_cpu_engine.h" + +namespace ge { +namespace hybrid { +REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::HOST_AICPU, HostAiCpuNodeExecutor); + +Status HostCpuNodeTaskBase::UpdateArgs(TaskContext &) { + // no need update args + return SUCCESS; +} + +Status HostCpuNodeTaskBase::ExecuteAsync(TaskContext &context, std::function done_callback) { + GELOGD("[%s] Start execute.", context.GetNodeName()); + + std::vector inputs; + std::vector outputs; + GE_CHK_STATUS_RET(ProcessInputs(context, inputs), "node:%s type:%s, process inputs failed.", node_->GetName().c_str(), + node_->GetType().c_str()); + GE_CHK_STATUS_RET(Execute(context, inputs, outputs), "node:%s type:%s, task execute failed.", + node_->GetName().c_str(), node_->GetType().c_str()); + GE_CHK_STATUS_RET(ProcessOutputs(context, outputs), "node:%s type:%s, process outputs failed.", + node_->GetName().c_str(), node_->GetType().c_str()); + + if (done_callback) { + GELOGD("[%s] Start invoke callback.", context.GetNodeName()); + done_callback(); + } + GELOGD("[%s] Done execute successfully.", context.GetNodeName()); + return SUCCESS; +} + +Status HostCpuNodeTaskBase::ProcessInputs(TaskContext &context, std::vector &inputs) { + int32_t input_num = context.NumInputs(); + for (auto i = 0; i < input_num; ++i) { + auto tensor_value = context.GetInput(i); + GE_CHECK_NOTNULL(tensor_value); + GeTensorPtr input_ptr = + MakeShared(node_->GetOpDesc()->GetInputDesc(i), + reinterpret_cast(tensor_value->GetData()), tensor_value->GetSize()); + if (input_ptr == nullptr) { + GELOGE(MEMALLOC_FAILED, "Make shared failed"); + return MEMALLOC_FAILED; + } + inputs.push_back(input_ptr); + } + return SUCCESS; +} + +Status HostCpuNodeTaskBase::ProcessOutputs(TaskContext &context, std::vector &outputs) { + int32_t output_num = context.NumOutputs(); + if (static_cast(output_num) != outputs.size()) { + GELOGE(INTERNAL_ERROR, "node %s type %s has %d output, but kernel compute only has %zu output.", + node_->GetName().c_str(), node_->GetType().c_str(), output_num, outputs.size()); + return INTERNAL_ERROR; + } + + // alloc output + GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); + + // copy data to output + for (auto i = 0; i < output_num; ++i) { + GeTensorPtr &tensor = outputs[i]; + GE_CHECK_NOTNULL(tensor); + auto tensor_data = tensor->GetData(); + auto tensor_value = context.MutableOutput(i); + GE_CHECK_NOTNULL(tensor_value); + if (tensor_data.GetSize() > tensor_value->GetSize()) { + GELOGE(INTERNAL_ERROR, "node:%s type:%s [%d]th compute data size=%zu, but context data size=%zu.", + node_->GetName().c_str(), node_->GetType().c_str(), i, tensor_data.GetSize(), tensor_value->GetSize()); + return INTERNAL_ERROR; + } + + GELOGI("node:%s type:%s [%d]th output data=%p, out size=%zu, data size=%zu.", node_->GetName().c_str(), + node_->GetType().c_str(), i, tensor_value->GetData(), tensor_value->GetSize(), tensor_data.GetSize()); + if (tensor_data.GetSize() > 0) { + GE_CHK_RT_RET(rtMemcpy(tensor_value->MutableData(), tensor_value->GetSize(), tensor_data.GetData(), + tensor_data.GetSize(), RT_MEMCPY_HOST_TO_HOST)); + } + GELOGI("node:%s type:%s [%d]th set data success, data size=%zu.", node_->GetName().c_str(), + node_->GetType().c_str(), i, tensor_data.GetSize()); + } + + return SUCCESS; +} + +Status CpuKernelNodeTask::Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) { + std::vector const_inputs; + for (const auto &input : inputs) { + const_inputs.emplace_back(input); + } + return FoldingPass::RunOpKernel(node_, const_inputs, outputs); +} + +Status HostKernelNodeTask::Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) { + auto kernel = KernelFactory::Instance().Create(node_->GetType()); + if (kernel == nullptr) { + GELOGE(UNSUPPORTED, "node %s type %s is not supported by host kernel.", node_->GetName().c_str(), + node_->GetType().c_str()); + return UNSUPPORTED; + } + + std::vector const_inputs; + for (const auto &input : inputs) { + const_inputs.emplace_back(input); + } + Status compute_ret = kernel->Compute(node_->GetOpDesc(), const_inputs, outputs); + if (compute_ret != SUCCESS) { + GELOGE(compute_ret, "node %s type %s compute failed or not imply.", node_->GetName().c_str(), + node_->GetType().c_str()); + return compute_ret; + } + + return SUCCESS; +} + +Status HostAiCpuNodeTask::ProcessInputs(TaskContext &context, std::vector &inputs) { return SUCCESS; } + +Status HostAiCpuNodeTask::ProcessOutputs(TaskContext &context, std::vector &outputs) { return SUCCESS; } + +Status HostAiCpuNodeTask::Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) { + RunContext run_context; + auto host_kernel = hybrid::host_aicpu::KernelFactory::Instance().CreateKernel(node_); + if (host_kernel == nullptr) { + GELOGE(UNSUPPORTED, "node %s type %s is not supported by host kernel.", node_->GetName().c_str(), + node_->GetType().c_str()); + return UNSUPPORTED; + } + + Status compute_ret = host_kernel->Compute(context); + if (compute_ret != SUCCESS) { + GELOGE(compute_ret, "node %s type %s compute failed or not imply.", node_->GetName().c_str(), + node_->GetType().c_str()); + return compute_ret; + } + + return SUCCESS; +} + +Status HostAiCpuNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { + return task.UpdateArgs(context); +} + +Status HostAiCpuNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &node, + std::shared_ptr &task) const { + GE_CHECK_NOTNULL(node); + const std::string &name = node->GetName(); + const std::string &type = node->GetType(); + if (HostCpuEngine::GetInstance().CheckSupported(type)) { + GELOGI("create CpuKernelNodeTask for node %s, type %s.", name.c_str(), type.c_str()); + task = MakeShared(node); + GE_CHECK_NOTNULL(task); + } else if (KernelFactory::Instance().Create(type) != nullptr) { + GELOGI("create HostKernelNodeTask for node %s, type %s.", name.c_str(), type.c_str()); + task = MakeShared(node); + GE_CHECK_NOTNULL(task); + } else if (hybrid::host_aicpu::KernelFactory::Instance().CreateKernel(node) != nullptr) { + GELOGI("create HostAiCpuNodeTask for node %s, type %s.", name.c_str(), type.c_str()); + task = MakeShared(node); + GE_CHECK_NOTNULL(task); + } else { + GELOGE(UNSUPPORTED, "node %s type %s is not support in HostAiCpuNodeExecutor now.", name.c_str(), type.c_str()); + return UNSUPPORTED; + } + return SUCCESS; +} +} // namespace hybrid +} // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.h b/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.h new file mode 100644 index 00000000..406d1597 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/host_aicpu_node_executor.h @@ -0,0 +1,83 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_KERNEL_HOST_AICPU_NODE_EXECUTOR_H_ +#define GE_HYBRID_KERNEL_HOST_AICPU_NODE_EXECUTOR_H_ + +#include "inc/kernel.h" +#include "hybrid/node_executor/node_executor.h" + +namespace ge { +namespace hybrid { +class HostCpuNodeTaskBase : public NodeTask { + public: + explicit HostCpuNodeTaskBase(const NodePtr &node) : node_(node) {} + ~HostCpuNodeTaskBase() = default; + virtual Status UpdateArgs(TaskContext &context); + virtual Status ExecuteAsync(TaskContext &context, std::function done_callback); + + protected: + NodePtr node_; + + private: + virtual Status Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) = 0; + virtual Status ProcessInputs(TaskContext &context, std::vector &inputs); + virtual Status ProcessOutputs(TaskContext &context, std::vector &outputs); +}; + +class CpuKernelNodeTask : public HostCpuNodeTaskBase { + public: + explicit CpuKernelNodeTask(const NodePtr &node) : HostCpuNodeTaskBase(node) {} + ~CpuKernelNodeTask() = default; + + private: + Status Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) override; +}; + +class HostKernelNodeTask : public HostCpuNodeTaskBase { + public: + explicit HostKernelNodeTask(const NodePtr &node) : HostCpuNodeTaskBase(node) {} + ~HostKernelNodeTask() = default; + + private: + Status Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) override; +}; + +class HostAiCpuNodeTask : public HostCpuNodeTaskBase { + public: + explicit HostAiCpuNodeTask(const NodePtr &node) : HostCpuNodeTaskBase(node) {} + ~HostAiCpuNodeTask() = default; + + private: + Status Execute(TaskContext &context, const std::vector &inputs, + std::vector &outputs) override; + Status ProcessInputs(TaskContext &context, std::vector &inputs) override; + Status ProcessOutputs(TaskContext &context, std::vector &outputs) override; +}; + +class HostAiCpuNodeExecutor : public NodeExecutor { + public: + Status PrepareTask(NodeTask &task, TaskContext &context) const override; + + virtual Status LoadTask(const HybridModel &model, const NodePtr &node, + std::shared_ptr &task) const override; +}; +} // namespace hybrid +} // namespace ge +#endif // GE_HYBRID_KERNEL_HOST_AICPU_NODE_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.cc b/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.cc new file mode 100644 index 00000000..02ce40e2 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.cc @@ -0,0 +1,61 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/kernel/assign_kernel.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" + +namespace { +const size_t kAssignInputNum = 2; +const size_t kAssignRefInputIndex = 0; +const size_t kAssignValueInputIndex = 1; +const size_t kAssignRefOutputIndex = 0; +} // namespace + +namespace ge { +namespace hybrid { +namespace host_aicpu { +Status AssignKernel::Compute(TaskContext& context) { + GELOGI("AssignKernel [%s, %s] compute begin.", node_->GetName().c_str(), node_->GetType().c_str()); + + auto ref_tensor = context.MutableInput(kAssignRefInputIndex); + GE_CHECK_NOTNULL(ref_tensor); + const auto value_tensor = context.GetInput(kAssignValueInputIndex); + GE_CHECK_NOTNULL(value_tensor); + if (value_tensor->GetSize() > ref_tensor->GetSize()) { + GELOGE(INTERNAL_ERROR, "[%s] value_input_size=%zu, but ref_input_size=%zu.", node_->GetName().c_str(), + value_tensor->GetSize(), ref_tensor->GetSize()); + return INTERNAL_ERROR; + } + + GELOGI("[%s] value_input_data=%p, ref_input_size=%zu, value_input_size=%zu.", node_->GetName().c_str(), + ref_tensor->GetSize(), ref_tensor->GetData(), value_tensor->GetSize()); + if (value_tensor->GetSize() > 0) { + GE_CHK_RT_RET(rtMemcpy(ref_tensor->MutableData(), ref_tensor->GetSize(), value_tensor->GetData(), + value_tensor->GetSize(), RT_MEMCPY_HOST_TO_HOST)); + } + GE_CHK_STATUS_RET(context.SetOutput(kAssignRefOutputIndex, *ref_tensor), "[%s] Failed to set output.", + context.GetNodeName()); + + GELOGI("AssignKernel [%s, %s] compute success.", node_->GetName().c_str(), node_->GetType().c_str()); + return SUCCESS; +} + +REGISTER_KERNEL_CREATOR(Assign, AssignKernel); +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.h b/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.h new file mode 100644 index 00000000..6af30926 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/assign_kernel.h @@ -0,0 +1,42 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_HOST_AICPU_KERNEL_ASSIGN_KERNEL_H_ +#define GE_HYBRID_HOST_AICPU_KERNEL_ASSIGN_KERNEL_H_ + +#include "hybrid/node_executor/hostaicpu/kernel/kernel.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +class AssignKernel : public Kernel { + public: + AssignKernel(const NodePtr &node) : Kernel(node) {} + ~AssignKernel() override = default; + AssignKernel &operator=(const AssignKernel &op) = delete; + AssignKernel(const AssignKernel &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(TaskContext &context) override; +}; +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_HOST_AICPU_KERNEL_ASSIGN_KERNEL_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/kernel.h b/src/ge/hybrid/node_executor/hostaicpu/kernel/kernel.h new file mode 100644 index 00000000..0e22f62a --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/kernel.h @@ -0,0 +1,43 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_HOST_AICPU_KERNEL_KERNEL_H_ +#define GE_HYBRID_HOST_AICPU_KERNEL_KERNEL_H_ + +#include "common/ge_inner_error_codes.h" +#include "graph/node.h" +#include "hybrid/node_executor/task_context.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +/** + * The base class for all host_kernel. + */ +class Kernel { + public: + Kernel(const NodePtr &node) : node_(node) {} + virtual ~Kernel() = default; + virtual Status Compute(TaskContext &context) = 0; + + protected: + const NodePtr &node_; +}; +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_HOST_AICPU_KERNEL_KERNEL_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.cc b/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.cc new file mode 100644 index 00000000..433f8d2f --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.cc @@ -0,0 +1,33 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/kernel/no_op_kernel.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +Status NoOpKernel::Compute(TaskContext& context) { + GELOGI("NoOpKernel [%s, %s] no need to compute.", node_->GetName().c_str(), node_->GetType().c_str()); + return SUCCESS; +} + +REGISTER_KERNEL_CREATOR(NoOp, NoOpKernel); +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.h b/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.h new file mode 100644 index 00000000..3c05c754 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/no_op_kernel.h @@ -0,0 +1,42 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_HOST_AICPU_KERNEL_NO_OP_KERNEL_H_ +#define GE_HYBRID_HOST_AICPU_KERNEL_NO_OP_KERNEL_H_ + +#include "hybrid/node_executor/hostaicpu/kernel/kernel.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +class NoOpKernel : public Kernel { + public: + NoOpKernel(const NodePtr &node) : Kernel(node) {} + ~NoOpKernel() override = default; + NoOpKernel &operator=(const NoOpKernel &op) = delete; + NoOpKernel(const NoOpKernel &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(TaskContext &context) override; +}; +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_HOST_AICPU_KERNEL_NO_OP_KERNEL_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.cc b/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.cc new file mode 100644 index 00000000..dfd8f1fe --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.cc @@ -0,0 +1,145 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.h" +#include +#include "common/fp16_t.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/utils/type_utils.h" +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +Status RandomUniformKernel::Compute(TaskContext& context) { + GELOGI("RandomUniformKernel [%s, %s] compute begin.", node_->GetName().c_str(), node_->GetType().c_str()); + int64_t seed = 0; + int64_t seed2 = 0; + (void)AttrUtils::GetInt(node_->GetOpDesc(), "seed", seed); + (void)AttrUtils::GetInt(node_->GetOpDesc(), "seed2", seed2); + DataType data_type = DT_UNDEFINED; + if (AttrUtils::GetDataType(node_->GetOpDesc(), VAR_ATTR_DTYPE, data_type) != GRAPH_SUCCESS) { + GELOGE(PARAM_INVALID, "get attr VAR_ATTR_DTYPE failed"); + return PARAM_INVALID; + } + + switch (data_type) { + case DT_FLOAT16: + if (GenerateFP16(node_->GetOpDesc(), seed, seed2, context) != SUCCESS) { + GELOGE(FAILED, "Generate random_distribution for RandomUniformOp failed, data_type=DT_FLOAT"); + return FAILED; + } + break; + case DT_FLOAT: + if (Generate(node_->GetOpDesc(), seed, seed2, context) != SUCCESS) { + GELOGE(FAILED, "Generate random_distribution for RandomUniformOp failed, data_type=DT_FLOAT"); + return FAILED; + } + break; + case DT_DOUBLE: + if (Generate(node_->GetOpDesc(), seed, seed2, context) != SUCCESS) { + GELOGE(FAILED, "Generate random_distribution for RandomUniformOp failed, data_type=DT_DOUBLE"); + return FAILED; + } + break; + default: + GELOGE(UNSUPPORTED, "Supported DataType for RandomUniformOp is DT_FLOAT16 / DT_FLOAT / DT_DOUBLE, but dtype=%s", + TypeUtils::DataTypeToSerialString(data_type).c_str()); + return UNSUPPORTED; + } + + GELOGI("RandomUniformKernel [%s, %s] compute success.", node_->GetName().c_str(), node_->GetType().c_str()); + return SUCCESS; +} + +template +Status RandomUniformKernel::Generate(const ge::OpDescPtr& op_desc_ptr, int64_t seed, int64_t seed2, + TaskContext& context) { + GE_CHECK_NOTNULL(op_desc_ptr); + // RandomUniformOp has and only has one output + int64_t data_num = op_desc_ptr->GetOutputDesc(0).GetShape().GetShapeSize(); + std::unique_ptr buf(new (std::nothrow) T[data_num]()); + if (buf == nullptr) { + GELOGE(MEMALLOC_FAILED, "New sizeof(T) * data_num(%zu) memory failed", static_cast(sizeof(T) * data_num)); + return MEMALLOC_FAILED; + } + + int64_t final_seed; + if (seed == 0) { + if (seed2 == 0) { + std::random_device rd; + final_seed = rd(); + } else { + final_seed = seed2; + } + } else { + final_seed = seed; + } + std::mt19937_64 gen(final_seed); + std::uniform_real_distribution distribution(0, 1); + for (int64_t i = 0; i < data_num; i++) { + *(buf.get() + i) = distribution(gen); + } + + std::shared_ptr output = MakeShared(buf.get(), data_num * sizeof(T)); + GE_CHECK_NOTNULL(output); + GE_CHK_STATUS_RET(context.SetOutput(0, *output), "[%s] Failed to set output.", context.GetNodeName()); + + return SUCCESS; +} + +Status RandomUniformKernel::GenerateFP16(const ge::OpDescPtr& op_desc_ptr, int64_t seed, int64_t seed2, + TaskContext& context) { + GE_CHECK_NOTNULL(op_desc_ptr); + // RandomUniformOp has and only has one output + int64_t data_num = op_desc_ptr->GetOutputDesc(0).GetShape().GetShapeSize(); + std::unique_ptr buf(new (std::nothrow) fp16_t[data_num]()); + if (buf == nullptr) { + GELOGE(MEMALLOC_FAILED, "New sizeof(fp16_t) * data_num(%zu) memory failed", + static_cast(sizeof(fp16_t) * data_num)); + return MEMALLOC_FAILED; + } + + int64_t final_seed; + if (seed == 0) { + if (seed2 == 0) { + std::random_device rd; + final_seed = rd(); + } else { + final_seed = seed2; + } + } else { + final_seed = seed; + } + std::mt19937_64 gen(final_seed); + std::uniform_real_distribution distribution(0, 1); + for (int64_t i = 0; i < data_num; i++) { + *(buf.get() + i) = static_cast(distribution(gen)); + } + + std::shared_ptr output = MakeShared(buf.get(), data_num * sizeof(fp16_t)); + GE_CHECK_NOTNULL(output); + GE_CHK_STATUS_RET(context.SetOutput(0, *output), "[%s] Failed to set output.", context.GetNodeName()); + + return SUCCESS; +} + +REGISTER_KERNEL_CREATOR(RandomUniform, RandomUniformKernel); +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.h b/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.h new file mode 100644 index 00000000..343c6d08 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/random_uniform_kernel.h @@ -0,0 +1,48 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_HOST_AICPU_KERNEL_RANDOM_UNIFORM_KERNEL_H_ +#define GE_HYBRID_HOST_AICPU_KERNEL_RANDOM_UNIFORM_KERNEL_H_ + +#include "hybrid/node_executor/hostaicpu/kernel/kernel.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +class RandomUniformKernel : public Kernel { + public: + RandomUniformKernel(const NodePtr &node) : Kernel(node) {} + ~RandomUniformKernel() override = default; + RandomUniformKernel &operator=(const RandomUniformKernel &op) = delete; + RandomUniformKernel(const RandomUniformKernel &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(TaskContext &context) override; + + private: + template + Status Generate(const ge::OpDescPtr &op_desc_ptr, int64_t seed, int64_t seed2, TaskContext &context); + + static Status GenerateFP16(const ge::OpDescPtr &op_desc_ptr, int64_t seed, int64_t seed2, TaskContext &context); +}; +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_HOST_AICPU_KERNEL_RANDOM_UNIFORM_KERNEL_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.cc b/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.cc new file mode 100644 index 00000000..a8259500 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.cc @@ -0,0 +1,43 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/kernel/variable_kernel.h" +#include "framework/common/debug/ge_log.h" +#include "framework/common/util.h" +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +Status VariableKernel::Compute(TaskContext& context) { + GELOGI("VariableKernel [%s, %s] compute begin.", node_->GetName().c_str(), node_->GetType().c_str()); + + auto tensor = context.GetVariable(node_->GetName()); + if (tensor == nullptr) { + GELOGE(PARAM_INVALID, "tensor is NULL."); + return PARAM_INVALID; + } + // Constant & Variable Op has and only has one output + GE_CHK_STATUS_RET(context.SetOutput(0, *tensor), "[%s] Failed to set output.", context.GetNodeName()); + GELOGI("VariableKernel [%s, %s] compute success.", node_->GetName().c_str(), node_->GetType().c_str()); + return SUCCESS; +} + +REGISTER_KERNEL_CREATOR(Variable, VariableKernel); +REGISTER_KERNEL_CREATOR(Constant, VariableKernel); +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.h b/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.h new file mode 100644 index 00000000..cb0a6834 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel/variable_kernel.h @@ -0,0 +1,42 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_HOST_AICPU_KERNEL_VARIABLE_KERNEL_H_ +#define GE_HYBRID_HOST_AICPU_KERNEL_VARIABLE_KERNEL_H_ + +#include "hybrid/node_executor/hostaicpu/kernel/kernel.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +class VariableKernel : public Kernel { + public: + VariableKernel(const NodePtr &node) : Kernel(node) {} + ~VariableKernel() override = default; + VariableKernel &operator=(const VariableKernel &op) = delete; + VariableKernel(const VariableKernel &op) = delete; + + /** + * @brief compute for node_task. + * @return result + */ + Status Compute(TaskContext &context) override; +}; +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_HOST_AICPU_KERNEL_VARIABLE_KERNEL_H_ diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.cc b/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.cc new file mode 100644 index 00000000..ca398500 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.cc @@ -0,0 +1,55 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "hybrid/node_executor/hostaicpu/kernel_factory.h" +#include "framework/common/debug/ge_log.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +KernelFactory &KernelFactory::Instance() { + static KernelFactory instance; + return instance; +} + +std::shared_ptr KernelFactory::CreateKernel(const NodePtr &node) { + if (node == nullptr) { + GELOGW("node is NULL."); + return nullptr; + } + auto iter = kernel_creator_map_.find(node->GetType()); + if (iter != kernel_creator_map_.end()) { + return iter->second(node); + } + GELOGE(FAILED, "Not supported, type = %s, name = %s", node->GetType().c_str(), node->GetName().c_str()); + return nullptr; +} + +void KernelFactory::RegisterCreator(const std::string &type, const KERNEL_CREATOR_FUNC &func) { + if (func == nullptr) { + GELOGW("Func is NULL."); + return; + } + auto iter = kernel_creator_map_.find(type); + if (iter != kernel_creator_map_.end()) { + GELOGW("%s creator already exist", type.c_str()); + return; + } + kernel_creator_map_[type] = func; +} +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.h b/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.h new file mode 100644 index 00000000..9ead2005 --- /dev/null +++ b/src/ge/hybrid/node_executor/hostaicpu/kernel_factory.h @@ -0,0 +1,86 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_NODE_EXECUTOR_HOST_AICPU_KERNEL_FACTORY_H_ +#define GE_HYBRID_NODE_EXECUTOR_HOST_AICPU_KERNEL_FACTORY_H_ + +#include +#include +#include +#include "common/ge/ge_util.h" +#include "hybrid/node_executor/hostaicpu/kernel/kernel.h" + +namespace ge { +namespace hybrid { +namespace host_aicpu { +using KERNEL_CREATOR_FUNC = std::function(const NodePtr &)>; + +/** + * manage all the host_aicpu_kernel, support create kernel. + */ +class KernelFactory { + public: + static KernelFactory &Instance(); + + /** + * @brief create Kernel. + * @param [in] node + * @return not nullptr success + * @return nullptr fail + */ + std::shared_ptr CreateKernel(const NodePtr &node); + + /** + * @brief Register Kernel create function. + * @param [in] type: Kernel type + * @param [in] func: Kernel create func + */ + void RegisterCreator(const std::string &type, const KERNEL_CREATOR_FUNC &func); + + KernelFactory(const KernelFactory &) = delete; + KernelFactory &operator=(const KernelFactory &) = delete; + KernelFactory(KernelFactory &&) = delete; + KernelFactory &operator=(KernelFactory &&) = delete; + + private: + KernelFactory() = default; + ~KernelFactory() = default; + + // the kernel creator function map + std::map kernel_creator_map_; +}; + +class KernelRegistrar { + public: + KernelRegistrar(const std::string &type, const KERNEL_CREATOR_FUNC &func) { + KernelFactory::Instance().RegisterCreator(type, func); + } + ~KernelRegistrar() = default; + + KernelRegistrar(const KernelRegistrar &) = delete; + KernelRegistrar &operator=(const KernelRegistrar &) = delete; + KernelRegistrar(KernelRegistrar &&) = delete; + KernelRegistrar &operator=(KernelRegistrar &&) = delete; +}; + +#define REGISTER_KERNEL_CREATOR(type, clazz) \ + std::shared_ptr Creator_##type##Kernel(const NodePtr &node) { return MakeShared(node); } \ + KernelRegistrar g_##type##Kernel_creator(#type, Creator_##type##Kernel) +} // namespace host_aicpu +} // namespace hybrid +} // namespace ge + +#endif // GE_HYBRID_NODE_EXECUTOR_HOST_AICPU_KERNEL_FACTORY_H_ diff --git a/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.cc b/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.cc index c3bc9a41..7cd10a83 100644 --- a/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.cc +++ b/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.cc @@ -17,14 +17,12 @@ #include "hybrid/node_executor/hostcpu/ge_local_node_executor.h" #include "graph/debug/ge_attr_define.h" #include "framework/common/util.h" -#include "framework/common/types.h" +#include "hybrid/model/hybrid_model.h" #include "inc/kernel.h" #include "inc/kernel_factory.h" -#include "common/ge/ge_util.h" namespace ge { namespace hybrid { - REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::GE_LOCAL, GeLocalNodeExecutor); const std::unordered_map> RefInputTask::out_ref_input_index_ = { @@ -64,7 +62,7 @@ Status RefInputTask::RefOneByOne(TaskContext &context) { for (uint32_t out_index = 0; out_index < output_num; ++out_index) { auto input = context.GetInput(out_index); GE_CHECK_NOTNULL(input); - context.SetOutput(out_index, *input); + GE_CHK_STATUS_RET(context.SetOutput(out_index, *input)); GELOGD("node %s type %s output[%u] ref input[%u] addr=%p.", node_name_.c_str(), node_type_.c_str(), out_index, out_index, input->GetData()); } @@ -84,7 +82,7 @@ Status RefInputTask::RefByOrder(const std::vector &ref_order, TaskCont auto ref_input_index = ref_order[out_index]; auto input = context.GetInput(ref_input_index); GE_CHECK_NOTNULL(input); - context.SetOutput(out_index, *input); + GE_CHK_STATUS_RET(context.SetOutput(out_index, *input)); GELOGD("node %s type %s output[%d] ref input[%u] addr=%p.", node_name_.c_str(), node_type_.c_str(), out_index, ref_input_index, input->GetData()); } @@ -132,7 +130,7 @@ Status DependInputShapeTask::Execute(TaskContext &context) { } // alloc output - GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); + GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs(NpuMemoryAllocator::AttrWithDefaultPadding())); // copy data to output for (auto i = 0; i < output_num; ++i) { @@ -194,6 +192,16 @@ Status GeLocalNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &no node_type.c_str()); return MEMALLOC_FAILED; } + } else if (node_type == CONSTANTOP || node_type == VARIABLE) { + GELOGI("node %s type %s, use ConstantNodeTask.", node->GetName().c_str(), node_type.c_str()); + auto tensor = model.GetVariable(node->GetName()); + if (tensor == nullptr) { + GELOGE(INTERNAL_ERROR, "Failed to get tensor by name: %s", node->GetName().c_str()); + return INTERNAL_ERROR; + } + + task = MakeShared(tensor); + GE_CHECK_NOTNULL(task); } else { GELOGE(UNSUPPORTED, "node %s type %s is not support in GeLocalNodeExecutor now.", node->GetName().c_str(), node_type.c_str()); @@ -202,5 +210,20 @@ Status GeLocalNodeExecutor::LoadTask(const HybridModel &model, const NodePtr &no return SUCCESS; } +ConstantNodeTask::ConstantNodeTask(const TensorValue *tensor) : tensor_(tensor) {} + +Status ConstantNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } + +Status ConstantNodeTask::ExecuteAsync(TaskContext &context, std::function done_callback) { + GELOGD("[%s] Start execute.", context.GetNodeName()); + GE_CHK_STATUS_RET(context.SetOutput(0, *tensor_), "[%s] Failed to set output.", context.GetNodeName()); + if (done_callback) { + GELOGD("[%s] Start invoke callback.", context.GetNodeName()); + done_callback(); + } + + GELOGD("[%s] Done execute successfully.", context.GetNodeName()); + return SUCCESS; +} } // namespace hybrid } // namespace ge \ No newline at end of file diff --git a/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.h b/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.h index beb1f50d..0195e76c 100644 --- a/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.h +++ b/src/ge/hybrid/node_executor/hostcpu/ge_local_node_executor.h @@ -23,7 +23,6 @@ namespace ge { namespace hybrid { - class RefInputTask : public NodeTask { public: explicit RefInputTask(const NodePtr &node) : node_name_(node->GetName()), node_type_(node->GetType()) {} @@ -68,6 +67,18 @@ class DependInputShapeTask : public NodeTask { static const std::unordered_set depend_input_shape_ops_; }; +class ConstantNodeTask : public NodeTask { + public: + explicit ConstantNodeTask(const TensorValue *tensor); + ~ConstantNodeTask() = default; + Status UpdateArgs(TaskContext &context) override; + + Status ExecuteAsync(TaskContext &context, std::function done_callback) override; + + private: + const TensorValue *tensor_; +}; + class GeLocalNodeExecutor : public NodeExecutor { public: Status PrepareTask(NodeTask &task, TaskContext &context) const override; diff --git a/src/ge/hybrid/node_executor/node_executor.cc b/src/ge/hybrid/node_executor/node_executor.cc index f3b86948..0f4c5494 100644 --- a/src/ge/hybrid/node_executor/node_executor.cc +++ b/src/ge/hybrid/node_executor/node_executor.cc @@ -16,6 +16,7 @@ #include "hybrid/node_executor/node_executor.h" #include "framework/common/debug/log.h" +#include "graph/utils/node_utils.h" #include "init/gelib.h" #include "hybrid/model/hybrid_model.h" @@ -25,9 +26,11 @@ namespace { const char *const kEngineNameAiCore = "AIcoreEngine"; const char *const kEngineNameGeLocal = "DNN_VM_GE_LOCAL_OP_STORE"; const char *const kEngineNameAiCpu = "aicpu_kernel"; +const char *const kEngineNameHccl = "ops_kernel_info_hccl"; } // namespace Status NodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { GE_CHK_STATUS_RET_NOLOG(context.AllocateOutputs()); + GE_CHK_STATUS_RET_NOLOG(task.UpdateTilingData(context)); // update op_desc before alloc ws GE_CHK_STATUS_RET_NOLOG(context.AllocateWorkspaces()); GE_CHK_STATUS_RET_NOLOG(task.UpdateArgs(context)); return SUCCESS; @@ -48,6 +51,7 @@ Status NodeExecutor::CompileTask(const HybridModel &model, const NodePtr &node, } Status NodeExecutorManager::EnsureInitialized() { + GE_CHK_STATUS_RET(InitializeExecutors()); std::lock_guard lk(mu_); if (initialized_) { return SUCCESS; @@ -56,6 +60,7 @@ Status NodeExecutorManager::EnsureInitialized() { engine_mapping_.emplace(kEngineNameAiCore, NodeExecutorManager::ExecutorType::AICORE); engine_mapping_.emplace(kEngineNameGeLocal, NodeExecutorManager::ExecutorType::GE_LOCAL); engine_mapping_.emplace(kEngineNameAiCpu, NodeExecutorManager::ExecutorType::AICPU_TF); + engine_mapping_.emplace(kEngineNameHccl, NodeExecutorManager::ExecutorType::HCCL); std::shared_ptr instance_ptr = GELib::GetInstance(); if ((instance_ptr == nullptr) || (!instance_ptr->InitFlag())) { @@ -66,23 +71,7 @@ Status NodeExecutorManager::EnsureInitialized() { OpsKernelManager &ops_kernel_manager = instance_ptr->OpsKernelManagerObj(); for (auto &it : ops_kernel_manager.GetAllOpsKernelInfoStores()) { GELOGD("add kernel store: %s", it.first.c_str()); - kernel_stores_.emplace(it.first, it.second); - } - - GELOGI("Start to Initialize NodeExecutors"); - for (auto &it : builders_) { - auto engine_type = it.first; - auto build_fn = it.second; - GE_CHECK_NOTNULL(build_fn); - auto executor = std::unique_ptr(build_fn()); - if (executor == nullptr) { - GELOGE(INTERNAL_ERROR, "Failed to create executor for engine type = %d", engine_type); - return INTERNAL_ERROR; - } - - GELOGD("Executor of engine type = %d was created successfully", engine_type); - GE_CHK_STATUS_RET(executor->Initialize(), "Failed to initialize NodeExecutor of type = %d", engine_type); - executors_.emplace(engine_type, std::move(executor)); + kernel_stores_.emplace(it.first, it.second.get()); } initialized_ = true; @@ -93,6 +82,11 @@ Status NodeExecutorManager::EnsureInitialized() { NodeExecutorManager::ExecutorType NodeExecutorManager::ResolveExecutorType(Node &node) const { auto op_type = node.GetType(); if (op_type == PARTITIONEDCALL) { + bool is_dynamic = false; + (void)NodeUtils::GetNodeUnknownShapeStatus(node, is_dynamic); + if (is_dynamic) { + return ExecutorType::DYNAMIC_SUBGRAPH; + } return ExecutorType::COMPILED_SUBGRAPH; } @@ -101,6 +95,10 @@ NodeExecutorManager::ExecutorType NodeExecutorManager::ResolveExecutorType(Node return ExecutorType::GE_LOCAL; } + if (op_type == IF || op_type == CASE || op_type == WHILE) { + return ExecutorType::CONTROL_OP; + } + auto op_desc = node.GetOpDesc(); // checked before const auto &lib_name = op_desc->GetOpKernelLibName(); auto it = engine_mapping_.find(lib_name); @@ -116,10 +114,11 @@ Status NodeExecutorManager::GetExecutor(Node &node, const NodeExecutor **executo auto executor_type = ResolveExecutorType(node); const auto it = executors_.find(executor_type); if (it == executors_.end()) { - GELOGE(INTERNAL_ERROR, "Failed to get executor by type: %d", executor_type); + GELOGE(INTERNAL_ERROR, "Failed to get executor by type: %d.", executor_type); return INTERNAL_ERROR; } + GELOGD("[%s] Set node executor by type: %d.", node.GetName().c_str(), executor_type); *executor = it->second.get(); return SUCCESS; } @@ -132,6 +131,11 @@ void NodeExecutorManager::RegisterExecutorBuilder(NodeExecutorManager::ExecutorT Status NodeExecutorManager::CalcOpRunningParam(Node &node) const { auto op_desc = node.GetOpDesc(); GE_CHECK_NOTNULL(op_desc); + if (op_desc->GetType() == PARTITIONEDCALL) { + GELOGD("[%s] Skipping CalcOpRunningParam for PartitionedCall.", node.GetName().c_str()); + return SUCCESS; + } + auto it = kernel_stores_.find(op_desc->GetOpKernelLibName()); if (it == kernel_stores_.end()) { GELOGE(INTERNAL_ERROR, "Failed to get OpKernelStore. libName = %s, node = %s", @@ -139,9 +143,91 @@ Status NodeExecutorManager::CalcOpRunningParam(Node &node) const { return INTERNAL_ERROR; } + // calc hccl output size independent, hccl ops kernel manager should GetSize for + // input which is the output size of input-op, but sometimes return error + // when multi-thread + if (op_desc->GetOpKernelLibName() == kEngineNameHccl) { + for (size_t i = 0; i < op_desc->GetOutputsSize(); ++i) { + GeTensorDesc output_tensor = op_desc->GetOutputDesc(static_cast(i)); + Format format = output_tensor.GetFormat(); + DataType data_type = output_tensor.GetDataType(); + GeShape output_shape = output_tensor.GetShape(); + int64_t output_mem_size = 0; + GE_CHK_STATUS_RET(TensorUtils::CalcTensorMemSize(output_shape, format, data_type, output_mem_size), + "hccl calc tensor mem size failed."); + output_mem_size = + ((output_mem_size + MEMORY_ALIGN_RATIO * MEMORY_ALIGN_SIZE - 1) / MEMORY_ALIGN_SIZE) * MEMORY_ALIGN_SIZE; + TensorUtils::SetSize(output_tensor, output_mem_size); + GE_CHK_STATUS_RET(op_desc->UpdateOutputDesc(static_cast(i), output_tensor), + "hccl update output size failed."); + GELOGD("%s output desc[%u], dim_size: %zu, mem_size: %ld.", node.GetName().c_str(), i, + output_tensor.GetShape().GetDimNum(), output_mem_size); + } + return SUCCESS; + } return it->second->CalcOpRunningParam(node); } +Status NodeExecutorManager::InitializeExecutors() { + std::lock_guard lk(mu_); + if (executor_initialized_) { + ++ref_count_; + GELOGI("Executor is already initialized. add ref count to [%d]", ref_count_); + return SUCCESS; + } + + GELOGI("Start to Initialize NodeExecutors"); + for (auto &it : builders_) { + auto engine_type = it.first; + auto build_fn = it.second; + GE_CHECK_NOTNULL(build_fn); + auto executor = std::unique_ptr(build_fn()); + if (executor == nullptr) { + GELOGE(INTERNAL_ERROR, "Failed to create executor for engine type = %d", engine_type); + return INTERNAL_ERROR; + } + + GELOGD("Executor of engine type = %d was created successfully", engine_type); + auto ret = executor->Initialize(); + if (ret != SUCCESS) { + GELOGE(ret, "Failed to initialize NodeExecutor of type = %d, clear executors", engine_type); + for (auto &executor_it : executors_) { + executor_it.second->Finalize(); + } + executors_.clear(); + return ret; + } + + executors_.emplace(engine_type, std::move(executor)); + } + + ++ref_count_; + executor_initialized_ = true; + GELOGI("Initializing NodeExecutors successfully."); + return SUCCESS; +} + +void NodeExecutorManager::FinalizeExecutors() { + std::lock_guard lk(mu_); + if (!executor_initialized_) { + GELOGD("No need for finalizing for not initialized."); + return; + } + + if (--ref_count_ > 0) { + GELOGD("Ref count = %d, do not finalize executors.", ref_count_); + return; + } + + GELOGD("Start to invoke Finalize on executors."); + for (auto &it : executors_) { + it.second->Finalize(); + } + executors_.clear(); + executor_initialized_ = false; + GELOGD("Done invoking Finalize successfully."); +} + NodeExecutorRegistrar::NodeExecutorRegistrar(NodeExecutorManager::ExecutorType executor_type, NodeExecutor *(*builder)()) { NodeExecutorManager::GetInstance().RegisterExecutorBuilder(executor_type, builder); diff --git a/src/ge/hybrid/node_executor/node_executor.h b/src/ge/hybrid/node_executor/node_executor.h index 613c0bb1..23e52428 100644 --- a/src/ge/hybrid/node_executor/node_executor.h +++ b/src/ge/hybrid/node_executor/node_executor.h @@ -14,70 +14,182 @@ * limitations under the License. */ -#ifndef GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ -#define GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ +#ifndef GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ +#define GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ #include "external/ge/ge_api_error_codes.h" #include "common/opskernel/ops_kernel_info_store.h" #include "graph/node.h" -#include "proto/task.pb.h" #include "task_context.h" namespace ge { +const uint32_t MEMORY_ALIGN_RATIO = 2; +const uint32_t MEMORY_ALIGN_SIZE = 32; namespace hybrid { class HybridModel; - +// Base class of Node Task class NodeTask { public: NodeTask() = default; virtual ~NodeTask() = default; + + /** + * Update tiling data + * @param context instance of TaskContext + * @return SUCCESS on success, error code otherwise + */ + virtual Status UpdateTilingData(TaskContext &context) { return SUCCESS; } + + /** + * Init + * @param context instance of TaskContext + * @return SUCCESS on success, error code otherwise + */ + virtual Status Init(TaskContext &context) { return SUCCESS; } + + /** + * Whether this task supports dynamic shape + * @return true if this task supports dynamic shape, false otherwise + */ + virtual bool IsSupportDynamicShape() { return true; } + + /** + * Update args for execution + * @param context instance of TaskContext + * @return SUCCESS on success, error code otherwise + */ virtual Status UpdateArgs(TaskContext &context) = 0; + + /** + * Execute task async + * @param context instance of TaskContext + * @param done_callback callback function, will be invoked after task is done + * @return SUCCESS on success, error code otherwise + */ virtual Status ExecuteAsync(TaskContext &context, std::function done_callback) = 0; - virtual Status Init(TaskContext &context) { return SUCCESS; } }; +// Node executor class NodeExecutor { public: NodeExecutor() = default; virtual ~NodeExecutor() = default; + /** + * Initialize node executor + * @return SUCCESS on success, error code otherwise + */ virtual Status Initialize() { return SUCCESS; } + /** + * Finalize node executor + * @return SUCCESS on success, error code otherwise + */ virtual Status Finalize() { return SUCCESS; } + /** + * Load task in load stage + * @param model instance of HybridModel + * @param node node + * @param task generated node task + * @return SUCCESS on success, error code otherwise + */ virtual Status LoadTask(const HybridModel &model, const NodePtr &node, std::shared_ptr &task) const; + /** + * Compile task in run stage + * @param model instance of HybridModel + * @param node node + * @param task generated node task + * @return SUCCESS on success, error code otherwise + */ virtual Status CompileTask(const HybridModel &model, const NodePtr &node, std::shared_ptr &task) const; + /** + * Preparation actions before execution + * @param task instance of NodeTask + * @param context instance of TaskContext + * @return SUCCESS on success, error code otherwise + */ virtual Status PrepareTask(NodeTask &task, TaskContext &context) const; + + /** + * Execute task + * @param task instance of NodeTask + * @param context instance of TaskContext + * @param callback callback function which will be invoked after computation is done + * @return SUCCESS on success, error code otherwise + */ virtual Status ExecuteTask(NodeTask &task, TaskContext &context, const std::function &callback) const; }; class NodeExecutorManager { public: - enum class ExecutorType { AICORE, GE_LOCAL, AICPU_TF, AICPU_CUSTOM, COMPILED_SUBGRAPH, HCCL, RESERVED }; + enum class ExecutorType { + AICORE, + AICPU_TF, + AICPU_CUSTOM, + COMPILED_SUBGRAPH, + DYNAMIC_SUBGRAPH, + GE_LOCAL, + CONTROL_OP, + HCCL, + RESERVED + }; static NodeExecutorManager &GetInstance() { static NodeExecutorManager instance; return instance; } - Status CalcOpRunningParam(Node &node) const; - + /** + * Register build of executor + * @param executor_type type of executor + * @param builder build function + */ void RegisterExecutorBuilder(ExecutorType executor_type, const std::function &builder); + /** + * Initialize executor if needed + * @return SUCCESS on success, error code otherwise + */ Status EnsureInitialized(); + Status InitializeExecutors(); + + void FinalizeExecutors(); + + /** + * CalcOpRunningParam + * @param node node + * @return SUCCESS on success, error code otherwise + */ + Status CalcOpRunningParam(Node &node) const; + + /** + * Get executor by node + * @param node node + * @param executor executor + * @return SUCCESS on success, error code otherwise + */ Status GetExecutor(Node &node, const NodeExecutor **executor) const; + /** + * Resolve executor type by node + * @param node node + * @return executor type + */ ExecutorType ResolveExecutorType(Node &node) const; + private: std::map> executors_; std::map> builders_; - std::map> kernel_stores_; + std::map kernel_stores_; std::map engine_mapping_; std::mutex mu_; bool initialized_ = false; + bool executor_initialized_ = false; + int ref_count_ = 0; }; class NodeExecutorRegistrar { @@ -99,4 +211,4 @@ class NodeExecutorRegistrar { ::ge::hybrid::NodeExecutorRegistrar( \ engine_type, []() -> ::ge::hybrid::NodeExecutor * { return new (std::nothrow) executor(); }) -#endif // GE_HYBRID_KERNEL_NODE_EXECUTOR_H_ +#endif // GE_HYBRID_NODE_EXECUTOR_NODE_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc b/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc new file mode 100644 index 00000000..cda9a275 --- /dev/null +++ b/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.cc @@ -0,0 +1,81 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "partitioned_call_node_executor.h" +#include "graph/utils/node_utils.h" + +namespace ge { +namespace hybrid { +REGISTER_NODE_EXECUTOR_BUILDER(NodeExecutorManager::ExecutorType::DYNAMIC_SUBGRAPH, PartitionedCallNodeExecutor); + +PartitionedCallNodeTask::PartitionedCallNodeTask(const GraphItem *graph_item) : graph_item_(graph_item) {} + +PartitionedCallNodeTask::~PartitionedCallNodeTask() { + GELOGD("[%s] PartitionedCallNodeTask destroyed.", graph_item_->GetName().c_str()); +} + +Status PartitionedCallNodeTask::Init(TaskContext &context) { + auto execution_context = const_cast(context.GetExecutionContext()); + subgraph_executor_.reset(new (std::nothrow) SubgraphExecutor(graph_item_, execution_context)); + GE_CHECK_NOTNULL(subgraph_executor_); + return SUCCESS; +} + +Status PartitionedCallNodeTask::ExecuteAsync(TaskContext &context, std::function done_callback) { + GE_CHK_STATUS_RET(subgraph_executor_->ExecuteAsync(context), "[%s] Failed to set inputs", + graph_item_->GetName().c_str()); + + auto callback = [=]() { Callback(done_callback); }; + + GE_CHK_STATUS_RET(context.RegisterCallback(callback), "[%s] Failed to register callback", + graph_item_->GetName().c_str()); + GELOGD("[%s] Done executing subgraph successfully.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status PartitionedCallNodeTask::Callback(const std::function &done_callback) { + GELOGD("[%s] On subgraph callback", graph_item_->GetName().c_str()); + if (done_callback != nullptr) { + done_callback(); + } + + GELOGD("[%s] To release sub graph tensors.", graph_item_->GetName().c_str()); + subgraph_executor_.reset(); + GELOGD("[%s] Done releasing sub graph tensors.", graph_item_->GetName().c_str()); + return SUCCESS; +} + +Status PartitionedCallNodeTask::UpdateArgs(TaskContext &context) { return SUCCESS; } + +Status PartitionedCallNodeExecutor::LoadTask(const ge::hybrid::HybridModel &model, const ge::NodePtr &node, + std::shared_ptr &task) const { + GELOGD("Load dynamic partitioned call: [%s]", node->GetName().c_str()); + auto subgraph = NodeUtils::GetSubgraph(*node, 0); + GE_CHECK_NOTNULL(subgraph); + auto partitioned_call = model.GetSubgraphItem(subgraph); + GE_CHECK_NOTNULL(partitioned_call); + task.reset(new (std::nothrow) PartitionedCallNodeTask(partitioned_call)); + GE_CHECK_NOTNULL(task); + GELOGD("Done loading dynamic partitioned call: [%s]", node->GetName().c_str()); + return SUCCESS; +} + +Status PartitionedCallNodeExecutor::PrepareTask(NodeTask &task, TaskContext &context) const { + GE_CHK_STATUS_RET(task.Init(context), "[%s] Failed to init task.", context.GetNodeName()); + return SUCCESS; +} +} // namespace hybrid +} // namespace ge diff --git a/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.h b/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.h new file mode 100644 index 00000000..fd87d6c1 --- /dev/null +++ b/src/ge/hybrid/node_executor/partitioned_call/partitioned_call_node_executor.h @@ -0,0 +1,54 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ +#define GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ + +#include "hybrid/node_executor/node_executor.h" +#include "hybrid/model/hybrid_model.h" +#include "hybrid/executor/node_state.h" +#include "hybrid/executor/subgraph_executor.h" +#include "common/thread_pool.h" + +namespace ge { +namespace hybrid { +class PartitionedCallNodeTask : public NodeTask { + public: + explicit PartitionedCallNodeTask(const GraphItem *graph_item); + ~PartitionedCallNodeTask() override; + + Status Init(TaskContext &context) override; + + Status UpdateArgs(TaskContext &context) override; + + Status ExecuteAsync(TaskContext &context, std::function done_callback) override; + + private: + Status Callback(const std::function &done_callback); + + const GraphItem *graph_item_; + std::unique_ptr subgraph_executor_; + GraphExecutionContext *context_ = nullptr; +}; + +class PartitionedCallNodeExecutor : public NodeExecutor { + public: + Status LoadTask(const HybridModel &model, const NodePtr &node, shared_ptr &task) const override; + Status PrepareTask(NodeTask &task, TaskContext &context) const override; +}; +} // namespace hybrid +} // namespace ge +#endif // GE_HYBRID_NODE_EXECUTOR_SUBGRAPH_SUBGRAPH_EXECUTOR_H_ diff --git a/src/ge/hybrid/node_executor/task_context.cc b/src/ge/hybrid/node_executor/task_context.cc index 42c653be..ee35bffa 100644 --- a/src/ge/hybrid/node_executor/task_context.cc +++ b/src/ge/hybrid/node_executor/task_context.cc @@ -19,12 +19,16 @@ #include "framework/common/debug/log.h" #include "graph/utils/tensor_utils.h" #include "hybrid/executor/hybrid_execution_context.h" +#include "hybrid/executor/subgraph_executor.h" namespace ge { namespace hybrid { -TaskContext::TaskContext(GraphExecutionContext *execution_context) : execution_context_(execution_context) {} +TaskContext::TaskContext(GraphExecutionContext *execution_context, const NodeItem *node_item, + SubgraphContext *subgraph_context) + : node_item_(node_item), execution_context_(execution_context), subgraph_context_(subgraph_context) {} + TaskContext::~TaskContext() { - GELOGD("To execute ~TaskContext(). node = %s", node_item_->NodeName().c_str()); + GELOGD("[%s] TaskContext destroyed.", node_item_->NodeName().c_str()); for (auto ws_addr : workspaces_) { execution_context_->allocator->Deallocate(ws_addr); } @@ -38,19 +42,28 @@ TaskContext::~TaskContext() { } } -std::unique_ptr TaskContext::Create(const NodeItem &node_item, GraphExecutionContext *graph_context) { - GELOGI("To create task context for node %s, input start = %d, num_inputs = %d, output start = %d, num_outputs = %d", +std::unique_ptr TaskContext::Create(const NodeItem &node_item, GraphExecutionContext *execution_context, + SubgraphContext *subgraph_context) { + GELOGI("[%s] To create task context, input start = %d, num_inputs = %d, output start = %d, num_outputs = %d.", node_item.NodeName().c_str(), node_item.input_start, node_item.num_inputs, node_item.output_start, node_item.num_outputs); - auto task_context = std::unique_ptr(new (std::nothrow) TaskContext(graph_context)); + if (node_item.input_start < 0 || node_item.output_start < 0) { + GELOGE(INTERNAL_ERROR, "NodeItem not property initialized. input_start = %d, output_start = %d", + node_item.input_start, node_item.output_start); + return nullptr; + } + + auto task_context = + std::unique_ptr(new (std::nothrow) TaskContext(execution_context, &node_item, subgraph_context)); if (task_context == nullptr) { - GELOGE(MEMALLOC_FAILED, "Failed to create instance of TaskContext. node = %s", node_item.NodeName().c_str()); + GELOGE(MEMALLOC_FAILED, "[%s] Failed to create instance of TaskContext.", node_item.NodeName().c_str()); return nullptr; } task_context->node_item_ = &node_item; - task_context->inputs_start_ = graph_context->all_inputs.data() + node_item.input_start; - task_context->outputs_start_ = graph_context->all_outputs.data() + node_item.output_start; + task_context->inputs_start_ = subgraph_context->all_inputs_.data() + node_item.input_start; + task_context->outputs_start_ = subgraph_context->all_outputs_.data() + node_item.output_start; + task_context->iteration_ = execution_context->iteration; return task_context; } @@ -59,7 +72,7 @@ int TaskContext::NumInputs() const { return node_item_->num_inputs; } int TaskContext::NumOutputs() const { return node_item_->num_outputs; } TensorValue *TaskContext::MutableInput(int index) { - if (index < 0 || index > node_item_->num_inputs) { + if (index < 0 || index >= node_item_->num_inputs) { GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_inputs = %d", index, node_item_->num_inputs); return nullptr; } @@ -68,7 +81,7 @@ TensorValue *TaskContext::MutableInput(int index) { } const TensorValue *TaskContext::GetOutput(int index) const { - if (index < 0 || index > node_item_->num_outputs) { + if (index < 0 || index >= node_item_->num_outputs) { GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_outputs = %d", index, node_item_->num_outputs); return nullptr; } @@ -77,7 +90,7 @@ const TensorValue *TaskContext::GetOutput(int index) const { } TensorValue *TaskContext::MutableOutput(int index) { - if (index < 0 || index > node_item_->num_outputs) { + if (index < 0 || index >= node_item_->num_outputs) { GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_outputs = %d", index, node_item_->num_outputs); return nullptr; } @@ -97,7 +110,7 @@ void *TaskContext::MutableWorkspace(int index) { } const TensorValue *TaskContext::GetInput(int index) const { - if (index < 0 || index > node_item_->num_inputs) { + if (index < 0 || index >= node_item_->num_inputs) { GELOGE(PARAM_INVALID, "Index out of range. index = %d, num_inputs = %d", index, node_item_->num_inputs); return nullptr; } @@ -120,7 +133,14 @@ Status TaskContext::AllocateWorkspaces() { } Status TaskContext::RegisterCallback(const std::function &callback_fun) const { - return execution_context_->callback_manager->RegisterCallback(callback_fun); + auto ret = execution_context_->callback_manager->RegisterCallback(callback_fun); + if (ret != SUCCESS) { + GELOGE(ret, "[%s] Failed to register callback", GetNodeName()); + execution_context_->callback_manager->Destroy(); + return ret; + } + + return SUCCESS; } string TaskContext::TensorDesc2String(const GeTensorDesc &desc) { @@ -137,7 +157,7 @@ string TaskContext::TensorDesc2String(const GeTensorDesc &desc) { return ss.str(); } -Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor) { +Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor, AllocationAttr *attr) { int64_t size = 0; if (ge::TensorUtils::GetSize(tensor_desc, size) != GRAPH_SUCCESS) { GELOGE(INTERNAL_ERROR, "Failed to get tensor size"); @@ -148,13 +168,14 @@ Status TaskContext::AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue GELOGW("size from tensor_desc == 0"); } - auto buffer = TensorBuffer::Create(execution_context_->allocator, size); + auto buffer = TensorBuffer::Create(execution_context_->allocator, size, attr); GE_CHECK_NOTNULL(buffer); tensor = TensorValue(shared_ptr(buffer.release())); return SUCCESS; } -Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor) { +Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor, + AllocationAttr *attr) { GELOGI("To allocate output for node: %s. index = %d, tensor desc = %s", node_item_->NodeName().c_str(), index, TensorDesc2String(tensor_desc).c_str()); @@ -178,9 +199,29 @@ Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, T GE_CHECK_NOTNULL(ref_tensor); outputs_start_[index] = *ref_tensor; } else { - GE_CHK_STATUS_RET_NOLOG(AllocateTensor(tensor_desc, outputs_start_[index])); - GELOGD("Allocating output successfully. node: %s. index = %d, size = %zu", node_item_->NodeName().c_str(), index, - outputs_start_[index].GetSize()); + auto reuse_input = node_item_->reuse_inputs.find(index); + if (reuse_input != node_item_->reuse_inputs.end()) { + GELOGD("[%s] Output[%d] is referenced to input[%d]", GetNodeName(), index, reuse_input->second); + outputs_start_[index] = inputs_start_[reuse_input->second]; + } else { + GE_CHK_STATUS_RET_NOLOG(AllocateTensor(tensor_desc, outputs_start_[index], attr)); + GELOGD("Allocating output successfully. node: %s. index = %d, size = %zu", node_item_->NodeName().c_str(), index, + outputs_start_[index].GetSize()); + } + } + + // Temp modification + if (node_item_->node_type == "UnsortedSegmentSum" || node_item_->node_type == "UnsortedSegmentSumD" || + node_item_->node_type == "ScatterNd") { + auto &out_tensor = outputs_start_[index]; + GELOGD("[%s] clear output tensor: %s", GetNodeName(), out_tensor.DebugString().c_str()); + auto *ctx = GetExecutionContext(); + string name = "rtMemsetAsync" + node_item_->node_name; + RegisterCallback([ctx, name]() { RECORD_CALLBACK_EVENT(ctx, name.c_str(), "[Compute] Start"); }); + RECORD_EXECUTION_EVENT(GetExecutionContext(), node_item_->node_name.c_str(), "[rtMemsetAsync] Start"); + GE_CHK_RT_RET(rtMemsetAsync(out_tensor.MutableData(), out_tensor.GetSize(), 0, out_tensor.GetSize(), GetStream())); + RECORD_EXECUTION_EVENT(GetExecutionContext(), node_item_->node_name.c_str(), "[rtMemsetAsync] End"); + RegisterCallback([ctx, name]() { RECORD_CALLBACK_EVENT(ctx, name.c_str(), "[Compute] End"); }); } if (execution_context_->trace_enabled) { @@ -194,11 +235,11 @@ Status TaskContext::AllocateOutput(int index, const GeTensorDesc &tensor_desc, T return SUCCESS; } -Status TaskContext::AllocateOutputs() { +Status TaskContext::AllocateOutputs(AllocationAttr *attr) { for (int i = 0; i < node_item_->num_outputs; ++i) { const auto &output_desc = node_item_->op_desc->MutableOutputDesc(i); GE_CHECK_NOTNULL(output_desc); - GE_CHK_STATUS_RET_NOLOG(AllocateOutput(i, *output_desc, nullptr)); + GE_CHK_STATUS_RET_NOLOG(AllocateOutput(i, *output_desc, nullptr, attr)); } return SUCCESS; @@ -230,7 +271,7 @@ Status TaskContext::SetOutput(int index, const TensorValue &tensor) { rtStream_t TaskContext::GetStream() { return execution_context_->stream; } -int64_t TaskContext::GetSessionId() { return execution_context_->session_id; } +int64_t TaskContext::GetSessionId() const { return execution_context_->session_id; } Status TaskContext::GetStatus() const { return status_; } @@ -238,7 +279,13 @@ void TaskContext::SetStatus(Status status) { status_ = status; } Status TaskContext::AllocateWorkspace(size_t size, void **buffer, void *ori_addr) { GE_CHECK_NOTNULL(buffer); - *buffer = execution_context_->allocator->Allocate(size, ori_addr); + if (ori_addr == nullptr) { + *buffer = execution_context_->allocator->Allocate(size, nullptr); + } else { + AllocationAttr attr(ori_addr); + *buffer = execution_context_->allocator->Allocate(size, &attr); + } + if (*buffer == nullptr) { GELOGE(MEMALLOC_FAILED, "Failed to allocate workspace of size = %zu", size); return MEMALLOC_FAILED; @@ -261,16 +308,21 @@ Status TaskContext::PropagateOutputs() { for (auto &dst_input_index_and_node : output_nodes) { auto dst_input_idx = dst_input_index_and_node.first; auto dst_node_item = dst_input_index_and_node.second; + auto input_offset = dst_node_item->input_start + dst_input_idx; GELOGI( "Propagate output of node %s, output index = %d, dst node = %s, " - "dst_input_index = %d, dst_input_offset = %d, addr = %p", - node_item_->NodeName().c_str(), i, dst_node_item->NodeName().c_str(), dst_input_idx, - dst_node_item->input_start + dst_input_idx, - execution_context_->all_inputs.data() + dst_node_item->input_start + dst_input_idx); - execution_context_->all_inputs[dst_node_item->input_start + dst_input_idx] = *tensor; + "dst_input_index = %d, dst_input_offset = %d.", + node_item_->NodeName().c_str(), i, dst_node_item->NodeName().c_str(), dst_input_idx, input_offset); + + if (subgraph_context_->all_inputs_.size() <= static_cast(input_offset)) { + GELOGE(INTERNAL_ERROR, "[%s] input index out of range. index = %d, total input num = %zu", GetNodeName(), + input_offset, subgraph_context_->all_inputs_.size()); + return INTERNAL_ERROR; + } + + subgraph_context_->all_inputs_[input_offset] = *tensor; if (execution_context_->trace_enabled) { - execution_context_->all_inputs[dst_node_item->input_start + dst_input_idx].SetName(node_item_->NodeName() + - "_in_" + std::to_string(i)); + subgraph_context_->all_inputs_[input_offset].SetName(node_item_->NodeName() + "_in_" + std::to_string(i)); } } } @@ -289,5 +341,37 @@ void TaskContext::ReleaseInput(int index) { GELOGD("[%s] Tensor of input[%d] released", GetNodeName(), index); } } + +ConstGeTensorDescPtr TaskContext::GetOutputDesc(int index) { + return node_item_->op_desc->MutableOutputDesc(static_cast(index)); +} + +ConstGeTensorDescPtr TaskContext::GetInputDesc(int index) { + return node_item_->op_desc->MutableInputDesc(static_cast(index)); +} + +GeTensorDescPtr TaskContext::MutableInputDesc(int index) { + return node_item_->op_desc->MutableInputDesc(static_cast(index)); +} + +GeTensorDescPtr TaskContext::MutableOutputDesc(int index) { + return node_item_->op_desc->MutableOutputDesc(static_cast(index)); +} + +bool TaskContext::IsForceInferShape() const { return force_infer_shape_; } + +void TaskContext::SetForceInferShape(bool force_infer_shape) { force_infer_shape_ = force_infer_shape; } + +void TaskContext::NodeDone() { subgraph_context_->NodeDone(node_item_->node); } + +void TaskContext::OnError(Status error) { subgraph_context_->OnError(error); } + +bool TaskContext::IsTraceEnabled() const { return execution_context_->trace_enabled; } + +TensorValue *TaskContext::GetVariable(const std::string &name) { return execution_context_->model->GetVariable(name); } + +uint64_t TaskContext::GetIterationNumber() const { return iteration_; } + +bool TaskContext::IsDumpEnabled() const { return execution_context_->dump_enabled; } } // namespace hybrid } // namespace ge diff --git a/src/ge/hybrid/node_executor/task_context.h b/src/ge/hybrid/node_executor/task_context.h index 841dcb17..5c42a347 100644 --- a/src/ge/hybrid/node_executor/task_context.h +++ b/src/ge/hybrid/node_executor/task_context.h @@ -22,16 +22,19 @@ #include #include "external/ge/ge_api_error_codes.h" #include "hybrid/common/tensor_value.h" +#include "hybrid/common/npu_memory_allocator.h" #include "hybrid/executor/rt_callback_manager.h" #include "hybrid/model/node_item.h" namespace ge { namespace hybrid { class GraphExecutionContext; +class SubgraphContext; class TaskContext { public: - static std::unique_ptr Create(const NodeItem &node_item, GraphExecutionContext *graph_context); + static std::unique_ptr Create(const NodeItem &node_item, GraphExecutionContext *execution_context, + SubgraphContext *subgraph_context); ~TaskContext(); @@ -41,19 +44,33 @@ class TaskContext { const NodeItem &GetNodeItem() const; const char *GetNodeName() const; TensorValue *MutableInput(int index); + ConstGeTensorDescPtr GetInputDesc(int index); + ConstGeTensorDescPtr GetOutputDesc(int index); + GeTensorDescPtr MutableInputDesc(int index); + GeTensorDescPtr MutableOutputDesc(int index); void ReleaseInput(int index); const TensorValue *GetInput(int index) const; const TensorValue *GetOutput(int index) const; TensorValue *MutableOutput(int index); + TensorValue *GetVariable(const std::string &name); rtStream_t GetStream(); - int64_t GetSessionId(); + int64_t GetSessionId() const; + uint64_t GetIterationNumber() const; + + void NodeDone(); + void OnError(Status error); Status SetOutput(int index, const TensorValue &tensor); - Status AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor); - Status AllocateOutputs(); + Status AllocateOutput(int index, const GeTensorDesc &tensor_desc, TensorValue **tensor, + AllocationAttr *attr = nullptr); + Status AllocateOutputs(AllocationAttr *attr = nullptr); Status AllocateWorkspaces(); Status AllocateWorkspace(size_t size, void **buffer, void *ori_addr = nullptr); + bool IsTraceEnabled() const; + + bool IsDumpEnabled() const; + const GraphExecutionContext *GetExecutionContext() { return execution_context_; } Status AllocateTemp(size_t size, TensorValue &tensor); @@ -68,17 +85,25 @@ class TaskContext { void SetStatus(Status status); + bool IsForceInferShape() const; + void SetForceInferShape(bool force_infer_shape); + void *handle_ = nullptr; + private: - explicit TaskContext(GraphExecutionContext *execution_context); - TensorValue *inputs_start_ = nullptr; - TensorValue *outputs_start_ = nullptr; + TaskContext(GraphExecutionContext *execution_context, const NodeItem *node_item, SubgraphContext *subgraph_context); + static string TensorDesc2String(const GeTensorDesc &desc); - Status AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor); + Status AllocateTensor(const GeTensorDesc &tensor_desc, TensorValue &tensor, AllocationAttr *attr); - GraphExecutionContext *execution_context_; const NodeItem *node_item_ = nullptr; + bool force_infer_shape_ = false; + GraphExecutionContext *execution_context_; + SubgraphContext *subgraph_context_; + TensorValue *inputs_start_ = nullptr; + TensorValue *outputs_start_ = nullptr; Status status_ = SUCCESS; std::vector workspaces_; + uint64_t iteration_ = 0; }; } // namespace hybrid } // namespace ge diff --git a/src/ge/inc/kernel_factory.h b/src/ge/inc/kernel_factory.h index c0624e14..61455836 100644 --- a/src/ge/inc/kernel_factory.h +++ b/src/ge/inc/kernel_factory.h @@ -103,5 +103,5 @@ class KernelFactory { return ptr; \ } \ KernelFactory::Registerar g_##type##_Kernel_Creator(type, Creator_##type##_Kernel) -}; // end namespace ge +} // namespace ge #endif // GE_INC_KERNEL_FACTORY_H_ diff --git a/src/ge/init/gelib.cc b/src/ge/init/gelib.cc index 5fcb0cd7..f7740a3c 100644 --- a/src/ge/init/gelib.cc +++ b/src/ge/init/gelib.cc @@ -37,6 +37,7 @@ #include "graph/load/new_model_manager/model_manager.h" #include "graph/manager/graph_mem_allocator.h" #include "graph/manager/graph_var_manager.h" +#include "graph/common/ge_call_wrapper.h" #include "omm/csa_interact.h" #include "runtime/kernel.h" @@ -46,6 +47,9 @@ namespace ge { namespace { const int kDecimal = 10; const int kSocVersionLen = 50; +const uint32_t kAicoreOverflow = (0x1 << 0); +const uint32_t kAtomicOverflow = (0x1 << 1); +const uint32_t kAllOverflow = (kAicoreOverflow | kAtomicOverflow); } // namespace static std::shared_ptr instancePtr_ = nullptr; @@ -75,7 +79,7 @@ Status GELib::Initialize(const map &options) { instancePtr_ = nullptr; return ret; } - GE_TIMESTAMP_END(Init, "GELib::Initialize"); + GE_TIMESTAMP_EVENT_END(Init, "GELib::Initialize"); return SUCCESS; } @@ -126,16 +130,6 @@ Status GELib::InnerInitialize(const map &options) { return initSmStatus; } - GELOGI("memoryMallocSize initial."); - GE_TIMESTAMP_START(SetMemoryMallocSize); - Status initMemStatus = VarManager::Instance(0)->SetMemoryMallocSize(options); - GE_TIMESTAMP_END(SetMemoryMallocSize, "InnerInitialize::SetMemoryMallocSize"); - if (initMemStatus != SUCCESS) { - GELOGE(initMemStatus, "failed to set malloc size"); - RollbackInit(); - return initMemStatus; - } - GELOGI("Start to initialize HostCpuEngine"); GE_TIMESTAMP_START(HostCpuEngineInitialize); Status initHostCpuEngineStatus = HostCpuEngine::GetInstance().Initialize(); @@ -160,37 +154,6 @@ Status GELib::SystemInitialize(const map &options) { } } - iter = options.find(HEAD_STREAM); - head_stream_ = (iter != options.end()) ? std::strtol(iter->second.c_str(), nullptr, kDecimal) : false; - - iter = options.find(OPTION_EXEC_ENABLE_DUMP); - if (iter != options.end()) { - int32_t enable_dump_flag = 1; - auto path_iter = options.find(OPTION_EXEC_DUMP_PATH); - if (iter->second == std::to_string(enable_dump_flag) && path_iter != options.end()) { - std::string dump_path = path_iter->second; - if (!dump_path.empty() && dump_path[dump_path.size() - 1] != '/') { - dump_path = dump_path + "/" + CurrentTimeInStr() + "/"; - } - - PropertiesManager::Instance().AddDumpPropertyValue(DUMP_ALL_MODEL, {}); - GELOGD("Get dump path %s successfully", dump_path.c_str()); - PropertiesManager::Instance().SetDumpOutputPath(dump_path); - } - auto step_iter = options.find(OPTION_EXEC_DUMP_STEP); - if (step_iter != options.end()) { - std::string dump_step = step_iter->second; - GELOGD("Get dump step %s successfully", dump_step.c_str()); - PropertiesManager::Instance().SetDumpStep(dump_step); - } - auto mode_iter = options.find(OPTION_EXEC_DUMP_MODE); - if (mode_iter != options.end()) { - std::string dump_mode = mode_iter->second; - GELOGD("Get dump mode %s successfully", dump_mode.c_str()); - PropertiesManager::Instance().SetDumpMode(dump_mode); - } - } - // In train and infer, profiling is always needed. InitOptions(options); InitProfiling(this->options_); diff --git a/src/ge/init/gelib.h b/src/ge/init/gelib.h index 0dfec391..b5621dfd 100644 --- a/src/ge/init/gelib.h +++ b/src/ge/init/gelib.h @@ -62,9 +62,6 @@ class GELib { // get TrainMode flag bool isTrainMode() { return is_train_mode_; } - // add head stream to model - bool HeadStream() const { return head_stream_; } - // get incre build flag bool IsIncreBuild() const { return is_incre_build_; } @@ -86,6 +83,8 @@ class GELib { Status SetRTSocVersion(const map &options, map &new_options); void RollbackInit(); void InitOptions(const map &options); + void SetDumpModelOptions(const map &options); + void SetOpDebugOptions(const map &options); DNNEngineManager engineManager_; OpsKernelManager opsManager_; @@ -98,7 +97,6 @@ class GELib { bool is_shutdown = false; bool is_use_hcom = false; bool is_incre_build_ = false; - bool head_stream_ = false; std::string incre_build_cache_path_; }; } // namespace ge diff --git a/src/ge/ir_build/atc_ir_common.cc b/src/ge/ir_build/atc_ir_common.cc index 12c85bc0..91fa17d4 100644 --- a/src/ge/ir_build/atc_ir_common.cc +++ b/src/ge/ir_build/atc_ir_common.cc @@ -16,6 +16,7 @@ #include "atc_ir_common.h" #include "common/util/error_manager/error_manager.h" +#include "common/model_parser/graph_parser_util.h" #include "external/ge/ge_api_types.h" #include "framework/common/string_util.h" #include "framework/common/types.h" @@ -29,11 +30,23 @@ namespace ge { namespace { const int64_t kDynamicInputDim = -1; const int64_t kDynamicImageSizeNum = 2; +const size_t kMaxDynamicDimNum = 100; +const size_t kMaxNDDimNum = 4; +const size_t kMinNDDimNum = 1; // datatype/formats from user to GE, Unified to util interface file later const std::map kOutputTypeSupportDatatype = { {"FP32", ge::DT_FLOAT}, {"FP16", ge::DT_FLOAT16}, {"UINT8", ge::DT_UINT8}}; -const std::set kBufferOptimizeSupportOption = {"l2_optimize", "off_optimize"}; -const std::string IR_OPTION_OP_SELECT_IMPLMODE_DEFAULT = "high_performance"; +const char *const kOutputTypeSupport = "only support FP32, FP16, UINT8"; +const std::set kBufferOptimizeSupportOption = {"l1_optimize", "l2_optimize", "off_optimize", + "l1_and_l2_optimize"}; +// The function is incomplete. Currently, only l2_optimize, off_optimize is supported. +const char *const kBufferOptimizeSupport = "only support l2_optimize, off_optimize"; +const char *const IR_OPTION_OP_SELECT_IMPLMODE_DEFAULT = "high_performance"; +const char *const IR_OPTION_OP_SELECT_IMPLMODE_PRECISON = "high_precision"; +const char *const kCompressWeightError = "it must be appointed when appoint parameter[--optypelist_for_implmode]"; +const char *const kSelectImplmodeError = "only support high_performance, high_precision"; +const char *const kDynamicBatchSizeError = "It can only contains digit, \",\", \" \""; + } // namespace bool CheckDynamicBatchSizeInputShapeValid(unordered_map> shape_map, @@ -42,7 +55,7 @@ bool CheckDynamicBatchSizeInputShapeValid(unordered_map> for (auto iter = shape_map.begin(); iter != shape_map.end(); ++iter) { vector shape = iter->second; if (shape.size() < 1) { - ErrorManager::GetInstance().ATCReportErrMessage("E10017"); + ErrorManager::GetInstance().ATCReportErrMessage("E10012"); GELOGE(ge::PARAM_INVALID, "--input_shape's shape size can not be less than 1 when set --dynamic_batch_size."); return false; } @@ -61,16 +74,17 @@ bool CheckDynamicBatchSizeInputShapeValid(unordered_map> } if (size == 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10043"); + ErrorManager::GetInstance().ATCReportErrMessage("E10031"); GELOGE(ge::PARAM_INVALID, "At least one batch n must be equal to -1 when set --dynamic_batch_size."); return false; } for (char c : dynamic_batch_size) { if (!isdigit(c) && (c != ',') && (c != ' ')) { - ErrorManager::GetInstance().ATCReportErrMessage("E10047", {"value"}, {dynamic_batch_size}); - GELOGE(ge::PARAM_INVALID, "Input parameter[--dynamic_batch_size]'s value[%s] is invalid.", - dynamic_batch_size.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10033", {"value", "reason"}, + {dynamic_batch_size, kDynamicBatchSizeError}); + GELOGE(ge::PARAM_INVALID, "Input parameter[--dynamic_batch_size]'s value[%s] is invalid. reason: %s", + dynamic_batch_size.c_str(), kDynamicBatchSizeError); return false; } } @@ -90,7 +104,7 @@ bool CheckDynamicImagesizeInputShapeValid(unordered_map> if (std::count(shape.begin(), shape.end(), kDynamicInputDim) > 0) { ErrorManager::GetInstance().ATCReportErrMessage("E10019"); GELOGE(ge::PARAM_INVALID, - "--input_shape's shape is invalid, only height or width can be -1 when set --dynamic_image_size."); + "--input_shape's shape is invalid, only height and width can be -1 when set --dynamic_image_size."); return false; } continue; @@ -116,21 +130,18 @@ bool CheckDynamicImagesizeInputShapeValid(unordered_map> } else { ErrorManager::GetInstance().ATCReportErrMessage("E10019"); GELOGE(ge::PARAM_INVALID, - "--input_shape's shape is invalid, only height or width can be -1 when set --dynamic_image_size."); + "--input_shape's shape is invalid, only height and width can be -1 when set --dynamic_image_size."); return false; } } if (size == 0) { ErrorManager::GetInstance().ATCReportErrMessage("E10019"); GELOGE(ge::PARAM_INVALID, - "--input_shape's shape is invalid, only height or width can be -1 when set --dynamic_image_size."); + "--input_shape's shape is invalid, only height and width can be -1 when set --dynamic_image_size."); return false; } - if (dynamic_image_size.back() == ';') { - dynamic_image_size.erase(dynamic_image_size.end() - 1); - } - + EraseEndSemicolon(dynamic_image_size); // Different parameter sets are split string by ';' std::vector split_set = StringUtils::Split(dynamic_image_size, ';'); // Different dimensions are split by ',' @@ -151,17 +162,106 @@ bool CheckDynamicImagesizeInputShapeValid(unordered_map> return true; } -Status CheckDynamicBatchSizeOrImageSizeParamValid(std::string &dynamic_batch_size, std::string &dynamic_image_size, - const std::string input_shape, const std::string input_format, - bool &is_dynamic_input) { - if (!dynamic_batch_size.empty() && !dynamic_image_size.empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10009", {"parameter0", "parameter1"}, - {"dynamic_batch_size", "dynamic_image_size"}); - GELOGE(ge::PARAM_INVALID, "dynamic_batch_size and dynamic_image_size can not both exist"); +bool CheckDynamicDimsInputShapeValid(const unordered_map> &shape_map, string input_format, + string &dynamic_dims) { + if (input_format != "ND") { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--input_format", input_format.c_str(), "input_format must be ND when set dynamic_dims"}); + GELOGE(ge::PARAM_INVALID, "input_format must be ND when set dynamic_dims."); + return false; + } + + int32_t dynamic_dim = 0; + for (auto &info_shapes : shape_map) { + auto &shapes = info_shapes.second; + if (shapes.size() > kMaxNDDimNum || shapes.size() < kMinNDDimNum) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--input_shape's dim", std::to_string(shapes.size()), "Dim num must within [1, 4] when set dynamic_dims"}); + GELOGE(ge::PARAM_INVALID, "Dim num must within [%zu, %zu] when set dynamic_dims.", kMinNDDimNum, kMaxNDDimNum); + return false; + } + int tmp = std::count(shapes.begin(), shapes.end(), kDynamicInputDim); + if (dynamic_dim != 0 && dynamic_dim != tmp) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--input_shape's -1 num", std::to_string(tmp), "Every set's num of -1 must be same"}); + GELOGE(ge::PARAM_INVALID, "input_shape's shape is invalid, every set's num of -1 must be same."); + return false; + } + dynamic_dim = tmp; + } + if (dynamic_dim == 0) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--input_shape's dynamic dim num", "0", "at least one dim should be -1 when set dynamic_dims"}); + GELOGE(ge::PARAM_INVALID, "input_shape's shape is invalid, at least one dim should be -1 when set dynamic_dims."); + return false; + } + + if (!CheckAndParseDynamicDims(dynamic_dim, dynamic_dims)) { + GELOGE(ge::PARAM_INVALID, "Check and parse dynamic dims: %s failed.", dynamic_dims.c_str()); + return false; + } + + return true; +} + +bool CheckAndParseDynamicDims(int32_t dynamic_dim_num, std::string &dynamic_dims) { + EraseEndSemicolon(dynamic_dims); + if (dynamic_dims.empty()) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--dynamic_dims", dynamic_dims.c_str(), "dynamic_dims can not be empty"}); + GELOGE(ge::PARAM_INVALID, "dynamic_dims can not be empty."); + return false; + } + // Different parameter sets are split by ';' + vector split_set = StringUtils::Split(dynamic_dims, ';'); + if (split_set.size() > kMaxDynamicDimNum) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10042", {"parameter", "reason"}, {"dynamic_dims", "dynamic_dims's num of parameter set can not exceed 100"}); + GELOGE(ge::PARAM_INVALID, "dynamic_dims's num of parameter set can not exceed %zu.", kMaxDynamicDimNum); + return false; + } + for (auto split_dim : split_set) { + vector one_set = StringUtils::Split(split_dim, ','); + if (one_set.size() != static_cast(dynamic_dim_num)) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--dynamic_dims's parameter num of each set", std::to_string(one_set.size()), + "must be same as input_shape's num of -1"}); + GELOGE(ge::PARAM_INVALID, "dynamic_dims's parameter num of each set must be same as input_shape's num of -1."); + return false; + } + for (auto dim : one_set) { + for (auto c : dim) { + if (!isdigit(c)) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--dynamic_dims's parameter", dim.c_str(), "must be positive integer"}); + GELOGE(ge::PARAM_INVALID, "dynamic_dims's parameter must be positive integer."); + return false; + } + } + } + } + return true; +} + +Status CheckDynamicInputParamValid(string &dynamic_batch_size, string &dynamic_image_size, string &dynamic_dims, + const string input_shape, const string input_format, bool &is_dynamic_input) { + int32_t param_size = static_cast(!dynamic_batch_size.empty()) + + static_cast(!dynamic_image_size.empty()) + static_cast(!dynamic_dims.empty()); + if (param_size > 1) { + ErrorManager::GetInstance().ATCReportErrMessage("E10009", {"parameter0", "parameter1", "parameter2"}, + {"dynamic_batch_size", "dynamic_image_size", "dynamic_dims"}); + GELOGE(ge::PARAM_INVALID, "dynamic_batch_size, dynamic_image_size and dynamic_dims can only be set one"); return ge::PARAM_INVALID; } - if (dynamic_batch_size.empty() && dynamic_image_size.empty()) { + if (param_size == 0) { return ge::SUCCESS; } @@ -169,8 +269,8 @@ Status CheckDynamicBatchSizeOrImageSizeParamValid(std::string &dynamic_batch_siz vector>> user_shape_map; is_dynamic_input = true; if (input_shape.empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"input_shape"}); - GELOGE(ge::PARAM_INVALID, "The input_shape can not be empty in dynamic batchsize scenario."); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {"input_shape"}); + GELOGE(ge::PARAM_INVALID, "The input_shape can not be empty in dynamic input size scenario."); return ge::PARAM_INVALID; } @@ -192,86 +292,22 @@ Status CheckDynamicBatchSizeOrImageSizeParamValid(std::string &dynamic_batch_siz return ge::PARAM_INVALID; } } - return ge::SUCCESS; -} - -bool ParseInputShape(const string &input_shape, unordered_map> &shape_map, - vector>> &user_shape_map, bool is_dynamic_input) { - vector shape_vec = StringUtils::Split(input_shape, ';'); - const int DEFAULT_SHAPE_PAIR_SIZE = 2; - for (const auto &shape : shape_vec) { - vector shape_pair_vec = StringUtils::Split(shape, ':'); - if (shape_pair_vec.size() != DEFAULT_SHAPE_PAIR_SIZE) { - ErrorManager::GetInstance().ATCReportErrMessage("E10010", {"shape"}, {shape}); - GELOGW( - "Input parameter[--input_shape]’s shape is [%s], " - "correct sample is input_name1:n1,c1,h1,w1", - shape.c_str()); - return false; - } - if (shape_pair_vec[1].empty()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10011", {"shape"}, {shape}); - GELOGW( - "Input parameter[--input_shape]’s shape is [%s], can not empty, " - "correct sample is input_name1:n1,c1,h1,w1", - shape.c_str()); - return false; - } - - vector shape_value_strs = StringUtils::Split(shape_pair_vec[1], ','); - vector shape_values; - for (auto &shape_value_str : shape_value_strs) { - // stoul: The method may throw an exception: invalid_argument/out_of_range - if (std::string::npos != shape_value_str.find('.')) { - ErrorManager::GetInstance().ATCReportErrMessage("E10012", {"shape"}, {shape_value_str}); - GELOGW("--input_shape's shape value[%s] exist float number the correct sample is \"input_name1:1,3,224,224\"", - shape_value_str.c_str()); - return false; - } - long left_result = 0; - try { - left_result = stol(StringUtils::Trim(shape_value_str)); - } catch (const std::out_of_range &) { - ErrorManager::GetInstance().ATCReportErrMessage("E10013", {"parameter", "shape"}, {"input_shape", shape}); - GELOGW("--input_shape’s shape_value_str[%s] cause out of range execption!", shape_value_str.c_str()); - return false; - } catch (const std::invalid_argument &) { - ErrorManager::GetInstance().ATCReportErrMessage("E10014", {"parameter", "shape"}, - {"input_shape", shape_value_str}); - GELOGW("--input_shape’s shape_value_str[%s] cause invalid argument!", shape_value_str.c_str()); - return false; - } catch (...) { - ErrorManager::GetInstance().ATCReportErrMessage("E10015", {"parameter", "shape"}, - {"input_shape", shape_value_str}); - GELOGW("--input_shape’s shape_value_str[%s] stol fail!", shape_value_str.c_str()); - return false; - } - int64_t result = left_result; - // - 1 is not currently supported - if (!is_dynamic_input && result <= 0) { - ErrorManager::GetInstance().ATCReportErrMessage("E10057", {"shape", "result"}, {shape, std::to_string(result)}); - GELOGW( - "Input parameter[--input_shape]’s shape value[%s] is invalid, " - "expect positive integer, but value is %ld.", - shape.c_str(), result); - return false; - } - shape_values.push_back(result); + if (!dynamic_dims.empty()) { + if (!CheckDynamicDimsInputShapeValid(shape_map, input_format, dynamic_dims)) { + GELOGE(ge::PARAM_INVALID, "Check dynamic dims: %s of input shape: %s failed.", dynamic_dims.c_str(), + input_shape.c_str()); + return ge::PARAM_INVALID; } - - shape_map.emplace(make_pair(StringUtils::Trim(shape_pair_vec[0]), shape_values)); - user_shape_map.push_back(make_pair(StringUtils::Trim(shape_pair_vec[0]), shape_values)); } - - return true; + return ge::SUCCESS; } Status CheckOutputTypeParamValid(const std::string output_type) { if ((!output_type.empty()) && (kOutputTypeSupportDatatype.find(output_type) == kOutputTypeSupportDatatype.end())) { - ErrorManager::GetInstance().ATCReportErrMessage("E10042", {"value"}, {output_type}); - GELOGE(ge::PARAM_INVALID, "Invalid value for --output_type[%s], only support DT_FLOAT, DT_FLOAT16, DT_UINT8!!", - output_type.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--output_type", output_type, kOutputTypeSupport}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --output_type[%s], %s.", output_type.c_str(), kOutputTypeSupport); return ge::PARAM_INVALID; } return ge::SUCCESS; @@ -280,23 +316,23 @@ Status CheckOutputTypeParamValid(const std::string output_type) { Status CheckBufferOptimizeParamValid(const std::string buffer_optimize) { if ((!buffer_optimize.empty()) && (kBufferOptimizeSupportOption.find(buffer_optimize) == kBufferOptimizeSupportOption.end())) { - ErrorManager::GetInstance().ATCReportErrMessage( - "E10068", {"parameter", "value", "reason"}, - {"buffer_optimize", buffer_optimize, "only support l2_optimize or off_optimize"}); - GELOGE(ge::PARAM_INVALID, "buffer_optimize flag %s is invalid, only support l2_optimize or off_optimize", - buffer_optimize.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--buffer_optimize", buffer_optimize, kBufferOptimizeSupport}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --buffer_optimize[%s], %s.", buffer_optimize.c_str(), + kBufferOptimizeSupport); return ge::PARAM_INVALID; } return ge::SUCCESS; } Status CheckCompressWeightParamValid(const std::string enable_compress_weight, const std::string compress_weight_conf) { - if ((!compress_weight_conf.empty()) && - (!CheckInputPathValid(compress_weight_conf, ge::ir_option::COMPRESS_WEIGHT_CONF))) { + if ((!compress_weight_conf.empty()) && (!CheckInputPathValid(compress_weight_conf, "--compress_weight_conf"))) { GELOGE(ge::PARAM_INVALID, "compress weight config file not found, file_name:%s", compress_weight_conf.c_str()); return ge::PARAM_INVALID; } if ((enable_compress_weight != "") && (enable_compress_weight != "true") && (enable_compress_weight != "false")) { + ErrorManager::GetInstance().ATCReportErrMessage("E10005", {"parameter", "value"}, + {"enable_compress_weight", enable_compress_weight}); GELOGE(ge::PARAM_INVALID, "Input parameter[--enable_compress_weight]'s value[%s] must be true or false.", enable_compress_weight.c_str()); return ge::PARAM_INVALID; @@ -336,7 +372,7 @@ int CheckLogParamValidAndSetLogLevel(const std::string log) { } Status CheckInsertOpConfParamValid(const std::string insert_op_conf) { - if ((!insert_op_conf.empty()) && (!CheckInputPathValid(insert_op_conf, ge::ir_option::INSERT_OP_FILE))) { + if ((!insert_op_conf.empty()) && (!CheckInputPathValid(insert_op_conf, "--insert_op_conf"))) { GELOGE(ge::PARAM_INVALID, "insert op config file not found: %s", insert_op_conf.c_str()); return ge::PARAM_INVALID; } @@ -361,7 +397,7 @@ Status CheckDisableReuseMemoryParamValid(const std::string disable_reuse_memory) Status CheckEnableSingleStreamParamValid(const std::string enable_single_stream) { if ((enable_single_stream != "") && (enable_single_stream != "true") && (enable_single_stream != "false")) { - ErrorManager::GetInstance().ATCReportErrMessage("E10033", {"parameter", "value"}, + ErrorManager::GetInstance().ATCReportErrMessage("E10005", {"parameter", "value"}, {"enable_single_stream", enable_single_stream}); GELOGE(ge::PARAM_INVALID, "Input parameter[--enable_single_stream]'s value[%s] must be true or false.", enable_single_stream.c_str()); @@ -373,16 +409,28 @@ Status CheckEnableSingleStreamParamValid(const std::string enable_single_stream) Status CheckImplmodeParamValid(const std::string &optypelist_for_implmode, std::string &op_select_implmode) { // only appointed op_select_implmode, can user appoint optypelist_for_implmode if (optypelist_for_implmode != "" && op_select_implmode == "") { - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"op_select_implmode"}); - GELOGE( - ge::FAILED, - "Input parameter[--op_select_implmode] must be appointed when appoint parameter[--optypelist_for_implmode]."); + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--op_select_implmode", op_select_implmode.c_str(), kCompressWeightError}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --op_select_implmode[%s], %s.", op_select_implmode.c_str(), + kCompressWeightError); return ge::PARAM_INVALID; } // op_select_implmode default value is high_performance if (op_select_implmode == "") { op_select_implmode = IR_OPTION_OP_SELECT_IMPLMODE_DEFAULT; + } else { + if (op_select_implmode != IR_OPTION_OP_SELECT_IMPLMODE_DEFAULT && + op_select_implmode != IR_OPTION_OP_SELECT_IMPLMODE_PRECISON) { + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--op_select_implmode", op_select_implmode.c_str(), kSelectImplmodeError}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --op_select_implmode[%s], %s.", op_select_implmode.c_str(), + kSelectImplmodeError); + return ge::PARAM_INVALID; + } } + return ge::SUCCESS; } @@ -393,4 +441,13 @@ void PrintOptionMap(std::map &options, std::string tip GELOGI("%s set successfully, key=%s, value=%s", tips.c_str(), key.c_str(), option_name.c_str()); } } + +void EraseEndSemicolon(string ¶m) { + if (param.empty()) { + return; + } + if (param.back() == ';') { + param.erase(param.end() - 1); + } +} } // namespace ge diff --git a/src/ge/ir_build/atc_ir_common.h b/src/ge/ir_build/atc_ir_common.h index b0a2b08b..e4d3103b 100644 --- a/src/ge/ir_build/atc_ir_common.h +++ b/src/ge/ir_build/atc_ir_common.h @@ -29,10 +29,12 @@ #include "framework/omg/omg_inner_types.h" namespace ge { - static std::set caffe_support_input_format = {"NCHW", "ND"}; static std::set tf_support_input_format = {"NCHW", "NHWC", "ND", "NCDHW", "NDHWC"}; static std::set onnx_support_input_format = {"NCHW", "ND"}; +static const char *const kCaffeFormatSupport = "only support NCHW, ND in Caffe model"; +static const char *const kTFFormatSupport = "only support NCHW, NHWC, ND, NCDHW, NDHWC in TF model"; +static const char *const kONNXFormatSupport = "only support NCHW, ND in ONNX model"; static std::map input_format_str_to_geformat = { {"ND", domi::DOMI_TENSOR_ND}, {"NCHW", domi::DOMI_TENSOR_NCHW}, {"NHWC", domi::DOMI_TENSOR_NHWC}, @@ -47,12 +49,14 @@ bool CheckDynamicBatchSizeInputShapeValid(unordered_map> bool CheckDynamicImagesizeInputShapeValid(unordered_map> shape_map, const std::string input_format, std::string &dynamic_image_size); -Status CheckDynamicBatchSizeOrImageSizeParamValid(std::string &dynamic_batch_size, std::string &dynamic_image_size, - const std::string input_shape, const std::string input_format, - bool &is_dynamic_input); +bool CheckDynamicDimsInputShapeValid(const std::unordered_map> &shape_map, + std::string input_format, std::string &dynamic_dims); + +bool CheckAndParseDynamicDims(int32_t dynamic_dim_num, std::string &dynamic_dims); -bool ParseInputShape(const std::string &input_shape, std::unordered_map> &shape_map, - std::vector>> &user_shape_map, bool is_dynamic_input = false); +Status CheckDynamicInputParamValid(std::string &dynamic_batch_size, std::string &dynamic_image_size, + std::string &dynamic_dims, const std::string input_shape, + const std::string input_format, bool &is_dynamic_input); Status CheckOutputTypeParamValid(const std::string output_type); Status CheckBufferOptimizeParamValid(const std::string buffer_optimize); @@ -63,5 +67,6 @@ Status CheckDisableReuseMemoryParamValid(const std::string disable_reuse_memory) Status CheckEnableSingleStreamParamValid(const std::string enable_single_stream); Status CheckImplmodeParamValid(const std::string &optypelist_for_implmode, std::string &op_select_implmode); void PrintOptionMap(std::map &options, std::string tips); +void EraseEndSemicolon(std::string ¶m); } // namespace ge #endif // FRAMEWORK_DOMI_ATC_IR_COMMON_H_ diff --git a/src/ge/ir_build/ge_ir_build.cc b/src/ge/ir_build/ge_ir_build.cc index 0be75b51..a9ff1ab5 100644 --- a/src/ge/ir_build/ge_ir_build.cc +++ b/src/ge/ir_build/ge_ir_build.cc @@ -26,6 +26,7 @@ #include "framework/common/util.h" #include "framework/omg/omg_inner_types.h" #include "framework/omg/omg_inner_types.h" +#include "common/model_parser/graph_parser_util.h" #include "ge/ge_api_types.h" #include "generator/ge_generator.h" #include "graph/compute_graph.h" @@ -151,6 +152,7 @@ class Impl { GetContext().is_dynamic_input = false; GetContext().dynamic_batch_size.clear(); GetContext().dynamic_image_size.clear(); + GetContext().dynamic_dims.clear(); }; ~Impl() { (void)generator_.Finalize(); }; graphStatus CheckOptions(const std::map &options); @@ -200,17 +202,20 @@ graphStatus Impl::Init(const std::map &options) { string dynamic_image_size = options_.find(ge::ir_option::DYNAMIC_IMAGE_SIZE) == options_.end() ? "" : options_[ge::ir_option::DYNAMIC_IMAGE_SIZE]; + string dynamic_dims = + options_.find(ge::ir_option::DYNAMIC_DIMS) == options_.end() ? "" : options_[ge::ir_option::DYNAMIC_DIMS]; - auto status = CheckDynamicBatchSizeOrImageSizeParamValid(dynamic_batch_size, dynamic_image_size, input_shape, - input_format, is_dynamic_input_); + auto status = CheckDynamicInputParamValid(dynamic_batch_size, dynamic_image_size, dynamic_dims, input_shape, + input_format, is_dynamic_input_); if (status != ge::SUCCESS) { - GELOGE(GRAPH_PARAM_INVALID, "check dynamic batch size or image size failed!"); + GELOGE(GRAPH_PARAM_INVALID, "Check dynamic input size failed!"); return GRAPH_PARAM_INVALID; } - GELOGD("user input dynamic_batch_size:%s,dynamic_image_size:%s", dynamic_batch_size.c_str(), - dynamic_image_size.c_str()); + GELOGD("User input dynamic_batch_size:%s, dynamic_image_size:%s, dynamic_dims:%s.", dynamic_batch_size.c_str(), + dynamic_image_size.c_str(), dynamic_dims.c_str()); GetContext().dynamic_batch_size = dynamic_batch_size; GetContext().dynamic_image_size = dynamic_image_size; + GetContext().dynamic_dims = dynamic_dims; // check output_type std::string output_type = options_.find(ge::ir_option::OUTPUT_TYPE) == options_.end() ? "" : options_[ge::ir_option::OUTPUT_TYPE]; @@ -243,11 +248,13 @@ graphStatus Impl::Init(const std::map &options) { graphStatus Impl::CreateInputsForIRBuild(const ge::Graph &graph, vector &inputs) { auto compute_graph = ge::GraphUtils::GetComputeGraph(graph); GE_CHECK_NOTNULL(compute_graph); + int64_t index = 0; for (ge::NodePtr &input_node : compute_graph->GetDirectNode()) { GE_CHECK_NOTNULL(input_node); ge::OpDescPtr op = input_node->GetOpDesc(); GE_CHECK_NOTNULL(op); if (op->GetType() == DATA) { + (void)AttrUtils::SetInt(op, ATTR_NAME_INDEX, index++); GELOGI("Data op inputDesc size is: %zu", op->GetAllInputsDesc().size()); ge::GeTensorDesc tensor = op->GetInputDesc(0); string data_op_name = op->GetName(); @@ -259,7 +266,7 @@ graphStatus Impl::CreateInputsForIRBuild(const ge::Graph &graph, vector(model.data.get()), static_cast(model.length)); } - } // namespace ge diff --git a/src/ge/model/ge_model.h b/src/ge/model/ge_model.h index 6305211a..be4b65bc 100644 --- a/src/ge/model/ge_model.h +++ b/src/ge/model/ge_model.h @@ -87,6 +87,6 @@ class GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY GeModel : public AttrHolder uint8_t platform_type_ = {0}; uint32_t model_id_ = INVALID_MODEL_ID; }; -}; // namespace ge +} // namespace ge using GeModelPtr = std::shared_ptr; #endif // GE_MODEL_GE_MODEL_H_ diff --git a/src/ge/offline/main.cc b/src/ge/offline/main.cc index 61a843c3..214e495a 100644 --- a/src/ge/offline/main.cc +++ b/src/ge/offline/main.cc @@ -26,6 +26,7 @@ #include "common/gflags_util.h" #include "common/util.h" #include "common/util/error_manager/error_manager.h" +#include "common/model_parser/graph_parser_util.h" #include "framework/common/debug/ge_log.h" #include "ge/ge_api.h" #include "generator/ge_generator.h" @@ -66,6 +67,10 @@ static bool is_dynamic_input = false; // 310 limited 8G size const char *const kGraphMemoryManagerMallocMaxSize = "8*1024*1024*1024"; +const char *const kModeSupport = + "only support 0(model to framework model), " + "1(framework model to json), 3(only pre-check), 5(pbtxt to json)"; +const char *const kModelToJsonSupport = "only support 0(Caffe) 3(TensorFlow)"; DEFINE_string(model, "", "The model file."); DEFINE_string(output, "", "The output file path&name."); @@ -138,10 +143,6 @@ DEFINE_string(optypelist_for_implmode, "", "Optional; Nodes need use implmode selected in op_select_implmode " "Format:\"node_name1,node_name2\""); -DEFINE_string(head_stream, "0", - "Optional; Is need head stream, default is not need." - "Format: \"0: no head stream; 1: add head stream;\""); - DEFINE_string(singleop, "", "Optional; If set, generate single op model with the given json file."); DEFINE_int32(disable_reuse_memory, 0, "Optional; If set to 1, disable reuse memory when generating if."); @@ -163,26 +164,36 @@ DEFINE_string(save_original_model, "", "Optional; enable output original offline DEFINE_string(dynamic_batch_size, "", "Optional; If set, generate dynamic multi batch model. " "Different batch sizes are split by ','." - "dynamic_batch_size and dynamic_imagesize can only be set one."); + "dynamic_batch_size, dynamic_image_size and dynamic_dims can only be set one."); DEFINE_string(dynamic_image_size, "", "Optional; If set, generate dynamic multi image size model." "Different groups of image size are split by ';'," "while different dimensions of each group are split by ','." - "dynamic_batch_size and dynamic_imagesize can only be set one."); + "dynamic_batch_size, dynamic_image_size and dynamic_dims can only be set one."); + +DEFINE_string(dynamic_dims, "", + "Optional; If set, generate dynamic input size model. " + "Different groups of size are split by ';', while different dimensions of each group are split by ','." + "dynamic_batch_size, dynamic_image_size and dynamic_dims can only be set one."); DEFINE_string(enable_small_channel, "0", "Optional; If set to 1, small channel is enabled."); -DEFINE_bool(enable_compress_weight, false, "Optional; enable compress weight. true: enable; false(default): disable"); +DEFINE_string(enable_compress_weight, "false", + "Optional; enable compress weight. true: enable; false(default): disable"); DEFINE_string(compress_weight_conf, "", "Optional; the config file to compress weight"); DEFINE_string(enable_single_stream, "", "Optional; enable single stream. true: enable; false(default): disable"); -DEFINE_string(log, "default", "Optional; generate atc log. Support debug, info, warning, error, null"); +DEFINE_string(log, "null", "Optional; generate atc log. Support debug, info, warning, error, null"); DEFINE_string(dump_mode, "0", "Optional; generate infershape json,only support 1 , 0."); +DEFINE_int32(op_debug_level, 0, + "Optional; configure debug level of compiler. 0(default): close debug;" + "1: open TBE compiler, export ccec file and TBE instruction mapping file; 2: open ccec compiler"); + class GFlagUtils { public: /** @@ -232,7 +243,7 @@ class GFlagUtils { "\"check_result.json\"\n" " --disable_reuse_memory The switch of reuse memory. Default value is : 0." "0 means reuse memory, 1 means do not reuse memory.\n" - " --input_fp16_nodes Input node datatype is fp16 and format is NCHW. Separate multiple nodes with semicolons " + " --input_fp16_nodes Input node datatype is fp16. Separate multiple nodes with semicolons " "(;)." "Use double quotation marks (\") to enclose each argument." "E.g.: \"node_name1;node_name2\"\n" @@ -252,8 +263,7 @@ class GFlagUtils { " --optypelist_for_implmode Appoint which op to use op_select_implmode, used with op_select_implmode ." "Separate multiple nodes with commas (,). Use double quotation marks (\") to enclose each argument." "E.g.: \"node_name1,node_name2\"\n" - " --head_stream Add head stream. 0(default): disable; 1: enable\n" - " --soc_version The soc version. E.g.: \"Ascend310\"\n" + " --soc_version The soc version.\n" " --core_type Set core type AiCore or VectorCore. VectorCore: use vector core. " "Default value is: AiCore\n" " --enable_compress_weight Enable compress weight. true: enable; false(default): disable\n" @@ -280,7 +290,7 @@ class GFlagUtils { static Status CheckDumpInfershapeJsonFlags() { Status ret = CheckFrameWorkValid(FLAGS_framework, FLAGS_weight); GE_CHK_BOOL_EXEC(ret == domi::SUCCESS, return domi::FAILED, "check custom aicpu run so failed!"); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_weight != "" && !ge::CheckInputPathValid(FLAGS_weight, "weight"), + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_weight != "" && !ge::CheckInputPathValid(FLAGS_weight, "--weight"), return domi::FAILED, "Input parameter[--weight]'s value[%s] is invalid!", FLAGS_weight.c_str()); return domi::SUCCESS; @@ -289,7 +299,7 @@ class GFlagUtils { static Status CheckFlags() { // No model file information passed in GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_model == "", - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"model"}); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {"model"}); return domi::PARAM_INVALID, "Input parameter[--model]'s value is empty!"); // check param disable_reuse_memory GE_CHK_BOOL_EXEC(ge::CheckDisableReuseMemoryParamValid(to_string(FLAGS_disable_reuse_memory)) == ge::SUCCESS, @@ -301,16 +311,16 @@ class GFlagUtils { return ge::FAILED, "check optypelist_for_implmode and op_select_implmode failed!"); // No output file information passed in GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_mode == GEN_OM_MODEL && FLAGS_output == "", - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"output"}); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {"output"}); return domi::PARAM_INVALID, "Input parameter[--output]'s value is empty!"); Status ret = CheckFrameWorkValid(FLAGS_framework, FLAGS_weight); GE_CHK_BOOL_EXEC(ret == domi::SUCCESS, return domi::FAILED, "CheckFrameWorkValid failed"); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(ge::CheckDynamicBatchSizeOrImageSizeParamValid( - FLAGS_dynamic_batch_size, FLAGS_dynamic_image_size, FLAGS_input_shape, - FLAGS_input_format, is_dynamic_input) != ge::SUCCESS, - return ge::FAILED, "check dynamic batch size or image size failed!"); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( + ge::CheckDynamicInputParamValid(FLAGS_dynamic_batch_size, FLAGS_dynamic_image_size, FLAGS_dynamic_dims, + FLAGS_input_shape, FLAGS_input_format, is_dynamic_input) != ge::SUCCESS, + return ge::FAILED, "check dynamic size(batch size, image size or dims) failed!"); #if !defined(__ANDROID__) && !defined(ANDROID) GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!CheckEncryptModeValid(FLAGS_encrypt_mode), return domi::FAILED, @@ -320,16 +330,16 @@ class GFlagUtils { GELOGI("domi will run with encrypt!"); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_encrypt_key), return domi::FAILED, - "encrypt_key file %s not found!!", FLAGS_encrypt_key.c_str()); + "encrypt_key file not found!!"); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_certificate), return domi::FAILED, - "certificate file %s not found!!", FLAGS_certificate.c_str()); + "certificate file not found!!"); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_hardware_key), return domi::FAILED, - "hardware_key file %s not found!!", FLAGS_hardware_key.c_str()); + "hardware_key file not found!!"); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_private_key), return domi::FAILED, - "private_key file %s not found!!", FLAGS_private_key.c_str()); + "private_key file not found!!"); } else { // No encryption GELOGI("domi will run without encrypt!"); } @@ -338,43 +348,37 @@ class GFlagUtils { /** * Check the validity of the I / O file path */ - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_model, "model"), return domi::FAILED, + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_model, "--model"), return domi::FAILED, "model file %s not found!!", FLAGS_model.c_str()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_weight != "" && !ge::CheckInputPathValid(FLAGS_weight, "weight"), + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_weight != "" && !ge::CheckInputPathValid(FLAGS_weight, "--weight"), return domi::FAILED, "weight file %s not found!!", FLAGS_weight.c_str()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_cal_conf != "" && !ge::CheckInputPathValid(FLAGS_cal_conf, "cal_conf"), + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_cal_conf != "" && !ge::CheckInputPathValid(FLAGS_cal_conf, "--cal_conf"), return domi::FAILED, "calibration config file %s not found!!", FLAGS_cal_conf.c_str()); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( - FLAGS_op_name_map != "" && !ge::CheckInputPathValid(FLAGS_op_name_map, "op_name_map"), return domi::FAILED, + FLAGS_op_name_map != "" && !ge::CheckInputPathValid(FLAGS_op_name_map, "--op_name_map"), return domi::FAILED, "op config file %s not found!!", FLAGS_op_name_map.c_str()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( - FLAGS_head_stream != "" && FLAGS_head_stream != "0" && FLAGS_head_stream != "1", - ErrorManager::GetInstance().ATCReportErrMessage("E10006", {"parameter"}, {"head_stream"}); - return domi::FAILED, "Input parameter[--head_stream] must be 0 or 1!!"); - GE_CHK_BOOL_EXEC(ge::CheckInsertOpConfParamValid(std::string(FLAGS_insert_op_conf)) == ge::SUCCESS, return ge::FAILED, "check insert op conf failed!"); GE_CHK_BOOL_EXEC( - ge::CheckCompressWeightParamValid(FLAGS_enable_compress_weight ? std::string("true") : std::string("false"), - FLAGS_compress_weight_conf) == ge::SUCCESS, + ge::CheckCompressWeightParamValid(FLAGS_enable_compress_weight, FLAGS_compress_weight_conf) == ge::SUCCESS, return ge::FAILED, "check compress weight failed!"); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckOutputPathValid(FLAGS_check_report, "check_report"), return domi::FAILED, + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckOutputPathValid(FLAGS_check_report, "--check_report"), return domi::FAILED, "check_report file %s not found!!", FLAGS_check_report.c_str()); - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( - FLAGS_mode == GEN_OM_MODEL && (!ge::CheckOutputPathValid(FLAGS_output) || !CheckPathWithName(FLAGS_output)), - return domi::FAILED, "output path %s is not valid!!", FLAGS_output.c_str()); + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_mode == GEN_OM_MODEL && (!ge::CheckOutputPathValid(FLAGS_output, "--output") || + !CheckPathWithName(FLAGS_output)), + return domi::FAILED, "output path %s is not valid!!", FLAGS_output.c_str()); GE_CHK_BOOL_TRUE_EXEC_WITH_LOG( FLAGS_save_original_model != "" && FLAGS_save_original_model != "true" && FLAGS_save_original_model != "false", - ErrorManager::GetInstance().ATCReportErrMessage("E10033", {"parameter", "value"}, + ErrorManager::GetInstance().ATCReportErrMessage("E10005", {"parameter", "value"}, {"save_original_model", FLAGS_save_original_model}); return domi::FAILED, "Input parameter[--save_original_model]'s value[%s] must be true or false.", FLAGS_save_original_model.c_str()); @@ -395,18 +399,18 @@ class GFlagUtils { static Status CheckConverJsonParamFlags() { // No model path passed in GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_om == "", - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"om"}); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {"om"}); return domi::PARAM_INVALID, "Input parameter[--om]'s value is empty!!"); // JSON path not passed in GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(FLAGS_json == "", - ErrorManager::GetInstance().ATCReportErrMessage("E10000", {"parameter"}, {"json"}); + ErrorManager::GetInstance().ATCReportErrMessage("E10004", {"parameter"}, {"json"}); return domi::PARAM_INVALID, "Input parameter[--json]'s value is empty!!"); // Check if the model path is valid - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_om, "om"), return domi::PARAM_INVALID, + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckInputPathValid(FLAGS_om, "--om"), return domi::PARAM_INVALID, "model file path is invalid: %s.", FLAGS_om.c_str()); // Check whether the JSON path is valid - GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckOutputPathValid(FLAGS_json, "om"), return domi::PARAM_INVALID, + GE_CHK_BOOL_TRUE_EXEC_WITH_LOG(!ge::CheckOutputPathValid(FLAGS_json, "--json"), return domi::PARAM_INVALID, "json file path is invalid: %s.", FLAGS_json.c_str()); return domi::SUCCESS; @@ -443,7 +447,8 @@ class GFlagUtils { if (framework != (int32_t)domi::CAFFE && framework != (int32_t)domi::TENSORFLOW && framework != (int32_t)domi::MINDSPORE && framework != (int32_t)domi::ONNX) { // No framework information was passed in or the entered framework is illegal - ErrorManager::GetInstance().ATCReportErrMessage("E10007", {"parameter"}, {"framework"}); + ErrorManager::GetInstance().ATCReportErrMessage("E10007", {"parameter", "support"}, + {"framework", "0(Caffe) or 1(MindSpore) or 3(TensorFlow)"}); DOMI_LOGE( "Input parameter[--framework] is mandatory and it's value must be: " "0(Caffe) or 1(MindSpore) or 3(TensorFlow)."); @@ -494,13 +499,16 @@ class GFlagUtils { } }; -void SetDynamicBatchSizeOrImagesizeOptions() { +void SetDynamicInputSizeOptions() { if (!FLAGS_dynamic_batch_size.empty()) { domi::GetContext().dynamic_batch_size = FLAGS_dynamic_batch_size; } if (!FLAGS_dynamic_image_size.empty()) { domi::GetContext().dynamic_image_size = FLAGS_dynamic_image_size; } + if (!FLAGS_dynamic_dims.empty()) { + domi::GetContext().dynamic_dims = FLAGS_dynamic_dims; + } } static bool CheckInputFormat() { @@ -516,31 +524,29 @@ static bool CheckInputFormat() { if (ge::caffe_support_input_format.find(FLAGS_input_format) != ge::caffe_support_input_format.end()) { return true; } - ErrorManager::GetInstance().ATCReportErrMessage("E10031", {"value"}, {FLAGS_input_format}); // only support NCHW ND - GELOGE(ge::FAILED, - "Input parameter[--input_format]'s value[%s] is wrong, " - "only support NCHW, ND in Caffe model.", - FLAGS_input_format.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--input_format", FLAGS_input_format, ge::kCaffeFormatSupport}); + GELOGE(ge::FAILED, "Invalid value for --input_format[%s], %s.", FLAGS_input_format.c_str(), + ge::kCaffeFormatSupport); return false; } else if ((FLAGS_framework == static_cast(domi::TENSORFLOW))) { // tf if (ge::tf_support_input_format.find(FLAGS_input_format) != ge::tf_support_input_format.end()) { return true; } - ErrorManager::GetInstance().ATCReportErrMessage("E10032", {"value"}, {FLAGS_input_format}); // only support NCHW NHWC ND NCDHW NDHWC - GELOGE(ge::FAILED, - "Input parameter[--input_format]'s value[%s] is wrong, " - "only support NCHW, NHWC, ND, NCDHW, NDHWC in tf model", - FLAGS_input_format.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--input_format", FLAGS_input_format, ge::kTFFormatSupport}); + GELOGE(ge::FAILED, "Invalid value for --input_format[%s], %s.", FLAGS_input_format.c_str(), ge::kTFFormatSupport); return false; } else if (FLAGS_framework == static_cast(domi::ONNX)) { if (ge::onnx_support_input_format.find(FLAGS_input_format) != ge::onnx_support_input_format.end()) { return true; } // only support NCHW ND - GELOGE(ge::FAILED, "Input parameter[--input_format]'s value[%s] is error, Only support NCHW, ND in onnx model", - FLAGS_input_format.c_str()); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--input_format", FLAGS_input_format, ge::kONNXFormatSupport}); + GELOGE(ge::FAILED, "Invalid value for --input_format[%s], %s.", FLAGS_input_format.c_str(), ge::kONNXFormatSupport); return false; } return true; @@ -579,12 +585,12 @@ void GetPluginSoFileList(const string &path, vector &fileList, string &c void LoadModelParserLib(std::string caffe_parser_path) { if (FLAGS_framework == static_cast(domi::TENSORFLOW)) { - void *tf_handle = dlopen("libfmk_tensorflow_parser.so", RTLD_NOW | RTLD_GLOBAL); + void *tf_handle = dlopen("libfmk_parser.so", RTLD_NOW | RTLD_GLOBAL); if (tf_handle == nullptr) { - GELOGW("dlopen fmk library [libfmk_tensorflow_parser.so] failed."); + GELOGW("dlopen fmk library [libfmk_parser.so] failed."); return; } - GELOGI("plugin load libfmk_tensorflow_parser.so success."); + GELOGI("plugin load libfmk_parser.so success."); } else if (FLAGS_framework == static_cast(domi::CAFFE)) { // What we are dealing with here is that the user modifies the caffe.proto scenario. // If no lib_Caffe_Parser.so is found under the plugin path, use the default lib_Caffe_Parser.so path. @@ -596,17 +602,17 @@ void LoadModelParserLib(std::string caffe_parser_path) { return; } GELOGI("plugin load %s success.", caffe_parser_path.c_str()); - // According to the dependency, the Caffe parsing module of the framework is loaded here( libfmk_caffe_parser.so). + // According to the dependency, the Caffe parsing module of the framework is loaded here( libfmk_parser.so). // (depend on the lib_caffe_parser.so) - void *fmk_handle = dlopen("libfmk_caffe_parser.so", RTLD_NOW | RTLD_GLOBAL); + void *fmk_handle = dlopen("libfmk_parser.so", RTLD_NOW | RTLD_GLOBAL); if (fmk_handle == nullptr) { - GELOGW("dlopen fmk library [libfmk_caffe_parser.so] failed."); + GELOGW("dlopen fmk library [libfmk_parser.so] failed."); if (dlclose(handle) != 0) { GELOGW("dlclose lib_caffe_parser.so failed."); } return; } - GELOGI("plugin load libfmk_caffe_parser.so success."); + GELOGI("plugin load libfmk_parser.so success."); } else if (FLAGS_framework == static_cast(domi::ONNX)) { void *handle = dlopen("libfmk_onnx_parser.so", RTLD_NOW | RTLD_GLOBAL); if (handle == nullptr) { @@ -622,8 +628,7 @@ void LoadModelParserLib(std::string caffe_parser_path) { return; } -void LoadCustomOpLib() { - OpRegistry::Instance()->registrationDatas.clear(); +void LoadCustomOpLib(bool need_load_ops_plugin) { std::string plugin_path; GetCustomOpPath(plugin_path); @@ -639,7 +644,11 @@ void LoadCustomOpLib() { } LoadModelParserLib(caffe_parser_path); - + if (!need_load_ops_plugin) { + GELOGI("No need to load ops plugin so."); + return; + } + OpRegistry::Instance()->registrationDatas.clear(); // load other so files except lib_caffe_parser.so in the plugin so path for (auto elem : fileList) { ge::StringUtils::Trim(elem); @@ -654,17 +663,23 @@ void LoadCustomOpLib() { std::vector registrationDatas = OpRegistry::Instance()->registrationDatas; for (OpRegistrationData reg_data : registrationDatas) { - bool ret = ge::OpRegistrationTbe::Instance()->Finalize(reg_data); - if (ret) { - OpRegistry::Instance()->Register(reg_data); + if (reg_data.GetFrameworkType() == static_cast(FLAGS_framework)) { + (void)ge::OpRegistrationTbe::Instance()->Finalize(reg_data); + (void)OpRegistry::Instance()->Register(reg_data); } } } void SaveCustomCaffeProtoPath() { GELOGI("Enter save custom caffe proto path."); - string customop_path; + std::string path_base = ge::GELib::GetPath(); + GELOGI("path_base is %s", path_base.c_str()); + path_base = path_base.substr(0, path_base.rfind('/')); + path_base = path_base.substr(0, path_base.rfind('/') + 1); + ge::GetParserContext().caffe_proto_path = path_base + "include/proto/"; + + string customop_path; const char *path_env = std::getenv("ASCEND_OPP_PATH"); if (path_env != nullptr) { std::string path = path_env; @@ -673,10 +688,6 @@ void SaveCustomCaffeProtoPath() { ge::GetParserContext().custom_proto_path = customop_path; return; } - std::string path_base = ge::GELib::GetPath(); - GELOGI("path_base is %s", path_base.c_str()); - path_base = path_base.substr(0, path_base.rfind('/')); - path_base = path_base.substr(0, path_base.rfind('/') + 1); customop_path = path_base + "ops/framework/custom/caffe/"; ge::GetParserContext().custom_proto_path = customop_path; return; @@ -720,15 +731,6 @@ Status CreateInputsForInference(const ge::Graph &graph, vector &in return ge::SUCCESS; } -void ChangeStringToBool(std::string &arg_s, bool arg_b) { - if (arg_s == "true") { - arg_b = true; - } else { - arg_b = false; - } - return; -} - domi::Status GenerateInfershapeJson() { if (!CheckInputFormat()) { GELOGE(ge::FAILED, "Check input_format failed"); @@ -737,8 +739,6 @@ domi::Status GenerateInfershapeJson() { Status ret = GFlagUtils::CheckDumpInfershapeJsonFlags(); GE_CHK_BOOL_EXEC(ret == domi::SUCCESS, return domi::FAILED, "Check flags failed!"); - // Load custom operator Library - LoadCustomOpLib(); ge::GeGenerator ge_generator; std::map options; ge::Status geRet = ge_generator.Initialize(options); @@ -780,24 +780,25 @@ static Status ConvertModelToJson(int fwk_type, const string &model_file, const s return ret; } - if ((fwk_type != domi::TENSORFLOW) && (fwk_type != domi::CAFFE)) { - ErrorManager::GetInstance().ATCReportErrMessage( - "E10068", {"param", "value", "supports"}, - {"framework", std::to_string(fwk_type), "only support 0(Caffe) 3(TensorFlow)"}); - GELOGE(ge::FAILED, "Input parameter[--framework] is mandatory and it's value must be: 0(Caffe) 3(TensorFlow)."); + if ((fwk_type != domi::TENSORFLOW) && (fwk_type != domi::CAFFE) && (fwk_type != domi::ONNX)) { + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--framework", std::to_string(fwk_type), kModelToJsonSupport}); + GELOGE(ge::FAILED, "Invalid value for --framework[%d], %s.", fwk_type, kModelToJsonSupport); return ge::FAILED; } - // Since the Caffe model's conversion to JSON file depends on lib_caffe_parser.so, loadcustomoplib is called here. - LoadCustomOpLib(); - if (FLAGS_dump_mode == "0") { + // Caffe or tf model to json depend on lib_caffe_parser.so or libfmk_parser.so. + LoadCustomOpLib(false); ret = ge::ConvertFwkModelToJson((domi::FrameworkType)fwk_type, model_file.c_str(), json_file.c_str()); return ret; } else if (FLAGS_dump_mode == "1") { + // Caffe or tf model to json depend on lib_caffe_parser.so or libfmk_parser.so and ops plugin so. + LoadCustomOpLib(true); ret = GenerateInfershapeJson(); return ret; } else { + ErrorManager::GetInstance().ATCReportErrMessage("E10006", {"parameter"}, {"dump_mode"}); GELOGE(ge::FAILED, "Input parameter[--dump_mode]'s value must be 1 or 0."); return ge::FAILED; } @@ -828,7 +829,7 @@ domi::Status GenerateModel(std::map &options, std::string output ge::Model load_model = ge::Model("loadmodel", "version2"); auto ret1 = load_model.LoadFromFile(FLAGS_model); if (ret1 != ge::GRAPH_SUCCESS) { - ErrorManager::GetInstance().ATCReportErrMessage("E10056", {"parameter"}, {FLAGS_model}); + ErrorManager::GetInstance().ATCReportErrMessage("E10041", {"parameter"}, {FLAGS_model}); DOMI_LOGE( "Load model from %s failed, please check model file or " "input parameter[--framework] is correct", @@ -893,7 +894,7 @@ domi::Status GenerateModel(std::map &options, std::string output (void)ge::GELib::GetInstance()->Finalize(); return domi::FAILED; } - if (SetOutputNodeInfo(graph, FLAGS_output_type, "") != domi::SUCCESS) { + if (ge::SetOutputNodeInfo(graph, FLAGS_output_type, "") != domi::SUCCESS) { DOMI_LOGE("Set output node info fail."); (void)ge_generator.Finalize(); (void)ge::GELib::GetInstance()->Finalize(); @@ -931,10 +932,11 @@ static void SetEnvForSingleOp(std::map &options) { options.emplace(ge::OPTYPELIST_FOR_IMPLMODE, FLAGS_optypelist_for_implmode); options.emplace(ge::AUTO_TUNE_MODE, FLAGS_auto_tune_mode); options.emplace(ge::GRAPH_MEMORY_MAX_SIZE, kGraphMemoryManagerMallocMaxSize); + options.emplace(ge::OP_DEBUG_LEVEL, to_string(FLAGS_op_debug_level)); } domi::Status GenerateSingleOp(const std::string &json_file_path) { - if (!FLAGS_output.empty() && !ge::CheckOutputPathValid(FLAGS_output)) { + if (!FLAGS_output.empty() && !ge::CheckOutputPathValid(FLAGS_output, "--output")) { DOMI_LOGE("output path %s is not valid!", FLAGS_output.c_str()); return domi::FAILED; } @@ -947,12 +949,6 @@ domi::Status GenerateSingleOp(const std::string &json_file_path) { // need to be changed when ge.ini plan is done SetEnvForSingleOp(options); - vector build_params; - if (ge::SingleOpParser::ParseSingleOpList(json_file_path, build_params) != ge::SUCCESS) { - DOMI_LOGE("parse single op json file failed"); - return domi::FAILED; - } - auto ret = ge::GELib::Initialize(options); if (ret != ge::SUCCESS) { DOMI_LOGE("GE initialize failed!"); @@ -967,6 +963,14 @@ domi::Status GenerateSingleOp(const std::string &json_file_path) { return domi::FAILED; } + vector build_params; + if (ge::SingleOpParser::ParseSingleOpList(json_file_path, build_params) != ge::SUCCESS) { + DOMI_LOGE("parse single op json file failed"); + (void)generator.Finalize(); + (void)ge::GELib::GetInstance()->Finalize(); + return domi::FAILED; + } + int index = 0; for (auto ¶m : build_params) { string output_path; @@ -1000,7 +1004,7 @@ domi::Status GenerateOmModel() { "quotation marks (\") to enclose each argument such as out_nodes, input_shape, dynamic_image_size"); #if !defined(__ANDROID__) && !defined(ANDROID) // Load custom operator Library - LoadCustomOpLib(); + LoadCustomOpLib(true); SaveCustomCaffeProtoPath(); @@ -1038,8 +1042,6 @@ domi::Status GenerateOmModel() { options.insert(std::pair(ge::INPUT_FP16_NODES, FLAGS_input_fp16_nodes)); } - options.insert(std::pair(string(ge::HEAD_STREAM), FLAGS_head_stream)); - options.insert(std::pair(string(ge::AUTO_TUNE_MODE), FLAGS_auto_tune_mode)); options.insert( @@ -1057,7 +1059,7 @@ domi::Status GenerateOmModel() { options.insert(std::pair(string(ge::FUSION_SWITCH_FILE), FLAGS_fusion_switch_file)); - options.insert(std::pair(string(ge::ENABLE_COMPRESS_WEIGHT), FLAGS_enable_compress_weight + options.insert(std::pair(string(ge::ENABLE_COMPRESS_WEIGHT), (FLAGS_enable_compress_weight == "true") ? ge::kEnableCompressWeightTrue : ge::kEnableCompressWeightFalse)); @@ -1065,13 +1067,15 @@ domi::Status GenerateOmModel() { options.insert(std::pair(string(ge::ENABLE_SINGLE_STREAM), FLAGS_enable_single_stream)); - SetDynamicBatchSizeOrImagesizeOptions(); + SetDynamicInputSizeOptions(); if (!FLAGS_save_original_model.empty()) { options.insert(std::pair(string(ge::SAVE_ORIGINAL_MODEL), FLAGS_save_original_model)); options.insert(std::pair(string(ge::ORIGINAL_MODEL_FILE), FLAGS_output + "_original.om")); } + options.insert(std::pair(string(ge::OP_DEBUG_LEVEL), to_string(FLAGS_op_debug_level))); + // print atc option map ge::PrintOptionMap(options, "atc option"); @@ -1095,8 +1099,8 @@ domi::Status ConvertModelToJson() { return domi::SUCCESS; } -bool CheckRet(domi::Status ret, ge::Status geRet) { - if (ret != domi::SUCCESS || geRet != ge::SUCCESS) { +bool CheckRet(domi::Status ret) { + if (ret != domi::SUCCESS) { if (FLAGS_mode == ONLY_PRE_CHECK) { GELOGW("ATC precheck failed."); } else if (FLAGS_mode == GEN_OM_MODEL) { @@ -1143,9 +1147,9 @@ int init(int argc, char *argv[]) { GFlagUtils::InitGFlag(argc, argv); // set log level int ret = -1; - const std::set log_level = {"default", "null", "debug", "info", "warning", "error"}; + const std::set log_level = {"null", "debug", "info", "warning", "error"}; if (log_level.count(FLAGS_log) == 0) { - std::cout << "E10016: invalid value for --log:" << FLAGS_log << ", only support debug, info, warning, error, null" + std::cout << "E10010: invalid value for --log:" << FLAGS_log << ", only support debug, info, warning, error, null" << std::endl; return ret; } @@ -1155,12 +1159,18 @@ int init(int argc, char *argv[]) { return ret; } + std::string path_base = ge::GELib::GetPath(); + ret = ErrorManager::GetInstance().Init(path_base); + if (ret != 0) { + DOMI_LOGE("ErrorManager init fail !"); + return ret; + } + return 0; } int main(int argc, char *argv[]) { Status ret = domi::SUCCESS; - ge::Status geRet = ge::SUCCESS; std::cout << "ATC start working now, please wait for a moment." << std::endl; try { // Initialize @@ -1185,12 +1195,9 @@ int main(int argc, char *argv[]) { GE_CHK_BOOL_EXEC(ConvertPbtxtToJson() == domi::SUCCESS, ret = domi::FAILED; break, "ATC convert pbtxt to json execute failed!!"); } else { - ErrorManager::GetInstance().ATCReportErrMessage("E10048", {"value"}, {std::to_string(FLAGS_mode)}); - DOMI_LOGE( - "Invalid value for --mode[%d], only support " - "0(model to framework model), 1(framework model to json), 3(only pre-check), " - "5(pbtxt to json)!", - FLAGS_mode); + ErrorManager::GetInstance().ATCReportErrMessage("E10001", {"parameter", "value", "reason"}, + {"--mode", std::to_string(FLAGS_mode), kModeSupport}); + GELOGE(ge::PARAM_INVALID, "Invalid value for --mode[%d], %s.", FLAGS_mode, kModeSupport); ret = domi::FAILED; break; } @@ -1205,11 +1212,16 @@ int main(int argc, char *argv[]) { std::cout << "ATC run failed, some exceptions occur !" << std::endl; } - if (!CheckRet(ret, geRet)) { + if (!CheckRet(ret)) { std::cout << "ATC run failed, Please check the detail log, Try \'atc --help\' for more information" << std::endl; + int result = ErrorManager::GetInstance().OutputErrMessage(STDOUT_FILENO); + if (result != 0) { + DOMI_LOGE("ErrorManager outputErrMessage fail !"); + } return ret; } else { std::cout << "ATC run success, welcome to the next use." << std::endl; + (void)ErrorManager::GetInstance().OutputMessage(STDOUT_FILENO); return 0; } -} +} /*lint +e530*/ diff --git a/src/ge/offline/module.mk b/src/ge/offline/module.mk index c97e7813..a347362a 100644 --- a/src/ge/offline/module.mk +++ b/src/ge/offline/module.mk @@ -42,7 +42,7 @@ LOCAL_SHARED_LIBRARIES := \ libge_compiler \ libruntime_compile \ libparser_common \ - libfmk_tensorflow_parser \ + libfmk_parser \ liberror_manager \ LOCAL_STATIC_LIBRARIES := libgflags diff --git a/src/ge/offline/single_op_parser.cc b/src/ge/offline/single_op_parser.cc index 4d589565..54b6df69 100644 --- a/src/ge/offline/single_op_parser.cc +++ b/src/ge/offline/single_op_parser.cc @@ -28,6 +28,8 @@ #include "common/ge_inner_error_codes.h" #include "framework/common/util.h" #include "graph/utils/tensor_utils.h" +#include "graph/utils/op_desc_utils.h" +#include "graph/operator_factory_impl.h" using Json = nlohmann::json; using std::map; @@ -43,10 +45,14 @@ constexpr char const *kKeyAttr = "attr"; constexpr char const *kKeyName = "name"; constexpr char const *kKeyType = "type"; constexpr char const *kKeyShape = "shape"; +constexpr char const *kKeyShapeRange = "shape_range"; constexpr char const *kKeyValue = "value"; constexpr char const *kKeyFormat = "format"; constexpr char const *kFileSuffix = ".om"; constexpr int kDumpJsonIndent = 2; +constexpr int kShapeRangePairSize = 2; +constexpr int kShapeRangeLow = 0; +constexpr int kShapeRangeHigh = 1; map kAttrTypeDict = { {"bool", GeAttrValue::VT_BOOL}, @@ -90,6 +96,10 @@ T GetValue(const map &dict, string &key, T default_val) { void from_json(const Json &j, SingleOpTensorDesc &desc) { desc.dims = j.at(kKeyShape).get>(); + auto it = j.find(kKeyShapeRange); + if (it != j.end()) { + desc.dim_ranges = j.at(kKeyShapeRange).get>>(); + } string format_str = j.at(kKeyFormat).get(); string type_str = j.at(kKeyType).get(); desc.format = GetValue(kFormatDict, format_str, FORMAT_RESERVED); @@ -200,13 +210,13 @@ bool SingleOpParser::Validate(const SingleOpDesc &op_desc) { for (auto &tensor_desc : op_desc.input_desc) { if (tensor_desc.type == DT_UNDEFINED) { ErrorManager::GetInstance().ATCReportErrMessage("E10027", {"input", "index"}, {"input", std::to_string(index)}); - GELOGE(false, "Input index[%d]'s dataType is invalid", index); + GELOGE(false, "Input's dataType is invalid when the index is %d", index); return false; } if (tensor_desc.format == FORMAT_RESERVED) { ErrorManager::GetInstance().ATCReportErrMessage("E10028", {"input", "index"}, {"input", std::to_string(index)}); - GELOGE(PARAM_INVALID, "Input index[%d]'s format is invalid", index); + GELOGE(PARAM_INVALID, "Input's format is invalid when the index is %d", index); return false; } ++index; @@ -216,13 +226,13 @@ bool SingleOpParser::Validate(const SingleOpDesc &op_desc) { for (auto &tensor_desc : op_desc.output_desc) { if (tensor_desc.type == DT_UNDEFINED) { ErrorManager::GetInstance().ATCReportErrMessage("E10027", {"input", "index"}, {"output", std::to_string(index)}); - GELOGE(PARAM_INVALID, "Output[%d] dataType is invalid", index); + GELOGE(PARAM_INVALID, "Output's dataType is invalid when the index is %d", index); return false; } if (tensor_desc.format == FORMAT_RESERVED) { ErrorManager::GetInstance().ATCReportErrMessage("E10028", {"input", "index"}, {"output", std::to_string(index)}); - GELOGE(PARAM_INVALID, "Output[%d] format is invalid", index); + GELOGE(PARAM_INVALID, "Output's format is invalid when the index is %d", index); return false; } ++index; @@ -245,11 +255,13 @@ bool SingleOpParser::Validate(const SingleOpDesc &op_desc) { return true; } -OpDesc *SingleOpParser::CreateOpDesc(const string &op_type) { return new (std::nothrow) OpDesc(op_type, op_type); } +std::unique_ptr SingleOpParser::CreateOpDesc(const string &op_type) { + return std::unique_ptr(new (std::nothrow) OpDesc(op_type, op_type)); +} Status SingleOpParser::ConvertToBuildParam(int index, const SingleOpDesc &single_op_desc, SingleOpBuildParam &build_param) { - auto *op_desc = CreateOpDesc(single_op_desc.op); + auto op_desc = CreateOpDesc(single_op_desc.op); if (op_desc == nullptr) { GELOGE(MEMALLOC_FAILED, "Failed to create instance of opDesc"); return MEMALLOC_FAILED; @@ -265,6 +277,7 @@ Status SingleOpParser::ConvertToBuildParam(int index, const SingleOpDesc &single } GeTensorDesc ge_tensor_desc(GeShape(desc.dims), desc.format, desc.type); ge_tensor_desc.SetOriginFormat(desc.format); + GE_CHK_STATUS_RET_NOLOG(SetShapeRange(desc, ge_tensor_desc)); TensorUtils::SetRealDimCnt(ge_tensor_desc, desc.dims.size()); TensorUtils::SetInputTensor(ge_tensor_desc, true); TensorUtils::SetOutputTensor(ge_tensor_desc, false); @@ -284,6 +297,7 @@ Status SingleOpParser::ConvertToBuildParam(int index, const SingleOpDesc &single GeTensorDesc ge_tensor_desc(GeShape(desc.dims), desc.format, desc.type); ge_tensor_desc.SetOriginFormat(desc.format); + GE_CHK_STATUS_RET_NOLOG(SetShapeRange(desc, ge_tensor_desc)); TensorUtils::SetRealDimCnt(ge_tensor_desc, desc.dims.size()); TensorUtils::SetInputTensor(ge_tensor_desc, false); TensorUtils::SetOutputTensor(ge_tensor_desc, true); @@ -295,10 +309,78 @@ Status SingleOpParser::ConvertToBuildParam(int index, const SingleOpDesc &single op_desc->SetAttr(attr.name, attr.value); } + if (VerifyOpInputOutputSizeByIr(*op_desc) != SUCCESS) { + GELOGE(PARAM_INVALID, "Verify op [%s] input or output size failed.", op_desc->GetType().c_str()); + return PARAM_INVALID; + } + file_name << kFileSuffix; build_param.file_name = file_name.str(); + build_param.op_desc.reset(op_desc.release()); + return SUCCESS; +} + +Status SingleOpParser::VerifyOpInputOutputSizeByIr(const OpDesc ¤t_op_desc) { + ge::Operator operator_ir = ge::OperatorFactory::CreateOperator("tmp_operator", current_op_desc.GetType()); + if (!operator_ir.IsEmpty()) { + auto opdesc_ir = ge::OpDescUtils::GetOpDescFromOperator(operator_ir); + GE_CHECK_NOTNULL(opdesc_ir); + size_t current_opdesc_inputs_num = current_op_desc.GetInputsSize(); + size_t ir_opdesc_inputs_num = opdesc_ir->GetInputsSize(); + if (current_opdesc_inputs_num < ir_opdesc_inputs_num) { + string reason = "is smaller than the ir needed input size " + std::to_string(ir_opdesc_inputs_num); + ErrorManager::GetInstance().ATCReportErrMessage( + "E19014", {"opname", "value", "reason"}, + {current_op_desc.GetName(), "input size " + std::to_string(current_opdesc_inputs_num), reason}); + GELOGE(PARAM_INVALID, "This op [%s] input size %zu is smaller than the ir needed input size %zu", + current_op_desc.GetName().c_str(), current_opdesc_inputs_num, ir_opdesc_inputs_num); + return PARAM_INVALID; + } + size_t current_opdesc_outputs_num = current_op_desc.GetOutputsSize(); + size_t ir_opdesc_outputs_num = opdesc_ir->GetOutputsSize(); + if (current_opdesc_outputs_num < ir_opdesc_outputs_num) { + string reason = "is smaller than the ir needed output size " + std::to_string(ir_opdesc_outputs_num); + ErrorManager::GetInstance().ATCReportErrMessage( + "E19014", {"opname", "value", "reason"}, + {current_op_desc.GetName(), "output size " + std::to_string(current_opdesc_outputs_num), reason}); + GELOGE(PARAM_INVALID, "This op [%s] output size %zu is smaller than the ir needed output size %zu", + current_op_desc.GetName().c_str(), current_opdesc_outputs_num, ir_opdesc_outputs_num); + return PARAM_INVALID; + } + } + return SUCCESS; +} + +Status SingleOpParser::SetShapeRange(const SingleOpTensorDesc &tensor_desc, GeTensorDesc &ge_tensor_desc) { + if (tensor_desc.dim_ranges.empty()) { + return SUCCESS; + } + + std::vector> shape_range; + size_t range_index = 0; + for (auto dim : tensor_desc.dims) { + if (dim >= 0) { + shape_range.emplace_back(dim, dim); + GELOGD("Adding shape range: [%ld, %ld]", dim, dim); + } else { + if (range_index >= tensor_desc.dim_ranges.size()) { + GELOGE(PARAM_INVALID, "The number of shape_range mismatches that of unknown dims."); + return PARAM_INVALID; + } + + auto &range = tensor_desc.dim_ranges[range_index]; + if (range.size() != kShapeRangePairSize) { + GELOGE(PARAM_INVALID, "Invalid shape range entry. index = %zu, size = %zu", range_index, range.size()); + return PARAM_INVALID; + } + + shape_range.emplace_back(range[kShapeRangeLow], range[kShapeRangeHigh]); + GELOGD("Adding shape range: [%ld, %ld]", range[kShapeRangeLow], range[kShapeRangeHigh]); + ++range_index; + } + } - build_param.op_desc.reset(op_desc); + ge_tensor_desc.SetShapeRange(shape_range); return SUCCESS; } @@ -316,17 +398,15 @@ Status SingleOpParser::ParseSingleOpList(const std::string &file, std::vector dims; + std::vector> dim_ranges; ge::Format format = ge::FORMAT_RESERVED; ge::DataType type = ge::DT_UNDEFINED; }; @@ -68,8 +69,10 @@ class SingleOpParser { private: static Status ReadJsonFile(const std::string &file, nlohmann::json &json_obj); static bool Validate(const SingleOpDesc &op_desc); - static OpDesc *CreateOpDesc(const std::string &op_type); + static std::unique_ptr CreateOpDesc(const std::string &op_type); static Status ConvertToBuildParam(int index, const SingleOpDesc &single_op_desc, SingleOpBuildParam &build_param); + static Status VerifyOpInputOutputSizeByIr(const OpDesc ¤t_op_desc); + static Status SetShapeRange(const SingleOpTensorDesc &tensor_desc, GeTensorDesc &ge_tensor_desc); }; } // namespace ge diff --git a/src/ge/opskernel_manager/ops_kernel_manager.cc b/src/ge/opskernel_manager/ops_kernel_manager.cc index a8a1be88..0d6f1e07 100644 --- a/src/ge/opskernel_manager/ops_kernel_manager.cc +++ b/src/ge/opskernel_manager/ops_kernel_manager.cc @@ -38,7 +38,7 @@ const char *const kFinalize = "Finalize"; namespace ge { OpsKernelManager::OpsKernelManager() - : plugin_manager_(), init_flag_(false), enable_fe_flag_(false), enable_aicpu_flag_(false) {} + : plugin_manager_(), op_tiling_manager_(), init_flag_(false), enable_fe_flag_(false), enable_aicpu_flag_(false) {} OpsKernelManager::~OpsKernelManager() { graph_optimizers_.clear(); @@ -76,6 +76,8 @@ Status OpsKernelManager::Initialize(const map &options_const) { GetExternalEnginePath(extern_engine_path); GELOGI("OPTION_EXEC_EXTERN_PLUGIN_PATH=%s.", extern_engine_path.c_str()); + op_tiling_manager_.LoadSo(); + ret = plugin_manager_.LoadSo(extern_engine_path, func_check_list); if (ret == SUCCESS) { initialize_ = options; @@ -134,7 +136,7 @@ void OpsKernelManager::GetExternalEnginePath(std::string &extern_engine_path) { std::string path = path_base + so_path; extern_engine_path = (path + "libfe.so" + ":") + (path + "libge_local_engine.so" + ":") + (path + "librts_engine.so" + ":") + (path + "libaicpu_engine.so" + ":") + - (path_base + "libhccl.so"); + (path_base + "libhcom_graph_adaptor.so"); } Status OpsKernelManager::InitPluginOptions(const map &options) { diff --git a/src/ge/opskernel_manager/ops_kernel_manager.h b/src/ge/opskernel_manager/ops_kernel_manager.h index 8d98ad3f..1d464201 100644 --- a/src/ge/opskernel_manager/ops_kernel_manager.h +++ b/src/ge/opskernel_manager/ops_kernel_manager.h @@ -24,6 +24,7 @@ #include "common/debug/log.h" #include "common/ge/plugin_manager.h" +#include "common/ge/op_tiling_manager.h" #include "common/ge_inner_error_codes.h" #include "common/opskernel/ops_kernel_info_store.h" #include "common/optimizer/graph_optimizer.h" @@ -105,6 +106,7 @@ class OpsKernelManager { Status InitGraphOptimizerPriority(); PluginManager plugin_manager_; + OpTilingManager op_tiling_manager_; // opsKernelInfoStore map ops_kernel_store_{}; // graph_optimizer diff --git a/src/ge/session/inner_session.cc b/src/ge/session/inner_session.cc index 74495e82..b97862e1 100644 --- a/src/ge/session/inner_session.cc +++ b/src/ge/session/inner_session.cc @@ -29,6 +29,34 @@ #include "runtime/mem.h" namespace ge { +namespace { +Status CheckReuseMemoryOption(const std::map &options) { + const int kDecimal = 10; + auto dump_op_env = std::getenv("DUMP_OP"); + int dump_op_flag = (dump_op_env != nullptr) ? std::strtol(dump_op_env, nullptr, kDecimal) : 0; + auto iter = options.find(OPTION_EXEC_DISABLE_REUSED_MEMORY); + if (iter != options.end()) { + if (iter->second == "0") { + GELOGD("%s=0, reuse memory is open", OPTION_EXEC_DISABLE_REUSED_MEMORY); + if (dump_op_flag) { + GELOGW("Will dump incorrect op data with ge option %s=0", OPTION_EXEC_DISABLE_REUSED_MEMORY); + } + } else if (iter->second == "1") { + GELOGD("%s=1, reuse memory is close", OPTION_EXEC_DISABLE_REUSED_MEMORY); + } else { + GELOGE(PARAM_INVALID, "option %s=%s is invalid", OPTION_EXEC_DISABLE_REUSED_MEMORY, iter->second.c_str()); + return FAILED; + } + } else { + if (dump_op_flag) { + GELOGW("Will dump incorrect op data with default reuse memory"); + } + } + + return SUCCESS; +} +} // namespace + static std::mutex mutex_; // BuildGraph and RunGraph use InnerSession::InnerSession(uint64_t session_id, const std::map &options) @@ -39,13 +67,36 @@ Status InnerSession::Initialize() { GELOGW("[InnerSession:%lu] session already initialize.", session_id_); return SUCCESS; } + + // If the global options and the session options are duplicated, the session options is preferred. + auto all_options = options_; + all_options.insert(GetMutableGlobalOptions().begin(), GetMutableGlobalOptions().end()); + + Status ret = CheckReuseMemoryOption(all_options); + if (ret != SUCCESS) { + GELOGE(ret, "[InnerSession:%lu] check reuse memory option failed.", session_id_); + return ret; + } + UpdateThreadContext(std::map{}); GE_CHK_RT_RET(rtSetDevice(GetContext().DeviceId())); - Status ret = graph_manager_.Initialize(options_); + PropertiesManager::Instance().GetDumpProperties(session_id_).InitByOptions(); + + ret = graph_manager_.Initialize(options_); if (ret != SUCCESS) { GELOGE(ret, "[InnerSession:%lu] initialize failed.", session_id_); + PropertiesManager::Instance().RemoveDumpProperties(session_id_); + return ret; + } + + ret = VarManager::Instance(session_id_)->SetMemoryMallocSize(all_options); + if (ret != SUCCESS) { + GELOGE(ret, "failed to set malloc size"); + (void)graph_manager_.Finalize(); + PropertiesManager::Instance().RemoveDumpProperties(session_id_); + GE_CHK_RT(rtDeviceReset(static_cast(GetContext().DeviceId()))); return ret; } @@ -55,6 +106,7 @@ Status InnerSession::Initialize() { ret = VarManager::Instance(session_id_)->Init(version, session_id_, DEFAULT_DEVICE_ID, DEFAULT_JOB_ID); if (ret != SUCCESS) { GELOGE(ret, "failed to init session instance"); + PropertiesManager::Instance().RemoveDumpProperties(session_id_); } init_flag_ = true; return SUCCESS; @@ -78,6 +130,9 @@ Status InnerSession::Finalize() { // release var memory GELOGI("VarManager free var memory."); (void)VarManager::Instance(session_id_)->FreeVarMemory(); + + PropertiesManager::Instance().RemoveDumpProperties(session_id_); + GE_CHK_RT(rtDeviceReset(static_cast(GetContext().DeviceId()))); return ret; @@ -223,6 +278,7 @@ void InnerSession::UpdateThreadContext(const std::map GetThreadLocalContext().SetGlobalOption(GetMutableGlobalOptions()); GetThreadLocalContext().SetSessionOption(options_); GetThreadLocalContext().SetGraphOption(options); + GetContext().SetSessionId(session_id_); } void InnerSession::UpdateThreadContext(uint32_t graph_id) { diff --git a/src/ge/session/omg.cc b/src/ge/session/omg.cc index 71dd631e..55075d6a 100644 --- a/src/ge/session/omg.cc +++ b/src/ge/session/omg.cc @@ -22,15 +22,16 @@ #include "common/convert/pb2json.h" #include "common/debug/log.h" #include "common/debug/memory_dumper.h" +#include "common/ge/ge_util.h" +#include "common/helper/model_helper.h" #include "common/model_parser/base.h" +#include "common/model_parser/graph_parser_util.h" #include "common/model_saver.h" #include "common/properties_manager.h" #include "common/string_util.h" #include "common/types.h" #include "common/util.h" #include "common/util/error_manager/error_manager.h" -#include "common/helper/model_helper.h" -#include "common/ge/ge_util.h" #include "framework/common/debug/ge_log.h" #include "framework/omg/parser/parser_inner_ctx.h" #include "google/protobuf/io/zero_copy_stream_impl.h" @@ -65,6 +66,9 @@ namespace ge { namespace { const std::string kGraphDefaultName = "domi_default"; const std::string kScopeIdAttr = "fusion_scope"; +const char *const kOutputTypeSample = "correct sample is \"opname:index:dtype\""; +const char *const kOutputTypeSupport = "only support FP32, FP16, UINT8"; +const char *const kOutputTypeError = "The multiple out nodes set in output_type must be found in out_nodes."; } // namespace // When the model is converted to a JSON file, the following operator attributes in the blacklist will be ignored @@ -78,7 +82,7 @@ static bool CheckInputTrueOrFalse(const std::string &s, const std::string &atc_p if ((s == "true") || (s == "false")) { return true; } else { - ErrorManager::GetInstance().ATCReportErrMessage("E10033", {"parameter", "value"}, {atc_param, s}); + ErrorManager::GetInstance().ATCReportErrMessage("E10005", {"parameter", "value"}, {atc_param, s}); GELOGE(PARAM_INVALID, "Input parameter[--%s]'s value[%s] must be true or false.", atc_param.c_str(), s.c_str()); return false; } @@ -97,12 +101,12 @@ static Status CheckInputShapeNode(const ComputeGraphPtr &graph) { std::string node_name = it.first; ge::NodePtr node = graph->FindNode(node_name); if (node == nullptr) { - ErrorManager::GetInstance().ATCReportErrMessage("E10034", {"parameter", "opname"}, {"input_shape", node_name}); + ErrorManager::GetInstance().ATCReportErrMessage("E10016", {"parameter", "opname"}, {"input_shape", node_name}); GELOGE(PARAM_INVALID, "Input parameter[--input_shape]'s opname[%s] is not exist in model", node_name.c_str()); return PARAM_INVALID; } if (node->GetType() != DATA) { - ErrorManager::GetInstance().ATCReportErrMessage("E10035", {"parameter", "opname"}, {"input_shape", node_name}); + ErrorManager::GetInstance().ATCReportErrMessage("E10017", {"parameter", "opname"}, {"input_shape", node_name}); GELOGE(PARAM_INVALID, "Input parameter[--input_shape]'s opname[%s] is not a input opname", node_name.c_str()); return PARAM_INVALID; } @@ -110,6 +114,22 @@ static Status CheckInputShapeNode(const ComputeGraphPtr &graph) { return SUCCESS; } +void AddAttrsForInputNodes(const vector &adjust_fp16_format_vec, const string &fp16_nodes_name, uint32_t index, + OpDescPtr &op_desc) { + if (AttrUtils::SetBool(op_desc, "input_fp16", true) && + AttrUtils::SetStr(op_desc, ATTR_ATC_USER_DEFINE_DATATYPE, TypeUtils::DataTypeToSerialString(DT_FLOAT16))) { + if ((index < adjust_fp16_format_vec.size()) && (adjust_fp16_format_vec[index] == "true")) { + GELOGI("This node [%s] should be set NC1HWC0", fp16_nodes_name.c_str()); + if (!AttrUtils::SetBool(op_desc, "input_set_nc1hwc0", true)) { + GELOGW("This node [%s] set NC1HWC0 failed", fp16_nodes_name.c_str()); + } + if (!AttrUtils::SetStr(op_desc, ATTR_ATC_USER_DEFINE_FORMAT, TypeUtils::FormatToSerialString(FORMAT_NC1HWC0))) { + GELOGW("This node [%s] set NC1HWC0 failed", fp16_nodes_name.c_str()); + } + } + } +} + static Status CheckInputFp16Nodes(const ComputeGraphPtr &graph, const string &input_fp16_nodes, const string &is_input_adjust_hw_layout) { GE_CHECK_NOTNULL(graph); @@ -133,28 +153,22 @@ static Status CheckInputFp16Nodes(const ComputeGraphPtr &graph, const string &in for (uint32_t i = 0; i < input_fp16_nodes_vec.size(); ++i) { ge::NodePtr node = graph->FindNode(input_fp16_nodes_vec[i]); if (node == nullptr) { - ErrorManager::GetInstance().ATCReportErrMessage("E10034", {"parameter", "opname"}, + ErrorManager::GetInstance().ATCReportErrMessage("E10016", {"parameter", "opname"}, {"input_fp16_nodes", input_fp16_nodes_vec[i]}); - GELOGE(PARAM_INVALID, "Can not find node [%s] in graph, please check input_fp16_nodes param", + GELOGE(PARAM_INVALID, "Input parameter[--input_fp16_nodes]'s opname[%s] is not exist in model", input_fp16_nodes_vec[i].c_str()); return PARAM_INVALID; } auto op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); if (op_desc->GetType() != DATA) { - ErrorManager::GetInstance().ATCReportErrMessage("E10035", {"parameter", "opname"}, + ErrorManager::GetInstance().ATCReportErrMessage("E10017", {"parameter", "opname"}, {"input_fp16_nodes", input_fp16_nodes_vec[i]}); - GELOGE(PARAM_INVALID, "input_fp16_nodes: %s is not a input node name", input_fp16_nodes_vec[i].c_str()); + GELOGE(PARAM_INVALID, "Input parameter[--input_fp16_nodes]'s opname[%s] is not a input opname", + input_fp16_nodes_vec[i].c_str()); return PARAM_INVALID; } - if (ge::AttrUtils::SetBool(op_desc, "input_fp16", true)) { - if ((i < adjust_fp16_format_vec.size()) && (adjust_fp16_format_vec[i] == "true")) { - GELOGI("This node [%s] should be set NC1HWC0", input_fp16_nodes_vec[i].c_str()); - if (!ge::AttrUtils::SetBool(op_desc, "input_set_nc1hwc0", true)) { - GELOGW("This node [%s] set NC1HWC0 failed", input_fp16_nodes_vec[i].c_str()); - } - } - } + AddAttrsForInputNodes(adjust_fp16_format_vec, input_fp16_nodes_vec[i], i, op_desc); } return SUCCESS; } @@ -197,30 +211,6 @@ static Status SetWeightCompressNodes(const ComputeGraphPtr &graph, const string return SUCCESS; } -static Status ParseOutputFp16NodesFormat(const string &is_output_fp16) { - if (is_output_fp16.empty()) { - return SUCCESS; - } - - vector &output_formats = domi::GetContext().output_formats; - output_formats.clear(); - vector node_format_vec = StringUtils::Split(is_output_fp16, ','); - for (auto &is_fp16 : node_format_vec) { - StringUtils::Trim(is_fp16); - if (!CheckInputTrueOrFalse(is_fp16, "is_output_adjust_hw_layout")) { - GELOGE(PARAM_INVALID, "Invalid Param, is_output_adjust_hw_layout only support true/false: but is [%s]", - is_output_fp16.c_str()); - return PARAM_INVALID; - } - if (is_fp16 == "false") { - output_formats.push_back(DOMI_TENSOR_ND); - } else if (is_fp16 == "true") { - output_formats.push_back(domi::DOMI_TENSOR_NC1HWC0); - } - } - return SUCCESS; -} - void FindParserSo(const string &path, vector &file_list, string &caffe_parser_path) { // path, Change to absolute path string real_path = RealPath(path.c_str()); @@ -302,160 +292,6 @@ Status SetOutFormatAndDataTypeAttr(ge::OpDescPtr op_desc, const ge::Format forma return domi::SUCCESS; } -Status StringToInt(std::string &str, int32_t &value) { - try { - value = stoi(str); - } catch (std::invalid_argument &) { - GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", str.c_str()); - return PARAM_INVALID; - } catch (std::out_of_range &) { - GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", str.c_str()); - return PARAM_INVALID; - } - return SUCCESS; -} - -Status VerifyOutputTypeAndOutNodes(std::vector &out_type_vec) { - std::vector> user_out_nodes = domi::GetContext().user_out_nodes; - std::set out_nodes_info; - for (uint32_t i = 0; i < user_out_nodes.size(); ++i) { - // out_nodes set should include output_type and output_format - std::string tmp = user_out_nodes[i].first + ":" + to_string(user_out_nodes[i].second); - out_nodes_info.emplace(tmp); - } - for (uint32_t i = 0; i < out_type_vec.size(); ++i) { - if (out_nodes_info.find(out_type_vec[i]) == out_nodes_info.end()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10059", {"value"}, {out_type_vec[i]}); - GELOGE(domi::FAILED, "Can not find this node (%s) in out_nodes.", out_type_vec[i].c_str()); - return domi::FAILED; - } - } - return domi::SUCCESS; -} - -Status ParseOutputType(const std::string &output_type, std::map> &out_type_index_map, - std::map> &out_type_dt_map) { - if (output_type.find(':') == std::string::npos) { - GELOGI("output_type is not multiple nodes, means all out nodes"); - auto it = output_type_str_to_datatype.find(output_type); - if (it == output_type_str_to_datatype.end()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10042", {"value"}, {output_type}); - GELOGE(ge::PARAM_INVALID, "Invalid value for --output_type[%s], only support DT_FLOAT, DT_FLOAT16, DT_UINT8!!", - output_type.c_str()); - return domi::FAILED; - } - return domi::SUCCESS; - } - std::vector out_type_vec; - vector nodes_v = StringUtils::Split(output_type, ';'); - for (const string &node : nodes_v) { - vector node_index_type_v = StringUtils::Split(node, ':'); - if (node_index_type_v.size() != 3) { // The size must be 3. - ErrorManager::GetInstance().ATCReportErrMessage("E10058", {"value"}, {node}); - GELOGE(PARAM_INVALID, - "The param of output_type is invalid, the correct format is [opname:index:dtype]," - "while the actual input is %s.", - node.c_str()); - return domi::FAILED; - } - ge::DataType tmp_dt; - std::string node_name = StringUtils::Trim(node_index_type_v[0]); - std::string index_str = StringUtils::Trim(node_index_type_v[1]); - int32_t index; - if (StringToInt(index_str, index) != SUCCESS) { - return domi::FAILED; - } - std::string dt_value = StringUtils::Trim(node_index_type_v[2]); - auto it = output_type_str_to_datatype.find(dt_value); - if (it == output_type_str_to_datatype.end()) { - ErrorManager::GetInstance().ATCReportErrMessage("E10042", {"value"}, {dt_value}); - GELOGE(ge::PARAM_INVALID, "output_type [%s] is invalid.", dt_value.c_str()); - return domi::FAILED; - } else { - tmp_dt = it->second; - } - out_type_vec.push_back(node_name + ":" + index_str); - auto it_index = out_type_index_map.find(node_name); - if (it_index == out_type_index_map.end()) { - vector tmp_vec; - tmp_vec.push_back(index); - out_type_index_map.emplace(node_name, tmp_vec); - } else { - it_index->second.push_back(index); - } - - auto it_dt = out_type_dt_map.find(node_name); - if (it_dt == out_type_dt_map.end()) { - vector tmp_vec; - tmp_vec.push_back(tmp_dt); - out_type_dt_map.emplace(node_name, tmp_vec); - } else { - it_dt->second.push_back(tmp_dt); - } - } - return VerifyOutputTypeAndOutNodes(out_type_vec); -} - -Status SetOutputNodeInfo(ge::Graph &graph, const std::string &output_type, const std::string &output) { - ge::ComputeGraphPtr compute_graph = ge::GraphUtils::GetComputeGraph(graph); - GE_CHECK_NOTNULL(compute_graph); - - std::vector> user_out_nodes = domi::GetContext().user_out_nodes; - std::vector output_formats = domi::GetContext().output_formats; - std::vector> output_nodes_info; - std::vector output_nodes_name; - - std::map> out_type_index_map; - std::map> out_type_dt_map; - if (!output_type.empty()) { - if (ParseOutputType(output_type, out_type_index_map, out_type_dt_map) != SUCCESS) { - GELOGE(domi::FAILED, "Parse output_type failed."); - return domi::FAILED; - } - } - - // User declared outputs - for (uint32_t i = 0; i < user_out_nodes.size(); ++i) { - ge::NodePtr out_node = compute_graph->FindNode(user_out_nodes[i].first); - if (out_node == nullptr) { - GELOGE(domi::FAILED, "Can not find src node (%s) in graph.", user_out_nodes[i].first.c_str()); - return domi::FAILED; - } - auto op_desc = out_node->GetOpDesc(); - GE_CHECK_NOTNULL(op_desc); - if (i < output_formats.size()) { - if (output_formats[i] == domi::DOMI_TENSOR_NC1HWC0) { - GELOGI("The output node [%s] should be set NC1HWC0", user_out_nodes[i].first.c_str()); - if (!ge::AttrUtils::SetBool(op_desc, "output_set_fp16_nc1hwc0", true)) { - GELOGW("The output node [%s] set NC1HWC0 failed", user_out_nodes[i].first.c_str()); - } - } - } - auto it_index = out_type_index_map.find(user_out_nodes[i].first); - auto it_dt = out_type_dt_map.find(user_out_nodes[i].first); - if ((it_index != out_type_index_map.end()) && (it_dt != out_type_dt_map.end())) { - GELOGI("The output node [%s] need to be set output_type", user_out_nodes[i].first.c_str()); - (void)ge::AttrUtils::SetListDataType(op_desc, "_output_dt_list", it_dt->second); - (void)ge::AttrUtils::SetListInt(op_desc, "_output_dt_index", it_index->second); - } - output_nodes_info.push_back(std::make_pair(out_node, user_out_nodes[i].second)); - output_nodes_name.push_back(out_node->GetName() + ":" + std::to_string(user_out_nodes[i].second)); - } - // default output node (leaf) - if (user_out_nodes.empty()) { - for (ge::NodePtr node : compute_graph->GetDirectNode()) { - if (!node->GetInDataNodes().empty() && node->GetOutDataNodes().empty()) { - Status ret = GetOutputLeaf(node, output_nodes_info); - GE_CHK_BOOL_RET_STATUS(ret == SUCCESS, ret, "find leaf fail."); - } - } - } - GetOutputNodesNameAndIndex(output_nodes_info, output_nodes_name); - compute_graph->SetGraphOutNodesInfo(output_nodes_info); - domi::GetContext().net_out_nodes = output_nodes_name; - return domi::SUCCESS; -} - void GetOutputNodesNameAndIndex(std::vector> &output_nodes_info, std::vector &output_nodes_name) { output_nodes_name.clear(); @@ -481,32 +317,6 @@ void GetOutputNodesNameAndIndex(std::vector> &ou } } -Status GetOutputLeaf(NodePtr node, std::vector> &output_nodes_info) { - ge::OpDescPtr tmpDescPtr = node->GetOpDesc(); - if (tmpDescPtr == nullptr) { - GELOGE(domi::FAILED, "Get outnode op desc fail."); - return domi::FAILED; - } - size_t size = tmpDescPtr->GetOutputsSize(); - if (node->GetType() != NETOUTPUT) { - for (size_t index = 0; index < size; ++index) { - output_nodes_info.push_back(std::make_pair(node, index)); - } - } else { - const auto in_anchors = node->GetAllInDataAnchors(); - for (auto in_anchor : in_anchors) { - auto out_anchor = in_anchor->GetPeerOutAnchor(); - if (out_anchor == nullptr) { - GELOGE(domi::FAILED, "Get leaf node op desc fail."); - return domi::FAILED; - } - auto out_node = out_anchor->GetOwnerNode(); - output_nodes_info.push_back(std::make_pair(out_node, out_anchor->GetIdx())); - } - } - return SUCCESS; -} - /// /// @ingroup domi_common /// @brief Initialize omgcontext based on command line input @@ -550,55 +360,12 @@ Status InitDomiOmgContext(const string &input_shape, const string &input_format, return SUCCESS; } -Status ParseOutNodes(const string &out_nodes) { - try { - // parse output node - if (!out_nodes.empty()) { - domi::GetContext().out_nodes_map.clear(); - domi::GetContext().user_out_nodes.clear(); - - vector nodes_v = StringUtils::Split(out_nodes, ';'); - for (const string &node : nodes_v) { - vector key_value_v = StringUtils::Split(node, ':'); - if (key_value_v.size() != 2) { // The size must be 2. - ErrorManager::GetInstance().ATCReportErrMessage("E10069", {"param", "value", "supports"}, - {"out_nodes", node, "opname:index"}); - GELOGE(PARAM_INVALID, - "The input format of --out_nodes is invalid, the correct format is " - "\"node_name1:0;node_name1:1;node_name2:0\", while the actual input is %s.", - node.c_str()); - return PARAM_INVALID; - } - auto iter = domi::GetContext().out_nodes_map.find(key_value_v[0]); - // stoi: The method may throw an exception: invalid_argument/out_of_range - int32_t index = stoi(StringUtils::Trim(key_value_v[1])); - if (iter != domi::GetContext().out_nodes_map.end()) { - iter->second.emplace_back(index); - } else { - std::vector index_v; - index_v.emplace_back(index); - domi::GetContext().out_nodes_map.emplace(key_value_v[0], index_v); - } - domi::GetContext().user_out_nodes.push_back(std::make_pair(key_value_v[0], index)); - } - } - } catch (std::invalid_argument &) { - GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", out_nodes.c_str()); - return PARAM_INVALID; - } catch (std::out_of_range &) { - GELOGE(PARAM_INVALID, "Invalid of out_nodes: %s ", out_nodes.c_str()); - return PARAM_INVALID; - } - - return SUCCESS; -} - /// @ingroup domi_common /// @brief Judge whether the op_Name_Map parameter matches the network /// @param [in] graph Input network graph /// @return SUCCESS: Input parameters are correct; PARAM_INVALID: Input parameters are incorrect /// -static Status CheckOpNameMap(const ComputeGraphPtr &graph) { +static Status CheckOpNameMap(const ComputeGraphPtr &graph, const std::string &op_conf) { GE_CHECK_NOTNULL(graph); unordered_map graphNodeTypes; for (const NodePtr &node : graph->GetAllNodes()) { @@ -613,7 +380,9 @@ static Status CheckOpNameMap(const ComputeGraphPtr &graph) { GE_RT_PARAM_INVALID_WITH_LOG_IF_TRUE(propertiesMap.empty(), "op_name_map file is empty, please check file!"); for (auto iter = propertiesMap.begin(); iter != propertiesMap.end(); iter++) { GE_IF_BOOL_EXEC(graphNodeTypes.find(iter->second) == graphNodeTypes.end(), - ErrorManager::GetInstance().ATCReportErrMessage("E10060", {"parameter"}, {"op_name_map"}); + ErrorManager::GetInstance().ATCReportErrMessage( + "E10003", {"parameter", "value", "reason"}, + {"op_name_map", op_conf, "type[" + iter->second + "] is not found in model"}); GELOGE(PARAM_INVALID, "Invalid parameter for op_name_map."); return PARAM_INVALID;); } return SUCCESS; @@ -659,7 +428,7 @@ FMK_FUNC_HOST_VISIBILITY Status ParseGraph(ge::Graph &graph, const std::mapCreateModelParser(framework); GE_CHK_BOOL_RET_STATUS(model_parser != nullptr, FAILED, "ATC create model parser ret fail, framework:%d.", framework); return model_parser->ToJson(model_file, json_file); } - ErrorManager::GetInstance().ATCReportErrMessage("E10045", {"parameter"}, {"model"}); + ErrorManager::GetInstance().ATCReportErrMessage( + "E10001", {"parameter", "value", "reason"}, + {"--framework", std::to_string(framework), "only support 0(Caffe) 3(TensorFlow)"}); GELOGE(PARAM_INVALID, "Input parameter[--framework] is mandatory and it's value must be: 0(Caffe) 3(TensorFlow)."); return PARAM_INVALID; } diff --git a/src/ge/session/session_manager.cc b/src/ge/session/session_manager.cc index c3439b0b..68a8aa70 100644 --- a/src/ge/session/session_manager.cc +++ b/src/ge/session/session_manager.cc @@ -51,11 +51,11 @@ Status SessionManager::Finalize() { return SUCCESS; } -Status SessionManager::SetrtContext(rtContext_t rt_context) { +Status SessionManager::SetRtContext(SessionId session_id, rtContext_t rt_context) { GELOGI("set rt_context RT_CTX_NORMAL_MODE, device id:%u.", GetContext().DeviceId()); GE_CHK_RT_RET(rtCtxCreate(&rt_context, RT_CTX_NORMAL_MODE, static_cast(GetContext().DeviceId()))); GE_CHK_RT_RET(rtCtxSetCurrent(rt_context)); - RtContextUtil::GetInstance().AddrtContext(rt_context); + RtContextUtil::GetInstance().AddRtContext(session_id, rt_context); return SUCCESS; } @@ -85,7 +85,7 @@ Status SessionManager::CreateSession(const std::map &o session_id = next_session_id; // create a context - ret = SetrtContext(rtContext_t()); + ret = SetRtContext(session_id, rtContext_t()); return ret; } @@ -106,7 +106,7 @@ Status SessionManager::DestroySession(SessionId session_id) { } // Unified destruct rt_context - RtContextUtil::GetInstance().DestroyrtContexts(); + RtContextUtil::GetInstance().DestroyRtContexts(session_id); SessionPtr innerSession = it->second; Status ret = innerSession->Finalize(); @@ -300,4 +300,4 @@ bool SessionManager::IsGraphNeedRebuild(SessionId session_id, uint32_t graph_id) } return innerSession->IsGraphNeedRebuild(graph_id); } -}; // namespace ge +} // namespace ge diff --git a/src/ge/session/session_manager.h b/src/ge/session/session_manager.h index 5cce5214..5cdb849f 100644 --- a/src/ge/session/session_manager.h +++ b/src/ge/session/session_manager.h @@ -33,7 +33,6 @@ class SessionManager { friend class GELib; public: - Status SetrtContext(rtContext_t rtContext); /// /// @ingroup ge_session /// @brief create session @@ -163,10 +162,12 @@ class SessionManager { Status GetNextSessionId(SessionId &next_session_id); + Status SetRtContext(SessionId session_id, rtContext_t rtContext); + std::map session_manager_map_; std::mutex mutex_; bool init_flag_ = false; }; -}; // namespace ge +} // namespace ge #endif // GE_SESSION_SESSION_MANAGER_H_ diff --git a/src/ge/single_op/single_op.cc b/src/ge/single_op/single_op.cc index 9578471a..1a63c964 100644 --- a/src/ge/single_op/single_op.cc +++ b/src/ge/single_op/single_op.cc @@ -17,11 +17,13 @@ #include "single_op/single_op.h" #include "common/fmk_types.h" +#include "common/math/math_util.h" #include "common/profiling/profiling_manager.h" #include "framework/common/debug/ge_log.h" #include "framework/common/util.h" #include "graph/load/new_model_manager/model_utils.h" #include "runtime/mem.h" +#include "single_op/single_op_manager.h" namespace ge { namespace { @@ -50,9 +52,13 @@ Status SingleOp::ValidateArgs(const std::vector &inputs, const std:: for (size_t i = 0; i < num_inputs; ++i) { // preventing from read out of bound size_t aligned_size = GetAlignedSize(inputs[i].length); + GELOGI("Input [%zu], aligned_size:%zu, inputs.length:%u, input_sizes_:%u", i, aligned_size, inputs[i].length, + input_sizes_[i]); if (aligned_size < input_sizes_[i]) { - GELOGE(PARAM_INVALID, "Input size mismatch. index = %zu, model expect %zu, but given %zu(after align)", i, - input_sizes_[i], aligned_size); + GELOGE(PARAM_INVALID, + "Input size mismatch. index = %zu, model expect %zu," + " but given %zu(after align)", + i, input_sizes_[i], aligned_size); return PARAM_INVALID; } } @@ -66,9 +72,13 @@ Status SingleOp::ValidateArgs(const std::vector &inputs, const std:: for (size_t i = 0; i < num_outputs; ++i) { // preventing from write out of bound size_t aligned_size = GetAlignedSize(outputs[i].length); + GELOGI("Output [%zu], aligned_size:%zu, outputs.length:%u, output_sizes_:%u", i, aligned_size, outputs[i].length, + output_sizes_[i]); if (aligned_size < output_sizes_[i]) { - GELOGE(PARAM_INVALID, "Output size mismatch. index = %zu, model expect %zu, but given %zu(after align)", i, - output_sizes_[i], aligned_size); + GELOGE(PARAM_INVALID, + "Output size mismatch. index = %zu, model expect %zu," + "but given %zu(after align)", + i, output_sizes_[i], aligned_size); return PARAM_INVALID; } } @@ -81,23 +91,11 @@ Status SingleOp::GetArgs(const std::vector &inputs, const std::vecto if (use_physical_addr_) { for (auto &input : inputs) { auto *addr = reinterpret_cast(input.data); - size_t aligned_size = GetAlignedSize(input.length); - auto ret = ModelUtils::ConvertVirtualAddressToPhysical(addr, aligned_size, addr); - if (ret != SUCCESS) { - GELOGE(ret, "ConvertVirtualAddressToPhysical failed. Arg index = %zu", arg_index); - return ret; - } args_[arg_index++] = reinterpret_cast(addr); } for (auto &output : outputs) { auto *addr = reinterpret_cast(output.data); - size_t aligned_size = GetAlignedSize(output.length); - auto ret = ModelUtils::ConvertVirtualAddressToPhysical(addr, aligned_size, addr); - if (ret != SUCCESS) { - GELOGE(ret, "ConvertVirtualAddressToPhysical failed. Arg index = %zu", arg_index); - return ret; - } args_[arg_index++] = reinterpret_cast(addr); } } else { @@ -117,6 +115,7 @@ Status SingleOp::UpdateArgs(const std::vector &inputs, const std::ve if (ret != SUCCESS) { return ret; } + // update tbe task args size_t num_args = arg_table_.size(); for (size_t i = 0; i < num_args; ++i) { std::vector &ptr_to_arg_in_tasks = arg_table_[i]; @@ -129,18 +128,34 @@ Status SingleOp::UpdateArgs(const std::vector &inputs, const std::ve *arg_addr = args_[i]; } } + // update aicpu_TF or aicpu_CC args for (auto &task : tasks_) { + size_t io_addr_num = args_.size(); if (task->GetOpTaskType() == OP_TASK_AICPU) { - GELOGD("Update aicpu task args"); + GELOGD("Update aicpu_TF task args"); AiCpuTask *task_aicpu = dynamic_cast(task); GE_CHECK_NOTNULL(task_aicpu); - auto *dstIOAddr = const_cast(reinterpret_cast(task_aicpu->GetIOAddr())); - auto rt_ret = rtMemcpyAsync(dstIOAddr, sizeof(uint64_t) * args_.size(), &args_[0], + auto *dst_io_addr = const_cast(reinterpret_cast(task_aicpu->GetIOAddr())); + GE_CHECK_NOTNULL(dst_io_addr); + auto rt_ret = rtMemcpyAsync(dst_io_addr, sizeof(uint64_t) * args_.size(), &args_[0], sizeof(uint64_t) * args_.size(), RT_MEMCPY_HOST_TO_DEVICE_EX, stream_); if (rt_ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "rtMemcpyAsync addresses failed, ret = %d", rt_ret); return RT_FAILED; } + } else if (task->GetOpTaskType() == OP_TASK_AICPUCC) { + GELOGD("Update aicpu_CC task args"); + AiCpuCCTask *task_aicpu_cc = dynamic_cast(task); + GE_CHECK_NOTNULL(task_aicpu_cc); + const uintptr_t *task_io_addr = reinterpret_cast(task_aicpu_cc->GetIOAddr()); + GE_CHECK_NOTNULL(task_io_addr); + auto io_addr = reinterpret_cast(const_cast(task_io_addr)); + for (size_t i = 0; i < io_addr_num; ++i) { + io_addr[i] = reinterpret_cast(args_[i]); + } + } else { + GELOGW("Only TF_kernel aicpu and aicpu_CC are supported, but got %u", task->GetOpTaskType()); + continue; } } return SUCCESS; @@ -164,8 +179,90 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status SingleOp::ExecuteAsync(c return ret; } } + return ret; } void SingleOp::SetStream(rtStream_t stream) { stream_ = stream; } + +DynamicSingleOp::DynamicSingleOp(uintptr_t resource_id, rtStream_t stream) + : resource_id_(resource_id), stream_(stream) {} + +Status DynamicSingleOp::ValidateParams(const vector &input_desc, const std::vector &inputs, + std::vector &output_desc, std::vector &outputs) const { + if (inputs.size() != input_desc.size()) { + GELOGE(PARAM_INVALID, "Input number mismatches input desc number. Input num = %zu, input desc num = %zu", + inputs.size(), input_desc.size()); + return PARAM_INVALID; + } + + if (outputs.size() != output_desc.size()) { + GELOGE(PARAM_INVALID, "Output number mismatches output desc number. Output num = %zu, output desc num = %zu", + outputs.size(), output_desc.size()); + return PARAM_INVALID; + } + + if (input_desc.size() != num_inputs_) { + GELOGE(PARAM_INVALID, "Input number mismatches. expect %zu, but given %zu", num_inputs_, input_desc.size()); + return PARAM_INVALID; + } + + if (output_desc.size() != num_outputs_) { + GELOGE(PARAM_INVALID, "Output number mismatches. expect %zu, but given %zu", num_outputs_, output_desc.size()); + return PARAM_INVALID; + } + + return SUCCESS; +} + +Status DynamicSingleOp::AllocateWorkspaces(const std::vector &workspace_sizes, + std::vector &workspaces) { + static const std::string kPurpose("malloc workspace memory for dynamic op."); + if (workspace_sizes.empty()) { + GELOGD("No need to allocate workspace."); + return SUCCESS; + } + int64_t total_size = 0; + std::vector ws_offsets; + for (auto ws_size : workspace_sizes) { + // alignment and padding should be done in OpParaCalculate + GE_CHK_STATUS_RET_NOLOG(CheckInt64AddOverflow(total_size, ws_size)); + ws_offsets.emplace_back(total_size); + total_size += ws_size; + } + + GELOGD("Total workspace size is %ld", total_size); + StreamResource *stream_resource = SingleOpManager::GetInstance().GetResource(resource_id_, stream_); + GE_CHECK_NOTNULL(stream_resource); + auto ws_base = stream_resource->MallocMemory(kPurpose, static_cast(total_size)); + if (ws_base == nullptr) { + GELOGE(MEMALLOC_FAILED, "Failed to allocate memory of size: %ld", total_size); + return MEMALLOC_FAILED; + } + GELOGD("Done allocating workspace memory successfully."); + + for (auto ws_offset : ws_offsets) { + workspaces.emplace_back(ws_base + ws_offset); + } + + return SUCCESS; +} + +Status DynamicSingleOp::ExecuteAsync(const vector &input_desc, const vector &input_buffers, + vector &output_desc, vector &output_buffers) { + GE_CHECK_NOTNULL(op_task_); + GE_CHK_STATUS_RET_NOLOG(ValidateParams(input_desc, input_buffers, output_desc, output_buffers)); + GE_CHK_STATUS_RET_NOLOG(op_task_->UpdateRunInfo(input_desc, output_desc)); + std::vector workspace_buffers; + GE_CHK_STATUS_RET_NOLOG(AllocateWorkspaces(op_task_->GetWorkspaceSizes(), workspace_buffers)); + std::vector inputs; + std::vector outputs; + for (auto &buffer : input_buffers) { + inputs.emplace_back(buffer.data); + } + for (auto &buffer : output_buffers) { + outputs.emplace_back(buffer.data); + } + return op_task_->LaunchKernel(inputs, outputs, workspace_buffers, stream_); +} } // namespace ge diff --git a/src/ge/single_op/single_op.h b/src/ge/single_op/single_op.h index 08782b3b..d86c79ee 100644 --- a/src/ge/single_op/single_op.h +++ b/src/ge/single_op/single_op.h @@ -53,5 +53,26 @@ class SingleOp { std::vector> arg_table_; bool use_physical_addr_ = false; }; + +class DynamicSingleOp { + public: + DynamicSingleOp(uintptr_t resource_id, rtStream_t stream); + ~DynamicSingleOp() = default; + Status ExecuteAsync(const vector &input_desc, const std::vector &inputs, + std::vector &output_desc, std::vector &outputs); + + private: + friend class SingleOpModel; + Status ValidateParams(const vector &input_desc, const std::vector &inputs, + std::vector &output_desc, std::vector &outputs) const; + + Status AllocateWorkspaces(const std::vector &workspace_sizes, std::vector &workspaces); + + std::unique_ptr op_task_; + uintptr_t resource_id_ = 0; + rtStream_t stream_ = nullptr; + size_t num_inputs_ = 0; + size_t num_outputs_ = 0; +}; } // namespace ge #endif // GE_SINGLE_OP_SINGLE_OP_H_ diff --git a/src/ge/single_op/single_op_manager.cc b/src/ge/single_op/single_op_manager.cc index 990ca9cc..aa6f6d2b 100644 --- a/src/ge/single_op/single_op_manager.cc +++ b/src/ge/single_op/single_op_manager.cc @@ -19,9 +19,6 @@ #include #include -#include "runtime/dev.h" -#include "framework/common/debug/ge_log.h" - namespace ge { FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY SingleOpManager::~SingleOpManager() { for (auto &it : stream_resources_) { @@ -34,32 +31,15 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status SingleOpManager::GetOpFr const ModelData &model_data, void *stream, SingleOp **single_op) { + GELOGI("GetOpFromModel in. model name = %s", model_name.c_str()); if (single_op == nullptr) { GELOGE(PARAM_INVALID, "single op is null"); return PARAM_INVALID; } - uintptr_t resource_id; - // runtime uses NULL to denote a default stream for each device - if (stream == nullptr) { - // get current context - rtContext_t rt_cur_ctx = nullptr; - auto rt_err = rtCtxGetCurrent(&rt_cur_ctx); - if (rt_err != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "get current context failed, runtime result is %d", static_cast(rt_err)); - return RT_FAILED; - } - // use current context as resource key instead - GELOGI("use context as resource key instead when default stream"); - resource_id = reinterpret_cast(rt_cur_ctx); - } else { - GELOGI("use stream as resource key instead when create stream"); - resource_id = reinterpret_cast(stream); - } - - GELOGI("GetOpFromModel in. model name = %s, resource id = 0x%lx", model_name.c_str(), - static_cast(resource_id)); - StreamResource *res = GetResource(resource_id); + uintptr_t resource_id = 0; + GE_CHK_STATUS_RET(GetResourceId(stream, resource_id)); + StreamResource *res = GetResource(resource_id, stream); if (res == nullptr) { GELOGE(MEMALLOC_FAILED, "GetResource failed"); return MEMALLOC_FAILED; @@ -79,26 +59,19 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status SingleOpManager::GetOpFr return ret; } - auto *new_op = new (std::nothrow) SingleOp(); + auto new_op = std::unique_ptr(new (std::nothrow) SingleOp()); if (new_op == nullptr) { GELOGE(MEMALLOC_FAILED, "new SingleOp failed"); return MEMALLOC_FAILED; } GELOGI("To build operator: %s", model_name.c_str()); - ret = model.BuildOp(*res, *new_op); - if (ret != SUCCESS) { - GELOGE(ret, "Build op failed. op = %s, resource id = 0x%lx, ret = %u", model_name.c_str(), - static_cast(resource_id), ret); - delete new_op; - new_op = nullptr; - return ret; - } + GE_CHK_STATUS_RET(model.BuildOp(*res, *new_op), "Build op failed. op = %s, ret = %u", model_name.c_str(), ret); // stream is nullable new_op->SetStream(stream); - res->CacheOperator(model_data.model_data, new_op); - *single_op = new_op; + *single_op = new_op.get(); + res->CacheOperator(model_data.model_data, std::move(new_op)); return SUCCESS; } @@ -116,13 +89,14 @@ FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY Status SingleOpManager::Release return SUCCESS; } -StreamResource *SingleOpManager::GetResource(uintptr_t resource_id) { +StreamResource *SingleOpManager::GetResource(uintptr_t resource_id, rtStream_t stream) { std::lock_guard lock(mutex_); auto it = stream_resources_.find(resource_id); StreamResource *res = nullptr; if (it == stream_resources_.end()) { res = new (std::nothrow) StreamResource(); if (res != nullptr) { + res->SetStream(stream); stream_resources_.emplace(resource_id, res); } } else { @@ -141,4 +115,74 @@ StreamResource *SingleOpManager::TryGetResource(uintptr_t resource_id) { return it->second; } + +Status SingleOpManager::GetDynamicOpFromModel(const string &model_name, const ModelData &model_data, void *stream, + DynamicSingleOp **single_op) { + GE_CHECK_NOTNULL(single_op); + uintptr_t resource_id = 0; + GE_CHK_STATUS_RET(GetResourceId(stream, resource_id)); + StreamResource *res = GetResource(resource_id, stream); + if (res == nullptr) { + GELOGE(MEMALLOC_FAILED, "GetResource failed"); + return MEMALLOC_FAILED; + } + + DynamicSingleOp *op = res->GetDynamicOperator(model_data.model_data); + if (op != nullptr) { + GELOGD("Got operator from stream cache"); + *single_op = op; + return SUCCESS; + } + + if (!tiling_func_registered_) { + RegisterTilingFunc(); + } + + SingleOpModel model(model_name, model_data.model_data, model_data.model_len); + auto ret = model.Init(); + if (ret != SUCCESS) { + GELOGE(ret, "Init model failed. model = %s, ret = %u", model_name.c_str(), ret); + return ret; + } + + auto new_op = std::unique_ptr(new (std::nothrow) DynamicSingleOp(resource_id, stream)); + GE_CHECK_NOTNULL(new_op); + + GELOGI("To build operator: %s", model_name.c_str()); + GE_CHK_STATUS_RET(model.BuildDynamicOp(*new_op), "Build op failed. op = %s, ret = %u", model_name.c_str(), ret); + *single_op = new_op.get(); + res->CacheDynamicOperator(model_data.model_data, std::move(new_op)); + return SUCCESS; +} + +void SingleOpManager::RegisterTilingFunc() { + std::lock_guard lk(mutex_); + if (tiling_func_registered_) { + return; + } + + op_tiling_manager_.LoadSo(); + tiling_func_registered_ = true; +} + +Status SingleOpManager::GetResourceId(rtStream_t stream, uintptr_t &resource_id) { + // runtime uses NULL to denote a default stream for each device + if (stream == nullptr) { + // get current context + rtContext_t rt_cur_ctx = nullptr; + auto rt_err = rtCtxGetCurrent(&rt_cur_ctx); + if (rt_err != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "get current context failed, runtime result is %d", static_cast(rt_err)); + return RT_FAILED; + } + // use current context as resource key instead + GELOGI("use context as resource key instead when default stream"); + resource_id = reinterpret_cast(rt_cur_ctx); + } else { + GELOGI("use stream as resource key instead when create stream"); + resource_id = reinterpret_cast(stream); + } + + return SUCCESS; +} } // namespace ge diff --git a/src/ge/single_op/single_op_manager.h b/src/ge/single_op/single_op_manager.h index 15d32316..09ae0e4e 100644 --- a/src/ge/single_op/single_op_manager.h +++ b/src/ge/single_op/single_op_manager.h @@ -20,7 +20,7 @@ #include #include #include - +#include "common/ge/op_tiling_manager.h" #include "single_op/single_op_model.h" #include "single_op/stream_resource.h" @@ -34,16 +34,27 @@ class SingleOpManager { return instance; } - Status GetOpFromModel(const std::string &key, const ge::ModelData &model_data, void *stream, SingleOp **single_op); + Status GetOpFromModel(const std::string &model_name, const ge::ModelData &model_data, void *stream, + SingleOp **single_op); + + Status GetDynamicOpFromModel(const std::string &model_name, const ge::ModelData &model_data, void *stream, + DynamicSingleOp **dynamic_single_op); + + StreamResource *GetResource(uintptr_t resource_id, rtStream_t stream); Status ReleaseResource(void *stream); + void RegisterTilingFunc(); + private: - StreamResource *GetResource(uintptr_t resource_id); + static Status GetResourceId(rtStream_t stream, uintptr_t &resource_id); + StreamResource *TryGetResource(uintptr_t resource_id); std::mutex mutex_; + bool tiling_func_registered_ = false; std::unordered_map stream_resources_; + OpTilingManager op_tiling_manager_; }; } // namespace ge diff --git a/src/ge/single_op/single_op_model.cc b/src/ge/single_op/single_op_model.cc index 9decdf75..27958e7c 100644 --- a/src/ge/single_op/single_op_model.cc +++ b/src/ge/single_op/single_op_model.cc @@ -28,6 +28,7 @@ #include "graph/utils/tensor_utils.h" #include "runtime/rt.h" #include "task/aicpu_task_builder.h" +#include "task/aicpu_kernel_task_builder.h" #include "task/tbe_task_builder.h" using domi::TaskDef; @@ -42,12 +43,8 @@ SingleOpModel::SingleOpModel(const std::string &model_name, const void *model_da : model_name_(model_name), ori_model_data_(model_data), ori_model_size_(model_size) {} Status SingleOpModel::Init() { - auto ret = InitModel(); - if (ret != SUCCESS) { - return ret; - } - - return ParseInputsAndOutputs(); + GE_CHK_STATUS_RET_NOLOG(InitModel()); + return LoadAllNodes(); } Status SingleOpModel::InitModel() { @@ -149,7 +146,7 @@ void SingleOpModel::ParseOutputNode(const OpDescPtr &op_desc) { } } -Status SingleOpModel::ParseInputsAndOutputs() { +Status SingleOpModel::LoadAllNodes() { auto ge_model = model_helper_.GetGeModel(); GE_CHECK_NOTNULL(ge_model); Graph graph = ge_model->GetGraph(); @@ -167,19 +164,18 @@ Status SingleOpModel::ParseInputsAndOutputs() { auto node = nodes.at(i); auto op_desc = node->GetOpDesc(); GE_CHECK_NOTNULL(op_desc); - op_list_[i] = op_desc; + op_list_[i] = node; auto op_type = op_desc->GetType(); GELOGI("[%s] node[%zu] = %s, type = %s", model_name_.c_str(), i, node->GetName().c_str(), op_type.c_str()); if (op_type == DATA_TYPE || op_type == AIPP_DATA_TYPE) { - auto ret = ParseInputNode(op_desc); - if (ret != SUCCESS) { - return ret; - } + data_ops_.emplace_back(op_desc); + continue; } if (op_type == NETOUTPUT) { - ParseOutputNode(op_desc); + netoutput_op_ = op_desc; + continue; } ge_model->GetTBEKernelStore().LoadTBEKernelBinToOpDesc(op_desc); @@ -188,6 +184,14 @@ Status SingleOpModel::ParseInputsAndOutputs() { return SUCCESS; } +Status SingleOpModel::ParseInputsAndOutputs() { + for (auto &op_desc : data_ops_) { + GE_CHK_STATUS_RET_NOLOG(ParseInputNode(op_desc)); + } + ParseOutputNode(netoutput_op_); + return SUCCESS; +} + Status SingleOpModel::SetInputsAndOutputs(SingleOp &single_op) { // for lhisi const char *use_physical_address = std::getenv("GE_USE_PHYSICAL_ADDRESS"); @@ -198,11 +202,6 @@ Status SingleOpModel::SetInputsAndOutputs(SingleOp &single_op) { int arg_index = 0; for (size_t i = 0; i < input_offset_list_.size(); ++i) { auto *addr = model_params_.mem_base + input_offset_list_[i]; - auto ret = ModelUtils::ConvertVirtualAddressToPhysical(addr, input_sizes_[i], addr); - if (ret != SUCCESS) { - GELOGE(ret, "ConvertVirtualAddressToPhysical failed. Input index = %zu", i); - return ret; - } model_params_.addr_mapping_.emplace(reinterpret_cast(addr), arg_index++); single_op.input_sizes_.emplace_back(input_sizes_[i]); single_op.input_addr_list_.emplace_back(addr); @@ -210,11 +209,6 @@ Status SingleOpModel::SetInputsAndOutputs(SingleOp &single_op) { for (size_t i = 0; i < output_offset_list_.size(); ++i) { auto *addr = model_params_.mem_base + output_offset_list_[i]; - auto ret = ModelUtils::ConvertVirtualAddressToPhysical(addr, output_sizes_[i], addr); - if (ret != SUCCESS) { - GELOGE(ret, "ConvertVirtualAddressToPhysical failed. Output index = %zu", i); - return ret; - } model_params_.addr_mapping_.emplace(reinterpret_cast(addr), arg_index++); single_op.output_sizes_.emplace_back(output_sizes_[i]); single_op.output_addr_list_.emplace_back(addr); @@ -234,16 +228,34 @@ Status SingleOpModel::BuildTaskList(SingleOp &single_op) { task_def.DebugString().c_str()); auto task_type = static_cast(task_def.type()); if (task_type == RT_MODEL_TASK_KERNEL) { - GELOGD("Building TBE task"); - OpTask *task = nullptr; - auto ret = BuildKernelTask(task_def.kernel(), single_op, &task); - if (ret != SUCCESS) { - return ret; + const domi::KernelDef &kernel_def = task_def.kernel(); + const auto &context = kernel_def.context(); + auto kernel_type = static_cast(context.kernel_type()); + if (kernel_type == cce::ccKernelType::TE) { + GELOGD("Building TBE task"); + TbeOpTask *tbe_task = nullptr; + auto ret = BuildKernelTask(task_def.kernel(), &tbe_task); + if (ret != SUCCESS) { + return ret; + } + + single_op.arg_table_.resize(single_op.input_sizes_.size() + single_op.output_sizes_.size()); + ParseArgTable(tbe_task, single_op); + single_op.tasks_.emplace_back(tbe_task); + } else if (kernel_type == cce::ccKernelType::AI_CPU) { + GELOGD("Building AICPU_CC task"); + OpTask *task = nullptr; + auto ret = BuildCpuKernelTask(task_def.kernel(), &task); + if (ret != SUCCESS) { + return ret; + } + single_op.tasks_.emplace_back(task); + } else { + GELOGE(UNSUPPORTED, "Only TBE kernel and AI_CPU kernek are supported, but got %u", context.kernel_type()); + return UNSUPPORTED; } - - single_op.tasks_.emplace_back(task); } else if (task_type == RT_MODEL_TASK_KERNEL_EX) { - GELOGD("Building AICPU task"); + GELOGD("Building AICPU_TF task"); OpTask *task = nullptr; auto ret = BuildKernelExTask(task_def.kernel_ex(), single_op, &task); if (ret != SUCCESS) { @@ -278,15 +290,9 @@ void SingleOpModel::ParseArgTable(TbeOpTask *task, SingleOp &op) { } } -Status SingleOpModel::BuildKernelTask(const domi::KernelDef &kernel_def, SingleOp &single_op, OpTask **task) { +Status SingleOpModel::BuildKernelTask(const domi::KernelDef &kernel_def, TbeOpTask **task) { GE_CHECK_NOTNULL(task); const auto &context = kernel_def.context(); - auto kernel_type = static_cast(context.kernel_type()); - if (kernel_type != cce::ccKernelType::TE) { - GELOGE(UNSUPPORTED, "Only TBE kernel is supported, but got %u", context.kernel_type()); - return UNSUPPORTED; - } - auto iter = op_list_.find(context.op_index()); if (iter == op_list_.end()) { GELOGE(INTERNAL_ERROR, "op desc not found. op index = %u", context.op_index()); @@ -307,9 +313,6 @@ Status SingleOpModel::BuildKernelTask(const domi::KernelDef &kernel_def, SingleO return ret; } - single_op.arg_table_.resize(single_op.input_sizes_.size() + single_op.output_sizes_.size()); - ParseArgTable(tbe_task, single_op); - *task = tbe_task; return SUCCESS; } @@ -323,13 +326,13 @@ Status SingleOpModel::BuildKernelExTask(const domi::KernelExDef &kernel_def, Sin std::unique_ptr aicpu_task(new (std::nothrow) AiCpuTask()); if (aicpu_task == nullptr) { - GELOGE(MEMALLOC_FAILED, "create aicpu op task failed"); + GELOGE(MEMALLOC_FAILED, "create aicpu_TF op task failed"); return MEMALLOC_FAILED; } - auto builder = AiCpuTaskBuilder(iter->second, kernel_def); + auto builder = AiCpuTaskBuilder(iter->second->GetOpDesc(), kernel_def); auto ret = builder.BuildTask(*aicpu_task, model_params_); if (ret != SUCCESS) { - GELOGE(ret, "build aicpu op task failed"); + GELOGE(ret, "build aicpu_TF op task failed"); return ret; } @@ -337,16 +340,63 @@ Status SingleOpModel::BuildKernelExTask(const domi::KernelExDef &kernel_def, Sin return SUCCESS; } -Status SingleOpModel::BuildOp(StreamResource &resource, SingleOp &single_op) { - auto ret = InitModelMem(resource); - if (ret != SUCCESS) { - return ret; +Status SingleOpModel::BuildCpuKernelTask(const domi::KernelDef &kernel_def, OpTask **task) { + std::unique_ptr aicpucc_task(new (std::nothrow) AiCpuCCTask()); + if (aicpucc_task == nullptr) { + GELOGE(MEMALLOC_FAILED, "create aicpu_CC op task failed"); + return MEMALLOC_FAILED; } - ret = SetInputsAndOutputs(single_op); + auto builder = AiCpuCCTaskBuilder(kernel_def); + auto ret = builder.BuildTask(*aicpucc_task); if (ret != SUCCESS) { + GELOGE(ret, "build aicpu_CC op task failed"); return ret; } + + *task = aicpucc_task.release(); + return SUCCESS; +} + +Status SingleOpModel::BuildOp(StreamResource &resource, SingleOp &single_op) { + GE_CHK_STATUS_RET_NOLOG(ParseInputsAndOutputs()); + GE_CHK_STATUS_RET_NOLOG(InitModelMem(resource)); + GE_CHK_STATUS_RET_NOLOG(SetInputsAndOutputs(single_op)); return BuildTaskList(single_op); } + +Status SingleOpModel::BuildTaskListForDynamicOp(DynamicSingleOp &single_op) { + auto ge_model = model_helper_.GetGeModel(); + GE_CHECK_NOTNULL(ge_model); + + auto tasks = ge_model->GetModelTaskDefPtr()->task(); + for (int i = 0; i < tasks.size(); ++i) { + const TaskDef &task_def = tasks[i]; + GELOGI("[%s] Task[%d], type = %u, DebugString = %s", model_name_.c_str(), i, task_def.type(), + task_def.DebugString().c_str()); + auto task_type = static_cast(task_def.type()); + if (task_type == RT_MODEL_TASK_KERNEL) { + if (single_op.op_task_ != nullptr) { + GELOGE(UNSUPPORTED, "Do not support dynamic op with multiple tasks."); + return UNSUPPORTED; + } + + TbeOpTask *task = nullptr; + GE_CHK_STATUS_RET_NOLOG(BuildKernelTask(task_def.kernel(), &task)); + single_op.op_task_.reset(task); + } else { + // skip + GELOGD("Skip task type: %d", static_cast(task_type)); + } + } + + return SUCCESS; +} + +Status SingleOpModel::BuildDynamicOp(DynamicSingleOp &single_op) { + single_op.num_inputs_ = data_ops_.size(); + single_op.num_outputs_ = netoutput_op_->GetAllInputsSize(); + ParseOpModelParams(model_helper_, model_params_); + return BuildTaskListForDynamicOp(single_op); +} } // namespace ge diff --git a/src/ge/single_op/single_op_model.h b/src/ge/single_op/single_op_model.h index 4d8aae30..caa958e5 100644 --- a/src/ge/single_op/single_op_model.h +++ b/src/ge/single_op/single_op_model.h @@ -50,9 +50,11 @@ class SingleOpModel { Status Init(); Status BuildOp(StreamResource &resource, SingleOp &single_op); + Status BuildDynamicOp(DynamicSingleOp &single_op); private: Status InitModel(); + Status LoadAllNodes(); Status ParseInputsAndOutputs(); Status SetInputsAndOutputs(SingleOp &single_op); @@ -62,8 +64,10 @@ class SingleOpModel { void ParseOutputNode(const OpDescPtr &op_desc); Status BuildTaskList(SingleOp &single_op); - Status BuildKernelTask(const domi::KernelDef &kernel_def, SingleOp &single_op, OpTask **task); + Status BuildTaskListForDynamicOp(DynamicSingleOp &dynamic_single_op); + Status BuildKernelTask(const domi::KernelDef &kernel_def, TbeOpTask **task); Status BuildKernelExTask(const domi::KernelExDef &kernel_def, SingleOp &single_op, OpTask **task); + Status BuildCpuKernelTask(const domi::KernelDef &kernel_def, OpTask **task); static void ParseOpModelParams(ModelHelper &model_helper, SingleOpModelParam ¶m); void ParseArgTable(TbeOpTask *task, SingleOp &op); @@ -74,13 +78,15 @@ class SingleOpModel { ModelHelper model_helper_; - map op_list_; + map op_list_; SingleOpModelParam model_params_; std::vector input_offset_list_; std::vector input_sizes_; std::vector output_offset_list_; std::vector output_sizes_; + std::vector data_ops_; + OpDescPtr netoutput_op_; }; } // namespace ge diff --git a/src/ge/single_op/stream_resource.cc b/src/ge/single_op/stream_resource.cc index e48afb96..703b22b2 100644 --- a/src/ge/single_op/stream_resource.cc +++ b/src/ge/single_op/stream_resource.cc @@ -23,12 +23,6 @@ namespace ge { StreamResource::~StreamResource() { - for (auto it : op_map_) { - // it's safe to delete a nullptr - delete it.second; - it.second = nullptr; - } - for (auto mem : memory_list_) { if (mem != nullptr) { auto rt_ret = rtFree(mem); @@ -44,7 +38,13 @@ StreamResource::~StreamResource() { } } -void StreamResource::CacheOperator(const void *key, SingleOp *single_op) { op_map_[key] = single_op; } +void StreamResource::CacheOperator(const void *key, std::unique_ptr &&single_op) { + op_map_[key] = std::move(single_op); +} + +void StreamResource::CacheDynamicOperator(const void *key, std::unique_ptr &&single_op) { + dynamic_op_map_[key] = std::move(single_op); +} SingleOp *StreamResource::GetOperator(const void *key) { auto it = op_map_.find(key); @@ -52,9 +52,20 @@ SingleOp *StreamResource::GetOperator(const void *key) { return nullptr; } - return it->second; + return it->second.get(); } +DynamicSingleOp *StreamResource::GetDynamicOperator(const void *key) { + auto it = dynamic_op_map_.find(key); + if (it == dynamic_op_map_.end()) { + return nullptr; + } + + return it->second.get(); +} + +void StreamResource::SetStream(rtStream_t stream) { stream_ = stream; } + uint8_t *StreamResource::DoMallocMemory(const std::string &purpose, size_t size, size_t &max_allocated, std::vector &allocated) { if (size <= max_allocated && !allocated.empty()) { @@ -62,6 +73,20 @@ uint8_t *StreamResource::DoMallocMemory(const std::string &purpose, size_t size, return allocated.back(); } + if (!allocated.empty()) { + GELOGD("Expand workspace memory size from %zu to %zu", max_allocated, size); + auto ret = rtStreamSynchronize(stream_); + if (ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtStreamSynchronize failed, ret = %d", ret); + return nullptr; + } + + auto addr = allocated.back(); + allocated.pop_back(); + (void)rtFree(addr); + max_allocated = 0; + } + uint8_t *buffer = nullptr; auto ret = rtMalloc(reinterpret_cast(&buffer), size, RT_MEMORY_HBM); if (ret != RT_ERROR_NONE) { diff --git a/src/ge/single_op/stream_resource.h b/src/ge/single_op/stream_resource.h index fc114c08..6f26c497 100644 --- a/src/ge/single_op/stream_resource.h +++ b/src/ge/single_op/stream_resource.h @@ -37,22 +37,27 @@ class StreamResource { StreamResource &operator=(const StreamResource &) = delete; StreamResource &operator=(StreamResource &&) = delete; - void CacheOperator(const void *key, SingleOp *single_op); + void CacheOperator(const void *key, std::unique_ptr &&single_op); + void CacheDynamicOperator(const void *key, std::unique_ptr &&single_op); + void SetStream(rtStream_t stream); SingleOp *GetOperator(const void *key); + DynamicSingleOp *GetDynamicOperator(const void *key); uint8_t *MallocMemory(const std::string &purpose, size_t size); uint8_t *MallocWeight(const std::string &purpose, size_t size); private: - static uint8_t *DoMallocMemory(const std::string &purpose, size_t size, size_t &max_allocated, - std::vector &allocated); + uint8_t *DoMallocMemory(const std::string &purpose, size_t size, size_t &max_allocated, + std::vector &allocated); size_t max_memory_size_ = 0; size_t max_weight_size_ = 0; std::vector memory_list_; std::vector weight_list_; - std::unordered_map op_map_; + std::unordered_map> op_map_; + std::unordered_map> dynamic_op_map_; + rtStream_t stream_ = nullptr; }; } // namespace ge diff --git a/src/ge/single_op/task/aicpu_kernel_task_builder.cc b/src/ge/single_op/task/aicpu_kernel_task_builder.cc new file mode 100644 index 00000000..936c7b67 --- /dev/null +++ b/src/ge/single_op/task/aicpu_kernel_task_builder.cc @@ -0,0 +1,56 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#include "single_op/task/aicpu_kernel_task_builder.h" + +namespace ge { +AiCpuCCTaskBuilder::AiCpuCCTaskBuilder(const domi::KernelDef &kernel_def) : kernel_def_(kernel_def) {} + +Status AiCpuCCTaskBuilder::SetKernelArgs(AiCpuCCTask &task) { + size_t aicpu_arg_size = kernel_def_.args_size(); + if (aicpu_arg_size <= 0) { + GELOGE(RT_FAILED, "aicpu_arg_size is invalid, value = %zu", aicpu_arg_size); + return RT_FAILED; + } + void *aicpu_args = malloc(aicpu_arg_size); + if (aicpu_args == nullptr) { + GELOGE(RT_FAILED, "malloc failed, size = %zu", aicpu_arg_size); + return RT_FAILED; + } + + task.SetKernelArgs(aicpu_args, aicpu_arg_size); + auto err = memcpy_s(aicpu_args, aicpu_arg_size, kernel_def_.args().data(), aicpu_arg_size); + if (err != EOK) { + GELOGE(RT_FAILED, "memcpy_s args failed, size = %zu, err = %d", aicpu_arg_size, err); + return RT_FAILED; + } + + task.SetIoAddr(static_cast(aicpu_args) + sizeof(aicpu::AicpuParamHead)); + return SUCCESS; +} + +Status AiCpuCCTaskBuilder::BuildTask(AiCpuCCTask &task) { + auto ret = SetKernelArgs(task); + if (ret != SUCCESS) { + return ret; + } + const std::string &so_name = kernel_def_.so_name(); + const std::string &kernel_name = kernel_def_.kernel_name(); + task.SetSoName(so_name); + task.SetkernelName(kernel_name); + return SUCCESS; +} +} // namespace ge \ No newline at end of file diff --git a/src/ge/single_op/task/aicpu_kernel_task_builder.h b/src/ge/single_op/task/aicpu_kernel_task_builder.h new file mode 100644 index 00000000..c445132e --- /dev/null +++ b/src/ge/single_op/task/aicpu_kernel_task_builder.h @@ -0,0 +1,40 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_SINGLE_OP_TASK_AICPU_KERNEL_TASK_BUILDER_H_ +#define GE_SINGLE_OP_TASK_AICPU_KERNEL_TASK_BUILDER_H_ + +#include +#include "aicpu/common/aicpu_task_struct.h" +#include "single_op/single_op.h" +#include "single_op/single_op_model.h" +#include "runtime/mem.h" + +namespace ge { +class AiCpuCCTaskBuilder { + public: + explicit AiCpuCCTaskBuilder(const domi::KernelDef &kernel_def); + ~AiCpuCCTaskBuilder() = default; + + Status BuildTask(AiCpuCCTask &task); + + private: + Status SetKernelArgs(AiCpuCCTask &task); + const domi::KernelDef &kernel_def_; +}; +} // namespace ge + +#endif // GE_SINGLE_OP_TASK_AICPUCC_TASK_BUILDER_H_ \ No newline at end of file diff --git a/src/ge/single_op/task/aicpu_task_builder.cc b/src/ge/single_op/task/aicpu_task_builder.cc index 1a4c37ca..bc2c76f6 100644 --- a/src/ge/single_op/task/aicpu_task_builder.cc +++ b/src/ge/single_op/task/aicpu_task_builder.cc @@ -129,7 +129,8 @@ Status AiCpuTaskBuilder::BuildTask(ge::AiCpuTask &task, const SingleOpModelParam task.task_info_ = kernel_def_.task_info(); task.workspace_addr_ = ws_addr_vec[0]; + auto debug_info = BuildTaskUtils::GetTaskInfo(op_desc_); + GELOGI("[TASK_INFO] %s %s", task.task_info_.c_str(), debug_info.c_str()); return SUCCESS; } - } // namespace ge diff --git a/src/ge/single_op/task/aicpu_task_builder.h b/src/ge/single_op/task/aicpu_task_builder.h index 0253ebd0..bd582a4f 100644 --- a/src/ge/single_op/task/aicpu_task_builder.h +++ b/src/ge/single_op/task/aicpu_task_builder.h @@ -36,7 +36,7 @@ class AiCpuTaskBuilder { Status SetInputOutputAddr(void **io_addr, const std::vector &addresses); Status SetFmkOpKernel(void *io_addr, void *ws_addr, STR_FWK_OP_KERNEL &kernel); - const OpDescPtr &op_desc_; + const OpDescPtr op_desc_; const domi::KernelExDef &kernel_def_; }; } // namespace ge diff --git a/src/ge/single_op/task/build_task_utils.cc b/src/ge/single_op/task/build_task_utils.cc index 883679be..9e97ee57 100644 --- a/src/ge/single_op/task/build_task_utils.cc +++ b/src/ge/single_op/task/build_task_utils.cc @@ -19,7 +19,9 @@ #include "runtime/rt.h" #include "graph/load/new_model_manager/model_utils.h" #include "graph/manager/graph_var_manager.h" +#include "graph/utils/type_utils.h" #include "framework/common/debug/ge_log.h" +#include "framework/common/types.h" namespace ge { namespace { @@ -62,4 +64,42 @@ std::vector BuildTaskUtils::GetKernelArgs(const OpDescPtr &op_desc, cons auto addresses = GetAddresses(op_desc, param); return JoinAddresses(addresses); } + +std::string BuildTaskUtils::GetTaskInfo(const OpDescPtr &op_desc) { + std::stringstream ss; + if (op_desc != nullptr) { + auto op_type = op_desc->GetType(); + if (op_type == ge::NETOUTPUT || op_type == ge::DATA) { + return ss.str(); + } + // Conv2D IN[DT_FLOAT16 NC1HWC0[256, 128, 7, 7, 16],DT_FLOAT16 FRACTAL_Z[128, 32, 16, 16]] + // OUT[DT_FLOAT16 NC1HWC0[256, 32, 7, 7, 16]] + ss << op_type << " IN["; + for (uint32_t idx = 0; idx < op_desc->GetInputsSize(); idx++) { + const GeTensorDescPtr &input = op_desc->MutableInputDesc(idx); + ss << TypeUtils::DataTypeToSerialString(input->GetDataType()) << " "; + ss << TypeUtils::FormatToSerialString(input->GetFormat()); + ss << VectorToString(input->GetShape().GetDims()); + if (idx < op_desc->GetInputsSize() - 1) { + ss << ","; + } + } + ss << "] OUT["; + + for (uint32_t idx = 0; idx < op_desc->GetOutputsSize(); idx++) { + const GeTensorDescPtr &output = op_desc->MutableOutputDesc(idx); + ss << TypeUtils::DataTypeToSerialString(output->GetDataType()) << " "; + Format out_format = output->GetFormat(); + const GeShape &out_shape = output->GetShape(); + const auto &dims = out_shape.GetDims(); + ss << TypeUtils::FormatToSerialString(out_format); + ss << VectorToString(dims); + if (idx < op_desc->GetOutputsSize() - 1) { + ss << ","; + } + } + ss << "]\n"; + } + return ss.str(); +} } // namespace ge diff --git a/src/ge/single_op/task/build_task_utils.h b/src/ge/single_op/task/build_task_utils.h index a5030e69..f5885fd2 100644 --- a/src/ge/single_op/task/build_task_utils.h +++ b/src/ge/single_op/task/build_task_utils.h @@ -18,6 +18,7 @@ #define GE_SINGLE_OP_TASK_BUILD_TASK_UTILS_H_ #include +#include #include "graph/op_desc.h" #include "single_op/single_op.h" @@ -31,6 +32,21 @@ class BuildTaskUtils { static std::vector> GetAddresses(const OpDescPtr &op_desc, const SingleOpModelParam ¶m); static std::vector JoinAddresses(const std::vector> &addresses); static std::vector GetKernelArgs(const OpDescPtr &op_desc, const SingleOpModelParam ¶m); + static std::string GetTaskInfo(const OpDescPtr &op_desc); + template + static std::string VectorToString(const std::vector &values) { + std::stringstream ss; + ss << '['; + auto size = values.size(); + for (size_t i = 0; i < size; ++i) { + ss << values[i]; + if (i != size - 1) { + ss << ", "; + } + } + ss << ']'; + return ss.str(); + } }; } // namespace ge #endif // GE_SINGLE_OP_TASK_BUILD_TASK_UTILS_H_ diff --git a/src/ge/single_op/task/op_task.cc b/src/ge/single_op/task/op_task.cc index e93fad71..ddc4992c 100644 --- a/src/ge/single_op/task/op_task.cc +++ b/src/ge/single_op/task/op_task.cc @@ -16,34 +16,48 @@ #include "single_op/task/op_task.h" +#include +#include +#include + #include "runtime/rt.h" -#include "framework/common/debug/ge_log.h" +#include "register/op_tiling.h" +#include "framework/common/debug/log.h" namespace ge { +namespace { +constexpr int kLaunchRetryTimes = 1000; +constexpr int kSleepTime = 10; +} // namespace + void TbeOpTask::SetStubFunc(const std::string &name, const void *stub_func) { this->stub_name_ = name; this->stub_func_ = stub_func; } -void TbeOpTask::SetKernelArgs(void *args, size_t arg_size, uint32_t block_dim) { - args_ = args; +void TbeOpTask::SetKernelArgs(std::unique_ptr &&args, size_t arg_size, uint32_t block_dim) { + args_ = std::move(args); arg_size_ = arg_size; block_dim_ = block_dim; } void TbeOpTask::SetSmDesc(void *sm_desc) { sm_desc_ = sm_desc; } -TbeOpTask::~TbeOpTask() { - if (args_ != nullptr) { - (void)rtFreeHost(args_); - } +const vector &OpTask::GetWorkspaceSizes() const { return workspace_sizes_; } +void OpTask::SetWorkspaceSizes(const vector &workspace_sizes) { workspace_sizes_ = workspace_sizes; } + +TbeOpTask::~TbeOpTask() { if (sm_desc_ != nullptr) { (void)rtMemFreeManaged(sm_desc_); } + + if (tiling_buffer_ != nullptr) { + (void)rtFree(tiling_buffer_); + } } -const void *TbeOpTask::GetArgs() const { return args_; } +const void *TbeOpTask::GetArgs() const { return args_.get(); } size_t TbeOpTask::GetArgSize() const { return arg_size_; } @@ -52,13 +66,118 @@ const std::string &TbeOpTask::GetStubName() const { return stub_name_; } Status TbeOpTask::LaunchKernel(rtStream_t stream) { GELOGD("To invoke rtKernelLaunch. task = %s, block_dim = %u", this->stub_name_.c_str(), block_dim_); auto *sm_desc = reinterpret_cast(sm_desc_); - auto ret = rtKernelLaunch(stub_func_, block_dim_, args_, static_cast(arg_size_), sm_desc, stream); + auto ret = rtKernelLaunch(stub_func_, block_dim_, args_.get(), static_cast(arg_size_), sm_desc, stream); + int retry_times = 0; + while (ret != RT_ERROR_NONE && retry_times < kLaunchRetryTimes) { + retry_times++; + GELOGW("Retry after %d ms, retry_times: %d", kSleepTime, retry_times); + std::this_thread::sleep_for(std::chrono::milliseconds(kSleepTime)); + ret = rtKernelLaunch(stub_func_, block_dim_, args_.get(), arg_size_, sm_desc, stream); + } + if (ret != RT_ERROR_NONE) { GELOGE(RT_FAILED, "Invoke rtKernelLaunch failed. ret = %d, task = %s", ret, this->stub_name_.c_str()); return RT_FAILED; } - GELOGD("Invoke rtKernelLaunch succeeded. task = %s", this->stub_name_.c_str()); + GELOGI("[TASK_INFO] %s", this->stub_name_.c_str()); + return SUCCESS; +} + +Status TbeOpTask::UpdateRunInfo(const vector &input_desc, const vector &output_desc) { + GE_CHK_STATUS_RET_NOLOG(UpdateNodeByShape(input_desc, output_desc)); + // invoke OpParaCalculate + GELOGD("Start to invoke OpParaCalculate."); + optiling::OpRunInfo run_info; + auto ret = optiling::OpParaCalculate(*node_, run_info); + if (ret != GRAPH_SUCCESS) { + GELOGE(FAILED, "Failed to invoke OpParaCalculate. ret = %u", ret); + return FAILED; + } + SetWorkspaceSizes(run_info.workspaces); + block_dim_ = run_info.block_dim; + tiling_data_ = run_info.tiling_data.str(); + GELOGD("Done invoking OpParaCalculate successfully. block_dim = %u, tiling size = %zu", block_dim_, + tiling_data_.size()); + return SUCCESS; +} + +Status TbeOpTask::UpdateTensorDesc(const GeTensorDesc &src_tensor, GeTensorDesc &dst_tensor) { + int64_t storage_format_val = static_cast(FORMAT_RESERVED); + (void)AttrUtils::GetInt(src_tensor, ge::ATTR_NAME_STORAGE_FORMAT, storage_format_val); + auto storage_format = static_cast(storage_format_val); + if (storage_format == FORMAT_RESERVED) { + GELOGD("Storage format not set. update shape to [%s], and original shape to [%s]", + src_tensor.GetShape().ToString().c_str(), src_tensor.GetOriginShape().ToString().c_str()); + dst_tensor.SetShape(src_tensor.GetShape()); + dst_tensor.SetOriginShape(src_tensor.GetOriginShape()); + } else { + std::vector storage_shape; + if (!AttrUtils::GetListInt(src_tensor, ge::ATTR_NAME_STORAGE_SHAPE, storage_shape)) { + GELOGE(PARAM_INVALID, "Failed to get storage_shape while storage_format was set"); + return PARAM_INVALID; + } + + GELOGD("Storage format set. update shape to [%s], and original shape to [%s]", + GeShape(storage_shape).ToString().c_str(), src_tensor.GetShape().ToString().c_str()); + dst_tensor.SetShape(GeShape(std::move(storage_shape))); + dst_tensor.SetOriginShape(src_tensor.GetShape()); + } + + return SUCCESS; +} + +Status TbeOpTask::UpdateNodeByShape(const vector &input_desc, const vector &output_desc) { + auto op_desc = node_->GetOpDesc(); + GE_CHECK_NOTNULL(op_desc); + // Set runtime shape to node + for (size_t i = 0; i < input_desc.size(); ++i) { + auto tensor_desc = op_desc->MutableInputDesc(i); + auto &runtime_tensor_desc = input_desc[i]; + GE_CHECK_NOTNULL(tensor_desc); + GE_CHK_STATUS_RET(UpdateTensorDesc(runtime_tensor_desc, *tensor_desc)); + } + + for (size_t i = 0; i < output_desc.size(); ++i) { + auto tensor_desc = op_desc->MutableOutputDesc(i); + auto &runtime_tensor_desc = output_desc[i]; + GE_CHECK_NOTNULL(tensor_desc); + GE_CHK_STATUS_RET(UpdateTensorDesc(runtime_tensor_desc, *tensor_desc)); + } + + return SUCCESS; +} + +void TbeOpTask::EnableDynamicSupport(const NodePtr &node, void *tiling_buffer, size_t max_tiling_size) { + node_ = node; + tiling_buffer_ = tiling_buffer; + max_tiling_size_ = max_tiling_size; +} + +Status TbeOpTask::LaunchKernel(const vector &inputs, const vector &outputs, + const vector &workspaces, rtStream_t stream) { + GELOGD("[%s] Start to launch kernel", node_->GetName().c_str()); + std::vector args; + args.insert(args.end(), inputs.begin(), inputs.end()); + args.insert(args.end(), outputs.begin(), outputs.end()); + args.insert(args.end(), workspaces.begin(), workspaces.end()); + + if (tiling_buffer_ != nullptr) { + GELOGD("[%s] Start to copy tiling info. size = %zu", node_->GetName().c_str(), tiling_data_.size()); + GE_CHK_RT_RET(rtMemcpyAsync(tiling_buffer_, max_tiling_size_, tiling_data_.data(), tiling_data_.size(), + RT_MEMCPY_HOST_TO_DEVICE_EX, stream)); + + args.emplace_back(tiling_buffer_); + } + + if (memcpy_s(args_.get(), arg_size_, args.data(), args.size() * sizeof(void *)) != EOK) { + GELOGE(INTERNAL_ERROR, "[%s] Failed to update kernel args.", node_->GetName().c_str()); + return INTERNAL_ERROR; + } + + GELOGD("[%s] Start to invoke rtKernelLaunch", node_->GetName().c_str()); + GE_CHK_RT_RET(rtKernelLaunch(stub_func_, block_dim_, args_.get(), arg_size_, nullptr, stream)); + GELOGD("[%s] Done invoking rtKernelLaunch successfully", node_->GetName().c_str()); return SUCCESS; } @@ -88,8 +207,49 @@ Status AiCpuTask::LaunchKernel(rtStream_t stream) { GELOGE(RT_FAILED, "Invoke rtKernelLaunch failed. ret = %d, task = %s", ret, this->op_type_.c_str()); return RT_FAILED; } + GELOGI("[TASK_INFO] %s", this->task_info_.c_str()); + return SUCCESS; +} + +void AiCpuCCTask::SetKernelArgs(void *args, size_t arg_size) { + args_ = args; + arg_size_ = arg_size; + // the blockdim value is defult "1" for rtCpuKernelLaunch + block_dim_ = 1; +} - GELOGD("Invoke rtKernelLaunch succeeded. task = %s", this->op_type_.c_str()); +void AiCpuCCTask::SetSoName(const std::string &so_name) { so_name_ = so_name; } + +void AiCpuCCTask::SetkernelName(const std::string &kernel_Name) { kernel_name_ = kernel_Name; } + +void AiCpuCCTask::SetIoAddr(void *io_addr) { io_addr_ = io_addr; } + +const void *AiCpuCCTask::GetIOAddr() const { return io_addr_; } + +const void *AiCpuCCTask::GetArgs() const { return args_; } + +size_t AiCpuCCTask::GetArgSize() const { return arg_size_; } + +AiCpuCCTask::~AiCpuCCTask() { + if (args_ != nullptr) { + free(args_); + args_ = nullptr; + } +} + +Status AiCpuCCTask::LaunchKernel(rtStream_t stream) { + GELOGI("To invoke rtCpuKernelLaunch. block_dim = %u, so_name is %s, kernel_name is %s", block_dim_, so_name_.data(), + kernel_name_.data()); + // sm_desc is nullptr, because l2 buffer does not support + auto *sm_desc = reinterpret_cast(sm_desc_); + auto ret = + rtCpuKernelLaunch(static_cast(so_name_.data()), static_cast(kernel_name_.data()), + block_dim_, args_, static_cast(arg_size_), sm_desc, stream); + if (ret != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "Invoke rtCpuKernelLaunch failed. ret = %d", ret); + return RT_FAILED; + } + GELOGD("Invoke rtCpuKernelLaunch succeeded"); return SUCCESS; } } // namespace ge diff --git a/src/ge/single_op/task/op_task.h b/src/ge/single_op/task/op_task.h index 168a71b3..3e261b3f 100644 --- a/src/ge/single_op/task/op_task.h +++ b/src/ge/single_op/task/op_task.h @@ -19,15 +19,18 @@ #include #include +#include #include "runtime/stream.h" #include "common/ge_inner_error_codes.h" #include "graph/op_kernel_bin.h" +#include "graph/node.h" namespace ge { enum OpTaskType { OP_TASK_TBE = 0, OP_TASK_AICPU, + OP_TASK_AICPUCC, OP_TASK_INVALID, }; @@ -36,7 +39,20 @@ class OpTask { OpTask() = default; virtual ~OpTask() = default; virtual Status LaunchKernel(rtStream_t stream) = 0; + virtual Status UpdateRunInfo(const vector &input_desc, const vector &output_desc) { + return UNSUPPORTED; + } + virtual Status LaunchKernel(const std::vector &inputs, const std::vector &outputs, + const std::vector &workspaces, rtStream_t stream) { + return UNSUPPORTED; + } virtual OpTaskType GetOpTaskType() = 0; + + const vector &GetWorkspaceSizes() const; + void SetWorkspaceSizes(const vector &workspace_sizes); + + private: + std::vector workspace_sizes_; }; class TbeOpTask : public OpTask { @@ -47,18 +63,33 @@ class TbeOpTask : public OpTask { void SetSmDesc(void *sm_desc); void SetStubFunc(const std::string &name, const void *stub_func); - void SetKernelArgs(void *args, size_t arg_size, uint32_t block_dim); + void SetKernelArgs(std::unique_ptr &&args, size_t arg_size, uint32_t block_dim); + + Status UpdateRunInfo(const vector &input_desc, const vector &output_desc) override; + + Status LaunchKernel(const vector &inputs, const vector &outputs, const vector &workspaces, + rtStream_t stream) override; + const void *GetArgs() const; size_t GetArgSize() const; const std::string &GetStubName() const; + void EnableDynamicSupport(const NodePtr &node, void *tiling_buffer, size_t max_tiling_size); private: + static Status UpdateTensorDesc(const GeTensorDesc &src_tensor, GeTensorDesc &dst_tensor); + Status UpdateNodeByShape(const vector &input_desc, const vector &output_desc); + const void *stub_func_ = nullptr; - void *args_ = nullptr; + std::unique_ptr args_; size_t arg_size_ = 0; uint32_t block_dim_ = 1; void *sm_desc_ = nullptr; std::string stub_name_; + + void *tiling_buffer_ = nullptr; + uint32_t max_tiling_size_ = 0; + std::string tiling_data_; + NodePtr node_; }; class AiCpuTask : public OpTask { @@ -79,6 +110,34 @@ class AiCpuTask : public OpTask { std::string op_type_; void *io_addr_ = nullptr; }; + +class AiCpuCCTask : public OpTask { + public: + AiCpuCCTask() = default; + ~AiCpuCCTask() override; + AiCpuCCTask(const AiCpuCCTask &) = delete; + AiCpuCCTask &operator=(const AiCpuCCTask &) = delete; + + Status LaunchKernel(rtStream_t stream) override; + OpTaskType GetOpTaskType() override { return OP_TASK_AICPUCC; } + const void *GetIOAddr() const; + const void *GetArgs() const; + void SetKernelArgs(void *args, size_t arg_size); + void SetSoName(const std::string &so_name); + void SetkernelName(const std::string &kernel_Name); + void SetIoAddr(void *io_addr); + size_t GetArgSize() const; + + private: + friend class AiCpuCCTaskBuilder; + std::string so_name_; + std::string kernel_name_; + void *args_ = nullptr; + size_t arg_size_ = 0; + uint32_t block_dim_ = 1; + void *sm_desc_ = nullptr; + void *io_addr_ = nullptr; +}; } // namespace ge #endif // GE_SINGLE_OP_TASK_OP_TASK_H_ diff --git a/src/ge/single_op/task/tbe_task_builder.cc b/src/ge/single_op/task/tbe_task_builder.cc index c0f6877f..23c023fd 100644 --- a/src/ge/single_op/task/tbe_task_builder.cc +++ b/src/ge/single_op/task/tbe_task_builder.cc @@ -17,20 +17,18 @@ #include "single_op/task/tbe_task_builder.h" #include -#include #include -#include "common/helper/model_helper.h" -#include "framework/common/debug/ge_log.h" #include "graph/load/new_model_manager/model_utils.h" #include "graph/debug/ge_attr_define.h" -#include "graph/load/new_model_manager/task_info/task_info.h" #include "graph/manager/graph_var_manager.h" #include "runtime/rt.h" #include "single_op/task/build_task_utils.h" namespace ge { namespace { +constexpr char const *kAttrSupportDynamicShape = "support_dynamicshape"; +constexpr char const *kAttrOpParamSize = "op_para_size"; std::mutex g_reg_mutex; inline void GetKernelName(const OpDescPtr &op_desc, std::string &kernel_name) { @@ -85,9 +83,11 @@ bool KernelBinRegistry::AddKernel(const std::string &stub_name, const KernelHold return ret.second; } -TbeTaskBuilder::TbeTaskBuilder(const std::string &model_name, const OpDescPtr &op_desc, - const domi::KernelDef &kernel_def) - : op_desc_(op_desc), kernel_def_(kernel_def), stub_name_(model_name + "/" + op_desc->GetName() + "_tvmbin") {} +TbeTaskBuilder::TbeTaskBuilder(const std::string &model_name, const NodePtr &node, const domi::KernelDef &kernel_def) + : node_(node), + op_desc_(node->GetOpDesc()), + kernel_def_(kernel_def), + stub_name_(model_name + "/" + node->GetName() + "_tvmbin") {} Status TbeTaskBuilder::DoRegisterBinary(const OpKernelBin &kernel_bin, void **bin_handle, const SingleOpModelParam ¶m) const { @@ -246,17 +246,11 @@ Status TbeTaskBuilder::GetSmDesc(void **sm_desc, const SingleOpModelParam ¶m } Status TbeTaskBuilder::SetKernelArgs(TbeOpTask &task, const SingleOpModelParam ¶m) { - uint8_t *args = nullptr; size_t arg_size = kernel_def_.args_size(); - auto rtRet = rtMallocHost(reinterpret_cast(&args), arg_size); - if (rtRet != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "rtMallocHost failed, size = %zu, ret = %d", arg_size, static_cast(rtRet)); - return RT_FAILED; - } - - task.SetKernelArgs(args, arg_size, kernel_def_.block_dim()); + auto args = std::unique_ptr(new (std::nothrow) uint8_t[arg_size]); + GE_CHECK_NOTNULL(args); - rtRet = rtMemcpy(args, arg_size, kernel_def_.args().data(), arg_size, RT_MEMCPY_HOST_TO_HOST); + auto rtRet = rtMemcpy(args.get(), arg_size, kernel_def_.args().data(), arg_size, RT_MEMCPY_HOST_TO_HOST); if (rtRet != RT_ERROR_NONE) { GELOGE(RT_FAILED, "rtMemcpy args failed, size = %zu, ret = %d", arg_size, static_cast(rtRet)); return RT_FAILED; @@ -266,16 +260,23 @@ Status TbeTaskBuilder::SetKernelArgs(TbeOpTask &task, const SingleOpModelParam & const auto *args_offset_tmp = reinterpret_cast(context.args_offset().data()); uint16_t offset = *args_offset_tmp; - // copy args - std::vector tensor_device_addr_vec = BuildTaskUtils::GetKernelArgs(op_desc_, param); - void *src_addr = reinterpret_cast(tensor_device_addr_vec.data()); - uint64_t src_len = sizeof(void *) * tensor_device_addr_vec.size(); - rtRet = rtMemcpy(args + offset, arg_size - offset, src_addr, src_len, RT_MEMCPY_HOST_TO_HOST); - if (rtRet != RT_ERROR_NONE) { - GELOGE(RT_FAILED, "rtMemcpy addresses failed, ret = %d", static_cast(rtRet)); - return RT_FAILED; + bool is_dynamic = false; + (void)AttrUtils::GetBool(op_desc_, kAttrSupportDynamicShape, is_dynamic); + if (is_dynamic) { + GE_CHK_STATUS_RET_NOLOG(InitTilingInfo(task)); + } else { + // copy args + std::vector tensor_device_addr_vec = BuildTaskUtils::GetKernelArgs(op_desc_, param); + void *src_addr = reinterpret_cast(tensor_device_addr_vec.data()); + uint64_t src_len = sizeof(void *) * tensor_device_addr_vec.size(); + rtRet = rtMemcpy(args.get() + offset, arg_size - offset, src_addr, src_len, RT_MEMCPY_HOST_TO_HOST); + if (rtRet != RT_ERROR_NONE) { + GELOGE(RT_FAILED, "rtMemcpy addresses failed, ret = %d", static_cast(rtRet)); + return RT_FAILED; + } } + task.SetKernelArgs(std::move(args), arg_size, kernel_def_.block_dim()); return SUCCESS; } @@ -290,6 +291,8 @@ Status TbeTaskBuilder::BuildTask(TbeOpTask &task, const SingleOpModelParam ¶ if (ret != SUCCESS) { return ret; } + auto task_info = BuildTaskUtils::GetTaskInfo(op_desc_); + GELOGI("[TASK_INFO] %s %s", stub_name_.c_str(), task_info.c_str()); void *stub_func = nullptr; auto rtRet = rtGetFunctionByName(stub_name_.c_str(), &stub_func); @@ -301,4 +304,23 @@ Status TbeTaskBuilder::BuildTask(TbeOpTask &task, const SingleOpModelParam ¶ task.SetStubFunc(stub_name_, stub_func); return SUCCESS; } + +Status TbeTaskBuilder::InitTilingInfo(TbeOpTask &task) { + GELOGD("Start alloc tiling data of node %s.", op_desc_->GetName().c_str()); + int64_t max_size = -1; + (void)AttrUtils::GetInt(op_desc_, kAttrOpParamSize, max_size); + GELOGD("Got op param size by key: %s, ret = %ld", kAttrOpParamSize, max_size); + if (max_size <= 0) { + GELOGE(PARAM_INVALID, "[%s] Invalid op_param_size: %ld.", op_desc_->GetName().c_str(), max_size); + return PARAM_INVALID; + } + + void *tiling_buffer = nullptr; + GE_CHK_RT_RET(rtMalloc(&tiling_buffer, static_cast(max_size), RT_MEMORY_HBM)); + GE_CHECK_NOTNULL(tiling_buffer); + GELOGD("[%s] Done allocating tiling buffer, size=%ld.", op_desc_->GetName().c_str(), max_size); + + task.EnableDynamicSupport(node_, tiling_buffer, static_cast(max_size)); + return SUCCESS; +} } // namespace ge diff --git a/src/ge/single_op/task/tbe_task_builder.h b/src/ge/single_op/task/tbe_task_builder.h index 5e0965bf..7c5f8054 100644 --- a/src/ge/single_op/task/tbe_task_builder.h +++ b/src/ge/single_op/task/tbe_task_builder.h @@ -65,12 +65,13 @@ class KernelBinRegistry { class TbeTaskBuilder { public: - TbeTaskBuilder(const std::string &model_name, const OpDescPtr &op_desc, const domi::KernelDef &kernel_def); + TbeTaskBuilder(const std::string &model_name, const NodePtr &node, const domi::KernelDef &kernel_def); ~TbeTaskBuilder() = default; Status BuildTask(TbeOpTask &task, const SingleOpModelParam ¶m); private: + Status InitTilingInfo(TbeOpTask &task); Status SetKernelArgs(TbeOpTask &task, const SingleOpModelParam ¶m); Status GetSmDesc(void **sm_desc, const SingleOpModelParam ¶m) const; @@ -82,7 +83,8 @@ class TbeTaskBuilder { static Status DoRegisterFunction(void *bin_handle, const char *stub_name, const char *kernel_name); - const OpDescPtr &op_desc_; + const NodePtr node_; + const OpDescPtr op_desc_; const domi::KernelDef &kernel_def_; const std::string stub_name_; }; diff --git a/src/ge/stub/Makefile b/src/ge/stub/Makefile deleted file mode 100644 index a0b35b42..00000000 --- a/src/ge/stub/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -inc_path := $(shell pwd)/inc/external/ -out_path := $(shell pwd)/out/atc/lib64/stub/ -stub_path := $(shell pwd)/framework/domi/stub/ - -mkdir_stub := $(shell mkdir -p $(out_path)) -local_stub := $(shell $(HI_PYTHON) $(stub_path)/gen_stubapi.py $(inc_path) $(out_path)) diff --git a/src/ge/stub/README b/src/ge/stub/README deleted file mode 100644 index ca98ce85..00000000 --- a/src/ge/stub/README +++ /dev/null @@ -1,4 +0,0 @@ -################################################################################### -the directory (stub) saves the stub file -gen_stubapi.py is using for retrieving API and generating stub functions -################################################################################### diff --git a/src/ge/stub/gen_stubapi.py b/src/ge/stub/gen_stubapi.py deleted file mode 100644 index 6185c479..00000000 --- a/src/ge/stub/gen_stubapi.py +++ /dev/null @@ -1,573 +0,0 @@ -import os -import re -import sys -import logging - -logging.basicConfig(stream=sys.stdout, format='[%(asctime)s] [%(lineno)s] %(levelname)s: %(message)s', - level=logging.INFO) - -""" - this attr is used for symbol table visible -""" -GE_ATTR = 'GE_FUNC_DEV_VISIBILITY GE_FUNC_HOST_VISIBILITY' - -""" - generate stub func body by return type -""" -RETURN_STATEMENTS = { - 'graphStatus': ' return GRAPH_SUCCESS;', - 'Status': ' return SUCCESS;', - 'Graph': ' return Graph();', - 'Graph&': ' return *this;', - 'Format': ' return Format();', - 'Format&': ' return *this;', - 'Shape': ' return Shape();', - 'Shape&': ' return *this;', - 'TensorDesc': ' return TensorDesc();', - 'TensorDesc&': ' return *this;', - 'Tensor': ' return Tensor();', - 'Tensor&': ' return *this;', - 'Operator': ' return Operator();', - 'Operator&': ' return *this;', - 'Ptr': ' return nullptr;', - 'std::string': ' return "";', - 'std::string&': ' return "";', - 'string': ' return "";', - 'int': ' return 0;', - 'DataType': ' return DT_FLOAT;', - 'InferenceContextPtr': ' return nullptr;', - 'SubgraphBuilder': ' return nullptr;', - 'OperatorImplPtr': ' return nullptr;', - 'OutHandler': ' return nullptr;', - 'std::vector': ' return {};', - 'std::vector': ' return {};', - 'std::map': ' return {};', - 'uint32_t': ' return 0;', - 'int64_t': ' return 0;', - 'uint64_t': ' return 0;', - 'size_t': ' return 0;', - 'float': ' return 0.0f;', - 'bool': ' return false;', -} - -""" - max code len per line in hua_wei software programming specifications -""" -max_code_len_per_line = 100 - -""" - white_list_for_debug, include_dir_key_words is to - determines which header files to generate cc files from - when DEBUG on -""" -white_list_for_debug = ["operator.h", "tensor.h", - "graph.h", "operator_factory.h", - "ge_ir_build.h"] -include_dir_key_words = ["ge", "graph"] -DEBUG = True - - -def need_generate_func(func_line): - """ - :param func_line: - :return: - """ - if func_line.strip().endswith("default") or func_line.strip().endswith("delete") \ - or func_line.strip().startswith("typedef") or func_line.strip().startswith("using"): - return False - return True - - -def file_endswith_white_list_suffix(file): - """ - :param file: - :return: - """ - if DEBUG: - for suffix in white_list_for_debug: - if file.endswith(suffix): - return True - return False - else: - return True - - -""" - belows are patterns used for analyse .h file -""" -# pattern function -pattern_func = re.compile(r"""(^[\s]*) #leading with space,we will find and delete after -([a-zA-Z~_] # void int likely -.* -[)] #we find ) -(?!.*{) # we do not want the case int abc() const { return 1;} -.*) -(;.*) #we want to find ; and after for we will replace these later -\n$ -""", re.VERBOSE | re.MULTILINE | re.DOTALL) - -# pattern comment -pattern_comment = re.compile(r'^\s*//') -pattern_comment_2_start = re.compile(r'^\s*/[*]') -pattern_comment_2_end = re.compile(r'[*]/\s*$') -# pattern define -pattern_define = re.compile(r'^\s*#define') -pattern_define_return = re.compile(r'\\\s*$') -# blank line -pattern_blank_line = re.compile(r'^\s*$') -# virtual,explicit,friend,static -pattern_keyword = re.compile(r'(virtual\s+|explicit\s+|friend\s+|static\s+)') -# lead space -pattern_leading_space = re.compile(r'(^[\s]*)[a-zA-Z~_]') -# functions will have patterns such as func ( or func( -# but operator is an exception; the class name is preceded by an operator, and the above mode does not exist -# format like :"operator = ()" -pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*|operator?.*)[(]') -# template -pattern_template = re.compile(r'^\s*template') -pattern_template_end = re.compile(r'>\s*$') -# namespace -pattern_namespace = re.compile(r'namespace.*{') -# class : which can handle classA a and {not on the same line, but if found ';' after class,then don't deal with -pattern_class = re.compile(r'^[\s]*(class|struct)\s+(%s\s+)?([a-zA-Z0-9_\-]+ 0 and not friend_match: - line, func_name = self.handle_class_member_func(line, template_string) - # Normal functions - else: - line, func_name = self.handle_normal_func(line, template_string) - - need_generate = need_generate_func(line) - # func body - line += self.implement_function(line) - # comment - line = self.gen_comment(start_i) + line - # write to out file - self.write_func_content(line, func_name, need_generate) - # next loop - self.line_index += 1 - - logging.info('Added %s functions', len(self.func_list_exist)) - logging.info('Successfully converted,please see ' + self.output_file) - - def handle_func1(self, line): - """ - :param line: - :return: - """ - find1 = re.search('[(]', line) - if not find1: - self.line_index += 1 - return "continue", line, None - find2 = re.search('[)]', line) - start_i = self.line_index - space_match = pattern_leading_space.search(line) - # deal with - # int abc(int a, - # int b) - if find1 and (not find2): - self.line_index += 1 - line2 = self.input_content[self.line_index] - if space_match: - line2 = re.sub('^' + space_match.group(1), '', line2) - line += line2 - while self.line_index < len(self.input_content) and (not re.search('[)]', line2)): - self.line_index += 1 - line2 = self.input_content[self.line_index] - line2 = re.sub('^' + space_match.group(1), '', line2) - line += line2 - - match_start = pattern_start.search(self.input_content[self.line_index]) - match_end = pattern_end.search(self.input_content[self.line_index]) - if match_start: # like ) { or ) {} int the last line - if not match_end: - self.stack.append('normal_now') - ii = start_i - while ii <= self.line_index: - ii += 1 - self.line_index += 1 - return "continue", line, start_i - logging.info("line[%s]", line) - # ' int abc();'->'int abc()' - (line, match) = pattern_func.subn(r'\2\n', line) - logging.info("line[%s]", line) - # deal with case: - # 'int \n abc(int a, int b)' - if re.search(r'^\s*(inline)?\s*[a-zA-Z0-9_]+\s*$', self.input_content[start_i - 1]): - line = self.input_content[start_i - 1] + line - line = line.lstrip() - if not match: - self.line_index += 1 - return "continue", line, start_i - return "pass", line, start_i - - def handle_stack(self, match_start): - """ - :param match_start: - :return: - """ - line = self.input_content[self.line_index] - match_end = pattern_end.search(line) - if match_start: - self.stack.append('normal_now') - if match_end: - top_status = self.stack.pop() - if top_status == 'namespace_now': - self.output_fd.write(line + '\n') - elif top_status == 'class_now': - self.stack_class.pop() - self.stack_template.pop() - if match_start or match_end: - self.line_index += 1 - return "continue" - - if len(self.stack) > 0 and self.stack[-1] == 'normal_now': - self.line_index += 1 - return "continue" - return "pass" - - def handle_class(self, template_string, line, match_start, match_class): - """ - :param template_string: - :param line: - :param match_start: - :param match_class: - :return: - """ - if match_class: # we face a class - self.stack_template.append(template_string) - self.stack.append('class_now') - class_name = match_class.group(3) - - # class template specializations: class A > - if '<' in class_name: - k = line.index('<') - fit = 1 - for ii in range(k + 1, len(line)): - if line[ii] == '<': - fit += 1 - if line[ii] == '>': - fit -= 1 - if fit == 0: - break - class_name += line[k + 1:ii + 1] - logging.info('class_name[%s]', class_name) - self.stack_class.append(class_name) - while not match_start: - self.line_index += 1 - line = self.input_content[self.line_index] - match_start = pattern_start.search(line) - self.line_index += 1 - return "continue" - return "pass" - - def handle_template(self): - line = self.input_content[self.line_index] - match_template = pattern_template.search(line) - template_string = '' - if match_template: - match_template_end = pattern_template_end.search(line) - template_string = line - while not match_template_end: - self.line_index += 1 - line = self.input_content[self.line_index] - template_string += line - match_template_end = pattern_template_end.search(line) - self.line_index += 1 - return template_string - - def handle_namespace(self): - line = self.input_content[self.line_index] - match_namespace = pattern_namespace.search(line) - if match_namespace: # we face namespace - self.output_fd.write(line + '\n') - self.stack.append('namespace_now') - self.line_index += 1 - - def handle_normal_func(self, line, template_string): - template_line = '' - self.stack_template.append(template_string) - if self.stack_template[-1] != '': - template_line = re.sub(r'\s*template', 'template', self.stack_template[-1]) - # change '< class T = a, class U = A(3)>' to '' - template_line = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_line) - template_line = re.sub(r'\s*=.*,', ',', template_line) - template_line = re.sub(r'\s*=.*', '', template_line) - line = re.sub(r'\s*=.*,', ',', line) - line = re.sub(r'\s*=.*\)', ')', line) - line = template_line + line - self.stack_template.pop() - func_name = re.search(r'^.*\)', line, re.MULTILINE | re.DOTALL).group() - logging.info("line[%s]", line) - logging.info("func_name[%s]", func_name) - return line, func_name - - def handle_class_member_func(self, line, template_string): - template_line = '' - x = '' - if template_string != '': - template_string = re.sub(r'\s*template', 'template', template_string) - template_string = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_string) - template_string = re.sub(r'\s*=.*,', ',', template_string) - template_string = re.sub(r'\s*=.*', '', template_string) - if self.stack_template[-1] != '': - if not (re.search(r'<\s*>', stack_template[-1])): - template_line = re.sub(r'^\s*template', 'template', stack_template[-1]) - if not (re.search(r'<.*>', self.stack_class[-1])): - # for x we get like template -> - x = re.sub(r'template\s*<', '<', template_line) # remove template -> - x = re.sub(r'\n', '', x) - x = re.sub(r'\s*=.*,', ',', x) - x = re.sub(r'\s*=.*\>', '>', x) - x = x.rstrip() # remove \n - x = re.sub(r'(class|typename)\s+|(|\s*class)', '', - x) # remove class,typename -> - x = re.sub(r'<\s+', '<', x) - x = re.sub(r'\s+>', '>', x) - x = re.sub(r'\s+,', ',', x) - x = re.sub(r',\s+', ', ', x) - line = re.sub(r'\s*=\s+0', '', line) - line = re.sub(r'\s*=\s+.*,', ',', line) - line = re.sub(r'\s*=\s+.*\)', ')', line) - logging.info("x[%s]\nline[%s]", x, line) - # if the function is long, void ABC::foo() - # breaks into two lines void ABC::\n foo() - temp_line = pattern_func_name.sub(self.stack_class[-1] + x + '::' + r'\1(', line, count=1) - if len(temp_line) > max_code_len_per_line: - line = pattern_func_name.sub(self.stack_class[-1] + x + '::\n' + r'\1(', line, count=1) - else: - line = temp_line - logging.info("line[%s]", line) - # add template as the above if there is one - template_line = re.sub(r'\s*=.*>(\s*)$', r'>\1', template_line) - template_line = re.sub(r'\s*=.*,', ',', template_line) - template_line = re.sub(r'\s*=.*', '', template_line) - line = template_line + template_string + line - func_name = re.search(r'^.*\)', line, re.MULTILINE | re.DOTALL).group() - logging.info("line[%s]", line) - logging.info("func_name[%s]", func_name) - return line, func_name - - def write_func_content(self, content, func_name, need_generate): - if not (func_name in self.func_list_exist) and need_generate: - self.output_fd.write(content) - self.func_list_exist.append(func_name) - logging.info('add func:[%s]', func_name) - - def gen_comment(self, start_i): - comment_line = '' - # Function comments are on top of function declarations, copy them over - k = start_i - 1 # one line before this func start - if pattern_template.search(self.input_content[k]): - k -= 1 - if pattern_comment_2_end.search(self.input_content[k]): - comment_line = self.input_content[k].lstrip() - while not pattern_comment_2_start.search(self.input_content[k]): - k -= 1 - comment_line = self.input_content[k].lstrip() + comment_line - else: - for j in range(k, 0, -1): - c_line = self.input_content[j] - if pattern_comment.search(c_line): - c_line = re.sub(r'\s*//', '//', c_line) - comment_line = c_line + comment_line - else: - break - return comment_line - - @staticmethod - def implement_function(func): - function_def = '' - function_def += '{\n' - - all_items = func.split() - start = 0 - return_type = all_items[start] - if return_type == "const": - start += 1 - return_type = all_items[start] - if return_type.startswith(('std::map', 'std::set', 'std::vector')): - return_type = "std::map" - if return_type.endswith('*') or (len(all_items) > start + 1 and all_items[start + 1].startswith('*')): - return_type = "Ptr" - if len(all_items) > start + 1 and all_items[start + 1].startswith('&'): - return_type += "&" - if RETURN_STATEMENTS.__contains__(return_type): - function_def += RETURN_STATEMENTS[return_type] - else: - logging.warning("Unhandled return type[%s]", return_type) - - function_def += '\n' - function_def += '}\n' - function_def += '\n' - return function_def - - -def collect_header_files(path): - """ - :param path: - :return: - """ - header_files = [] - shared_includes_content = [] - for root, dirs, files in os.walk(path): - files.sort() - for file in files: - if file.find("git") >= 0: - continue - if not file.endswith('.h'): - continue - file_path = os.path.join(root, file) - file_path = file_path.replace('\\', '/') - header_files.append(file_path) - include_str = '#include "{}"\n'.format(file_path[path.rindex('/') + 1:]) - shared_includes_content.append(include_str) - return header_files, shared_includes_content - - -def generate_stub_file(inc_dir, out_cc_dir): - """ - :param inc_dir: - :param out_cc_dir: - :return: - """ - target_header_files, shared_includes_content = collect_header_files(inc_dir) - for header_file in target_header_files: - if not file_endswith_white_list_suffix(header_file): - continue - cc_file = re.sub('.h*$', '.cc', header_file) - h_2_cc = H2CC(header_file, out_cc_dir + cc_file[cc_file.rindex('/') + 1:], shared_includes_content) - h_2_cc.h2cc() - - -def gen_code(inc_dir, out_cc_dir): - """ - :param inc_dir: - :param out_cc_dir: - :return: - """ - if not inc_dir.endswith('/'): - inc_dir += '/' - if not out_cc_dir.endswith('/'): - out_cc_dir += '/' - for include_dir_key_word in include_dir_key_words: - generate_stub_file(inc_dir + include_dir_key_word, out_cc_dir) - - -if __name__ == '__main__': - inc_dir = sys.argv[1] - out_cc_dir = sys.argv[2] - gen_code(inc_dir, out_cc_dir) diff --git a/tests/depends/cce/src/op_kernel_registry.cc b/tests/depends/cce/src/op_kernel_registry.cc index 9bb32a31..5ccd1391 100644 --- a/tests/depends/cce/src/op_kernel_registry.cc +++ b/tests/depends/cce/src/op_kernel_registry.cc @@ -1,19 +1,3 @@ -/** - * Copyright 2019 Huawei Technologies 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. - */ - #include "register/op_kernel_registry.h" namespace ge { diff --git a/tests/st/resnet50/common.cc b/tests/st/resnet50/common.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/graph/passes/flow_ctrl_pass_unittest.cc b/tests/ut/ge/graph/passes/flow_ctrl_pass_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/graph/passes/folding_kernel/expanddims_kernel_unittest.cc b/tests/ut/ge/graph/passes/folding_kernel/expanddims_kernel_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/graph/passes/merge_pass_unittest.cc b/tests/ut/ge/graph/passes/merge_pass_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/graph/passes/net_output_pass_unittest.cc b/tests/ut/ge/graph/passes/net_output_pass_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/graph/passes/snapshot_pass_unittest.cc b/tests/ut/ge/graph/passes/snapshot_pass_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/single_op/single_op_manager_unittest.cc b/tests/ut/ge/single_op/single_op_manager_unittest.cc old mode 100755 new mode 100644 diff --git a/tests/ut/ge/single_op/single_op_model_unittest.cc b/tests/ut/ge/single_op/single_op_model_unittest.cc old mode 100755 new mode 100644 diff --git a/third_party/fwkacllib/inc/cce/fwk_adpt_struct.h b/third_party/fwkacllib/inc/cce/fwk_adpt_struct.h index 35134faa..023812dd 100644 --- a/third_party/fwkacllib/inc/cce/fwk_adpt_struct.h +++ b/third_party/fwkacllib/inc/cce/fwk_adpt_struct.h @@ -37,6 +37,7 @@ enum FWKAdptAPIRetCode { FWK_ADPT_SESSION_NOT_EXIST = 10, // session id not exist FWK_ADPT_SESSION_ALREADY_EXIST = 11, // session id alread exist for create session FWK_ADPT_NATIVE_END_OF_SEQUENCE = 12, // end of sequence + FWK_ADPT_EXTEND_TYPE_NOT_EXIST = 13, // extend info type not exist FWK_ADPT_UNKNOWN_ERROR = 99 // unknown error code }; @@ -55,9 +56,17 @@ enum FWKTaskExtInfoType { FWK_ADPT_EXT_SHAPE_TYPE = 0, FWK_ADPT_EXT_INPUT_SHAPE, FWK_ADPT_EXT_OUTPUT_SHAPE, + FWK_ADPT_EXT_UPDATE_ADDR, FWK_ADPT_EXT_INVALID }; +enum FWKExtUpdateAddrType { + FWK_ADPT_UPDATE_NULL = 0, + FWK_ADPT_UPDATE_INPUT, + FWK_ADPT_UPDATE_OUTPUT, + FWK_ADPT_UPDATE_INPUT_OUTPUT +}; + // API Parameter Structure struct StrFWKKernel { FWKOperateType opType; diff --git a/third_party/fwkacllib/inc/hccl/base.h b/third_party/fwkacllib/inc/hccl/base.h index 74163baf..1d83d7bf 100644 --- a/third_party/fwkacllib/inc/hccl/base.h +++ b/third_party/fwkacllib/inc/hccl/base.h @@ -102,6 +102,11 @@ typedef enum tagHcclDataType { HCCL_DATA_TYPE_RESERVED /**< reserved */ } hcclDataType_t; +constexpr u32 HCCL_UNIQUE_ID_BYTES = 2060; // 2060: unique id length +using hcclUniqueId = struct hcclUniqueIdDef { + char internal[HCCL_UNIQUE_ID_BYTES]; +}; + const u32 HCCL_MAX_SEGMENT_NUM = 8; // The max number of gradient segments. /** @@ -120,6 +125,12 @@ enum GradSplitForceMode { FORCE_RESERVED /**< reserved */ }; +enum OriginalGraphShapeType { + KNOWN_SHAPE, + UNKNOWN_SHAPE, + SHAPE_RESERVED /**< reserved */ +}; + /** * @brief stream handle. */ diff --git a/third_party/fwkacllib/inc/hccl/hcom.h b/third_party/fwkacllib/inc/hccl/hcom.h index a448d411..19bf4fb3 100644 --- a/third_party/fwkacllib/inc/hccl/hcom.h +++ b/third_party/fwkacllib/inc/hccl/hcom.h @@ -22,7 +22,6 @@ #ifndef HCOM_H_ #define HCOM_H_ -#include #include #ifdef __cplusplus @@ -246,8 +245,9 @@ hcclResult_t hcom_receive(const char *tag, void *outputPtr, u64 count, hcclDataT * @param segmentIdx A list identifying the index of end gradient in each segment. * @return hcclResult_t */ -hcclResult_t hcom_get_split_strategy(const char *group, const struct model_feature *feature, - u32 maxSegmentNum, u32 *segmentNum, u32 *segmentIdx, GradSplitForceMode force = FORCE_NONE); +hcclResult_t hcom_get_split_strategy(const char *group, const struct model_feature *feature, u32 maxSegmentNum, + u32 *segmentNum, u32 *segmentIdx, GradSplitForceMode force = FORCE_NONE, + OriginalGraphShapeType shapeType = KNOWN_SHAPE); /** * @brief Set the gradient split strategy with in the group, according to gradient index. diff --git a/third_party/fwkacllib/inc/mmpa/mmpa_api.h b/third_party/fwkacllib/inc/mmpa/mmpa_api.h index f1e30538..ce1c9720 100644 --- a/third_party/fwkacllib/inc/mmpa/mmpa_api.h +++ b/third_party/fwkacllib/inc/mmpa/mmpa_api.h @@ -20,7 +20,7 @@ #define LINUX 0 #define WIN 1 -#if(OS_TYPE == LINUX) +#if(OS_TYPE == LINUX) //lint !e553 #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -84,7 +84,7 @@ #endif -#if(OS_TYPE == WIN) +#if(OS_TYPE == WIN) //lint !e553 #include #include #include "Windows.h" diff --git a/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_linux.h b/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_linux.h index ce83d143..6ac8f8f6 100644 --- a/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_linux.h +++ b/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_linux.h @@ -344,6 +344,8 @@ extern INT32 mmRealPath(const CHAR *path, CHAR *realPath, INT32 realPathLen); extern INT32 mmDup2(INT32 oldFd, INT32 newFd); +extern INT32 mmDup(INT32 fd); + extern INT32 mmUnlink(const CHAR *filename); extern INT32 mmChmod(const CHAR *filename, INT32 mode); diff --git a/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_win.h b/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_win.h index ef15f371..68a70c27 100644 --- a/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_win.h +++ b/third_party/fwkacllib/inc/mmpa/sub_inc/mmpa_win.h @@ -378,6 +378,7 @@ _declspec(dllexport) INT32 mmGetRealPath(CHAR *path, CHAR *realPath); _declspec(dllexport) INT32 mmRealPath(const CHAR *path, CHAR *realPath, INT32 realPathLen); _declspec(dllexport) INT32 mmDup2(INT32 oldFd, INT32 newFd); +_declspec(dllexport) INT32 mmDup(INT32 fd); _declspec(dllexport) INT32 mmUnlink(const CHAR *filename); _declspec(dllexport) INT32 mmChmod(const CHAR *filename, INT32 mode); _declspec(dllexport) INT32 mmFileno(FILE *stream); diff --git a/third_party/fwkacllib/inc/ops/all_ops.h b/third_party/fwkacllib/inc/ops/all_ops.h index 031e955c..c30bf32b 100644 --- a/third_party/fwkacllib/inc/ops/all_ops.h +++ b/third_party/fwkacllib/inc/ops/all_ops.h @@ -31,7 +31,9 @@ #include "functional_ops.h" #include "get_data_ops.h" #include "hcom_ops.h" +#include "hvd_ops.h" #include "image_ops.h" +#include "internal_ops.h" #include "linalg_ops.h" #include "logging_ops.h" #include "lookup_ops.h" diff --git a/third_party/fwkacllib/inc/ops/array_ops.h b/third_party/fwkacllib/inc/ops/array_ops.h index 0d2a05a3..7c6f9b2c 100644 --- a/third_party/fwkacllib/inc/ops/array_ops.h +++ b/third_party/fwkacllib/inc/ops/array_ops.h @@ -1084,6 +1084,43 @@ REG_OP(TransShape) .ATTR(outShape,ListInt ,{}) .OP_END_FACTORY_REG(TransShape); +/** +*@brief Computes the (possibly normalized) Levenshtein Edit Distance. + +*@par Inputs: +*@li hypothesis_indices: The indices of the hypothesis list SparseTensor.\n +This is an N x R int64 matrix. +*@li hypothesis_shape: The values of the hypothesis list SparseTensor.\n +This is an N-length vector. +*@li hypothesis_shape: The shape of the hypothesis list SparseTensor.\n +This is an R-length vector. +*@li truth_indices: The indices of the truth list SparseTensor.\n +This is an M x R int64 matrix. +*@li truth_shape: The values of the truth list SparseTensor.\n +This is an M-length vector. +*@li truth_shape: The shape of the truth list SparseTensor.\n +This is an R-length vector + +*@par Attributes: +*@li normalize: boolean (if true, edit distances are normalized by length of truth). + +*@par Outputs: +*@li output: A dense float tensor with rank R - 1. + +*@par Third-party framework compatibility +* Compatible with TensorFlow EditDistance operator. +*/ +REG_OP(EditDistance) + .INPUT(hypothesis_indices, TensorType({DT_INT64})) + .INPUT(hypothesis_values, TensorType::BasicType()) + .INPUT(hypothesis_shape, TensorType({DT_INT64})) + .INPUT(truth_indices, TensorType({DT_INT64})) + .INPUT(truth_values, TensorType::BasicType()) + .INPUT(truth_shape, TensorType({DT_INT64})) + .ATTR(normalize, Bool, true) + .OUTPUT(output, TensorType({DT_FLOAT})) + .OP_END_FACTORY_REG(EditDistance) + } // namespace ge #endif // GE_OP_ARRAY_OPS_H_ diff --git a/third_party/fwkacllib/inc/ops/ctc_ops.h b/third_party/fwkacllib/inc/ops/ctc_ops.h index 00485a14..74b797f3 100644 --- a/third_party/fwkacllib/inc/ops/ctc_ops.h +++ b/third_party/fwkacllib/inc/ops/ctc_ops.h @@ -50,7 +50,6 @@ If not specified, defaults to true *@par Third-party framework compatibility * Compatible with TensorFlow CTCLoss operator. */ - REG_OP(CTCLoss) .INPUT(inputs, TensorType({DT_FLOAT, DT_DOUBLE})) .INPUT(labels_indices, TensorType({DT_INT64})) @@ -63,6 +62,77 @@ REG_OP(CTCLoss) .ATTR(ignore_longer_outputs_than_inputs, Bool, false) .OP_END_FACTORY_REG(CTCLoss) +/** +*@brief Performs greedy decoding on the logits given in inputs. + +*@par Inputs: +*@li inputs: 3-D, shape: `(max_time x batch_size x num_classes)`, the logits. +*@li sequence_length: A vector containing sequence lengths, size `(batch_size)`. + +*@par Attributes: +*@li merge_repeated: If True, merge repeated classes in output. + +*@par Outputs: +*@li decoded_indices: Indices matrix, size `(total_decoded_outputs x 2)`,\n +of a `SparseTensor`. The rows store: [batch, time]. +*@li decoded_values: Values vector, size: `(total_decoded_outputs)`,\n +of a `SparseTensor`. The vector stores the decoded classes. +*@li decoded_shape: Shape vector, size `(2)`, of the decoded SparseTensor.\n +Values are: `[batch_size, max_decoded_length]`. +*@li log_probability: Matrix, size `(batch_size x 1)`, containing sequence\n +log-probabilities. + +*@par Third-party framework compatibility +* Compatible with TensorFlow CTCGreedyDecoder operator. +*/ +REG_OP(CTCGreedyDecoder) + .INPUT(inputs, TensorType({DT_FLOAT, DT_DOUBLE})) + .INPUT(sequence_length, TensorType({DT_INT32})) + .ATTR(merge_repeated, Bool, false) + .OUTPUT(decoded_indices, TensorType({DT_INT64})) + .OUTPUT(decoded_values, TensorType({DT_INT64})) + .OUTPUT(decoded_shape, TensorType({DT_INT64})) + .OUTPUT(log_probability, TensorType({DT_FLOAT, DT_DOUBLE})) + .OP_END_FACTORY_REG(CTCGreedyDecoder) + +/** +*@brief Performs beam search decoding on the logits given in input. + +*@par Inputs: +*@li inputs: 3-D, shape: `(max_time x batch_size x num_classes)`, the logits. +*@li sequence_length: A vector containing sequence lengths, size `(batch_size)`. + +*@par Attributes: +*@li merge_repeated: If True, merge repeated classes in output. + +*@par Outputs: +*@li decoded_indices: A list (length: top_paths) of indices matrices. Matrix j,\n +size `(total_decoded_outputs[j] x 2)`, has indices of a\n +`SparseTensor`. The rows store: [batch, time]. +*@li decoded_values: A list (length: top_paths) of values vectors. Vector j,\n +size `(length total_decoded_outputs[j])`, has the values of a\n +`SparseTensor`. The vector stores the decoded classes for beam j. +*@li decoded_shape: A list (length: top_paths) of shape vector. Vector j,\n +size `(2)`, stores the shape of the decoded `SparseTensor[j]`.\n +Its values are: `[batch_size, max_decoded_length[j]]`. +*@li log_probability: A matrix, shaped: `(batch_size x top_paths)`. The\n +sequence log-probabilities. + +*@par Third-party framework compatibility +* Compatible with TensorFlow CTCBeamSearchDecoder operator. +*/ +REG_OP(CTCBeamSearchDecoder) + .INPUT(inputs, TensorType({DT_FLOAT, DT_DOUBLE})) + .INPUT(sequence_length, TensorType({DT_INT32})) + .REQUIRED_ATTR(beam_width, Int) + .REQUIRED_ATTR(top_paths, Int) + .ATTR(merge_repeated, Bool, true) + .DYNAMIC_OUTPUT(decoded_indices, TensorType({DT_INT64})) + .DYNAMIC_OUTPUT(decoded_values, TensorType({DT_INT64})) + .DYNAMIC_OUTPUT(decoded_shape, TensorType({DT_INT64})) + .OUTPUT(log_probability, TensorType({DT_FLOAT, DT_DOUBLE})) + .OP_END_FACTORY_REG(CTCBeamSearchDecoder) + } // namespace ge #endif //GE_OP_CTC_OPS_H \ No newline at end of file diff --git a/third_party/fwkacllib/inc/ops/elewise_calculation_ops.h b/third_party/fwkacllib/inc/ops/elewise_calculation_ops.h index 04e1cea3..1022880f 100644 --- a/third_party/fwkacllib/inc/ops/elewise_calculation_ops.h +++ b/third_party/fwkacllib/inc/ops/elewise_calculation_ops.h @@ -483,9 +483,9 @@ REG_OP(Equal) *x: A Tensor. Must be one of the following types: float16, float32, double, complex64, complex128. *@par Attributes: -*@li base: An optional attribute of type float32, specifying the base gamma. Defaults to "-1". -*@li scale: An optional attribute of type float32, specifying the scale alpha. Defaults to "1". -*@li shift: An optional attribute of type float32, specifying the shift beta. Defaults to "0". +*@li base: An optional attribute of type float32, specifying the base gamma. Defaults to "-1.0". +*@li scale: An optional attribute of type float32, specifying the scale alpha. Defaults to "1.0". +*@li shift: An optional attribute of type float32, specifying the shift beta. Defaults to "0.0". *@par Outputs: *y: A Tensor of the same type as "x". @@ -1016,17 +1016,17 @@ REG_OP(BesselI1e) * y = log_base(shift + scale * x), with "base" > 0. * @par Inputs: -* @li x: A Tensor of type UnaryDataType. +* @li x: A Tensor of type complex64, complex128, float16, float32 or double. * @par Attributes: -* @li base: An optional float32, specifying the base "e". Defaults to "-1" +* @li base: An optional float32, specifying the base "e". Defaults to "-1.0" * @li scale: An optional float32, specifying the scale of input "x". Defaults -* to "1" -* @li shift: An optional float32, specifying the shift. Defaults to "0" +* to "1.0" +* @li shift: An optional float32, specifying the shift. Defaults to "0.0" * @par Outputs: -* y: A Tensor of type UnaryDataType. +* y: A Tensor has same type as "x". * @attention Constraints: * @li "base" is supposed to be greater than 0. Retaining the default @@ -1100,12 +1100,6 @@ REG_OP(SqrtGrad) .OUTPUT(z, TensorType(UnaryDataType)) .OP_END_FACTORY_REG(SqrtGrad) -REG_OP(Multiply) - .INPUT(x, TensorType({DT_FLOAT,DT_UINT8,DT_INT8,DT_UINT16,DT_INT16,DT_INT32,DT_INT64,DT_DOUBLE,DT_FLOAT16})) - .INPUT(y, TensorType({DT_FLOAT,DT_UINT8,DT_INT8,DT_UINT16,DT_INT16,DT_INT32,DT_INT64,DT_DOUBLE,DT_FLOAT16})) - .OUTPUT(z, TensorType({DT_FLOAT,DT_UINT8,DT_INT8,DT_UINT16,DT_INT16,DT_INT32,DT_INT64,DT_DOUBLE,DT_FLOAT16})) - .OP_END_FACTORY_REG(Multiply) - /** *@brief Returns x + y element-wise. *@par Inputs: @@ -2262,7 +2256,7 @@ REG_OP(ArgMinD) *dtype: The output type, either "int32" or "int64". Defaults to "int64". *@par Outputs: -*y: A multi-dimensional Tensor of type int32, specifying the index with the largest value. The dimension is one less than that of "x". +*y: A multi-dimensional Tensor of type int32 or int64, specifying the index with the largest value. The dimension is one less than that of "x". *@attention Constraints: *@li x: If there are multiple maximum values, the index of the first maximum value is used. @@ -2398,8 +2392,8 @@ REG_OP(ArgMinWithValue) *y: A Tensor. Has the same type and format as "x". *@par Attributes: -*@li N: A required attribute. the number of input x, max size is 32. -*@li model: An optional attribute. Defaults to "1". +*@li N: A required attribute. the number of input x, max size is 32. Type is int. +*@li model: An optional attribute. Type is int. Defaults to "1". * "0": product, "1": sum, "2": max. *@li coeff: A required attribute. Must met all of following rules: * size of "coeff" must be equal to len("x") or is null. @@ -2693,6 +2687,86 @@ REG_OP(AdamApplyOne) .OP_END_FACTORY_REG(AdamApplyOne) /** +*@brief A fusion operator for bert lamb. + +*@par Inputs: +*Eleven inputs, including: +* @li input0: A Tensor. Must be one of the following types: float16, float32. +* @li input1: A Tensor. Must be one of the following types: float16, float32. +* @li input2: A Tensor. Must be one of the following types: float16, float32. +* @li input3: A Tensor. Must be one of the following types: float16, float32. +* @li input4: A Tensor. Must be one of the following types: float16, float32. +* @li mul0_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul1_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul2_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul3_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul4_x: A Tensor. Must be one of the following types: float16, float32. +* @li add2_y: A Tensor. Must be one of the following types: float16, float32. + +*@par Outputs: +*Three outputs, including: +* @li output0: A Tensor. Must be one of the following types: float16, float32. +* @li output1: A Tensor. Must be one of the following types: float16, float32. +* @li output2: A Tensor. Must be one of the following types: float16, float32. + +*/ +REG_OP(AdamApplyOneWithDecayAssign) + .INPUT(input0, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input1, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input2, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input3, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input4, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul0_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul1_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul2_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul3_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul4_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(add2_y, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output0, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output1, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output2, TensorType({DT_FLOAT16,DT_FLOAT})) + .OP_END_FACTORY_REG(AdamApplyOneWithDecayAssign) + +/** +*@brief A fusion operator for bert lamb. + +*@par Inputs: +*Ten inputs, including: +* @li input0: A Tensor. Must be one of the following types: float16, float32. +* @li input1: A Tensor. Must be one of the following types: float16, float32. +* @li input2: A Tensor. Must be one of the following types: float16, float32. +* @li input3: A Tensor. Must be one of the following types: float16, float32. +* @li input4: A Tensor. Must be one of the following types: float16, float32. +* @li mul0_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul1_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul2_x: A Tensor. Must be one of the following types: float16, float32. +* @li mul3_x: A Tensor. Must be one of the following types: float16, float32. +* @li add2_y: A Tensor. Must be one of the following types: float16, float32. + +*@par Outputs: +*Three outputs, including: +* @li output0: A Tensor. Must be one of the following types: float16, float32. +* @li output1: A Tensor. Must be one of the following types: float16, float32. +* @li output2: A Tensor. Must be one of the following types: float16, float32. + +*/ +REG_OP(AdamApplyOneAssign) + .INPUT(input0, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input1, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input2, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input3, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(input4, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul0_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul1_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul2_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(mul3_x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(add2_y, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output0, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output1, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(output2, TensorType({DT_FLOAT16,DT_FLOAT})) + .OP_END_FACTORY_REG(AdamApplyOneAssign) + +/** *@brief Confuse select, maximum, greater and sqrt. *@par Inputs: @@ -2781,22 +2855,19 @@ REG_OP(SquareSumAll) *@brief Confuse broadcast, addn and mul. *@par Inputs: -*Five inputs, including: -* @li x1: A Tensor. Must be one of the following types:int32 float16, float32. +*Three inputs, including: +* @li x1: A Tensor. Must be one of the following types:int32, int16, float16, float32. * @li x2: A Tensor of the same type as "x1". * @li x3: A Tensor of the same type as "x1". *@par Outputs: -*@li y: A Tensor. Has the same type as "x1". - -*@par Third-party framework compatibility: -* Compatible with the TensorFlow operator LRN. +* y: A Tensor. Has the same type as "x1". */ REG_OP(FusedMulAddN) - .INPUT(x1, TensorType::NumberType()) - .INPUT(x2, TensorType::NumberType()) - .INPUT(x3, TensorType::NumberType()) - .OUTPUT(y, TensorType::NumberType()) + .INPUT(x1, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) + .INPUT(x2, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) + .INPUT(x3, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) + .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) .OP_END_FACTORY_REG(FusedMulAddN) /** @@ -3042,6 +3113,22 @@ REG_OP(KLDiv) .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) .OP_END_FACTORY_REG(KLDiv) +/** +*@brief copy data from x to y.. + +*@par Inputs: +*One inputs, including: +* @li x: A Tensor. Must be one of the following types: float16, float32, int8, uint8, int32, bool. + +*@par Outputs: +*y: A Tensor. Has the same type as "x". + +*@par Third-party framework compatibility +*/ +REG_OP(TensorMove) + .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT8, DT_UINT8, DT_BOOL})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT8, DT_UINT8, DT_BOOL})) + .OP_END_FACTORY_REG(TensorMove) } // namespace ge diff --git a/third_party/fwkacllib/inc/ops/hvd_ops.h b/third_party/fwkacllib/inc/ops/hvd_ops.h new file mode 100644 index 00000000..09748b8e --- /dev/null +++ b/third_party/fwkacllib/inc/ops/hvd_ops.h @@ -0,0 +1,77 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_OP_HVD_OPS_H_ +#define GE_OP_HVD_OPS_H_ + +#include "graph/operator_reg.h" + +namespace ge { +/** + * @brief Outputs a tensor gathering all input tensors. + * @par Inputs: + * x: A tensor. Must be one of the following types: uint8, int8, uint16, int16, int32, + * int64, float16, bool. + * @par Attributes: + * @li rank_size: A required integer identifying the number of ranks + * participating in the op. + * @par Outputs: + * y: A Tensor. Has the same type as "x". + */ +REG_OP(HorovodAllgather) + // GE not support float64 currently + .INPUT(x, TensorType({DT_UINT8, DT_INT8, DT_UINT16, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_BOOL})) + .OUTPUT(y, TensorType({DT_UINT8, DT_INT8, DT_UINT16, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_BOOL})) + // add rank_size attr + .REQUIRED_ATTR(rank_size, Int) + .OP_END_FACTORY_REG(HorovodAllgather) + +/** + * @brief Outputs a tensor containing the reduction across all input tensors + * passed to op. + * @par Inputs: + * x: A tensor. Must be one of the following types: int32, int64, float16, float32 + * @par Attributes: + * @li reduce_op: A required int identifying the reduction operation to + * perform.The supported operation are: "sum", "max", "min", "prod". + * @par Outputs: + * y: A Tensor. Has the same type as "x". + */ +REG_OP(HorovodAllreduce) + .INPUT(x, TensorType({DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT})) + .OUTPUT(y, TensorType({DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT})) + .REQUIRED_ATTR(reduce_op, Int) + .OP_END_FACTORY_REG(HorovodAllreduce) + +/** + * @brief Broadcasts the input tensor in root rank to all ranks. + * @par Inputs: + * x: A list of dynamic input tensor. Must be one of the following types: + * int8, int32, float16, float32. + * @par Attributes: + * @li root_rank: A required integer identifying the root rank in the op + * input of this rank will be broadcast to other ranks. + * @par Outputs: + * y: A list of dynamic output tensor. Has the same type and length as "x". + */ +REG_OP(HorovodBroadcast) + .INPUT(x, TensorType({DT_UINT8, DT_INT8, DT_UINT16, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_BOOL})) + .OUTPUT(y, TensorType({DT_UINT8, DT_INT8, DT_UINT16, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_BOOL})) + .REQUIRED_ATTR(root_rank, Int) + .OP_END_FACTORY_REG(HorovodBroadcast) + +} // namespace ge +#endif // GE_OP_HVD_OPS_H_ diff --git a/third_party/fwkacllib/inc/ops/image_ops.h b/third_party/fwkacllib/inc/ops/image_ops.h index f5ddaf5e..59b99841 100644 --- a/third_party/fwkacllib/inc/ops/image_ops.h +++ b/third_party/fwkacllib/inc/ops/image_ops.h @@ -991,6 +991,40 @@ REG_OP(ResizeBilinearV2D) .OP_END_FACTORY_REG(ResizeBilinearV2D) /** +*@brief Resizes "images" to "size" using bilinear interpolation and keep ration at the time. + +*@par Inputs: +* One input: +*images: An NC1HWC0 Tensor. \n +* Must be one of the following types: float16, float32. + +*@par Attributes: +*@li min_dimension: A required int32 attribute for the min dimension for the images. +* No default value. +*@li max_dimension: A required int32 attribute for the max dimension for the images. +* No default value. +*@li align_corners: An optional bool. If "true", the centers of the corner +* pixels of the input and output tensors are aligned. Defaults to "false". +*@li half_pixel_centers: indicates if the offset coordinates are normalized +* Defaults to "false". + +*@par Outputs: +*y: A Tensor with type float32 and the same format as input "images". + +*@attention Constraints: +* The input "images" must be a tensor of 5 elements: images[2] <= 2048, \n +images[3] <= 2048. +*/ +REG_OP(KeepRationResizeBilinear) + .INPUT(images, TensorType({DT_FLOAT16, DT_FLOAT})) + .OUTPUT(y, TensorType({DT_FLOAT})) + .REQUIRED_ATTR(min_dimension, Int) + .REQUIRED_ATTR(max_dimension, Int) + .ATTR(align_corners, Bool, false) + .ATTR(half_pixel_centers, Bool, false) + .OP_END_FACTORY_REG(KeepRationResizeBilinear) + +/** *@brief Resizes "images" to "size" using nearest neighbor interpolation. *@par Inputs: diff --git a/third_party/fwkacllib/inc/ops/internal_ops.h b/third_party/fwkacllib/inc/ops/internal_ops.h new file mode 100644 index 00000000..8c261382 --- /dev/null +++ b/third_party/fwkacllib/inc/ops/internal_ops.h @@ -0,0 +1,61 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef GE_OP_INTERNAL_OPS_H_ +#define GE_OP_INTERNAL_OPS_H_ + +#include "graph/operator_reg.h" +#include "graph/operator.h" + +namespace ge { + +/** +*@brief aicpu assit help op for auxiliary matrix generation. + +*@par Inputs: +*The input is dynamic for attribute func_name \n + +*@par Attributes: +*@li func_name:An required param, for example "topkv2". \n + +*@par Outputs: +*The output is dynamic for attribute func_name. +*/ +REG_OP(AssistHelp) + .DYNAMIC_INPUT(x, TensorType({ DT_FLOAT, DT_FLOAT16, DT_INT8, DT_INT16, DT_UINT16, + DT_UINT8, DT_INT32, DT_INT64, DT_UINT32, DT_UINT64, DT_BOOL, DT_DOUBLE })) + .DYNAMIC_OUTPUT(y, TensorType({ DT_FLOAT, DT_FLOAT16, DT_INT8, DT_INT16, DT_UINT16, + DT_UINT8, DT_INT32, DT_INT64, DT_UINT32, DT_UINT64, DT_BOOL, DT_DOUBLE})) + . REQUIRED_ATTR (func_name, String) + . OP_END_FACTORY_REG(AssistHelp) + +/** +*@brief aicpu cache help for lhisi cache flush. + +*@par Inputs: +*The input is dynamic for attribute func_name \n + +*@par Outputs: +*The output is dynamic for attribute func_name. +*/ +REG_OP(CacheUpdate) + .INPUT(x, TensorType::BasicType()) + .OUTPUT(x, TensorType::BasicType()) + .OP_END_FACTORY_REG(CacheUpdate) + +} // namespace ge + +#endif // GE_OP_INTERNAL_OPS_H_ diff --git a/third_party/fwkacllib/inc/ops/math_ops.h b/third_party/fwkacllib/inc/ops/math_ops.h index 5d34804c..b0c35c28 100644 --- a/third_party/fwkacllib/inc/ops/math_ops.h +++ b/third_party/fwkacllib/inc/ops/math_ops.h @@ -29,9 +29,9 @@ namespace ge { * x: A Tensor of type float16 or float32. *@par Attributes: -*@li power: Optional. Defaults to 1.0. -*@li scale: Optional. Defaults to 1.0. -*@li shift: Optional. Defaults to 0.0. +*@li power: Optional. Must be one of the following types: float32. Defaults to 1.0. +*@li scale: Optional. Must be one of the following types: float32. Defaults to 1.0. +*@li shift: Optional. Must be one of the following types: float32. Defaults to 0.0. *@par Outputs: * y: A Tensor. Has the same type and shape as "x". diff --git a/third_party/fwkacllib/inc/ops/matrix_calculation_ops.h b/third_party/fwkacllib/inc/ops/matrix_calculation_ops.h index 29cf0df3..7cb24ee7 100644 --- a/third_party/fwkacllib/inc/ops/matrix_calculation_ops.h +++ b/third_party/fwkacllib/inc/ops/matrix_calculation_ops.h @@ -167,50 +167,6 @@ REG_OP(BatchMatMul) .ATTR(adj_x2, Bool, false) .OP_END_FACTORY_REG(BatchMatMul) -REG_OP(MeanCCE) - .INPUT(x, TensorType::ALL()) - .INPUT(indices, TensorType::ALL()) - .OUTPUT(y, TensorType::ALL()) - .ATTR(keep_dims, Bool, false) - .ATTR(value1, ListInt, {}) - .ATTR(mode, Int, 3) // 0:max pooling or 1:avg pooling - .ATTR(pad_mode, Int, 0) - .ATTR(global_pooling, Bool, true) // tensorflow have no attr, set default value - .ATTR(window, ListInt, {1,1}) // kernel size - .ATTR(pad, ListInt, {0,0,0,0}) // pad size - .ATTR(stride, ListInt, {1,1}) // stride size - .ATTR(ceil_mode, Int, 0) - .ATTR(data_mode, Int, 1) - .ATTR(nan_opt, Int, 0) - .ATTR(fomart, Int, 0) - .OP_END_FACTORY_REG(MeanCCE) - -REG_OP(MeanGrad) - .INPUT(x, TensorType::ALL()) - .OUTPUT(y, TensorType::ALL()) - .ATTR(mode, Int, 1) // 0:max pooling or 1:avg pooling - .ATTR(pad_mode, Int, 0) - .ATTR(global_pooling, Bool, false) - .ATTR(window, ListInt, {1,1}) // kernel size - .ATTR(pad, ListInt, {0,0,0,0}) // pad size - .ATTR(stride, ListInt, {1,1}) // stride size - .ATTR(ceil_mode, Int, 0) - .ATTR(data_mode, Int, 1) - .ATTR(nan_opt, Int, 0) - .ATTR(mean_grad_output_shape_value, ListInt, {1,1,1,1}) - .ATTR(mean_grad_output_shape_format, Int, 1) //must be NHWC - .OP_END_FACTORY_REG(MeanGrad) - -REG_OP(MatMulCCE) - .INPUT(x1, TensorType({DT_FLOAT})) - .INPUT(x2, TensorType({DT_FLOAT})) - .OPTIONAL_INPUT(x3, TensorType({DT_FLOAT})) - .OUTPUT(y, TensorType({DT_FLOAT})) - .ATTR(transpose_a, Bool, false) - .ATTR(transpose_b, Bool, false) - .ATTR(has_bias, Bool, false) - .OP_END_FACTORY_REG(MatMulCCE) - /** *@brief Computes half the L2 norm of a tensor without the sqrt. @@ -673,8 +629,9 @@ REG_OP(DiagPart) *@par Attributes: *@li num_output: Reserved. -*@li transpose: A bool, specifying whether to transpose, either "true" or "false". Defaults to "false". -*@li axis: Optional. A int. 1 or 2. +*@li transpose: A bool, specifying weight whether to transpose, either "true" or "false". Defaults to "false". +*@li axis: Optional. A int, 1 or 2, specifying which dimension the input "K" starts from. Defaults to 1. + * The product of the subsequent dimensions starting form first dimension or the second dimension is "K". *@li offset_x: Reserved. *@par Outputs: @@ -699,6 +656,45 @@ REG_OP(FullyConnection) .OP_END_FACTORY_REG(FullyConnection) /** +*@brief Also known as a "fully-connected-compress" layer, computes an inner product with a set of learned weights, and (optionally) adds biases. + +*@par Inputs: +* Four inputs, including: +*@li x: A Tensor of type uint8, int8. +*@li w: A weight matrix of type int8, int8. +*@li w: A compress index matrix of type int8, int8. +*@li b: A Tensor of type float16, int32, int32. +*@li offset_w: A Tensor of type int8.i + +*@par Attributes: +*@li num_output: Reserved. +*@li transpose: A bool, specifying whether to transpose, either "true" or "false". Defaults to "false". +*@li axis: Reserved. +*@li offset_x: Reserved. + +*@par Outputs: +*y: The result tensor of type int32. + +*@par Third-party framework compatibility +* Compatible with the Caffe operator InnerProduct. + +*@par Quantization supported or not +* Yes +*/ +REG_OP(FullyConnectionCompress) + .INPUT(x, TensorType({DT_UINT8, DT_INT8})) + .INPUT(w, TensorType({DT_INT8})) + .INPUT(comress_index, TensorType({DT_INT8})) + .OPTIONAL_INPUT(b, TensorType({DT_INT32})) + .OPTIONAL_INPUT(offset_w, TensorType({DT_INT8})) + .OUTPUT(y, TensorType({DT_INT32})) + .REQUIRED_ATTR(num_output, Int) + .ATTR(transpose, Bool, false) + .ATTR(axis, Int, 1) + .ATTR(offset_x, Int, 0) + .OP_END_FACTORY_REG(FullyConnectionCompress) + +/** *@brief Computes the confusion matrix from predictions and labels. *@par Inputs: diff --git a/third_party/fwkacllib/inc/ops/nn_batch_norm_ops.h b/third_party/fwkacllib/inc/ops/nn_batch_norm_ops.h index e8eb4769..296dd63c 100644 --- a/third_party/fwkacllib/inc/ops/nn_batch_norm_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_batch_norm_ops.h @@ -22,95 +22,6 @@ namespace ge { /** -*@brief A fusion operator for batchnorm. - -*@par Inputs: -*Ten inputs, including: -* @li x: A Tensor. Must be one of the following types: float32. -* @li scale: A Tensor. Must be one of the following types: float32. -* @li b: A Tensor. Must be one of the following types: float32. -* @li mean: A Tensor. Must be one of the following types: float32. -* @li variance: A Tensor. Must be one of the following types: float32. - -*@par Attributes: -* @li mode: A Tensor. Must be one of the following types: int. -* @li epsilon: A Tensor. Must be one of the following types: float32. -* @li momentum: A Tensor. Must be one of the following types: float32. -* @li is_training: A Tensor. Must be one of the following types: bool. -* @li is_training_fusion: A Tensor. Must be one of the following types: bool. -* @li moving_average_fraction: A Tensor. Must be one of the following types: float32. - -*@par Outputs: -*Three outputs, including: -* @li y: A Tensor. Must be one of the following types: float32. -* @li running_mean: A Tensor. Must be one of the following types: float32. -* @li running_variance: A Tensor. Must be one of the following types: float32. -* @li save_mean: A Tensor. Must be one of the following types: float32. -* @li save_inv_variance: A Tensor. Must be one of the following types: float32. -* @li save_inv_variance1: A Tensor. Must be one of the following types: float32. - -*/ -REG_OP(FusedBatchNorm) - .INPUT(x, TensorType{DT_FLOAT}) - .INPUT(scale, TensorType{DT_FLOAT}) - .INPUT(b, TensorType{DT_FLOAT}) - .INPUT(mean, TensorType{DT_FLOAT}) - .INPUT(variance, TensorType{DT_FLOAT}) - .OUTPUT(y, TensorType{DT_FLOAT}) - .OUTPUT(running_mean, TensorType{DT_FLOAT}) - .OUTPUT(running_variance, TensorType{DT_FLOAT}) - .OUTPUT(save_mean, TensorType{DT_FLOAT}) - .OUTPUT(save_inv_variance, TensorType{DT_FLOAT}) - .OUTPUT(save_inv_variance1, TensorType{DT_FLOAT}) - .ATTR(mode, Int, 1) - .ATTR(epsilon, Float, 1e-5f) - .ATTR(momentum, Float, 0.9) - .ATTR(is_training, Bool, true) - .ATTR(is_training_fusion, Bool, true) - .ATTR(moving_average_fraction, Float, 0.00300002098) - .OP_END_FACTORY_REG(FusedBatchNorm) - -/** -*@brief A fusion operator for batchnorm. - -*@par Inputs: -*Ten inputs, including: -* @li dy: A Tensor. Must be one of the following types: float32. -* @li x: A Tensor. Must be one of the following types: float32. -* @li scale: A Tensor. Must be one of the following types: float32. -* @li save_mean: A Tensor. Must be one of the following types: float32. -* @li save_inv_variance: A Tensor. Must be one of the following types: float32. -* @li save_inv_variance1: A Tensor. Must be one of the following types: float32. - -*@par Attributes: -* @li epsilon: A Tensor. Must be one of the following types: float32. -* @li momentum: A Tensor. Must be one of the following types: float32. - -*@par Outputs: -*Three outputs, including: -* @li dx: A Tensor. Must be one of the following types: float32. -* @li bn_scale: A Tensor. Must be one of the following types: float32. -* @li bn_bias: A Tensor. Must be one of the following types: float32. - -*@par Third-party framework compatibility -* Compatible with the L2 scenario of PyTorch operator Normalize. -*/ - -REG_OP(FusedBatchNormGrad) - .INPUT(dy, TensorType{DT_FLOAT}) - .INPUT(x, TensorType{DT_FLOAT}) - .INPUT(scale, TensorType{DT_FLOAT}) - .INPUT(save_mean, TensorType{DT_FLOAT}) - .INPUT(save_inv_variance, TensorType{DT_FLOAT}) - .INPUT(save_inv_variance1, TensorType{DT_FLOAT}) - .OUTPUT(dx, TensorType{DT_FLOAT}) - .OUTPUT(bn_scale, TensorType{DT_FLOAT}) - .OUTPUT(bn_bias, TensorType{DT_FLOAT}) - .ATTR(epsilon, Float, 0.0) - .ATTR(momentum, Float, 0.0) - .OP_END_FACTORY_REG(FusedBatchNormGrad) - -/** *@brief Normalizes elements of a specific dimension of eigenvalues (L2). *@par Inputs: @@ -361,14 +272,14 @@ REG_OP(BatchNormGradExt2) *@par Inputs: *@li x: A 4D or 5D Tensor of type float16 or float32, with format NHWC or NCHW for 4D or NC1HWC0 for 5D. *@li mean: A Tensor of type float32 or float16. Must be 1D if input "x" Specifies the mean used for inference. -*@li variance: A Tensor of type float32 or float16. Must be 1D if input "x" Specifies the variance used for inference. -*@li momentum: A Tensor of type float32 or float16, represents the mean and the variance's scale factor +*@li variance: A Tensor of type float32 or float16 . Must be 1D if input "x" Specifies the variance used for inference. +*@li momentum: A Tensor,represents the mean and the variance's scale factor *@li scale: An optional tensor of type float16 or float32, no use *@li offset: An optional tensor of type float16 or float32, no use *@par Attributes: *@li epsilon: An optional float32, specifying the small value added to variance to avoid dividing by zero. Defaults to "0.00001". *@li use_global_stats: mean inference mode , only can be "True". -*@li mode: An optional attr, not use +*@li mode: An optional input, not use *@par Outputs:\n *@li y: A 4D or 5D Tensor of type float16 or float32 for the normalized "x" */ @@ -391,11 +302,11 @@ REG_OP(BNInference) *@li mean: A Tensor of type float32 or float16. Must be 1D if input "x" Specifies the mean used for inference. *@li variance: A Tensor of type float32 or float16 . Must be 1D if input "x" Specifies the variance used for inference. -*@li momentum: A Tensor of type float32 or float16, the mean and the variance's Scale factor +*@li momentum: An optional float, mean and variance's Scale factor *@par Attributes: *@li epsilon: An optional float32, specifying the small value added to variance to avoid dividing by zero. Defaults to "0.00001". *@li use_global_stats: mean inference mode , only can be "True". -*@li mode: An optional inpout, not use +*@li mode: An optional attr, not use *@par Outputs: *@li alpha: A Tensor of type float16 or float32 for the cpu calculate mean *@li beta: A Tensor of type float16 or float32 for the cpu calculate variance @@ -418,8 +329,8 @@ REG_OP(BnHost) *@par Inputs: *@li x: A 4D or 5D Tensor of type float16 or float32, with format NHWC or NCHW for 4D or NC1HWC0 for 5D. -*@li mean: A Tensor of type float32 or float16. Must be 1D if input "x" Specifies the mean used for inference. -*@li variance: A Tensor of type float32 or float16 . Must be 1D if input "x" Specifies the variance used for inference. +*@li mean: A Tensor of type float32 or float16. Must be 1D if input "x" Specifies the mean used for inference. +*@li variance: A Tensor of type float32 or float16 . Must be 1D if input "x" Specifies the variance used for inference. *@li scale: An optional tensor of type float16 or float32, no use *@li offset: An optional tensor of type float16 or float32, no use *@par Attributes: diff --git a/third_party/fwkacllib/inc/ops/nn_calculation_ops.h b/third_party/fwkacllib/inc/ops/nn_calculation_ops.h index 3529e9ca..e9180332 100644 --- a/third_party/fwkacllib/inc/ops/nn_calculation_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_calculation_ops.h @@ -143,31 +143,29 @@ REG_OP(DepthwiseConv2DBackpropFilterD) * @par Inputs: * Three inputs include: \n * @li input_size: 4D shape of input tensor [N, C, H, W] or [N, H, W, C], -* support int32 -* @li filter: 4D filter tensor with shape of [H, W, C, K], support float16, -* float32, double +* support int32, int64 +* @li filter: 4D filter tensor with shape of [H, W, C, K], support float16. * @li out_backprop: 4D tensor with shape [N, C, H, W] or [N, H, W, C]. -* Must be one of the following types: float16, float32, double. +* Must be one of the following types: float16. * @par Attributes: -* @li strides: A required list or tuple. The stride of the sliding window for +* @li strides: A required list or tuple of int32. The stride of the sliding window for * height and width of input "x" of the convolution. * Must be with shape [1, 1, stride_height, stride_width] or [1, stride_height, * stride_width, 1]. -* @li dilations: An optional list or tuple. The dilation factor for each -* dimension of input "x". +* @li dilations: An optional list or tuple of int32. The dilation factor for each +* dimension of input "x". Defaults to "[1, 1, 1, 1]". * If set to k > 1, there will be k-1 skipped cells between each filter element * on that dimension. Must be with shape [1, 1, dilation_height, dilation_width] * or [1, dilation_height, dilation_width, 1]. -* @li pads: A required list or tuple. Padding added to each dimension of the +* @li pads: A required list or tuple of int32. Padding added to each dimension of the * input. * @li data_format: An optional string. Input data format, either "NHWC" or -* "NCHW". +* "NCHW". Defaults to "NHWC". * @par Outputs: * input_grad: Gradient of the deep convolution relative to the input with shape -* [N, C, H, W] or [N, H, W, C] Must be one of the following types: float16, -* float32, double. +* [N, C, H, W] or [N, H, W, C] Must be one of the following types: float16. * @attention Constraints:\n * The feature map is 4D with shape [N, C, Hi, Wi] or [N, Hi, Wi, C], but @@ -259,8 +257,8 @@ REG_OP(DepthwiseConv2DBackpropInputD) *@par Inputs: *Two required inputs and two optional inputs, including: \n -* @li x: A 4D tensor of type float16, with shape [N, C, H, W] or [N, H, W, C] -* @li filter: A 4D tensor of type float16, with shape [H, W, C, K] +* @li x: A 4D tensor of type float16 or int8, with shape [N, C, H, W] or [N, H, W, C] +* @li filter: A 4D tensor of type float16 or int8, with shape [H, W, C, K] * @li bias: An optional tensor of type float16 or int32 * @li offset_w: An optional float16 or int8, used for quantized inference @@ -273,8 +271,8 @@ REG_OP(DepthwiseConv2DBackpropInputD) * dimension of input "x". * If set to k > 1, there will be k-1 skipped cells between each filter element * on that dimension. Must be with shape [1, 1, dilation_height, dilation_width] -* or [1, dilation_height, dilation_width, 1]. -* @li pads: A required list or tuple. Padding added to each dimension of the +* or [1, dilation_height, dilation_width, 1]. Defaults to "[1, 1, 1, 1]". +* @li pads: A required list or tuple of int32. Padding added to each dimension of the * input. * @li data_format: An optional string. Input data format, either "NHWC" or * "NCHW". Defaults to "NHWC". @@ -282,7 +280,7 @@ REG_OP(DepthwiseConv2DBackpropInputD) * Defaults to 0. * @par Outputs: -* y: 4D tensor of type float16, with shape [N, C, H, W] or [N, H, W, C] +* y: 4D tensor of type float16 or int32, with shape [N, C, H, W] or [N, H, W, C] * @attention Constraints:\n * The feature map is 4D with shape [N, C, Hi, Wi] or [N, Hi, Wi, C], but @@ -314,53 +312,6 @@ REG_OP(DepthwiseConv2D) .ATTR(offset_x, Int, 0) .OP_END_FACTORY_REG(DepthwiseConv2D) -REG_OP(Conv2DCCE) - .INPUT(x, TensorType{DT_FLOAT}) // The input tensor - .INPUT(w, TensorType({DT_FLOAT, DT_INT8})) // The weight tensor ,If QuantType =1 ,shall use type""tensor(int8) - .OPTIONAL_INPUT(b, TensorType{DT_FLOAT}) // Optional 1D bias to be added to the convolution, has size of M. - .OUTPUT(y, TensorType{DT_FLOAT}) // The output tensor - .ATTR(mode, Int, 1) - .ATTR(group, Int, 1) // number of groups input channels and output channels are divided into - .ATTR(num_output, Int, 0) // number of output tensor - .ATTR(pad, ListInt, {0, 0, 0, 0}) // Padding for the beginning and ending along each axis - .ATTR(kernel, ListInt, {0, 0}) - .ATTR(stride, ListInt, {1, 1}) // Stride along each axis. - .ATTR(dilation, ListInt, {1, 1}) // dilation value along each axis of the filter. - .ATTR(pad_mode, Int, 0) // pad mode, 0:NOTSET, 1:SAME_UPPER, SAME_LOWER or 2:VALID.defaul default value is 0:NOTSET - .ATTR(algo, Int, 2) - .OP_END_FACTORY_REG(Conv2DCCE) - -REG_OP(Conv2DBackpropFilterCCE) - .INPUT(x, TensorType{DT_FLOAT}) - .INPUT(filter_sizes, TensorType{DT_INT8}) - .INPUT(out_backprop, TensorType{DT_FLOAT}) - .OUTPUT(y, TensorType{DT_FLOAT}) - .ATTR(conv_grad_filter_output_shape, ListInt, {0, 0, 0, 0}) - .ATTR(mode, Int, 1) - .ATTR(group, Int, 1) - .ATTR(pad, ListInt, {0, 0, 0, 0}) - .ATTR(stride, ListInt, {1, 1}) - .ATTR(dilation, ListInt, {1, 1}) - .ATTR(padding, Int, 0) //pad_mode:same valid - .ATTR(algo, Int, 0) - .OP_END_FACTORY_REG(Conv2DBackpropFilterCCE) - -REG_OP(Conv2DBackpropInputCCE) - .INPUT(input_sizes, TensorType{DT_INT8}) - .INPUT(filter, TensorType{DT_FLOAT}) - .INPUT(out_backprop, TensorType{DT_FLOAT}) - .OUTPUT(output, TensorType{DT_FLOAT}) - .ATTR(conv_grad_input_output_shape, ListInt, {0, 0, 0, 0}) - .ATTR(mode, Int, 1) - .ATTR(format, Int, 0) - .ATTR(group, Int, 1) - .ATTR(pad_mode, Int, 0) - .ATTR(stride, ListInt, {1, 1}) - .ATTR(dilation, ListInt, {1, 1}) - .ATTR(pad, ListInt, {0, 0, 0, 0}) - .ATTR(algo, Int, 0) - .OP_END_FACTORY_REG(Conv2DBackpropInputCCE) - /** *@brief Performs the the backward operation for "BiasAdd" on the "bias" tensor. * It accumulates all the values from out_backprop into the feature @@ -462,24 +413,24 @@ REG_OP(Conv2DBackpropInputD) * @li x: A Tensor. Must have the same type as "filter". 4D with shape * [batch, out_channels, out_height, out_width]. Gradients with respect * to the output of the convolution. - * @li filter: A Tensor of type float16. + * @li filter: A Tensor of type float16, float32, double or int8. * 4D with shape [out_channels, in_channel, filter_height, filter_width].\n * Two optional inputs: - * @li bias: An optional tensor of type float16 - * @li offset_w: An optional 1D tensor for quantized deconvolution. Reserved.\n + * @li bias: An optional tensor of type float16, float32, int32 or int64. + * @li offset_w: An optional 1D tensor for quantized deconvolution. Type is int8. Reserved.\n *@par Attributes: * Six attributes: * @li strides: A tuple or list of 2 integers. The stride of the sliding window - * for H/W dimension. + * for H/W dimension. Defaults to [1, 1, 1, 1]. * @li pads: A tuple or list of 4 integers. The [top, bottom, left, right] - * padding on the feature map + * padding on the feature map. Defaults to [0, 0, 0, 0]. * @li dilations: A tuple or list of 4 integers. The dilation factor for each * dimension of input. Must be [1, 1, 1, 1]. * @li groups: Number of blocked connections from input channels to - * output channels. - * @li data_format: An optional string from: "NCHW". Defaults to "NCHW".\n + output channels. Defaults to "1". + * @li data_format: An optional string from: "NCHW". Defaults to "NCHW". \n Specify the data format of the input and output data. - * @li offset_x: An optional integer for quantized deconvolution. + * @li offset_x: An optional integer for quantized deconvolution. Defaults to "0". *@par Outputs: * y: A Tensor. Has the same type as "filter". 4D tensor with shape * [batch, channels, height, width]. @@ -577,17 +528,17 @@ REG_OP(Conv2DBackpropFilterD) * * The input and output tensor attributes are listed as follows: * @verbatim - Tensor | x | filter | bias | offset_w | y + |Tensor | x | filter | bias | offset_w | y -----------|---------|---------|---------|----------|-------- - Data Type | float16 | float16 | float16 | _ | float16 - |---------|---------|---------|----------|-------- - | float32 | float32 | float32 | _ | float32 - |---------|---------|---------|----------|-------- - | int8 | int8 | int32 | int8 | int32 + |Data Type | float16 | float16 | float16 | _ | float16 + | |---------|---------|---------|----------|-------- + | | float32 | float32 | float32 | _ | float32 + | |---------|---------|---------|----------|-------- + | | int8 | int8 | int32 | int8 | int32 -----------|---------|---------|---------|----------|-------- - Format | NCHW | NCHW | ND | ND | NCHW - | NHWC | NHWC | | | NHWC - | | HWCN | | | + |Format | NCHW | NCHW | ND | ND | NCHW + | | NHWC | NHWC | | | NHWC + | | | HWCN | | | @endverbatim * It should be noted that the data types must correspond to each other, but the * format does not need to. @@ -602,10 +553,10 @@ REG_OP(Conv2DBackpropFilterD) * for dilated convolution. Has the same dimension order and value as "strides". * @li groups: Number of blocked connections from input channels to output * channels. Input channels and output channels must both be divisible by -* "groups". -* @li offset_x: An optional integer for quantized convolution. +* "groups".Type is int32. +* @li offset_x: An optional integer for quantized convolution. Type is int32. Defaults to "0". * @li data_format: An optional string from: "NHWC", "NCHW". Specifying the -* data format of the input and output images. Reserved. +* data format of the input and output images. Type is string. Defaults to "NHWC". Reserved. *@par Outputs: * @li y: A 4D Tensor of output images. @@ -613,23 +564,23 @@ REG_OP(Conv2DBackpropFilterD) *@attention * @li The parameter scope is listed as follows: * @verbatim - Name | Field | Scope + |Name | Field | Scope ------------------|--------------|---------- - Input Image Size | H dimension | [1, 4096] - | W dimension | [1, 4096] + |Input Image Size | H dimension | [1, 4096] + | | W dimension | [1, 4096] ------------------|--------------|---------- - Filter Size | H dimension | [1, 255] - | W dimension | [1, 255] + |Filter Size | H dimension | [1, 255] + | | W dimension | [1, 255] ------------------|--------------|---------- - Stride Size | H dimension | [1, 63] - | W dimension | [1, 63] + |Stride Size | H dimension | [1, 63] + | | W dimension | [1, 63] ------------------|--------------|---------- - Padding Size | top side | [0, 255] - | bottom side | [0, 255] - | left side | [0, 255] - | right side | [0, 255] + |Padding Size | top side | [0, 255] + | | bottom side | [0, 255] + | | left side | [0, 255] + | | right side | [0, 255] ------------------|--------------|---------- - Dilation Size | H dimension | [1, 255] + |Dilation Size | H dimension | [1, 255] | W dimension | [1, 255] @endverbatim @@ -684,36 +635,46 @@ REG_OP(Conv2DCompress) /** *@brief Computes a 3D convolution given 5D "x" and "filter" tensors. -*@par Inputs: -*@li x: A 5D tensor. Must be one of the following types: float16, float32, float64. The format is NCDHW or NDHWC. -*@li filter: A 5D tensor of the same type as "x". The format is NCDHW, NDHWC or DHWCN. -*@li bias: An optional 1D tensor of the same type as "x". + *@par Inputs: + * @li x: A 5D tensor. Must be one of the following types: float16, float32, float64. The format is NCDHW or NDHWC. + * @li filter: A 5D tensor of the same type as "x". The format is NCDHW, NDHWC or DHWCN. + +*@par Optional input: + * @li bias: An optional 1D tensor of the same type as "x". + * @li offset_w: An optional 1D tensor for quantized deconvolution. Reserved. + +*@par Required Attributes: +* @li strides: A list of 5 ints. Specifies the stride of the sliding window for each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". +* @li pads: A list of 6 ints. Supports only padding along the D, H and W dimensions in sequence of head, tail, top, bottom, left and right. *@par Attributes: -*@li strides: A list of 5 ints. Specifies the stride of the sliding window for each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". -*@li pads: A list of 6 ints. Supports only padding along the D, H and W dimensions in sequence of head, tail, top, bottom, left and right. -*@li data_format: An optional string from: "NDHWC", "NCDHW". Defaults to "NDHWC". Specify the data format of the input and output data. -*@li dilations: A list of 5 ints. Specifies the dilation factor for each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". + * @li groups: Number of blocked connections from input channels to output channels. + * @li data_format: An optional string from: "NDHWC", "NCDHW". Defaults to "NDHWC". Specify the data format of the input and output data. + * @li dilations: A list of 5 ints. Specifies the dilation factor for each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". + * @li offset_x: An optional int. Input offset, used for quantized inference. Defaults to 0. *@par Outputs: -*y: A Tensor. Has the same type as "x". + *y: A Tensor. Has the same type as "x". -*@attention Constraints:\n -*The image size after padding is greater than the filter size.\n +*@attention Constraints: + *The image size after padding is greater than the filter size. *@par Third-party framework compatibility -*@li Compatible with the TensorFlow operator conv3d. -*@li Compatible with the Caffe operator Convolution. + * @li Compatible with the TensorFlow operator conv3d. + * @li Compatible with the Caffe operator Convolution. */ REG_OP(Conv3D) .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) .INPUT(filter, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) .OPTIONAL_INPUT(bias, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .OPTIONAL_INPUT(offset_w, TensorType({DT_INT8})) .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) - .ATTR(strides, ListInt, {1, 1, 1, 1, 1}) - .ATTR(pads, ListInt, {0, 0, 0, 0, 0, 0}) - .ATTR(data_format, String, "NDHWC") + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) .ATTR(dilations, ListInt, {1, 1, 1, 1, 1}) + .ATTR(groups, Int, 1) + .ATTR(data_format, String, "NDHWC") + .ATTR(offset_x, Int, 0) .OP_END_FACTORY_REG(Conv3D) /** @@ -723,28 +684,35 @@ REG_OP(Conv3D) * @li input_size: A Tensor of type int32, int64. An integer vector representing the shape of input, * where input is a 5-D tensor [batch, depth, height, width, channels] or [batch, channels, depth, height, width]. * @li filter: A Tensor. Must be one of the following types: float16, float32, float64. - * @li grads: A Tensor. Must have the same type as filter. 5-D with shape [batch, depth, out_height, out_width, out_channels] + * @li out_backprop: A Tensor. Must have the same type as filter. 5-D with shape [batch, depth, out_height, out_width, out_channels] * or [batch, out_channels, depth, out_height, out_width]. Gradients with respect to the output of the convolution. + +*@par Required Attributes: + * @li strides: A list of 5 ints. Specifies the stride of the sliding window for each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". + * @li pads: A list of 6 ints. Supports only padding along the D, H and W dimensions in sequence of head, tail, top, bottom, left and right. + *@par Attributes: - * Four attributes: - * @li strides: A tuple/list of 3 integers. The stride of the sliding window for D/H/W dimension. - * @li pads: A tuple/list of 6 integers - * @li dilations: A tuple/list of 6 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] + * Three attributes: + * @li groups: Number of blocked connections from input channels to output channels. * @li data_format: An optional string from: "NDHWC", "NCHWD". Defaults to "NDHWC". Specify the data format of the input and output data. + * @li dilations: A tuple/list of 6 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] + *@par Outputs: * y: A Tensor. Has the same type as filter,and has same format as input_size + *@par Third-party framework compatibility * Compatible with Tensorflow's conv3d_backprop_input */ REG_OP(Conv3DBackpropInput) .INPUT(input_size, TensorType({DT_INT32, DT_INT64})) .INPUT(filter, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) - .INPUT(grads, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .INPUT(out_backprop, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) .REQUIRED_ATTR(strides, ListInt) - .ATTR(pads, ListInt, {0, 0, 0, 0, 0, 0}) - .ATTR(data_format, String, "NDHWC") + .REQUIRED_ATTR(pads, ListInt) .ATTR(dilations, ListInt, {1, 1, 1, 1, 1}) + .ATTR(groups, Int, 1) + .ATTR(data_format, String, "NDHWC") .OP_END_FACTORY_REG(Conv3DBackpropInput) /** @@ -752,46 +720,56 @@ REG_OP(Conv3DBackpropInput) *@par Inputs: * Two inputs: * @li filter: A Tensor. Types is float16. - * @li grads: A Tensor. Must have the same type as filter. + * @li out_backprop: A Tensor. Must have the same type as filter. + +*@par Required Attributes: + *@li strides: A list of 5 ints. Specifies the stride of the sliding window for + each dimension of "x". The N and C dimensions must be 1. Has the same format as "x". + *@li pads: A list of 6 ints. Supports only padding along the D, H and W + dimensions in sequence of head, tail, top, bottom, left and right. + *@li input_size: A Tensor of type int32, int64. An integer vector representing the shape of input, + * where input is a 5-D tensor [batch, depth, height, width, channels] or [batch, channels, depth, height, width]. + *@par Attributes: - * Five attributes: - * @li input_size A Tensor of type int32. An integer vector representing the shape of input, - * @li strides: A tuple/list of 3 integers. The stride of the sliding window for D/H/W dimension. - * @li pads: A tuple/list of 4 integers - * @li dilations: A tuple/list of 5 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] + * Three attributes: + * @li groups: Number of blocked connections from input channels to output channels. * @li data_format: An optional string from: "NDHWC", "NCHWD". Defaults to "NDHWC". Specify the data format of the input and output data. + * @li dilations: A tuple/list of 5 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] *@par Outputs: * y: A Tensor. Has the same type as filter *@par Third-party framework compatibility * Compatible with Tensorflow's conv3d_backprop_input */ + + REG_OP(Conv3DBackpropInputD) .INPUT(filter, TensorType({DT_FLOAT16})) - .INPUT(grads, TensorType({DT_FLOAT16})) + .INPUT(out_backprop, TensorType({DT_FLOAT16})) .OUTPUT(y, TensorType({DT_FLOAT16})) .REQUIRED_ATTR(input_size, ListInt) .REQUIRED_ATTR(strides, ListInt) - .ATTR(pads, ListInt, {0, 0, 0, 0, 0, 0}) - .ATTR(data_format, String, "NDHWC") + .REQUIRED_ATTR(pads, ListInt) .ATTR(dilations, ListInt, {1, 1, 1, 1, 1}) + .ATTR(groups, Int, 1) + .ATTR(data_format, String, "NDHWC") .OP_END_FACTORY_REG(Conv3DBackpropInputD) REG_OP(LSTM) - .INPUT(x, TensorType({DT_FLOAT16})) - .INPUT(cont, TensorType({DT_FLOAT32,DT_FLOAT16})) - .INPUT(w_x, TensorType({DT_FLOAT16})) - .INPUT(bias, TensorType({DT_FLOAT16,DT_FLOAT32,DT_INT16,DT_INT32})) - .INPUT(w_h, TensorType({DT_FLOAT16})) - .OPTIONAL_INPUT(x_static, TensorType({DT_FLOAT16})) - .OPTIONAL_INPUT(h_0, TensorType({DT_FLOAT16,DT_FLOAT32})) - .OPTIONAL_INPUT(c_0, TensorType({DT_FLOAT16,DT_FLOAT32})) - .OPTIONAL_INPUT(w_x_static, TensorType({DT_FLOAT16})) - .OUTPUT(h, TensorType({DT_FLOAT16, DT_FLOAT})) - .OUTPUT(h_t, TensorType({DT_FLOAT16, DT_FLOAT})) - .OUTPUT(c_t, TensorType({DT_FLOAT16, DT_FLOAT})) - .ATTR(num_output, Int, 0) - .ATTR(expose_hidden, Bool, false) - .OP_END_FACTORY_REG(LSTM) + .INPUT(x, TensorType({DT_FLOAT16})) + .INPUT(cont, TensorType({DT_FLOAT32,DT_FLOAT16})) + .INPUT(w_x, TensorType({DT_FLOAT16})) + .INPUT(bias, TensorType({DT_FLOAT16,DT_FLOAT32,DT_INT16,DT_INT32})) + .INPUT(w_h, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(x_static, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(h_0, TensorType({DT_FLOAT16,DT_FLOAT32})) + .OPTIONAL_INPUT(c_0, TensorType({DT_FLOAT16,DT_FLOAT32})) + .OPTIONAL_INPUT(w_x_static, TensorType({DT_FLOAT16})) + .OUTPUT(h, TensorType({DT_FLOAT16, DT_FLOAT})) + .OUTPUT(h_t, TensorType({DT_FLOAT16, DT_FLOAT})) + .OUTPUT(c_t, TensorType({DT_FLOAT16, DT_FLOAT})) + .ATTR(num_output, Int, 0) + .ATTR(expose_hidden, Bool, false) + .OP_END_FACTORY_REG(LSTM) /** *@brief Computes the gradients of convolution3D with respect to the filter @@ -851,6 +829,8 @@ REG_OP(Conv3DBackpropFilter) *@par Third-party framework compatibility * Compatible with Tensorflow's conv3d_backprop_filter */ + + REG_OP(Conv3DBackpropFilterD) .INPUT(x, TensorType({DT_FLOAT16})) .INPUT(out_backprop, TensorType({DT_FLOAT16})) @@ -862,5 +842,86 @@ REG_OP(Conv3DBackpropFilterD) .ATTR(groups, Int, 1) .ATTR(data_format, String, "NDHWC") .OP_END_FACTORY_REG(Conv3DBackpropFilterD) + +/** +*@brief Computes the transpose of convolution 3d with respect to the input. +*@par Inputs: + * Five inputs: + * @li input_size: A Tensor of type int32. An integer vector representing the shape of input + * @li x: A Tensor. + * @li filter: A Tensor. Types is float16. + * @li bias: An optional 1D tensor of the same type as "x". + * @li offset_w: An optional 1D tensor for quantized deconvolution. Reserved. + +*@par Required Attributes: + * @li strides: A tuple/list of 3 integers. The stride of the sliding window for D/H/W dimension. + * @li pads: A tuple/list of 6 integers +*@par Attributes: + * Five attributes: + * @li groups: Number of blocked connections from input channels to output channels. + * @li dilations: A tuple/list of 5 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] + * @li data_format: An optional string from: "NDHWC", "NCHWD". Defaults to "NDHWC". Specify the data format of the input and output data. + * @li output_padding: The size will be added in the output shape. + * @li offset_x: Input offset_x value +*@par Outputs: + * y: A Tensor. Has the same type as filter +*/ +REG_OP(Conv3DTranspose) + .INPUT(input_size, TensorType({DT_INT32, DT_INT64})) + .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .INPUT(filter, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .OPTIONAL_INPUT(bias, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(offset_w, TensorType({DT_INT8})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(dilations, ListInt, {1, 1, 1, 1, 1}) + .ATTR(groups, Int, 1) + .ATTR(data_format, String, "NDHWC") + .ATTR(output_padding, ListInt, {0, 0, 0, 0, 0}) + .ATTR(offset_x, Int, 0) + .OP_END_FACTORY_REG(Conv3DTranspose) + +/** +*@brief Computes the transpose of convolution 3d with respect to the input. +*@par Inputs: + * Four inputs: + * @li x: A Tensor. + * @li filter: A Tensor. Types is float16. + * @li bias: An optional 1D tensor of the same type as "x". + * @li offset_w: An optional 1D tensor for quantized deconvolution. Reserved. + +*@par Required Attributes: + * @li input_size: A Tensor of type int32. An integer vector representing the shape of input + * @li strides: A tuple/list of 3 integers. The stride of the sliding window for D/H/W dimension. + * @li pads: A tuple/list of 6 integers +*@par Attributes: + * Five attributes: + * @li dilations: A tuple/list of 5 integers, The dilation factor for each dimension of input, now only support [1,1,1,1,1] + * @li groups: Number of blocked connections from input channels to output channels. + * @li data_format: An optional string from: "NDHWC", "NCHWD". Defaults to "NDHWC". Specify the data format of the input and output data. + * @li output_padding: The size will be added in the output shape. + * @li offset_x: Input offset_x value +*@par Outputs: + * y: A Tensor. Has the same type as filter +*/ + + +REG_OP(Conv3DTransposeD) + .INPUT(x, TensorType({DT_FLOAT16})) + .INPUT(filter, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(bias, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(offset_w, TensorType({DT_INT8})) + .OUTPUT(y, TensorType({DT_FLOAT16})) + .REQUIRED_ATTR(input_size, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(dilations, ListInt, {1, 1, 1, 1, 1}) + .ATTR(groups, Int, 1) + .ATTR(data_format, String, "NDHWC") + .ATTR(output_padding, ListInt, {0, 0, 0, 0, 0}) + .ATTR(offset_x, Int, 0) + .OP_END_FACTORY_REG(Conv3DTransposeD) + } // namespace ge #endif // GE_OP_NN_CALCULATION_OPS_H diff --git a/third_party/fwkacllib/inc/ops/nn_detect_ops.h b/third_party/fwkacllib/inc/ops/nn_detect_ops.h index 5dca8a9d..0a91e237 100644 --- a/third_party/fwkacllib/inc/ops/nn_detect_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_detect_ops.h @@ -187,14 +187,15 @@ REG_OP(ROIAlignGrad) *@li features: A 5HD Tensor of type float32 or float16. *@li rois: ROI position. A 2D Tensor of float32 or float16 with shape (N, 5). "N" indicates the number of ROIs, the value "5" indicates the indexes of images where the ROIs are located, * "x0", "y0", "x1", and "y1". -*@li rois_n: An optional input, specifying the number of valid ROIs. This parameter is reserved. +*@li rois_n: An optional input of type int32, specifying the number of valid ROIs. This parameter is reserved. *@par Attributes: -*@li spatial_scale: A required attribute of type float, specifying the scaling ratio of "features" to the original image. -*@li pooled_height: A required attribute of type int, specifying the H dimension. -*@li pooled_width: A required attribute of type int, specifying the W dimension. -*@li sample_num: An optional attribute of type int, specifying the horizontal and vertical sampling frequency of each output. If this attribute is set to "0", +*@li spatial_scale: A required attribute of type float32, specifying the scaling ratio of "features" to the original image. +*@li pooled_height: A required attribute of type int32, specifying the H dimension. +*@li pooled_width: A required attribute of type int32, specifying the W dimension. +*@li sample_num: An optional attribute of type int32, specifying the horizontal and vertical sampling frequency of each output. If this attribute is set to "0", * the sampling frequency is equal to the rounded up value of "rois", which is a floating point number. Defaults to "2". +*@li roi_end_mode: An optional attribute of type int32. Defaults to "1". *@par Outputs: * output: Outputs the feature sample of each ROI position. The format is 5HD Tensor of type float32 or float16. The axis N is the number of input ROIs. Axes H, W, and C are consistent @@ -362,15 +363,15 @@ REG_OP(PSROIPooling) *@li im_info: An ND tensor of type float16 or float32, specifying the Image information. *@li actual_rois_num: An optional NCHW tensor of type int32, specifying the number of valid boxes per batch. *@par Attributes: -*@li batch_rois: An optional int32, specifying the number of images to be predicted. +*@li batch_rois: An optional int32, specifying the number of images to be predicted. Defaults to "1". *@li num_classes: An required int32, specifying the number of classes to be predicted. The value must be greater than 0. *@li score_threshold: An required float32, specifying the threshold for box filtering. The value range is [0.0, 1.0]. *@li iou_threshold: An required float32, specifying the confidence threshold for box filtering, which is the output "obj" of operator Region. The value range is (0.0, 1.0). *@par Outputs: -*@li box: An NCHW tensor of type float16 or float32, describing the information of each output box, including the coordinates, class, and confidence. -Proposal of actual output, with output shape [batch, numBoxes,8], 8 means [x1, y1, x2, y2, score, label, batchID, NULL], the maximum value of numBoxes is 1024. +*@li box: A tensor of type float16 or float32 for proposal of actual output, with output shape [batch, numBoxes,8]. +* 8 means [x1, y1, x2, y2, score, label, batchID, NULL], the maximum value of numBoxes is 1024. That is, take min (the maximum number of input boxes, 1024) -*@li actual_bbox_num: An NCHW tensor of type int32 With shape [bacth, num_classes], specifying the number of output boxes. +*@li actual_bbox_num: A tensor of type int32 With shape [bacth, num_classes], specifying the number of output boxes. *@attention Constraints:\n *@li totalnum < max_rois_num * batch_rois. @@ -414,9 +415,9 @@ REG_OP(FSRDetectionOutput) *@li confidence_threshold: An optional float32, specify the topk filter threshold. Only consider detections with confidence greater than the threshold *@li kernel_name: An optional string, specifying the operator name. Defaults to "ssd_detection_output". *@par Outputs: -*@li out_boxnum: An NCHW tensor of type int32, specifying the number of output boxes. -*@li y: An NCHW tensor of type float16 or float32 with shape [batch,keep_top_k, 8], describing the information of each output box, including the coordinates, -* class, and confidence. In output shape, 8 means (batchID, label(classID), score (class probability), xmin, ymin, xmax, ymax, null) +*@li out_boxnum: A tensor of type int32, specifying the number of output boxes. +*@li y: A tensor of type float16 or float32 with shape [batch,keep_top_k, 8], describing the information of each output box. +* In output shape, 8 means (batchID, label(classID), score (class probability), xmin, ymin, xmax, ymax, null) * It is a custom operator. It has no corresponding operator in Caffe. */ REG_OP(SSDDetectionOutput) @@ -447,10 +448,10 @@ REG_OP(SSDDetectionOutput) *@li boxes: A required int32, specifying the number of anchor boxes. Defaults to "5" for V2 or "3" for V3. *@li coords: An int32, specifying the number of parameters required for locating an object. The value is fixed at "4", corresponding to (x,y,w,h). *@li classes: An int32, specifying the number of prediction classes. Defaults to "80". The value range is [1, 1024]. -*@li yolo_version: A string, specifying the YOLO version, either "V2" or "V3". -*@li softmax: A bool, specifying whether to perform softmax, valid only when "yolo_version = V2". -*@li background: A bool, specifying the operation types of the obj and classes, used in conjunction with "softmax" and valid only when "yolo_version = V2". -*@li softmaxtree: A bool, Fixed to False, defined in Lite, but not used. +*@li yolo_version: A string, specifying the YOLO version, either "V2" or "V3".Defaults to "V3" +*@li softmax: A bool, specifying whether to perform softmax, valid only when "yolo_version = V2". Defaults to "false". +*@li background: A bool, specifying the operation types of the obj and classes, used in conjunction with "softmax" and valid only when "yolo_version = V2". Defaults to "false". +*@li softmaxtree: A bool, Fixed to False, defined in Lite, but not used. Defaults to "false". *@par Outputs: *@li coord_data: A float16 or float32 with shape [N, boxes*coords, ceilx(height*width*2+32, 32)/2], where "ceil" indicates that a detected box is aligned upwards with the second parameter. Specifies the coordinates of a detected box. @@ -501,10 +502,10 @@ and the actual image height and width. *@li pre_nms_topn: An optional int, specifying the number of boxes for non-maximum suppression (NMS). Defaults to "512". * *@par Outputs: -*@li boxout: An NCHW tensor of type float16 or float32 with shape [batch,6,post_nms_topn]. describing the information of each output box, including the coordinates, class, -and confidence. In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. -*@li boxoutnum: An NCHW tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. It means only the first one of the 8 numbers is valid, -the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 +*@li boxout: A tensor of type float16 or float32 with shape [batch,6,post_nms_topn]. describing the information of each output box, +* In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. +*@li boxoutnum: A tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. It means only the first one of the 8 numbers is valid, +* the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 * *@attention Constraints:\n *@li This operator applies only to the YOLO v2 network. @@ -561,10 +562,10 @@ and the actual image height and width. *@li pre_nms_topn: An optional int, specifying the number of boxes for non-maximum suppression (NMS). Defaults to "512". * *@par Outputs: -*@li boxout: An NCHW tensor of type float16, describing the information of each output box, including the coordinates, class, and confidence. -With shape [batch,6,post_nms_topn], 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. -*@li boxoutnum: An NCHW tensor of type int32, specifying the number of output boxes. -With shape [batch,8,1,1], means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 +*@li boxout: A tensor of type float16 or float32 with shape [batch,6,post_nms_topn]. describing the information of each output box, +* In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. +*@li boxoutnum: A tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. It means only the first one of the 8 numbers is valid, +* the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 * *@attention Constraints:\n *@li This operator applies only to the YOLO v2 network. @@ -621,11 +622,11 @@ and the actual image height and width. *@li pre_nms_topn: An optional int, specifying the number of boxes for non-maximum suppression (NMS). Defaults to "512". * *@par Outputs: -*@li boxout: An NCHW tensor of type float16 or float32 with shape [batch,6,post_nms_topn], describing the information of each output box, including the coordinates, class, and confidence. -In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. -*@li boxoutnum: An NCHW tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. -The output shape means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 - +*@li boxout: A tensor of type float16 or float32 with shape [batch,6,post_nms_topn], describing the information of each output box. +* In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. +*@li boxoutnum: A tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. +* The output shape means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 +* *@attention Constraints:\n *@li This operator applies only to the YOLO v3 network. *@li The preceding layer of operator Yolov3DetectionOutput must be three Yolo operators. @@ -688,12 +689,11 @@ and the actual image height and width. *@li pre_nms_topn: An optional int, specifying the number of boxes for non-maximum suppression (NMS). Defaults to "512". * *@par Outputs: -*@li boxout: An NCHW tensor of type float16, describing the information of each output box, including the coordinates, class, and confidence. -With shape [batch,6,post_nms_topn], 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. -*@li boxoutnum: An NCHW tensor of type int32, specifying the number of output boxes. -With shape [batch,8,1,1], means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 +*@li boxout: A tensor of type float16 or float32 with shape [batch,6,post_nms_topn], describing the information of each output box. +* In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. +*@li boxoutnum: A tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. +* The output shape means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 * - *@attention Constraints:\n *@li This operator applies only to the YOLO v3 network. *@li The preceding layer of operator Yolov3DetectionOutput must be three Yolo operators. @@ -735,6 +735,65 @@ REG_OP(YoloV3DetectionOutputD) .OP_END_FACTORY_REG(YoloV3DetectionOutputD) /** +*@brief Performs YOLO V3 detection. + +*@par Inputs: +*16 Input, including: +*@li The outputs of operator Yolo at the preceding layer (that is, three Yolo operators on YOLO v3) are used as the inputs of operator Yolov3DetectionOutput. \n +A Yolo operator has three outputs: "coords", "obj", and "class". For details, see the description of operator Yolo. +*@li imginfo: A float16, describing the image information including the required image height and width \n +and the actual image height and width. +*@li windex: A windex tensor with shape [height,weight]. Has the same type as the inputs. [[0,1,2...(weight-1)],[0,1,2...(w-1)]...[0,1,2...(weight-1)]] consisting of h groups of [0, 1, 2...(weight-1)] is formed for the three Yolo outputs, respectively. + +*@li hindex: A hindex tensor with shape [height,weight]. Has the same type as the inputs. [[0,0...0],[1,1...1],[2,2...2]...[height-1,height-1...,height-1]] is formed for the three Yolo outputs, respectively. + +* +*@par Attributes: +*@li biases: A required float32. "biases = Number of Yolo operators at the preceding layer x 2 x boxes" +*@li boxes: A required int32, specifying the number of anchor boxes predicted for each Yolo layer. +*@li coords: Specifies the number of coordinate parameters. Must be 4. +*@li classes: A required int32, specifying the number of classes to be predicted. The value range is [1, 80]. +*@li relative: An optional bool. Defaults to and must be "true". +*@li obj_threshold: A required float, specifying the confidence threshold for box filtering, which is the output "obj" of operator Yolo). The value range is [0.0, 1.0]. +*@li post_nms_topn: An optional int32. This attribute is reserved. +*@li score_threshold: A required float, specifying the class score threshold for box filtering, which is the output "class" of operator Yolo). The value range is [0.0, 1.0]. +*@li iou_threshold: A required float, specifying the intersection-over-union (IOU) threshold for box filtering. The value range is [0.0, 1.0].\n +*@li pre_nms_topn: An optional int, specifying the number of boxes for non-maximum suppression (NMS). Defaults to "512". +* +*@par Outputs: +*@li boxout: A tensor of type float16 or float32 with shape [batch,6,post_nms_topn], describing the information of each output box. +* In output shape, 6 means x1, y1, x2, y2, score, label(class). Output by the number of box_out_num. +*@li boxoutnum: A tensor of type int32 with shape [batch,8,1,1], specifying the number of output boxes. +* The output shape means only the first one of the 8 numbers is valid, the number of valid boxes in each batch, the maximum number of valid boxes in each batch is 1024 +* +*@attention Constraints:\n +*@li This operator applies only to the YOLO v3 network. +*@li The preceding layer of operator Yolov3DetectionOutput must be three Yolo operators. +*@see Yolo() +*@par Third-party framework compatibility +* It is a custom operator. It has no corresponding operator in Caffe. +*/ +REG_OP(YoloV3DetectionOutputV2) + .DYNAMIC_INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .DYNAMIC_INPUT(windex, TensorType({DT_FLOAT16,DT_FLOAT})) + .DYNAMIC_INPUT(hindex, TensorType({DT_FLOAT16,DT_FLOAT})) + .REQUIRED_ATTR(biases, ListFloat) + .ATTR(boxes, Int, 3) + .ATTR(coords, Int, 4) + .ATTR(classes, Int, 80) + .ATTR(relative, Bool, true) + .ATTR(obj_threshold, Float, 0.5) + .ATTR(post_nms_topn, Int, 512) + .ATTR(score_threshold, Float, 0.5) + .ATTR(iou_threshold, Float, 0.45) + .ATTR(pre_nms_topn, Int, 512) + .ATTR(N, Int, 10) + .ATTR(resize_origin_img_to_net, Bool, false) + .OUTPUT(box_out, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(box_out_num, TensorType({DT_INT32})) + .OP_END_FACTORY_REG(YoloV3DetectionOutputV2) + +/** *@brief Spatial Pyramid Pooling, multi-level pooling. * Pooling out(n, sigma(c*2^i*2^i)) tensor, i in range[0,pyramid_height). @@ -1084,6 +1143,131 @@ REG_OP(DecodeWheelsTarget) .OUTPUT(boundary_encoded, TensorType({DT_FLOAT16})) .OP_END_FACTORY_REG(DecodeWheelsTarget) +/** +*@brief Computes nms for input boxes and score, support multiple batch and classes. +* will do clip to window, score filter, top_k, and nms + +*@par Inputs: +* Four inputs, including: \n +*@li boxes: boxes, a 4D Tensor of type float16 with +* shape (batch, num_anchors, num_classes, 4). "batch" indicates the batch size of image, +* and "num_anchors" indicates num of boxes, and "num_classes" indicates classes of detect. +* and the value "4" refers to "x0", "x1", "y0", and "y1". +*@li scores: boxes, a 4D Tensor of type float16 with +* shape (batch, num_anchors, num_classes). +*@li clip_window: window size, a 2D Tensor of type float16 with +* shape (batch, 4). 4" refers to "anchor_x0", "anchor_x1", "anchor_y0", and "anchor_y1". +*@li num_valid_boxes: valid boxes number for each batch, a 1D Tensor of type int32 with +* shape (batch,). + +*@par Attributes: +*@li score_threshold: A required attribute of type float32, specifying the score filter iou iou_threshold. +*@li iou_threshold: A required attribute of type float32, specifying the nms iou iou_threshold. +*@li max_size_per_class: A required attribute of type int, specifying the nms output num per class. +*@li max_total_size: A required attribute of type int, specifying the the nms output num per batch. +*@li change_coordinate_frame: A required attribute of type bool, whether to normalize coordinates after clipping. +*@li transpose_box: A required attribute of type bool, whether inserted transpose before this op. + +*@par Outputs: +*@li nmsed_boxes: A 3D Tensor of type float16 with shape (batch, max_total_size, 4), +* specifying the output nms boxes per batch. +*@li nmsed_scores: A 2D Tensor of type float16 with shape (N, 4), +* specifying the output nms score per batch. +*@li nmsed_classes: A 2D Tensor of type float16 with shape (N, 4), +* specifying the output nms class per batch. +*@li nmsed_num: A 1D Tensor of type float16 with shape (N, 4), specifying the valid num of nmsed_boxes. + +*@attention Constraints: +* Only computation of float16 data is supported. +*/ +REG_OP(BatchMultiClassNonMaxSuppression) + .INPUT(boxes, TensorType({DT_FLOAT16})) + .INPUT(scores, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(clip_window, TensorType({DT_FLOAT16})) + .OPTIONAL_INPUT(num_valid_boxes, TensorType({DT_INT32})) + .OUTPUT(nmsed_boxes, TensorType({DT_FLOAT16})) + .OUTPUT(nmsed_scores, TensorType({DT_FLOAT16})) + .OUTPUT(nmsed_classes, TensorType({DT_FLOAT16})) + .OUTPUT(nmsed_num, TensorType({DT_INT32})) + .REQUIRED_ATTR(score_threshold, Float) + .REQUIRED_ATTR(iou_threshold, Float) + .REQUIRED_ATTR(max_size_per_class, Float) + .REQUIRED_ATTR(max_total_size, Float) + .ATTR(change_coordinate_frame, Bool, false) + .ATTR(transpose_box, Bool, false) + .OP_END_FACTORY_REG(BatchMultiClassNonMaxSuppression) + +/** +* @brief To absolute the bounding box. + +* @par Inputs: +* @li normalized_boxes: A 3D Tensor of type float16 or float32. +* @li shape_hw: A 1D Tensor of type int32. + +* @par Attributes: +* @li reversed_box: An optional bool, specifying the last two dims is "4,num" or +* "num,4", "true" for "4,num", "false" for "num,4". Defaults to "false". + +* @par Outputs: +* y: A Tensor. Has the same type and shape as "normalized_boxes". + +* @attention Constraints: +* "normalized_boxes"'s shape must be (batch,num,4) or (batch,4,num). +* "shape_hw"'s shape must be (4,) +*/ +REG_OP(ToAbsoluteBBox) + .INPUT(normalized_boxes, TensorType({DT_FLOAT16, DT_FLOAT})) + .INPUT(shape_hw, TensorType({DT_INT32})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT})) + .ATTR(reversed_box, Bool, false) + .OP_END_FACTORY_REG(ToAbsoluteBBox) + +/** +*@brief Computes Normalize bbox function. +* +*@par Inputs: +*Inputs include: +* @li boxes: A Tensor. Must be float16 or float32. +* @li shape_hw: A Tensor. Must be int32. +* +*@par Attributes: +* reversed_box: optional, bool. Defaults to "False" +* +*@par Outputs: +* y: A Tensor. Must have the same type and shape as boxes. +*/ +REG_OP(NormalizeBBox) + .INPUT(boxes, TensorType({DT_FLOAT16, DT_FLOAT})) + .INPUT(shape_hw, TensorType({DT_INT32})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT})) + .ATTR(reversed_box, Bool, false) + .OP_END_FACTORY_REG(NormalizeBBox) + +/** +*@brief Computes decode bboxv2 function. +* +*@par Inputs: +*Inputs include: +* @li boxes: A Tensor. Must be float16 or float32. +* @li anchors: A Tensor. Must be int32. +* +*@par Attributes: +* @li scales: optional, listfloat, . +* @li decode_clip: optional, float, threahold of decode process. +* @li reversed_boxes: optional, bool,. +* +*@par Outputs: +* y: A Tensor. Must have the same type as box_predictions. +*/ +REG_OP(DecodeBboxV2) + .INPUT(boxes, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(anchors, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(y, TensorType({DT_FLOAT16,DT_FLOAT})) + .ATTR(scales, ListFloat, {1.0, 1.0, 1.0, 1.0}) + .ATTR(decode_clip, Float, 0.0) + .ATTR(reversed_box, Bool, false) + .OP_END_FACTORY_REG(DecodeBboxV2) + } // namespace ge #endif // GE_OP_NN_DETECT_OPS_H_ diff --git a/third_party/fwkacllib/inc/ops/nn_norm_ops.h b/third_party/fwkacllib/inc/ops/nn_norm_ops.h index d4db7cf0..f5b20cdd 100644 --- a/third_party/fwkacllib/inc/ops/nn_norm_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_norm_ops.h @@ -44,16 +44,6 @@ REG_OP(LogSoftmaxGrad) .ATTR(axis, ListInt, {-1}) .OP_END_FACTORY_REG(LogSoftmaxGrad) -REG_OP(SparseSoftmaxCrossEntropyWithLogitsCCE) - .INPUT(features, TensorType{DT_FLOAT}) - .INPUT(labels, TensorType{DT_FLOAT}) - .OUTPUT(out, TensorType{DT_FLOAT}) - .OUTPUT(non, TensorType{DT_FLOAT}) - .ATTR(cross_entropy_is_grad, Bool, 0) - .ATTR(cross_entropy_mode, Int, 1) - .ATTR(softmax_cross_entropy_lossscale_div_batch, Float, 1.0) - .OP_END_FACTORY_REG(SparseSoftmaxCrossEntropyWithLogitsCCE) - /** *@brief Computes sparse softmax cross entropy cost and gradients to backpropagate. @@ -291,8 +281,8 @@ REG_OP(BinaryCrossEntropyGrad) * double. Should be a Variable Tensor. *@par Attributes: -*axes: A list of ints. The dimension softmax would be performed on. Defaults -* to "{-1}". +*axes: A list of int. The dimension softmax would be performed on. Defaults +* to "[-1]". *@par Outputs: *y: A Tensor. Has the same dimensionality and shape as the "x" with values in @@ -330,22 +320,6 @@ REG_OP(LogSoftmaxV2) .ATTR(axes, ListInt, {-1}) .OP_END_FACTORY_REG(LogSoftmaxV2) -REG_OP(FusedBatchNormV2) - .INPUT(x, TensorType{DT_FLOAT}) /* Input data tensor from the previous operator"" */ - .INPUT(scale, TensorType{DT_FLOAT}) /* If spatial is true, the dimension of bias is (C) If spatial is false, the dimensions of scale are (C x D1 x ... x Dn)*/ - .INPUT(b, TensorType{DT_FLOAT}) /* If spatial is true, the dimension of bias is (C) If spatial is false, the dimensions of scale are (C x D1 x ... x Dn)*/ - .OPTIONAL_INPUT(mean, TensorType{DT_FLOAT}) /* If spatial is true, the dimension of the running mean (training) or the estimated mean (testing) is (C).If spatial is false, the dimensions of the running mean (training) or the estimated mean (testing) are (C x D1 x ... x Dn)*/ - .OPTIONAL_INPUT(variance, TensorType{DT_FLOAT}) /* If spatial is true, the dimension of the running variance(training) or the estimated variance (testing) is (C). If spatial is false, the dimensions of the running variance(training) or the estimated variance (testing) are (C x D1 x ... x Dn).*/ - .OUTPUT(y, TensorType{DT_FLOAT}) /* The output tensor of the same shape as X */ - .ATTR(momentum, Float, 0.9) // Factor used in computing the running mean and variance. - .ATTR(epsilon, Float, 1e-5f) // The epsilon value to use to avoid division by zero - .ATTR(mode, Int, 1) // 1 means using "CC_BATCHNORM_SPATIAL"; 0 means using "CC_BATCHNORM_PER_ACTIVATION"; only support 1 now - .ATTR(use_global_stats, Bool, true) - .ATTR(alpha, Float, 1) - .ATTR(beta, Float, 0) - .OP_END_FACTORY_REG(FusedBatchNormV2) - - /** *@brief Confuse mul, sum and sub. @@ -632,7 +606,7 @@ REG_OP(DropOutDoMask) * Three inputs, including: *@li x: An ND tensor of type float16 or float32. *@li scale: An ND tensor of type float16 or float32. -*@li bias: An ND tensor of type float16 or float32. +*@li bias: An optional ND tensor of type float16 or float32. *@par Attributes: *@li axis: An optional int32 used to compute the shape of scale and bias input from the online bottoms. Defaults to "1". @@ -679,11 +653,11 @@ REG_OP(Scale) * depth_radius = (local_size - 1) / 2. local_size is the number of channels to sum over (for ACROSS_CHANNELS) * or the side length of the square region to sum over (for WITHIN_CHANNEL). *@li bias: An optional float32. An offset, usually > 0 to avoid dividing by 0. -* Defaults to "1". +* Defaults to "1.0". *@li alpha: An optional float32. A scaling factor, usually positive. -* Defaults to "1". +* Defaults to "1.0". *@li beta: An optional float32. An exponent. Defaults to "0.75" for the caffe framework, Defaults to "0.5" for others. -*@li norm_region: An optional string. A mode option. "ACROSS_CHANNELS":0, "WITHIN_CHANNEL":1. Defaults to "ACROSS_CHANNELS". +*@li norm_region: An optional string. A mode option. "ACROSS_CHANNELS":0. Defaults to "ACROSS_CHANNELS". *@par Outputs: *y: A Tensor. Has the same data type and shape as "x". @@ -836,6 +810,56 @@ REG_OP(GroupNorm) .ATTR(num_groups, Int, 2) .OP_END_FACTORY_REG(GroupNorm) +/** +*@brief Performs instance normalization. + +*@par Inputs:\n +* Five inputs, including: (NC1HWC0, supported) +*@li x: A 5D Tensor of type float16 or float32, NC1HWC0. +*@li gamma: A Tensor of type float32. +A 5D Tensor for scaling factor, to scale the normalized x. +*@li beta: A Tensor of type float32. +A 5D Tensor for offset, to shift to the normalized x. +*@li mean: A Tensor of type float32. +A 5D Tensor Specifies the mean used for inference. Reserved. +*@li variance: A Tensor of type float32. +A 5D Tensor Specifies the variance used for inference. Reserved. + +*@par Attributes: +*@li is_training: An optional bool, specifying if the operation is used for \n +training or inference. Defaults to "True". +*@li momentum: An optional float32, \n +the value used for the running_mean and running_var computation. Default: "0.1". +*@li epsilon: An optional float32, specifying the small value added to \n +variance to avoid dividing by zero. Defaults to "0.00001". + +*@par Outputs:\n +* Three outputs, including: (NHWC, NCHW NC1HWC0 supported) +*@li y: A 5D tensor of type float16 or float32 for the normalized "x", \n +*@li batch_mean: A Tensor of type float32. +Specifies the mean of "x". +*@li batch_variance: A Tensor of type float32. +Specifies the variance of "x". + +*@par Third-party framework compatibility +*@li Compatible with the PyTorch operator InstanceNorm. +*/ +REG_OP(InstanceNormV2) + .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT})) + .OPTIONAL_INPUT(gamma, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(beta, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(mean, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(variance, TensorType({DT_FLOAT})) + + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT})) + .OUTPUT(batch_mean, TensorType({DT_FLOAT})) + .OUTPUT(batch_variance, TensorType({DT_FLOAT})) + + .ATTR(is_training, Bool, true) + .ATTR(momentum, Float, 0.1) + .ATTR(epsilon, Float, 0.00001) + .OP_END_FACTORY_REG(InstanceNormV2) + } // namespace ge #endif //GE_OP_NN_NORM_OPS_H diff --git a/third_party/fwkacllib/inc/ops/nn_pooling_ops.h b/third_party/fwkacllib/inc/ops/nn_pooling_ops.h index 5eb11445..98c4b246 100644 --- a/third_party/fwkacllib/inc/ops/nn_pooling_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_pooling_ops.h @@ -102,6 +102,42 @@ REG_OP(AvgPool) .OP_END_FACTORY_REG(AvgPool) /** +*@brief Performs average pooling on the input. + +*@par Inputs: +*x: A 5-D Tensor of shape [batch, depth, height, width, channels] and type float16, float32, double. + +*@par Attributes: +*@li ksize: List of ints that has length 1, 3 or 5. The size of the window for each dimension of the input tensor. +*@li strides:List of ints that has length 1, 3 or 5. The stride of the sliding window for each dimension of the input tensor. +*@li pads: List of ints, implicit zero paddings on both sides of the input. +*@li ceil_mode: When true, will use ceil instead of floor in the formula to compute the output shape. +*@li count_include_pad: When true, will include the zero-padding in the averaging calculation. +*@li divisor_override: if specified, it will be used as divisor, otherwise size of the pooling region will be used. +*@li data_format: A string, format of input data. + +*@par Outputs: +*y: The average pooled output tensor. + +*@attention Constraints: +*@li "ksize" is in the range [1, 255]. "strides" is in the range [1, 63] + +*@par Third-party framework compatibility +* Compatible with the TensorFlow operator AvgPool3D. +*/ +REG_OP(AvgPool3D) + .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT32, DT_DOUBLE})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT32, DT_DOUBLE})) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(ceil_mode, Bool, false) + .ATTR(count_include_pad, Bool, true) + .ATTR(divisor_override, Int, 0) + .ATTR(data_format, String, "NDHWC") + .OP_END_FACTORY_REG(AvgPool3D) + +/** *@brief Performs max_pool_ext2 on the input. *@par Inputs: @@ -184,17 +220,62 @@ REG_OP(MaxPool) .OP_END_FACTORY_REG(MaxPool) REG_OP(MaxPool3D) - .INPUT(x, TensorType({DT_FLOAT16})) - .OUTPUT(y, TensorType({DT_FLOAT16})) + .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT32, DT_DOUBLE})) + .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT32, DT_DOUBLE})) .REQUIRED_ATTR(ksize, ListInt) .REQUIRED_ATTR(strides, ListInt) .REQUIRED_ATTR(padding, String) .ATTR(pads, ListInt, {0,0,0}) - .ATTR(dilation, ListInt, {0,0,0}) + .ATTR(dilation, ListInt, {1,1,1}) .ATTR(ceil_mode, Int, 0) .ATTR(data_format, String, "NDHWC") .OP_END_FACTORY_REG(MaxPool3D) + +/** +* @brief Computes second-order gradients of the maxpooling3d function. + +* @par Inputs: +* @li orig_x: Original forward input tensor(NDC1HWC0) of type float16 +* @li orig_y: Original forward output tensor(NDC1HWC0) of type float16 +* @li grads: Gradient tensor(NDC1HWC0) of type float16 +* @li assist: Assist tensor(NDC1HWC0) of type float16 + +* @par Attributes: +* @li ksize: A required list or tuple, +* specifying the size of the sliding window. +* @li strides: A required list or tuple, +* specifying the stride of the sliding window. +* @li pads: A required list or tuple +* @li padding: A required string, window sliding mode. Either SAME or VALID. +* @li data_format: An optional string. +* Format of the original input, either NCDHW or NDHWC. Defaults to NDHWC. + +* @attention Constraints: +* @li Only the Ascend 910 platform is supported. +* @li "orig_x" and "grads" must have the same shape. +* @li "orig_y" and "y" must have the same shape. Otherwise, an error is reported. +* @li "orig_x", "orig_y", "grads", and "y" must be NDC1HWC0 tensors. + +* @par Outputs: +* @li y: Result tensor of type float16 + +* @par Third-party framework compatibility +* @li Compatible with the TensorFlow operator MaxPool3DGradGrad. +*/ + +REG_OP(MaxPool3DGradGrad) + .INPUT(orig_x, TensorType::RealNumberType()) + .INPUT(orig_y, TensorType::RealNumberType()) + .INPUT(grads, TensorType::RealNumberType()) + .OUTPUT(y, TensorType::RealNumberType()) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(data_format, String, "NDHWC") + .OP_END_FACTORY_REG(MaxPool3DGradGrad) + + /** * @brief Computes gradients of the maxpooling function. @@ -239,9 +320,10 @@ REG_OP(MaxPoolGrad) * @brief Computes second-order gradients of the maxpooling function. * @par Inputs: -* @li x1: Original forward input tensor of type RealNumberType -* @li x2: Original forward output tensor of type RealNumberType -* @li grad: Gradient tensor of type RealNumberType +* @li x1: Original forward input tensor. Supported type:float, double, int32, + * uint8, int16, int8, int64, uint16, half, uint32, uint64. +* @li x2: Has the same type and format as input "x1". +* @li grad:Has the same type and format as input "x1". * @par Attributes: * @li ksize: A required list or tuple, @@ -262,7 +344,7 @@ REG_OP(MaxPoolGrad) * @li Other dimensions of ksize and strides is 1. * @par Outputs: -* @li y: Result tensor of type RealNumberType +* @li y: Has the same type and format as input "x1". * @par Third-party framework compatibility * @li Compatible with the TensorFlow operator MaxPoolGradGrad. @@ -398,18 +480,55 @@ REG_OP(MaxPoolGradWithArgmax) .OP_END_FACTORY_REG(MaxPoolGradWithArgmax) /** +*@brief Performs transform mask to argmax. + +*@par Inputs: +* Two input: +*x: An NC1HWC0 Tensor of type float16. +*mask: An NC1HWC0 Tensor of type uint16. + +*@par Attributes: +*@li ksize: A required list of int8, int16, int32, or int64 values, specifying the size of the window for each dimension of the input tensor. No default value. +*@li strides: A required list of int8, int16, int32, or int64 values, specifying the stride of the sliding window for each dimension of the input tensor. No default value. +*@li padding: A required string. No default value. + +*@par Outputs: +*argmax: An NC1HWC0 Tensor of type int32. + +*@attention Constraints: +*@li "ksize" is a list that has length 4: ksize[0] = 1 or ksize[3] = 1, ksize[1] * ksize[2] <= 255. +*@li "stride is a list that has length 4: strides[0] = 1 or strides[3] = 1, strides[1] <= 63, strides[0] >= 1, strides[2] <= 63, strides[2] >= 1. +*@li "padding" is either "SAME" or "VALID". + +*@par Third-party framework compatibility +* Compatible with the TensorFlow operator Mask2Argmax. +*/ +REG_OP(Mask2Argmax) + .INPUT(x, TensorType::RealNumberType()) + .INPUT(mask, TensorType::IndexNumberType()) + .OUTPUT(argmax, TensorType::IndexNumberType()) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(padding, String) + .REQUIRED_ATTR(originshape, ListInt) + .OP_END_FACTORY_REG(Mask2Argmax) + +/** * @brief Computes second-order gradients of the maxpooling function. * @par Inputs: -* @li x: Original forward input tensor of type RealNumberType -* @li grad: Gradient tensor of type RealNumberType -* @li argmax: An tensor of type IndexNumberType +* @li x: Original forward input tensor. Supported type: float, double, int32, + * uint8, int16, int8, int64, uint16, half, uint32, uint64. +* @li grad: Gradient tensor. Supported type: float, double, int32, + * uint8, int16, int8, int64, uint16, half, uint32, uint64. +* @li argmax: An tensor of type int32 or int64. * @par Attributes: * @li ksize: A required list, specifying the size of the sliding window. * @li strides: A required list, specifying the stride of the sliding window. * @li padding: A required string, window sliding mode. Either SAME or VALID. * @par Outputs: -* @li y:Result tensor of type RealNumberType +* @li y:Result tensor. Supported type: float, double, int32, + * uint8, int16, int8, int64, uint16, half, uint32, uint64 * @attention Constraints: * @li Only the cloud platform is supported. @@ -495,35 +614,7 @@ REG_OP(AvgPoolGradD) .OP_END_FACTORY_REG(AvgPoolGradD) -REG_OP(MaxPoolWithArgmaxCCE) - .INPUT(x, TensorType::ALL()) - .OUTPUT(y, TensorType::ALL()) - .OUTPUT(argmax, TensorType::ALL()) - .ATTR(mode, Int, 0) - .ATTR(pad_mode, Int, 0) - .ATTR(window, ListInt, {1,1}) - .ATTR(stride, ListInt, {1,1}) - .ATTR(pad, ListInt, {0,0,0,0}) - .ATTR(ceil_mode, Int, 0) - .ATTR(data_mode, Int, 1) - .ATTR(nan_opt, Int, 0) - .OP_END_FACTORY_REG(MaxPoolWithArgmaxCCE) - -REG_OP(MaxPoolGradWithArgmaxCCE) - .INPUT(x, TensorType::ALL()) - .INPUT(grad,TensorType::ALL()) - .INPUT(arg,TensorType::ALL()) - .OUTPUT(output,TensorType::ALL()) - .ATTR(mode, Int, 0) - .ATTR(max_pool_grad_output_shape, ListInt, {0,0,0,0}) - .ATTR(pad_mode, Int, 0) - .ATTR(window, ListInt, {1,1}) - .ATTR(stride, ListInt, {1,1}) - .ATTR(pad, ListInt, {0,0,0,0}) - .ATTR(ceil_mode, Int, 0) - .ATTR(data_mode, Int, 1) - .ATTR(nan_opt, Int, 0) - .OP_END_FACTORY_REG(MaxPoolGradWithArgmaxCCE) + /** *@brief :upsample the layer @@ -531,7 +622,7 @@ REG_OP(MaxPoolGradWithArgmaxCCE) * one input, including: *@li x: A tensor of type float16 or float32. *@par Attributes: -*@li scale: A optional float, scale factor of x. Defaults to "1.0". +*@li scale: A optional float32, scale factor of x. Defaults to "1.0". *@li stride_h: An optional int32, broadcast the axis of h. Defaults to "2". *@li stride_w: An optional int32, broadcast the axis of w. Defaults to "2". *@par Outputs: @@ -749,7 +840,186 @@ REG_OP(DataFormatVecPermute) .ATTR(dst_format, String, "NCHW") .OP_END_FACTORY_REG(DataFormatVecPermute) +/** +* @brief Computes gradients of the MaxPool3D function. + +* @par Inputs: +* @li orig_x: A mutable NDC1HWC0 tensor of type float16. +* @li orig_y: A mutable NDC1HWC0 tensor of type float16. +* @li grads: A mutable NDC1HWC0 tensor of type float16. +* @par Attributes: +* @li ksize: A required tuple or list, specifying the size of the window for +* each dimension of the input tensor. +* @li strides: A required tuple or list, specifying the stride of the sliding +* window for each dimension of the input tensor. +* @li pads: A list of 6 ints. Supports only padding along the D, +* H and W dimensions in sequence of head, tail, top, bottom, left and right. +* to use. +* @li data_format: An optional string, Specify the data format of the input and +* output data. With the default format "NDHWC". + +* @par Outputs: +* y: A mutable tensor. Has the same shape as "orig_x", but type is float32. + +* @par Third-party framework compatibility +* Compatible with the TensorFlow operator MaxPool3DGrad. +*/ +REG_OP(MaxPool3DGrad) + .INPUT(orig_x, TensorType::RealNumberType()) + .INPUT(orig_y, TensorType::RealNumberType()) + .INPUT(grads, TensorType::RealNumberType()) + .OUTPUT(y, TensorType::RealNumberType()) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(data_format, String, "NDHWC") + .OP_END_FACTORY_REG(MaxPool3DGrad) + +/** +*@brief Performs AvgPool1D on the input. + +*@par Inputs: +*x: A Tensor. Must be one of the following types: int8, uint8, int16, int32, int64, float16, float32, float64. + +*@par Attributes: +*@li ksize: An required int, specifying the size of the window. +*@li strides: An required int. +*@li pads: A required tuple or list. +*@li ceil_mode: An optional bool. Defaults to False. +*@li count_include_pad: An optional bool. Defaults to False. + +*@par Outputs: +*y: A Tensor. Has the same type as x. + +*@par Third-party framework compatibility +*@li compatible with pytorch AvgPool1D operator. +*/ +REG_OP(AvgPool1D) + .INPUT(x, TensorType({DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .OUTPUT(y, TensorType({DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .REQUIRED_ATTR(ksize, Int) + .REQUIRED_ATTR(strides, Int) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(ceil_mode, Bool, false) + .ATTR(count_include_pad, Bool, false) + .OP_END_FACTORY_REG(AvgPool1D) + +/** +*@brief Performs AvgPool1D on the input. + +*@par Inputs: +*x: A Tensor. Must be one of the following types: int8, uint8, int16, int32, int64, float16, float32, float64. + +*@par Attributes: +*@li ksize: An required int, specifying the size of the window. +*@li strides: An required int. +*@li pads: A required tuple or list. +*@li ceil_mode: An optional bool. Defaults to False. +*@li count_include_pad: An optional bool. Defaults to False. + +*@par Outputs: +*y: A Tensor. Has the same type as x. + +*@par Third-party framework compatibility +*@li compatible with pytorch AvgPool1D operator. +*/ +REG_OP(AvgPool1DD) + .INPUT(x, TensorType({DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .INPUT(assist_matrix, TensorType({DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .OUTPUT(y, TensorType({DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_INT64, DT_FLOAT16, DT_FLOAT, DT_DOUBLE})) + .REQUIRED_ATTR(ksize, Int) + .REQUIRED_ATTR(strides, Int) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(ceil_mode, Bool, false) + .ATTR(count_include_pad, Bool, false) + .OP_END_FACTORY_REG(AvgPool1DD) +/** +*@brief Performs max pooling on the input and outputs both max values and indices. + +*@par Inputs: +* One input: +*x: An NC1HWC0 Tensor of type float16. +*@par Attributes: +*@li ksize: A required list of int8, int16, int32, or int64 values, specifying the size of the window for +* each dimension of the input tensor. No default value. +*@li strides: A required list of int8, int16, int32, or int64 values, specifying the stride of the sliding window for +* each dimension of the input tensor. No default value. +*@li pads: A required string. No default value. +*@li dtype: A optional int. default value is 3. +*@li dilation: A optional list of int8, int16, int32, or int64 values. +*@li ceil_mode: A optional bool. default value is false. + +*@par Outputs: +*y: A Tensor. Has the same type and format as input "x". +*argmax: A Tensor. type:uint16, format:NC1HWC0. +*@attention Constraints: +*@li "ksize" is a list that has length 4: ksize[0] = 1 or ksize[3] = 1, ksize[1] * ksize[2] <= 255. +*@li "strides is a list that has length 4: strides[0] = 1 or strides[3] = 1, strides[1] <= 63, strides[0] >= 1, +* strides[2] <= 63, strides[2] >= 1. +*@li "dilation" is a list that has length 4. +*@li "ceil_mode" is a bool, default is false. + +*@par Third-party framework compatibility +* Compatible with the TensorFlow operator MaxPoolWithArgmax. +*/ +REG_OP(MaxPoolWithArgmaxV2) + .INPUT(x, TensorType({DT_FLOAT16})) + .OUTPUT(y, TensorType({DT_FLOAT16})) + .OUTPUT(argmax, TensorType({DT_UINT16})) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(dtype, Int, 3) + .ATTR(dilation, ListInt, {1, 1, 1, 1}) + .ATTR(ceil_mode, Bool, false) + .OP_END_FACTORY_REG(MaxPoolWithArgmaxV2) + +/** +*@brief Performs the backpropagation of MaxPoolWithArgmaxV2. + +*@par Inputs: +* Three inputs, including: +*@li x: An NC1HWC0 tensor of type float16. +*@li grad: An NC1HWC0 tensor of type float16. +*@li argmx: An NC1HWC0 tensor of type uint16 or int64. + +*@par Attributes: +*@li ksize: A required list of int8, int16, int32, or int64 values, specifying the size of the window for + * each dimension of the input tensor. No default value. +*@li strides: A required list of int8, int16, int32, or int64 values, specifying the stride of the sliding window for + * each dimension of the input tensor. No default value. +*@li pads: A required string. No default value. +*@li dtype: A optional int. default value is 3. +*@li dilation: A optional list of int8, int16, int32, or int64 values. +*@li ceil_mode: A optional bool. default value is false. + +*@par Outputs: +*y: A Tensor. Has the same type and format as input "x". + +*@attention Constraints: +*@li "ksize" is a list that has length 4: ksize[0] = 1 or ksize[3] = 1, ksize[1] * ksize[2] <= 255. +*@li "strides" is a list that has length 4: strides[0] = 1 or strides[3] = 1 +*@li "dilation" is a list that has length 4. +*@li "ceil_mode" is a bool, default is false. + +*@see max_pool_grad_with_argmaxv2 +*@par Third-party framework compatibility +* Compatible with the TensorFlow operator MaxPoolGradWithArgmaxV2. +*/ + +REG_OP(MaxPoolGradWithArgmaxV2) + .INPUT(x, TensorType({DT_FLOAT16})) + .INPUT(grad, TensorType({DT_FLOAT16})) + .INPUT(argmax, TensorType({DT_UINT16})) + .OUTPUT(y, TensorType({DT_FLOAT16})) + .REQUIRED_ATTR(ksize, ListInt) + .REQUIRED_ATTR(strides, ListInt) + .REQUIRED_ATTR(pads, ListInt) + .ATTR(dtype, Int, 3) + .ATTR(dilation, ListInt, {1,1,1,1}) + .ATTR(ceil_mode, Bool, false) + .OP_END_FACTORY_REG(MaxPoolGradWithArgmaxV2) } // namespace ge #endif // GE_OP_NN_POOLING_OPS_H diff --git a/third_party/fwkacllib/inc/ops/nn_training_ops.h b/third_party/fwkacllib/inc/ops/nn_training_ops.h index 1c9aa516..cc17103c 100644 --- a/third_party/fwkacllib/inc/ops/nn_training_ops.h +++ b/third_party/fwkacllib/inc/ops/nn_training_ops.h @@ -307,16 +307,6 @@ REG_OP(ApplyMomentum) .ATTR(use_locking, Bool, false) .OP_END_FACTORY_REG(ApplyMomentum) -REG_OP(ApplyMomentumCCE) - .INPUT(var, TensorType::NumberType()) - .INPUT(accum, TensorType::NumberType()) - .INPUT(lr, TensorType::NumberType()) - .INPUT(grad, TensorType::NumberType()) - .INPUT(momentum, TensorType::NumberType()) - .OUTPUT(var, TensorType::NumberType()) - .ATTR(use_nesterov, Bool, false) - .ATTR(use_locking, Bool, false) - .OP_END_FACTORY_REG(ApplyMomentumCCE) /** *@brief Updates "var" according to the momentum scheme. Set use_nesterov = True if you @@ -1508,7 +1498,7 @@ REG_OP(ApplyProximalAdagradD) *@par Attributes: *use_locking: An optional bool. Defaults to "False".\n * If "True", updating of the var and accum tensors will be protected by a lock; \n -* If "False", the behavior is undefined, but may exhibit less contention. +* If "False", the behavior is undefined, but may exhibit less contention. *@par Outputs: *var: A mutable Tensor. Has the same type as "var". diff --git a/third_party/fwkacllib/inc/ops/nonlinear_fuc_ops.h b/third_party/fwkacllib/inc/ops/nonlinear_fuc_ops.h index 1405fdb7..a01073cf 100644 --- a/third_party/fwkacllib/inc/ops/nonlinear_fuc_ops.h +++ b/third_party/fwkacllib/inc/ops/nonlinear_fuc_ops.h @@ -83,7 +83,7 @@ REG_OP(TanhGrad) *@par Inputs: *One input: -*x: A Tensor. Must be one of the following types: float16, float32, complex64, complex128, int32, int64 +*x: A Tensor. Must be one of the following types: float16, float32, complex64, complex128, double. *@par Outputs: *y: A Tensor. Has the same type as "x". @@ -184,7 +184,7 @@ REG_OP(Relu6Grad) * @brief Compute sigmoid of "x" element-wise. * @par Inputs: -* A Tensor of type UnaryDataType. +* A Tensor of type complex64, complex128, float16, float32 or double. * @par Outputs: * A Tensor. Has the same type as "x". @@ -220,7 +220,7 @@ REG_OP(SigmoidGrad) *if x>0, x+log(1+exp(-x)); otherwise log(1+exp(x)). *@par Inputs: -*x: A Tensor of type float16 or float32. +*x: A Tensor of type double, float16 or float32. *@par Outputs: *y: A tensor. Has the same type and format as input "x". @@ -442,7 +442,7 @@ REG_OP(PReluGrad) *x: A float16, float32 or double, for the input data type. *@par Attributes: -*alpha: A float. Defines at which negative value the ELU saturates. Defaults to "1.0". +*alpha: A float32. Defines at which negative value the ELU saturates. Defaults to "1.0". *@par Outputs: *y: A float16, float32 or double, for the normalized result. diff --git a/third_party/fwkacllib/inc/ops/reduce_ops.h b/third_party/fwkacllib/inc/ops/reduce_ops.h index 8819d2d5..8cf9f342 100644 --- a/third_party/fwkacllib/inc/ops/reduce_ops.h +++ b/third_party/fwkacllib/inc/ops/reduce_ops.h @@ -673,7 +673,7 @@ REG_OP(ReduceAnyD) *@par Attributes: *@li operation: An optional int32 from 1(SUM), 2(ASUM), 3(SUMSQ), and 4(MEAN), -*specifying the reduction algorithm. Defaults to 1. +*specifying the reduction algorithm. Defaults to "1". *@li axis: An optional int32, specifying the first axis to reduce. Defaults to "0". *The value range is [-N, N-1], where N is the input tensor rank. *@li coeff: An optional float32, specifying the scale coefficient. Defaults to "1.0". @@ -745,7 +745,190 @@ REG_OP(EuclideanNormD) .ATTR(keep_dims, Bool, false) .OP_END_FACTORY_REG(EuclideanNormD) -} //namespace ge +/** +*@brief Performs instance normalization for inference. + +*@par Inputs:\n +* Five inputs, including: (NC1HWC0 supported) +*@li x: A Tensor of type float16 or float32. +*@li gamma: A [N, C1, 1, 1, C0] Tensor of type float32, for the scaling gamma. +*@li beta: A [N, C1, 1, 1, C0] Tensor of type float32, for the scaling beta. +*@li mean: A [N, C1, 1, 1, C0] ensor of type float32, for the mean. +*@li variance: A [N, C1, 1, 1, C0] Tensor of type float32, for the variance. + +*@par Attributes: +*epsilon: An optional float32, specifying the small value added to variance to avoid dividing by zero. +Defaults to "0.00001". + +*@par Outputs:\n +*y: A Tensor of type float16 or float32 for the normalized "x". +*batch_mean: A Tensor of type float32 for the result mean. +*batch_ variance: A Tensor of type float32 for the result variance. + +*@attention Constraints: +*For Ascend 310, the result accuracy fails to reach 1‰ due to the square root instruction. +*/ +REG_OP(INInferV2) + .INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .OPTIONAL_INPUT(gamma, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(beta, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(mean, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(variance, TensorType({DT_FLOAT})) + .ATTR(epsilon, Float, 0.00001) + .OUTPUT(y, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(batch_mean, TensorType({DT_FLOAT})) + .OUTPUT(batch_variance, TensorType({DT_FLOAT})) + .OP_END_FACTORY_REG(INInferV2) + +/** +*@brief Performs reduced instance normalization. + +*@par Inputs:\n +*x: A Tensor of type float16 or float32, with format NC1HWC0. + +*@par Outputs: +*@li sum: A Tensor of type float32 for SUM reduced "x". +*@li square_sum: A Tensor of type float32 for SUMSQ reduced "x". + +*@attention Constraints:\n +* This operator is a InstanceNorm fusion operator for updating the moving averages for training. \n +* This operator is used in conjunction with INTrainingUpdateV2. +*/ +REG_OP(INTrainingReduceV2) + .INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(sum, TensorType({DT_FLOAT})) + .OUTPUT(square_sum, TensorType({DT_FLOAT})) + .OP_END_FACTORY_REG(INTrainingReduceV2) + + +/** +*@brief Performs update instance normalization. + +*@par Inputs:\n +* Seven inputs, including: (NC1HWC0supported) +*@li x: A Tensor of type float16 or float32. +*@li sum: A T [N, C1, 1, 1, C0] ensor of type float32 for the output of operator INTrainingReduceV2. +*@li square_sum: A [N, C1, 1, 1, C0] Tensor of type float32 for the output of operator INTrainingReduceV2. +*@li gamma: A [N, C1, 1, 1, C0] Tensor of type float32, for the scaling gamma. +*@li beta: A [N, C1, 1, 1, C0] Tensor of type float32, for the scaling beta. +*@li mean: A [N, C1, 1, 1, C0] Tensor of type float32, for the updated mean. +*@li variance: A [N, C1, 1, 1, C0] Tensor of type float32, for the updated variance. + +*@par Attributes: +*@li momentum: A required float32, specifying the momentum to update mean and var. +*@li epsilon: A required float32, specifying the small value added to variance to avoid dividing by zero. + +*@par Outputs:\n +* Three outputs, including: (NC1HWC0 supported) +*@li y: A Tensor of type float16 or float32, for normalized "x". +*@li batch_mean: A Tensor of type float32, for the updated mean. +*@li batch_variance: A Tensor of type float32, for the updated variance. + +*@attention Constraints: +*@li This operator is a InstanceNorm fusion operator for updating the moving averages for training. \n +* This operator is used in conjunction with INTrainingReduceV2. +*@li For Ascend 310, the result accuracy fails to reach 1‰ due to the square root instruction. +*/ +REG_OP(INTrainingUpdateV2) + .INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(sum, TensorType({DT_FLOAT})) + .INPUT(square_sum, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(gamma, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(beta, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(mean, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(variance, TensorType({DT_FLOAT})) + .ATTR(momentum, Float, 0.1) + .ATTR(epsilon, Float, 0.00001) + .OUTPUT(y, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(batch_mean, TensorType({DT_FLOAT})) + .OUTPUT(batch_variance, TensorType({DT_FLOAT})) + .OP_END_FACTORY_REG(INTrainingUpdateV2) + + +/** +*@brief Performs reduced group normalization. + +*@par Inputs:\n +*x: A Tensor of type float16 or float32, with format NCHW NHWC. + +*@par Outputs: +*@li sum: A Tensor of type float32 for SUM reduced "x". +*@li square_sum: A Tensor of type float32 for SUMSQ reduced "x". + + +*@par Attributes: +*@li num_groups: Int, specifying the num of groups. required, same to GNTrainingUpdate. + +*@attention Constraints:\n +* This operator is a GroupNorm fusion operator for updating the moving averages for training. \n +* This operator is used in conjunction with GNTrainingUpdate. +*/ +REG_OP(GNTrainingReduce) + .INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(sum, TensorType({DT_FLOAT})) + .OUTPUT(square_sum, TensorType({DT_FLOAT})) + .ATTR(num_groups, Int, 2) + .OP_END_FACTORY_REG(GNTrainingReduce) + + +/** +*@brief Performs update group normalization. + +*@par Inputs:\n +* Eight inputs, including: (NCHW NHWC supported) +*@li x: A Tensor of type float16 or float32. +*@li sum: A 5D Tensor of type float32, +shape is [N, G, 1, 1, 1] for NCHW, [N, 1, 1, G, 1] for NHWC +for the output of operator GNTrainingReduce. +*@li square_sum: A 5D Tensor of type float32, +shape is [N, G, 1, 1, 1] for NCHW, [N, 1, 1, G, 1] for NHWC +for the output of operator GNTrainingReduce. +*@li scale: A 5D Tensor of type float32, +shape is [1, G, 1, 1, 1] for NCHW, [1, 1, 1, G, 1] for NHWC +is for the scaling gamma. +*@li offset: A 5D Tensor of type float32, +shape is [1, G, 1, 1, 1] for NCHW, [1, 1, 1, G, 1] for NHWC +for the scaling beta. +*@li mean: A 5D Tensor of type float32, +shape is [N, G, 1, 1, 1] for NCHW, [N, 1, 1, G, 1] for NHWC +for the updated mean. +*@li variance: A 5D Tensor of type float32, +shape is [N, G, 1, 1, 1] for NCHW, [N, 1, 1, G, 1] for NHWC +for the updated variance. + + +*@par Attributes: +*@li epsilon: A float32, specifying the small value added to variance to avoid dividing by zero. +*@li num_groups: Int, specifying the num of groups. required, same to GNTrainingReduce + +*@par Outputs:\n +* Three outputs, including: (NC1HWC0 supported) +*@li y: A Tensor of type float16 or float32, for normalized "x". +*@li batch_mean: A Tensor of type float32, for the updated mean. +*@li batch_variance: A Tensor of type float32, for the updated variance. + +*@attention Constraints: +*@li This operator is a InstanceNorm fusion operator for updating the moving averages for training. \n +* This operator is used in conjunction with GNTrainingUpdate. +*@li For Ascend 310, the result accuracy fails to reach 1‰ due to the square root instruction. +*/ +REG_OP(GNTrainingUpdate) + .INPUT(x, TensorType({DT_FLOAT16,DT_FLOAT})) + .INPUT(sum, TensorType({DT_FLOAT})) + .INPUT(square_sum, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(scale, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(offset, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(mean, TensorType({DT_FLOAT})) + .OPTIONAL_INPUT(variance, TensorType({DT_FLOAT})) + .ATTR(num_groups, Int, 2) + .ATTR(epsilon, Float, 0.0001) + .OUTPUT(y, TensorType({DT_FLOAT16,DT_FLOAT})) + .OUTPUT(batch_mean, TensorType({DT_FLOAT})) + .OUTPUT(batch_variance, TensorType({DT_FLOAT})) + .OP_END_FACTORY_REG(GNTrainingUpdate) + +} //namespace ge + #endif /* GE_OP_REDUCE_OPS_H */ diff --git a/third_party/fwkacllib/inc/ops/rnn.h b/third_party/fwkacllib/inc/ops/rnn.h index c4d64b0a..b72d9a79 100644 --- a/third_party/fwkacllib/inc/ops/rnn.h +++ b/third_party/fwkacllib/inc/ops/rnn.h @@ -67,6 +67,13 @@ REG_OP(BasicLSTMCell) .ATTR(activation, String, "tanh") .OP_END_FACTORY_REG(BasicLSTMCell) +REG_OP(DynamicLSTM) + .INPUT(x, TensorType({DT_FLOAT32})) + .INPUT(w, TensorType({DT_FLOAT32})) + .INPUT(b, TensorType({DT_FLOAT32})) + .OUTPUT(output_h, TensorType({DT_FLOAT32})) + .OP_END_FACTORY_REG(DynamicLSTM) + /** *@brief: Basic LSTM Cell backward calculation.Calculate the gradient of input and hidden state. *@par Inputs: @@ -87,7 +94,7 @@ REG_OP(BasicLSTMCellInputGrad) .INPUT(dgate, TensorType({DT_FLOAT16})) .INPUT(w, TensorType({DT_FLOAT16})) .OPTIONAL_INPUT(dropout_mask, TensorType({DT_UINT8})) - .OUTPUT(dxt, TensorType({DT_FLOAT16})) + .OUTPUT(dxt, TensorType({DT_FLOAT16, DT_FLOAT32})) .OUTPUT(dht, TensorType({DT_FLOAT16, DT_FLOAT32})) .ATTR(keep_prob, Float, 1.0) .OP_END_FACTORY_REG(BasicLSTMCellInputGrad) diff --git a/third_party/fwkacllib/inc/ops/selection_ops.h b/third_party/fwkacllib/inc/ops/selection_ops.h index aafcece0..c2e6f13a 100644 --- a/third_party/fwkacllib/inc/ops/selection_ops.h +++ b/third_party/fwkacllib/inc/ops/selection_ops.h @@ -89,7 +89,8 @@ REG_OP(RangeD) *@par Inputs: *Two inputs, including: -* @li x: A Tensor of type TensorType::BasicType(). +* @li x: A Tensor. +* Must be one of the following types: float16, float32, double, int64, int32, uint8, uint16, uint32, uint64, int8, int16, complex64, complex128, qint8, quint8, qint16, quint16, qint32. * @li multiples: A 1D Tensor of type int32 or int64. * The length must be the same as the number of dimensions in "input" @@ -496,7 +497,7 @@ REG_OP(UnsortedSegmentSumD) *@par Inputs: * Two inputs, including:\n *@li x: An ND Tensor (up to 8D). \n -*Must be one of the following types: int8, uint8, int16, uint16, int32, int64, bool, float32, double +*Must be one of the following types: int8, uint8, int16, uint16, int32, int64, bool, float16, float32, double, complex64, complex128, string. *@li axis: A 1D Tensor.\n *Must be one of the following types: int32, int64 @@ -1003,9 +1004,8 @@ REG_OP(StridedSliceAssign) * @par Inputs: * Two inputs, including: -* @li var: A mutable ND Tensor of type BasicType. -* @li input_value: A mutable ND "Tensor" of type BasicType. - +* @li var: A mutable ND Tensor of the following types:int32, int16, float16, float32. +* @li input_value: A mutable ND "Tensor" of the following types:int32, int16, float16, float32. * @par Attributes: * @li begin: A required list of ints. @@ -1029,9 +1029,9 @@ REG_OP(StridedSliceAssign) * @see StridedSlice() */ REG_OP(StridedSliceAssignD) - .INPUT(var, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32})) - .INPUT(input_value, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32})) - .OUTPUT(var, TensorType(BasicType)) + .INPUT(var, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT16})) + .INPUT(input_value, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT16})) + .OUTPUT(var, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT16})) .REQUIRED_ATTR(begin, ListInt) .REQUIRED_ATTR(end, ListInt) .REQUIRED_ATTR(strides, ListInt) @@ -1396,24 +1396,23 @@ REG_OP(UnsortedSegmentMin) * @brief Computes the minimum along segments of a tensor. * @par Inputs: -* Three inputs, including: -* @li x: A Tensor of type RealNumberType. -* @li segment_ids: A 1D Tensor of type IndexNumberType, whose shape is a prefix +* Two inputs, including: +* @li x: A Tensor of the following types:int32, int16, float16, float32. +* @li segment_ids: A 1D Tensor of type int32, whose shape is a prefix * of "x.shape". -* @li k: A Tensor. * @par Attributes: * num_segments: A required int32, specifying the number of distinct segment IDs. * @par Outputs: -* y: A Tensor of type RealNumberType. +* y: A Tensor.Must have the same type as input "x". * @see UnsortedSegmentProdD(), */ REG_OP(UnsortedSegmentMinD) - .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32})) + .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) .INPUT(segment_ids, TensorType({DT_INT32})) - .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32})) + .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) .REQUIRED_ATTR(num_segments, Int) .OP_END_FACTORY_REG(UnsortedSegmentMinD) @@ -1446,24 +1445,23 @@ REG_OP(UnsortedSegmentProd) * @brief Computes the product along segments of a tensor. * @par Inputs: -* Three inputs, including: -* @li x: A Tensor of type RealNumberType. -* @li segment_ids: A 1D Tensor of type IndexNumberType, whose shape is a prefix +* Two inputs, including: +* @li x: A Tensor of the following types:int32, int16, float16, float32. +* @li segment_ids: A 1D Tensor of type int32, whose shape is a prefix * of "x.shape". -* @li k: A Tensor. * @par Attributes: * num_segments: An int32, specifying the number of distinct segment IDs. * @par Outputs: -* y: A Tensor of type RealNumberType. +* y: A Tensor.Must have the same type as input "x". * @see UnsortedSegmentMinD() */ REG_OP(UnsortedSegmentProdD) - .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32})) + .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) .INPUT(segment_ids, TensorType({DT_INT32})) - .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32})) + .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_INT32, DT_INT16})) .REQUIRED_ATTR(num_segments, Int) .OP_END_FACTORY_REG(UnsortedSegmentProdD) @@ -1559,14 +1557,14 @@ REG_OP(ProposalD) * If reverse=false: (N, H, W, C)->(N, H/stride, W/stride, C*(stride*stride)) *@par Inputs: -*x: An (N, H, W, C) tensor. All types except double are supported. +*x: An (N, H, W, C) tensor. Type is float16, float32, int8, uint8, int16, uint16, int32, uint32, int64 or uint64.. *@par Attributes: *@li stride: An optional int32, specifying the plane or channel scaling factor. Defaults to "2". *@li reverse: An optional bool, specifying the conversion mode. If "true", depth to space conversion is performed. If "false", space to depth conversion is performed. Defaults to "false". *@par Outputs: -*y: An (N, H, W, C) tensor. All types except double are supported. +*y: An (N, H, W, C) tensor. Has same type as "x". *@attention Constraints: *@li If reverse=true: C/(stride*stride) yields an integer result. If reverse=false: W/stride and H/stride yield integer results. @@ -1593,7 +1591,7 @@ REG_OP(PassThrough) * @li x: A required Tensor. Must be one of the following types: float16, float32, int8, uint8, int16, uint16, int32, uint32,int64, uint64. * @li size: A required Tensor. Must be one of the following types: float16, float32, int8, uint8, int16, uint16, int32, uint32, int64, uint64. *@par Attributes: -*@li axis: A required int32, specifying the first dimension to crop. +*@li axis: A required int32, specifying the first dimension to crop. Defaults to "2". *@li offset: A required array, specifying the shift for all/each dimension to align the cropped bottom with the reference bottom. Must be one of the following types: float16, float32, int8, uint8, int16, uint16, int32, uint32, int64, uint64. *@par Outputs: *y: A required Tensor. Has the same type and shape as "size". @@ -1774,6 +1772,6 @@ REG_OP(CumulativeLogsumexpD) .ATTR(exclusive, Bool, false) .ATTR(reverse, Bool, false) .OP_END_FACTORY_REG(CumulativeLogsumexpD) - } // namespace ge + #endif // GE_OP_SELECTION_OPS_H diff --git a/third_party/fwkacllib/inc/ops/split_combination_ops.h b/third_party/fwkacllib/inc/ops/split_combination_ops.h index 700d34b7..7e4428d0 100644 --- a/third_party/fwkacllib/inc/ops/split_combination_ops.h +++ b/third_party/fwkacllib/inc/ops/split_combination_ops.h @@ -25,11 +25,11 @@ namespace ge { *@par Inputs: * Two inputs, including: *@li x: An ND Tensor. -*Must be one of the following types: float16, float32, int32, int8, int16, int64, uint8, uint16, uint32, uint64 +*Must be one of the types:float16, float32, double, int64, int32, uint8, uint16, uint32, uint64, int8, int16, complex64, complex128, qint8, quint8, qint16, quint16, qint32. *@li split_dim: Must be the following type:int32. Specifies the dimension along which to split. *@par Attributes: -*num_split: A required int8, int16, int32, or int64. Specifies the number of output tensors. No default value. +*num_split: A required int32. Specifies the number of output tensors. No default value. *@par Outputs: *y: Dynamic output.A list of output tensors. Has the same type and format as "x". @@ -186,6 +186,7 @@ REG_OP(ParallelConcat) *@par Attributes: *concat_dim: A required int8, int16, int32, or int64. Specifies the dimension along which to concatenate. No default value. +*N: An attribute int8, int16, int32, or int64. Specifies the number of elements in "x". Defaults to "1". *@par Outputs: *y: A Tensor. Has the same type and format as "x". @@ -267,7 +268,9 @@ REG_OP(ConcatD) *@par Inputs: * Two inputs, including: *@li x: Dynamic input.An NC1HWC0 or ND Tensor. -*Must be one of the following types: float16, float32, int32, int8, int16, int64, uint8, uint16, uint32, uint64 +*Must be one of the following types: float16, float32, double, int32, +* uint8, int16, int8, complex64, int64, qint8, quint8, qint32, uint16, +* complex128, uint32, uint64, qint16, quint16. *@li concat_dim: An int32, or int64. Specifies the dimension along which to concatenate. *@par Attributes: diff --git a/third_party/fwkacllib/inc/ops/transformation_ops.h b/third_party/fwkacllib/inc/ops/transformation_ops.h index 69951da9..5bbf1e78 100644 --- a/third_party/fwkacllib/inc/ops/transformation_ops.h +++ b/third_party/fwkacllib/inc/ops/transformation_ops.h @@ -21,6 +21,35 @@ namespace ge { /** +*@brief This operation convert output dataType and shape + +*@par Inputs: +*The input handle must have the resource type. Inputs include: \n +*@li x:A list of Tensor objects. One or more tensors from which \n +the enqueued tensors should be taken. + +*@par Outputs: +*@li y:A list of Tensor objects. One or more tensors from which \n +the enqueued tensors should be taken. + +*@par Attributes: +*@li type: An optional ge::DataType. It refers to the target data type of outputs. + +*@par Third-party framework compatibility +*Compatible with tensorflow QueueIsClosed operator. +*/ + +REG_OP(Bitcast) + .INPUT(x, TensorType({DT_BOOL, DT_FLOAT16, DT_FLOAT, DT_INT8, DT_INT32, DT_UINT32, DT_UINT8, + DT_INT64, DT_UINT64, DT_INT16, DT_UINT16, DT_DOUBLE, DT_COMPLEX64, + DT_COMPLEX128, DT_QINT8, DT_QUINT8, DT_QINT16, DT_QUINT16, DT_QINT32})) + .OUTPUT(y, TensorType({DT_BOOL, DT_FLOAT16, DT_FLOAT, DT_INT8, DT_INT32, DT_UINT32, DT_UINT8, + DT_INT64, DT_UINT64, DT_INT16, DT_UINT16, DT_DOUBLE, DT_COMPLEX64, + DT_COMPLEX128, DT_QINT8, DT_QUINT8, DT_QINT16, DT_QUINT16, DT_QINT32})) + .REQUIRED_ATTR(type, Type) + .OP_END_FACTORY_REG(Bitcast) + +/** *@brief Convert tensor format from HWCN to C1HWNCoC0. *@par Inputs: @@ -94,6 +123,13 @@ REG_OP(Transpose) .OUTPUT(y, TensorType::BasicType()) .OP_END_FACTORY_REG(Transpose) +REG_OP(TransData) + .INPUT(src, TensorType::BasicType()) + .OUTPUT(dst, TensorType::BasicType()) + .REQUIRED_ATTR(src_format, String) + .REQUIRED_ATTR(dst_format, String) + .OP_END_FACTORY_REG(TransData) + /** *@brief Permutes the dimensions according to order.\n The returned tensor's dimension i will correspond to the input dimension order[i]. @@ -102,7 +138,7 @@ REG_OP(Transpose) *x: A Tensor. Must be one of the following types: float16, float32. *@par Attributes: -*order: A permutation of the dimensions of "x".support any axis transformation +*order: A permutation of the dimensions of "x".Type is int32.support any axis transformation.Defaults to "{0}" *@par Outputs: *y: A Tensor. Has the same type as "x". @@ -291,7 +327,7 @@ REG_OP(DepthToSpace) *@brief Permutes data into spatial data blocks and then prunes them. *@par Inputs: -*@li x: A 4D Tensor with format NC1HWC0. +*@li x: A 4D Tensor with format NHWC. *@li crops: A 1D list or tuple of int32 or int64. *Must be one of the following types: float16, float32 @@ -300,7 +336,7 @@ REG_OP(DepthToSpace) *block_size: A required int8, int16, int32, or int64. No default value. *@par Outputs: -*y: A 4D Tensor with format NC1HWC0, +*y: A 4D Tensor with format NHWC, * of type float16 or float32. @@ -365,7 +401,7 @@ REG_OP(BatchToSpaceD) *@par Inputs: * Two inputs, including: -*@li x: An NC1HWC0 Tensor. Must be one of the following types: +*@li x: An NHWC Tensor. Must be one of the following types: * float16, float32, double, int64, int32, uint8, uint16, uint32, uint64, int8, * int16, complex64, complex128, qint8, quint8, qint16, quint16, qint32. *@li paddings: A 2D tensor of type int, specifying the input. @@ -389,7 +425,7 @@ REG_OP(SpaceToBatch) *@brief Outputs a copy of the input tensor where values from the "height" and "width" dimensions are padded and rearranged to the "batch" dimension. *@par Inputs: -*x: An NC1HWC0 Tensor. Must be one of the following types: float16, float32, double, int64, int32, uint8, uint16, uint32, uint64, int8, int16, complex64, complex128, qint8, quint8, qint16, quint16, qint32. +*x: An NHWC Tensor. Must be one of the following types: float16, float32, double, int64, int32, uint8, uint16, uint32, uint64, int8, int16, complex64, complex128, qint8, quint8, qint16, quint16, qint32. *@par Attributes: @@ -598,6 +634,13 @@ REG_OP(Compress) .OUTPUT(compress_index, TensorType({DT_INT8})) .REQUIRED_ATTR(compress_parameters, ListInt) .OP_END_FACTORY_REG(Compress) + +REG_OP(CompressFcOp) + .INPUT(weight, TensorType({DT_INT8})) + .OUTPUT(weight_compress, TensorType({DT_INT8})) + .OUTPUT(compress_index, TensorType({DT_INT8})) + .REQUIRED_ATTR(compress_parameters, ListInt) + .OP_END_FACTORY_REG(CompressFcOp) } // namespace ge #endif // GE_OP_TRANSFORMATION_OPS_H diff --git a/third_party/fwkacllib/inc/register/op_kernel_registry.h b/third_party/fwkacllib/inc/register/op_kernel_registry.h index 2c479e92..5fed8960 100644 --- a/third_party/fwkacllib/inc/register/op_kernel_registry.h +++ b/third_party/fwkacllib/inc/register/op_kernel_registry.h @@ -41,6 +41,7 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY OpKernelRegistry { private: OpKernelRegistry(); class OpKernelRegistryImpl; + /*lint -e148*/ std::unique_ptr impl_; }; } // namespace ge diff --git a/third_party/fwkacllib/inc/register/op_registry.h b/third_party/fwkacllib/inc/register/op_registry.h index 1fcdf9de..1dc14b8b 100644 --- a/third_party/fwkacllib/inc/register/op_registry.h +++ b/third_party/fwkacllib/inc/register/op_registry.h @@ -35,6 +35,7 @@ enum RemoveInputType { OMG_MOVE_TYPE_SCALAR_VALUE, OMG_REMOVE_TYPE_WITH_COND = 1000, OMG_REMOVE_INPUT_WITH_ORIGINAL_TYPE, + OMG_INPUT_REORDER, }; struct RemoveInputConfigure { @@ -43,6 +44,7 @@ struct RemoveInputConfigure { RemoveInputType moveType; bool attrValue = false; std::string originalType; + std::vector input_order; }; class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY OpRegistry { @@ -57,11 +59,11 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY OpRegistry { void GetOpTypeByImplyType(std::vector &vec_op_type, const domi::ImplyType &imply_type); - domi::ParseParamFunc GetParseParamFunc(const std::string &op_type); + domi::ParseParamFunc GetParseParamFunc(const std::string &op_type, const std::string &ori_type); - domi::ParseParamByOpFunc GetParseParamByOperatorFunc(const std::string &op_type); + domi::ParseParamByOpFunc GetParseParamByOperatorFunc(const std::string &ori_type); - domi::FusionParseParamFunc GetFusionParseParamFunc(const std::string &op_type); + domi::FusionParseParamFunc GetFusionParseParamFunc(const std::string &op_type, const std::string &ori_type); domi::ParseSubgraphFunc GetParseSubgraphPostFunc(const std::string &op_type); @@ -72,14 +74,13 @@ class FMK_FUNC_HOST_VISIBILITY FMK_FUNC_DEV_VISIBILITY OpRegistry { bool GetOmTypeByOriOpType(const std::string &ori_optype, std::string &om_type); private: - std::unordered_map> op_ori_optype_map_; std::unordered_map op_run_mode_map_; - std::unordered_map opParseParamsFnMap_; + std::unordered_map op_parse_params_fn_map_; std::unordered_map parse_params_by_op_func_map_; - std::unordered_map fusionOpParseParamsFnMap_; + std::unordered_map fusion_op_parse_params_fn_map_; std::unordered_map op_types_to_parse_subgraph_post_func_; std::unordered_map> remove_input_configure_map_; - std::unordered_map originOpType2OmOpType_; + std::unordered_map origin_type_to_om_type_; }; } // namespace domi #endif // INC_REGISTER_OP_REGISTRY_H_ diff --git a/third_party/fwkacllib/inc/register/op_tiling.h b/third_party/fwkacllib/inc/register/op_tiling.h new file mode 100644 index 00000000..e9d19f94 --- /dev/null +++ b/third_party/fwkacllib/inc/register/op_tiling.h @@ -0,0 +1,133 @@ +/** + * Copyright 2019-2020 Huawei Technologies 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. + */ + +#ifndef INC_OP_TILING_H_ +#define INC_OP_TILING_H_ + +#include "external/register/register_types.h" +#include "graph/debug/ge_attr_define.h" +#include "graph/node.h" + +#include +#include +#include +#include +#include +#include +#include +#include "graph/node.h" + +#define REGISTER_OP_TILING_FUNC(optype, opfunc) \ + REGISTER_OP_TILING_FUNC_UNIQ_HELPER(optype, opfunc, __COUNTER__) + +#define REGISTER_OP_TILING_FUNC_UNIQ_HELPER(optype, opfunc, counter) \ + REGISTER_OP_TILING_FUNC_UNIQ(optype, opfunc, counter) + +#define REGISTER_OP_TILING_FUNC_UNIQ(optype, opfunc, counter) \ + static OpTilingInterf g_##optype##TilingInterf##counter(#optype, opfunc) + +namespace optiling { + +enum TensorArgType { + TA_NONE, + TA_SINGLE, + TA_LIST, +}; + + +using ByteBuffer = std::stringstream; + +struct TeOpTensor { + std::vector shape; + std::vector ori_shape; + std::string format; + std::string ori_format; + std::string dtype; + std::map attrs; +}; + + +struct TeOpTensorArg { + TensorArgType arg_type; + std::vector tensor; +}; + +struct OpRunInfo { + uint32_t block_dim; + std::vector workspaces; + ByteBuffer tiling_data; +}; + + +using TeOpAttrArgs = std::vector; +using TeConstTensorData = std::tuple; + +struct TeOpParas { + std::vector inputs; + std::vector outputs; + std::map const_inputs; + TeOpAttrArgs attrs; +}; + + +using OpTilingFunc = std::function; + +using OpTilingFuncPtr = bool(*)(const std::string&, const TeOpParas&, const nlohmann::json& , OpRunInfo&); + +class FMK_FUNC_HOST_VISIBILITY OpTilingInterf +{ +public: + OpTilingInterf(std::string op_type, OpTilingFunc func); + ~OpTilingInterf() = default; + static std::map &RegisteredOpInterf(); +}; + + +template +ByteBuffer& ByteBufferPut(ByteBuffer &buf, const T &value) +{ + buf.write(reinterpret_cast(&value), sizeof(value)); + buf.flush(); + return buf; +} + +template +ByteBuffer& ByteBufferGet(ByteBuffer &buf, T &value) +{ + buf.read(reinterpret_cast(&value), sizeof(value)); + return buf; +} + +inline size_t ByteBufferGetAll(ByteBuffer &buf, char *dest, size_t dest_len) +{ + size_t nread = 0; + size_t rn = 0; + do { + rn = buf.readsome(dest + nread, dest_len - nread); + nread += rn; + } while (rn > 0 && dest_len > nread); + + return nread; +} + + +extern "C" ge::graphStatus OpParaCalculate(const ge::Node &node, OpRunInfo &run_info); +extern "C" ge::graphStatus OpAtomicCalculate(const ge::Node &node, OpRunInfo &run_info); + +} + +#endif // INC_OP_TILING_H_ diff --git a/third_party/fwkacllib/inc/runtime/base.h b/third_party/fwkacllib/inc/runtime/base.h index 49c9de6a..2d6503f9 100644 --- a/third_party/fwkacllib/inc/runtime/base.h +++ b/third_party/fwkacllib/inc/runtime/base.h @@ -62,12 +62,20 @@ typedef enum tagRtError { RT_ERROR_DEVICE_POWER_DOWN_FAIL = 0x16, RT_ERROR_FEATURE_NOT_SUPPROT = 0x17, RT_ERROR_KERNEL_DUPLICATE = 0x18, // register same kernel repeatly + RT_ERROR_STREAM_DUPLICATE = 0x19, // streamId Map is repeatly + RT_ERROR_STREAM_NOT_EXIST = 0x1a, // streamId is not exist + RT_ERROR_SQ_NO_EXIST_SQ_TO_REUSE = 0x1b, // no exist sq to reuse + RT_ERROR_SQID_FULL = 0x3C, RT_ERROR_MODEL_STREAM_EXE_FAILED = 0x91, // the model stream failed RT_ERROR_MODEL_LOAD_FAILED = 0x94, // the model stream failed RT_ERROR_END_OF_SEQUENCE = 0x95, // end of sequence RT_ERROR_NO_STREAM_CB_REG = 0x96, // no callback register info for stream RT_ERROR_DATA_DUMP_LOAD_FAILED = 0x97, // data dump load info fail RT_ERROR_CALLBACK_THREAD_UNSUBSTRIBE = 0x98, // callback thread unsubstribe + RT_ERROR_DEBUG_REGISTER_FAILED = 0x99, // debug register fail + RT_ERROR_DEBUG_UNREGISTER_FAILED = 0x9A, // debug unregister fail + RT_ERROR_GROUP_NOT_SET = 0x9B, + RT_ERROR_GROUP_NOT_CREATE = 0x9C, RT_ERROR_RESERVED } rtError_t; @@ -156,6 +164,12 @@ RTS_API rtError_t rtProfilerInit(const char *profdir, const char *address, const /** * @ingroup profiling_base + * @brief config rts profiler. + */ +RTS_API rtError_t rtProfilerConfig(uint16_t type); + +/** + * @ingroup profiling_base * @brief start rts profiler. */ RTS_API rtError_t rtProfilerStart(void); @@ -186,14 +200,6 @@ RTS_API rtError_t rtPeekAtLastError(); /** * @ingroup dvrt_base - * @brief set polling receive mode for task report - * @param [out] NA - * @return RT_ERROR_NONE for ok - */ -RTS_API rtError_t rtSetPollingMode(); - -/** - * @ingroup dvrt_base * @brief register callback for error code * @param [out] NA * @return RT_ERROR_NONE for ok diff --git a/third_party/fwkacllib/inc/runtime/config.h b/third_party/fwkacllib/inc/runtime/config.h index 2e48cc57..c64ed16f 100644 --- a/third_party/fwkacllib/inc/runtime/config.h +++ b/third_party/fwkacllib/inc/runtime/config.h @@ -41,8 +41,7 @@ typedef enum tagRtChipType { CHIP_CLOUD, CHIP_MDC, CHIP_LHISI, - CHIP_OTHER_PHN, - CHIP_OTHER_OLD, + CHIP_DC, CHIP_END, } rtChipType_t; @@ -62,6 +61,7 @@ typedef enum tagRtPlatformType { PLATFORM_MINI_V2, PLATFORM_LHISI_ES, PLATFORM_LHISI_CS, + PLATFORM_DC, PLATFORM_END, } rtPlatformType_t; diff --git a/third_party/fwkacllib/inc/runtime/context.h b/third_party/fwkacllib/inc/runtime/context.h index ed1f13c2..70437b74 100644 --- a/third_party/fwkacllib/inc/runtime/context.h +++ b/third_party/fwkacllib/inc/runtime/context.h @@ -39,6 +39,17 @@ typedef enum tagCtxMode { RT_CTX_GEN_MODE = 1, } rtCtxMode_t; +typedef struct tagRtGroupInfo { + int32_t groupId; + int32_t flag; + uint32_t aicoreNum; + uint32_t aicpuNum; + uint32_t aivectorNum; + uint32_t sdmaNum; + uint32_t activeStreamNum; + void* extrPtr; +} rtGroupInfo_t; + /** * @ingroup rt_context * @brief create context and associates it with the calling thread @@ -115,17 +126,32 @@ RTS_API rtError_t rtGetPriCtxByDeviceId(int32_t device, rtContext_t *ctx); RTS_API rtError_t rtCtxGetDevice(int32_t *device); /** - * @ingroup rt_context - * @brief set ctx run mode: normal or dryrun - * @param [in] ctx: context - * @param [in] enable: set true means enable dryrun mode - * @param [in] flag: reserved - * @return RT_ERROR_NONE for ok + * @ingroup + * @brief set group id + * @param [in] groupid + * @return RT_ERROR_NONE for ok, errno for failed + */ +RTS_API rtError_t rtSetGroup(int32_t groupId); + +/** + * @ingroup + * @brief get group info + * @param [in] groupid count + * @return RT_ERROR_NONE for ok, errno for failed */ -RTS_API rtError_t rtCtxSetDryRun(rtContext_t ctx, rtDryRunFlag_t enable, uint32_t flag); +RTS_API rtError_t rtGetGroupInfo(int32_t groupId, rtGroupInfo_t* groupInfo, uint32_t count); + +/** + * @ingroup + * @brief get group count + * @param [in] groupid count + * @return RT_ERROR_NONE for ok, errno for failed + */ +RTS_API rtError_t rtGetGroupCount(uint32_t *count); #ifdef __cplusplus } #endif -#endif // __CCE_RUNTIME_CONTEXT_H__ \ No newline at end of file + +#endif // __CCE_RUNTIME_CONTEXT_H__ diff --git a/third_party/fwkacllib/inc/runtime/dev.h b/third_party/fwkacllib/inc/runtime/dev.h index 928f2822..f79f060c 100644 --- a/third_party/fwkacllib/inc/runtime/dev.h +++ b/third_party/fwkacllib/inc/runtime/dev.h @@ -23,6 +23,9 @@ extern "C" { #endif +#define RT_CAPABILITY_SUPPORT (0x1) +#define RT_CAPABILITY_NOT_SUPPORT (0x0) + typedef struct tagRTDeviceInfo { uint8_t env_type; // 0: FPGA 1: EMU 2: ESL uint32_t ctrl_cpu_ip; @@ -32,6 +35,7 @@ typedef struct tagRTDeviceInfo { uint32_t ts_cpu_core_num; uint32_t ai_cpu_core_num; uint32_t ai_core_num; + uint32_t ai_core_freq; uint32_t ai_cpu_core_id; uint32_t ai_core_id; uint32_t aicpu_occupy_bitmap; @@ -46,6 +50,23 @@ typedef enum tagRtRunMode { RT_RUN_MODE_RESERVED } rtRunMode; +typedef enum tagRtAicpuDeployType { + AICPU_DEPLOY_CROSS_OS = 0x0, + AICPU_DEPLOY_CROSS_PROCESS = 0x1, + AICPU_DEPLOY_CROSS_THREAD = 0x2, + AICPU_DEPLOY_RESERVED +} rtAicpuDeployType_t; + +typedef enum tagRtFeatureType { + FEATURE_TYPE_MEMCPY = 0, + FEATURE_TYPE_RSV +} rtFeatureType_t; + +typedef enum tagMemcpyInfo { + MEMCPY_INFO_SUPPORT_ZEROCOPY = 0, + MEMCPY_INFO_RSV +} rtMemcpyInfo_t; + /** * @ingroup dvrt_dev * @brief get total device number. @@ -62,15 +83,40 @@ RTS_API rtError_t rtGetDeviceCount(int32_t *count); * @return RT_ERROR_DRV_ERR for error */ RTS_API rtError_t rtGetDeviceIDs(uint32_t *devices, uint32_t len); + /** * @ingroup dvrt_dev - * @brief get total device infomation. + * @brief get device infomation. * @param [in] device the device id - * @param [out] info the device info + * @param [in] moduleType module type + typedef enum { + MODULE_TYPE_SYSTEM = 0, system info + MODULE_TYPE_AICPU, aicpu info + MODULE_TYPE_CCPU, ccpu_info + MODULE_TYPE_DCPU, dcpu info + MODULE_TYPE_AICORE, AI CORE info + MODULE_TYPE_TSCPU, tscpu info + MODULE_TYPE_PCIE, PCIE info + } DEV_MODULE_TYPE; + * @param [in] infoType info type + typedef enum { + INFO_TYPE_ENV = 0, + INFO_TYPE_VERSION, + INFO_TYPE_MASTERID, + INFO_TYPE_CORE_NUM, + INFO_TYPE_OS_SCHED, + INFO_TYPE_IN_USED, + INFO_TYPE_ERROR_MAP, + INFO_TYPE_OCCUPY, + INFO_TYPE_ID, + INFO_TYPE_IP, + INFO_TYPE_ENDIAN, + } DEV_INFO_TYPE; + * @param [out] value the device info * @return RT_ERROR_NONE for ok * @return RT_ERROR_NO_DEVICE for can not find any device */ -RTS_API rtError_t rtGetDeviceInfo(int32_t device, rtDeviceInfo_t *info); +RTS_API rtError_t rtGetDeviceInfo(uint32_t deviceId, int32_t moduleType, int32_t infoType, int64_t *value); /** * @ingroup dvrt_dev @@ -132,6 +178,25 @@ RTS_API rtError_t rtDisableP2P(uint32_t devIdDes, uint32_t phyIdSrc); /** * @ingroup dvrt_dev + * @brief get status + * @param [in] devIdDes the logical device id + * @param [in] phyIdSrc the physical device id + * @param [in|out] status status value + * @return RT_ERROR_NONE for ok + * @return RT_ERROR_NO_DEVICE for can not find any device + */ +RTS_API rtError_t rtGetP2PStatus(uint32_t devIdDes, uint32_t phyIdSrc, uint32_t *status); + +/** + * @ingroup dvrt_dev + * @brief get value of current thread + * @param [in|out] pid value of pid + * @return RT_ERROR_NONE for ok + */ +RTS_API rtError_t rtDeviceGetBareTgid(uint32_t *pid); + +/** + * @ingroup dvrt_dev * @brief get target device of current thread * @param [in|out] device the device id * @return RT_ERROR_NONE for ok @@ -214,6 +279,15 @@ RTS_API rtError_t rtGetRunMode(rtRunMode *mode); /** * @ingroup dvrt_dev + * @brief get aicpu deploy + * @param [out] aicpu deploy + * @return RT_ERROR_NONE for ok + * @return RT_ERROR_DRV_ERR for can not get aicpu deploy + */ +RTS_API rtError_t rtGetAicpuDeploy(rtAicpuDeployType_t *deplyType); + +/** + * @ingroup dvrt_dev * @brief set chipType * @return RT_ERROR_NONE for ok */ @@ -225,6 +299,35 @@ RTS_API rtError_t rtSetSocVersion(const char *version); * @return RT_ERROR_NONE for ok */ rtError_t rtGetSocVersion(char *version, const uint32_t maxLen); + +/** + * @ingroup dvrt_dev + * @brief get status + * @param [in] devId the logical device id + * @param [in] otherDevId the other logical device id + * @param [in] infoType info type + * @param [in|out] value pair info + * @return RT_ERROR_NONE for ok + */ +RTS_API rtError_t rtGetPairDevicesInfo(uint32_t devId, uint32_t otherDevId, int32_t infoType, int64_t *value); + +/** + * @ingroup dvrt_dev + * @brief get capability infomation. + * @param [in] featureType feature type + typedef enum tagRtFeatureType { + FEATURE_TYPE_MEMCPY = 0, + FEATURE_TYPE_RSV, + } rtFeatureType_t; + * @param [in] infoType info type + typedef enum tagMemcpyInfo { + MEMCPY_INFO_SUPPORT_ZEROCOPY = 0, + MEMCPY_INFO _RSV, + } rtMemcpyInfo_t; + * @param [out] value the capability info + * @return RT_ERROR_NONE for ok + */ +RTS_API rtError_t rtGetRtCapability(rtFeatureType_t featureType, int32_t featureInfo, int64_t *value); #ifdef __cplusplus } #endif diff --git a/third_party/fwkacllib/inc/runtime/mem.h b/third_party/fwkacllib/inc/runtime/mem.h index 7c2a0728..e70ebd38 100644 --- a/third_party/fwkacllib/inc/runtime/mem.h +++ b/third_party/fwkacllib/inc/runtime/mem.h @@ -17,7 +17,9 @@ #ifndef __CCE_RUNTIME_MEM_H__ #define __CCE_RUNTIME_MEM_H__ +/*lint -e7*/ #include +/*lint +e7*/ #include "base.h" #include "config.h" #include "stream.h" @@ -222,17 +224,15 @@ RTS_API rtError_t rtMemAllocManaged(void **ptr, uint64_t size, uint32_t flag); * @return RT_ERROR_INVALID_DEVICE_POINTER for error device memory pointer */ RTS_API rtError_t rtMemFreeManaged(void *ptr); - /** * @ingroup dvrt_mem - * @brief advise memory - * @param [in] ptr memory pointer - * @param [in] size memory size - * @param [in] advise memory advise + * @brief alloc cached device memory + * @param [in| devPtr memory pointer + * @param [in] size memory size + * @param [in] type memory type * @return RT_ERROR_NONE for ok - * @return RT_ERROR_INVALID_DEVICE_POINTER for error device memory pointer */ -RTS_API rtError_t rtMemAdvise(void *ptr, uint64_t size, uint32_t advise); +RTS_API rtError_t rtMallocCached(void **devPtr, uint64_t size, rtMemType_t type); /** * @ingroup dvrt_mem @@ -241,7 +241,7 @@ RTS_API rtError_t rtMemAdvise(void *ptr, uint64_t size, uint32_t advise); * @param [in] len memory size * @return RT_ERROR_NONE for ok, errno for failed */ -RTS_API rtError_t rtFlushCache(uint64_t base, uint32_t len); +RTS_API rtError_t rtFlushCache(void *base, size_t len); /** * @ingroup dvrt_mem @@ -250,7 +250,7 @@ RTS_API rtError_t rtFlushCache(uint64_t base, uint32_t len); * @param [in] len memory size * @return RT_ERROR_NONE for ok, errno for failed */ -RTS_API rtError_t rtInvalidCache(uint64_t base, uint32_t len); +RTS_API rtError_t rtInvalidCache(void *base, size_t len); /** * @ingroup dvrt_mem @@ -428,19 +428,6 @@ RTS_API rtError_t rtRDMASend(uint32_t index, uint32_t wqe_index, rtStream_t stre /** * @ingroup dvrt_mem - * @brief Set the memory readCount value - * @param [in] devPtr memory pointer - * @param [in] size memory size - * @param [in] readCount readCount value - * @return RT_ERROR_NONE for ok - * @return RT_ERROR_INVALID_VALUE for error input - * @return RT_ERROR_INVALID_RESOURCE_HANDLE for invalid resource handle - * @return RT_ERROR_DRV_ERR for driver error - */ -RTS_API rtError_t rtMemSetRC(const void *devPtr, uint64_t size, uint32_t readCount); - -/** - * @ingroup dvrt_mem * @brief Ipc set mem pid * @param [in] name name to be queried * @param [in] pid process id diff --git a/third_party/fwkacllib/inc/runtime/rt_model.h b/third_party/fwkacllib/inc/runtime/rt_model.h index 790492fc..5c85a3d7 100644 --- a/third_party/fwkacllib/inc/runtime/rt_model.h +++ b/third_party/fwkacllib/inc/runtime/rt_model.h @@ -65,6 +65,13 @@ typedef enum tagModelQueueFlag { #define EXECUTOR_TS ((uint32_t)0x01) #define EXECUTOR_AICPU ((uint32_t)0x02) +/* + * @ingroup rt_model + * @brief debug flag for kernel exception dump + */ +#define RT_DEBUG_FLAG_AICORE_OVERFLOW (0x1 << 0) +#define RT_DEBUG_FLAG_ATOMIC_ADD_OVERFLOW (0x1 << 1) + /** * @ingroup * @brief the type defination of aicpu model task command @@ -403,6 +410,26 @@ RTS_API rtError_t rtModelBindQueue(rtModel_t model, uint32_t queueId, rtModelQue */ RTS_API rtError_t rtModelGetId(rtModel_t model, uint32_t *modelId); +/* + * @ingroup rt_model + * @brief enable debug for dump overflow exception + * @param [in] addr: ddr address of kernel exception dumpped + * @param [in] model: model handle + * @param [in] flag: debug flag + * @return RT_ERROR_NONE for ok + * @return RT_ERROR_INVALID_VALUE for error input handle + */ +rtError_t rtDebugRegister(rtModel_t model, uint32_t flag, const void *addr, uint32_t *streamId, uint32_t *taskId); + +/* + * @ingroup rt_model + * @brief disable debug for dump overflow exception + * @param [in] model: model handle + * @return RT_ERROR_NONE for ok + * @return RT_ERROR_INVALID_VALUE for error input handle + */ +RTS_API rtError_t rtDebugUnRegister(rtModel_t model); + #ifdef __cplusplus } #endif diff --git a/third_party/fwkacllib/inc/toolchain/slog.h b/third_party/fwkacllib/inc/toolchain/slog.h index f77df225..261fe866 100644 --- a/third_party/fwkacllib/inc/toolchain/slog.h +++ b/third_party/fwkacllib/inc/toolchain/slog.h @@ -91,6 +91,10 @@ extern "C" { * max log length */ #define MSG_LENGTH 1024 +#define DEBUG_LOG_MASK (0x00010000) +#define SECURITY_LOG_MASK (0x00100000) +#define RUN_LOG_MASK (0x01000000) +#define OPERATION_LOG_MASK (0x10000000) typedef struct tagDCODE { const char *cName; @@ -169,83 +173,11 @@ enum { PROCMGR, // Process Manager, Base Platform BBOX, AIVECTOR, + TBE, + FV, INVLID_MOUDLE_ID }; -#ifdef MODULE_ID_NAME - -/** - * @ingroup slog - * - * set module id to map - */ -#define SET_MOUDLE_ID_MAP_NAME(x) \ - { #x, x } - -static DCODE g_moduleIdName[] = {SET_MOUDLE_ID_MAP_NAME(SLOG), - SET_MOUDLE_ID_MAP_NAME(IDEDD), - SET_MOUDLE_ID_MAP_NAME(IDEDH), - SET_MOUDLE_ID_MAP_NAME(HCCL), - SET_MOUDLE_ID_MAP_NAME(FMK), - SET_MOUDLE_ID_MAP_NAME(HIAIENGINE), - SET_MOUDLE_ID_MAP_NAME(DVPP), - SET_MOUDLE_ID_MAP_NAME(RUNTIME), - SET_MOUDLE_ID_MAP_NAME(CCE), -#if (OS_TYPE == LINUX) - SET_MOUDLE_ID_MAP_NAME(HDC), -#else - SET_MOUDLE_ID_MAP_NAME(HDCL), -#endif // OS_TYPE - SET_MOUDLE_ID_MAP_NAME(DRV), - SET_MOUDLE_ID_MAP_NAME(MDCFUSION), - SET_MOUDLE_ID_MAP_NAME(MDCLOCATION), - SET_MOUDLE_ID_MAP_NAME(MDCPERCEPTION), - SET_MOUDLE_ID_MAP_NAME(MDCFSM), - SET_MOUDLE_ID_MAP_NAME(MDCCOMMON), - SET_MOUDLE_ID_MAP_NAME(MDCMONITOR), - SET_MOUDLE_ID_MAP_NAME(MDCBSWP), - SET_MOUDLE_ID_MAP_NAME(MDCDEFAULT), - SET_MOUDLE_ID_MAP_NAME(MDCSC), - SET_MOUDLE_ID_MAP_NAME(MDCPNC), - SET_MOUDLE_ID_MAP_NAME(MLL), - SET_MOUDLE_ID_MAP_NAME(DEVMM), - SET_MOUDLE_ID_MAP_NAME(KERNEL), - SET_MOUDLE_ID_MAP_NAME(LIBMEDIA), - SET_MOUDLE_ID_MAP_NAME(CCECPU), - SET_MOUDLE_ID_MAP_NAME(ASCENDDK), - SET_MOUDLE_ID_MAP_NAME(ROS), - SET_MOUDLE_ID_MAP_NAME(HCCP), - SET_MOUDLE_ID_MAP_NAME(ROCE), - SET_MOUDLE_ID_MAP_NAME(TEFUSION), - SET_MOUDLE_ID_MAP_NAME(PROFILING), - SET_MOUDLE_ID_MAP_NAME(DP), - SET_MOUDLE_ID_MAP_NAME(APP), - SET_MOUDLE_ID_MAP_NAME(TS), - SET_MOUDLE_ID_MAP_NAME(TSDUMP), - SET_MOUDLE_ID_MAP_NAME(AICPU), - SET_MOUDLE_ID_MAP_NAME(LP), - SET_MOUDLE_ID_MAP_NAME(TDT), - SET_MOUDLE_ID_MAP_NAME(FE), - SET_MOUDLE_ID_MAP_NAME(MD), - SET_MOUDLE_ID_MAP_NAME(MB), - SET_MOUDLE_ID_MAP_NAME(ME), - SET_MOUDLE_ID_MAP_NAME(IMU), - SET_MOUDLE_ID_MAP_NAME(IMP), - SET_MOUDLE_ID_MAP_NAME(GE), - SET_MOUDLE_ID_MAP_NAME(MDCFUSA), - SET_MOUDLE_ID_MAP_NAME(CAMERA), - SET_MOUDLE_ID_MAP_NAME(ASCENDCL), - SET_MOUDLE_ID_MAP_NAME(TEEOS), - SET_MOUDLE_ID_MAP_NAME(ISP), - SET_MOUDLE_ID_MAP_NAME(SIS), - SET_MOUDLE_ID_MAP_NAME(HSM), - SET_MOUDLE_ID_MAP_NAME(DSS), - SET_MOUDLE_ID_MAP_NAME(PROCMGR), - SET_MOUDLE_ID_MAP_NAME(BBOX), - SET_MOUDLE_ID_MAP_NAME(AIVECTOR), - { NULL, -1 }}; -#endif // MODULE_ID_NAME - #if (OS_TYPE == LINUX) /** * @ingroup slog @@ -386,6 +318,11 @@ extern int CheckLogLevel(int moduleId, int logLevel); DlogWithKVInner(moduleId, level, pstKVArray, kvNum, "[%s:%d]" fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ } while (0) +/** + * @ingroup slog + * @brief DlogFlush: flush log buffer to file + */ +void DlogFlush(void); /** * @ingroup slog diff --git a/third_party/prebuild/aarch64/liberror_manager.so b/third_party/prebuild/aarch64/liberror_manager.so new file mode 100755 index 0000000000000000000000000000000000000000..759d8e30accaaca6dd3cd9dcecbc97d03f1cb20b GIT binary patch literal 888880 zcmV+W{{#SkMNCEl0RaO500000000030Ji`E0002suLJ-90000$0000000026hz$S$ z000000000$05|{$06+j90384U000050000000000000000000000000000000002C z$Or%c0002C$Or%c000000096100001000060001B$p`=d0001B$q4`e0001B$q4`e z0002MHUIzs0002MJOBUy000000096100002000060001R%m@Gg0001R%n1Mh0001R z%n1Mh0001h0ssI20001h0ssI200008000000000400004000000ssI2000000ssI2 z000000ssI20000a000000000a00000000040000000007000040001B$p`=d0001B z$q4`e0001B$q4`e00000000000000G0000000008000000000`<#c2O0000my$1jQ z0000my$1jQ0000my$1jQ0000)EdT%j0000)EdT%j00004000000000{<#c2Q00000 z0000000000000000000000000000000000000000000000000G000000000|<#c2O z0001B$p`=d0001B$q4`e0001B$q4`e0001>HUIzs0001>HUIzs000010000000004 z0000K000030000-PE`N};h9r8S)U)U)ww8Xy)Y=<!p-5CKaC zFiH@#A|Nm|zyU520RRaAK>)x2h5!NxC_o^A(Ln)n7zzxz0YU%(Qar#;Nx~oilnfXl z5CAAFKmjlgNP++X1(-Y&LI8jOk^q1J6bKCf1ORX(Mo|O+KmtN|2yh58fS@QzjWD7B zfFubd0%|BAqzpl@QlJ2UC_(`MUGWY-x5d;DNLIFe^1Q3ftKmecsumC6k00amD z0ulfW11ty#AOHoDL&n+00000 zgbDy~CnhkWf&dHvAc#RkZ~y=h03iWF0001DfdCMo00cyYmBN6A3;-Zl2PhB_0ux98QkEjr00|(N003|ULBIek2mlBI000=W z0BVOoK>!E{6rdm|fC)k%L_i<_U;-#K2!JXC;Y0!;01^Nc5F~&okR+5qKmY*+!hnJh zKmrB`kSL4*h-v@|NFfA808sz{01$u$0vbesC=DDS5CA1a2>{TEh^PRX0zd!)Pyz^q zP$&cd0l-2NLWm%MLIB{T03ZPZKmY&$2mk;80SQn*Ko|f3a0oy_fdE<(0|k#k3_t*Y zNB{{4ffW$|ARz{@1ONa4A^-vafD!-@00002*#L%Ypc0100008 zfB*mh5Cq^5nGjR}fd~K+1b_?x000350000W0B9os2vG_NW?%pa2$BE*1ON~a077B~ z0sv4*0EG;qfFuwUfCLBtNFYKWAt00ppa1{}Ktllm0H6_w28AS<016SnXi|g(0)z+# z!T&u z2nYcP001x)kN_YEMFa`}0Du4h0dz78i48!23IRZwgph~`gjWb~08j)#02mk`ffxY* z03-kbfIz@l5|U&LH~=6(L4%Mq5C8y#Km-6df>0q;ga8Z>0BIlu6ySgW1OfyAfFa@m z2p|9eKmY)OB47fr2mk03nb7009I9000023jhcd3`7DT!KMHi0U(q>AP@px2>?L= z5r7c@L=FG~Apj5{aR4wxpa=*FULlPhn6#U8n8e~ckKmY)Y0096*0w4eYK>||&00=Wk0tmtY3#R1G%d*h0|27XN(qG!Q3};UMFxNZ2v7i!K>+|55g-5x0RR91 z0DuJmKnMnr4j>R9umVK@AOiq^2p|A+0001W0001Y0001a0001f000000001h0001j z0001m0001p000000001s0001u0001x0001z000000001!0001#0001%0001*0001+ z0001-0001<0001@0001|0001~0002100022000240002500026000280002A0002C z000000002D00000000000002I0002K0002N0002Q0002R0002S000000002T0002W z0002Y0002b0002d0002e000000002g0002i0002k0002l000000002n0002q0002s z0002u000000002v0002w000000002!0002#0002%000000002&000000002(0002+ z0002;0002<000000002=0002>0002?0002@0002`0002|0002}000000RR950RR91 z00000000070RR990RR910000A0RR910000D0RR9F0RR910000F0RR9H0RR9J0RR91 z0000K0RR9N0RR9O0RR9Q0RR9S0RR9W0RR9Y0RR9a0RR9b0RR9d0RR910000d0RR9g z0RR9h0RR9i0RR9k0RR9o0RR910000r0RR9v0RR9x0RR9!0RR9%0RR9&0RR9(0RR9* z0RR9+0RR910000+0RR9;0RR9?0RR9|0RR9~0RRA00RRA30RR91000130RRA70RR91 z000170RRA90RRAA0RRAD0RR91000000001D0RRAH0RRAI0RRAN0RRAP0RRAU0RR91 z0001V0RR910001Z0RRAb0RR910001d0RR91000000001g0RRAj0RR910000000000 z0001k0RRAn0RRAr0RR91000000001r0RRAt0RRAv0RRAz0RRA#0RRA%0RR910001& z0RRA*0RRA-0RRA=0RRA>0RRA_0RR910001_0RR910001|0RRA~0RRB10RRB30RRB4 z0RRB50RRB80RRBB0RRBE0RRBF0RRBG0RRBH0RRBJ0RRBK0RR910002M0RR910002N z0RRBP0RRBR0RRBS0RRBU0RRBV0RRBX0RRBY0RRBb0RRBe0RRBg0RRBm0RRBn0RRBp z0RRBr0RRBs0RRBv0RRBx0RR910002y0RRB!0RRB#0RR910002$0RRB&0RRB)0RRB* z0RRB+0RRB;0RRB<0RRB>0RR91000000002>0RRB@0RRB`0RRB~0RR91000000002~ z0RRC10RR910ssI40ssI60ssI80ssI2000070ssIB0ssIE0ssIH0ssII0ssI20000K z0ssIN0ssIO0ssIP0ssIR0ssI20000R0ssIX0ssIY0ssI20000Y0ssIb0ssI20000c z0ssIm0ssIq0ssIs0ssIt0ssIu0ssIw0ssIx0ssIz0ssI!0ssI#0ssI20000#0ssI2 z0000$0ssI)0ssI+0ssI2000000000+0ssI<0ssI20000@0ssI|0ssI~0ssJ00ssI2 z0000~0ssI2000110ssI2000130ssJ60ssJ70ssJA0ssJC0ssJF0ssI20001F0ssJK z0ssJL0ssJN0ssJQ0ssJR0ssJS0ssJW0ssJZ0ssJe0ssJi0ssJm0ssJp0ssI200000 z0001o0ssI20001p0ssJt0ssJx0ssJ!0ssJ$0ssJ(0ssI20001&0ssJ-0ssJ=0ssJ` z0ssJ}0ssK00ssK10ssK30ssK80ssK90ssKB0ssI20002A0ssKG0ssKH0ssKI0ssKJ z0ssKK0ssKL0ssKN0ssKP0ssKQ0ssKR0ssKT0ssI20002T0ssKW0ssI20002V0ssKY z0ssKb0ssKf0ssKh0ssKk0ssKp0ssKs0ssKv0ssKw0ssKz0ssI20002y0ssK$0ssK) z0ssK+0ssK<0ssK=0ssK>0ssI200000000000002?0ssK_0ssK}0ssI20002|0ssL1 z0ssI20{{R40{{R60{{RA0{{RC0{{RD0{{RE0{{RF0{{RI0{{R30000H0{{RL0{{RN z0{{RP0{{RQ0{{RS0{{R30000S0{{RZ0{{Rb0{{Rd0{{Re0{{R30000e0{{Rj0{{Rk z0{{Rn0{{Rs0{{Ru0{{Rv0{{Ry0{{R!0{{R$0{{R&0{{R(0{{R30000&0{{R-0{{R< z0{{R=0{{R>0{{R`0{{R|0{{R~0{{R3000100{{S40{{S60{{S80{{S90{{SB0{{SD z0{{SE0{{SF0{{SG0{{SI0{{SK0{{SL0{{SM0{{SP0{{R30001N0{{R30001O0{{SS z0{{ST0{{SU0{{SV0{{SW0{{SY0{{Sc0{{Sd0{{Se0{{R30001c0{{Sh0{{Si0{{Sm z0{{So0{{Ss0{{Su0{{R3000000001u0{{S$0{{S&0{{S(0{{R30001&0{{S+0{{S- z0{{S;0{{S<0{{S@0{{S^0{{S_0{{S{0{{R30001_0{{T10{{T20{{T40{{T50{{T6 z0{{T70{{T80{{R3000280{{TH0{{TI0{{TJ0{{TK0{{TM0{{TP0{{R3000000002P z0{{TV0{{R30002T0{{TX0{{TY0{{Tb0{{Te0{{Tf0{{Th0{{Tk0{{To0{{Tq0{{Tr z0{{Tu0{{R30002u0{{T!0{{T#0{{R30002!0{{R30002$0{{T;0{{T<0{{T>0{{R3 z0002?0{{T{0{{T~0{{R30002~0{{R51ONa81ONaA1ONaB1ONaD1ONaF1ONaH1ONaM z1ONaP1ONaT1ONaV1ONaX1ONa40000V1ONae1ONaf1ONa40000d1ONaj1ONan1ONar z1ONaw1ONa40000v1ONa#1ONa%1ONa(1ONa)1ONa4000000000*1ONa40000-1ONa? z1ONa_1ONa40000@1ONb11ONb51ONa400000000121ONb71ONbA1ONbB1ONbC1ONa4 z000191ONbF1ONbJ1ONa40001H1ONa40001K1ONbQ1ONa40001N1ONbT1ONbV1ONbZ z1ONbb1ONbc1ONbe1ONbf1ONbg1ONbj1ONbn1ONbp1ONbq1ONbs1ONa40001p1ONbv z1ONby1ONbz1ONb#1ONb$1ONb%1ONb)1ONb+1ONb;1ONb=1ONb?1ONb@1ONb_1ONb{ z1ONc01ONa40001}1ONc31ONa4000221ONc71ONc81ONcA1ONcC1ONcH1ONcI1ONcJ z1ONcK1ONcM1ONcN1ONcO1ONa4000000002L1ONcR1ONcT1ONcU1ONcV1ONcY1ONa4 z0002V1ONcc1ONcf1ONa40002e1ONck1ONco1ONcr1ONcs1ONct1ONcv1ONcw1ONcx z1ONc!1ONc#1ONa40002y1ONa40002z1ONa4000000002#1ONc*1ONc-1ONc;1ONc^ z1ONc{1ONc|1ONc~1ONd01ONd31ONa41poj71poj81poj91poj5000051pojE1pojI z1pojJ1pojM1pojO1poj50000M1pojU1pojX1poj50000T1pojZ1poj50000V1pojc z1pojf1poj5000000000e1poj50000g1pojm1pojn1pojq1pojr1pojt1poju1pojx z1pojy1poj50000u1poj50000v1poj$1poj%1poj50000!1poj50000#1poj50000& z1poj;1poj>1poj^1poj`1poj{1poj50000^1poj50000{1pok31pok51poj500000 z000121pok81poj5000141pokB1pokC1pokF1pokI1pokK1poj50001J1pokQ1pokS z1pokU1pokV1pokX1pokb1pokc1poj50001Y1poke1poj50001a1pokh1pokl1pokm z1pokn1poko1pokq1poj500000000000001m1poks1poj50001p1pokw1pokx1pok! z1pok#1pok%1pok)1poj50001$1pok<1pok=1pok_1pok{1pok}1pol01poj500000 z0001{1pol31pol41pol91poj5000271polF1polG1poj5000000002C1polK1polL z1polQ1polS1polV1polX1polb1pole1poj50002d1polj1poll1polp1poj50002m z1poj5000000002p1pol!1pol%1pol(1pol)1pol+1pol;1poj50002+1pol?1pol^ z1poj50002?1pol~1poj5000000002{1pom31poj61^@sB1^@sC1^@sE1^@sF1^@sH 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 z9Uk5^UW}o+h?O%0*X23|BJNz8S-}chI#4l^bmX(d=-!7xNZ3DuRm$7Sdi=mI&!1J^ zxgm+R43KZqasa-61yMI161RCvUdH1i1B4&rj}2J*H$)B~B}kTg=9$=*SQTvI6`{hl zv(INX;ilBkANtnZQV`@zsGl_e0000000000000000000000000000000000300{tK zPy_$~0000000000000000000301*IS$q4`e00000000000002>!2kdf0000000000 z00000000000002dDF6Tx000000000000000000000000n*8l(#000000000000000 z000000000&wEzGT000000000000000000000001qJpcd_00000000000000000000 z0002XGXMY*000000000000000000000002~GXMY*000000000000000000000002m zEC2u!000000000000000000000001vCjbBv000000000000000000000001s0RR9J z000000000000000000000002sxB>to000000000000000000000000*0ssIK00000 z0000000000000000002IU;zLU000000000000000000000001;fB^s!0000000000 z00000000000002m4FCWV0000000000000000000000020WB>pX000000000000000 z0000000027G5`P)000000000000000000000002y0RR9I00000000000000000000 z0000V7XSbf000000000000000000000002(EdT%#000000000000000000000000n zRR91I0000000000000000000000002GXMY*000000000000000000000001yYybcf z000000000000000000000001^*Z=?$000000000000000000000002E7XSbf00000 z0000000000000000000iaRC4l000000000000000000000002VEC2u!0000000000 z000000000000008asdDm000000000000000000000000(4*&oX000000000000000 z000000000*Jpcd_000000000000000000000000+0000Y00000000000000000000 z0002TZ2|xi000000000000000000000002gAOHXo000000000000000000000002t zG5`P)000000000000000000000001UF#rG(000000000000000000000001}!2kdf z000000000000000000000000XIRO9?000000000000000000000001uv;qJT00000 z0000000000000000002_G5`P)000000000000000000000001PaRC4l0000000000 z00000000000002+RR91I000000000000000000000001aJpcd_000000000000000 z000000002nJOBU^000000000000000000000000XCjbBv00000000000000000000 z0000d761Se0000000000000000000000002A^-pq000000000000000000000002m zCjbBv000000000000000000000002%4*&oX000000000000000000000000MaRC4l z000000000000000000000002&aRC4l000000000000000000000002hU;zLU00000 z0000000000000000001v4*&oX000000000000000000000002-H~|0>0000000000 z00000000000000eE&u=$000000000000000000000002b5C8xY000000000000000 z000000000pJpcd_000000000000000000000001RDF6Tx00000000000000000000 z0000$5C8xY0000000000000000000000002Apigp000000000000000000000002_ z0RR9J000000000000000000000002wCIA2u000000000000000000000002fG5`P) z000000000000000000000002wCjbBv000000000000000000000001K0000H00000 z00000000000000000026p8^09000000000000000000000002(JOBU^0000000000 z00000000000000uC;$Kw000000000000000000000001&EdT%!000000000000000 z000000002?vjPAS000000000000000000000001?EdT%#00000000000000000000 z0002!G5`P)000000000000000000000001AdjS9v000000000000000000000001C z+5rF(000000000000000000000001Y4FCWV000000000000000000000002o5C8xY z000000000000000000000002^0RR9J000000000000000000000000a8vy_k00000 z0000000000000000001{0000I000000000000000000000001gg8%>$0000000000 z00000000000001&C;$Kw0000000000000000000000004FCWV00000 z00000000000000000005wgLbV00000000000000000000000010000W0000000000 z00000000000000EvH}1S000000000000000000000000i0000W000000000000000 z000000002ZaRC4l000000000000000000000000vE&u=$00000000000000000000 z0000tp)%90000W000000002xtO5Wc01E(&PzL}20000K000000000iEdT%_01E)z zT?GID0000m000000001UUH||h01E)nlLY_(0000i000000000JP67ZT01E)bEC&Dp z0001R000000002x(*Xb?01E&(=mr1)0000K000000000v00ICa01E(A3kLuI0000W z000000001y1pojd01E(YF$Dks0000y000000002_Tmk?h01E)@Fb4nt0000W00000 z0002cTLJ(g01E)bFb4nt0000e0000000003)d2t^01E)bvjzYF0000W000000001> zApig(01E)@RRsV50000m000000001E!~g&y01E)bw*>$I0000y000000001jWB>pn z01E)9mjwU-0001B000000001&X955s01E&FH3t9y00013000000001;vjPAi02BZ) z%n1Mh0000O000000000ok^ulB01E&Z&;|ei0000;000000000^H~|1601E){AO-*c z0000;000000000n&Hw-+01E&Z(FFhi0000W000000001uX8-^q01E(Ym<0d;0000u z000000002YwEzGj01E)D1_l5C0000e000000001ewEzGj01E(c1_l5C0000y00000 z0002#1Ofme01E(6+6Djs0000`000000001|c>w?-01E)bwgvzI0001(000000001r ziUI&401E)fK?eW;0000$000000000>e*pj@01E&}zy<&S0000m000000001gDF6Tx z01E&(v;+VE0000S1poj50000qs{jBZ01E(w{{;X50000?000000001QmjM7G01E&} z)dm0n0001-000000001mc>w?-01E(=wgvzI0000m000000001zqW}OR01E(I_5}a{ z0000K000000001|BLDy*01E&FNCf}@0000W000000001P836zy01E&dK?VQ-0000S z000000002Uivj>501E(|LI(f<0000e000000000LfC2y_01E)XJ_i5*0000O00000 z0002=%K-o)01E)zdj$Xh z0000K000000001wcLD$+01E&#JqG{)0000e000000001s!vFvx01E(2w*>$I0000y z00000000236aWAs01E)jKm`B*0000e0000000012_y7PR01E)vF$Mqt0000m00000 z0002Ug#rK~01E){F9!es0000$000000000)VgLXl01E&}Y6SoQ0000q000000002w z9RdI%01E)b69)hQ0000S0000000018b^!n)01E)@v<3hG0000W0000000001^Z@`O z01E(k_67g|0000)000000000(6951r01E&ZKLr2)0000)000000000`4*&on01E)T zHU$6x0001V000000000APyhfT01E)LgarTq0000W000000001Ao0000` z000000001d$^ZZ&01E)P9R>gZ0000i0000000000zySav01E)v;06Ey0000S00000 z00028(*OV>01E(I)CB+l0000)000000000E%>e)+01E&V<^})&0000a000000000j zX#fBs01E(QnFRm<0000K000000002zcL4w*01E&NwFUqH0000K000000000Z_W%GQ z01E(oF$Mqt0000u000000001>oB;qL01E&B*#-ar0000a000000000iJplkB01E&> zCk6lj0000m000000000IMJ+ z0000u000000001*4gmln01E(Y`vm|10000K000000001it^fcc01E(&nFRm<0000? z000000002t{r~_X01E)XGX?+v0000S0000000023H2?r201E(6Oa%Y{0000W00000 z0001~r2qgT01E&N`UL<000017000000000V3jhEj01E*4G6ett0000u000000002f zfdK#_01E&VS_S|B0000K000000001@V*mgm01E&FYXtxR0000K000000000}&;S4; z01E)b9tHpa0000e000000002qvH$=g01E)H0|o#90000O000000000bp8^0P01E&J zN(TS{0000?000000000EkpKW901E&piv<7x0000e000000002m9RUC$01E)r1_l5C z0000W000000000WE&%`{01E){hz0-v0000K0000000000aRC4#01E(ou?7GD0000O z000000000dX#xNu01E*89R~ma0000K000000001{tpETb01E)`3G01E(=CN%01E&N z;|2f#0001x000000000V$^if(01E&x0000K000000001Sd;kC<01E(s(FFhi0000m00000 z0000#nE(JH01E(Q?gan<0000O000000001ug8%>`01E&V+64dr0000S000000002c zdjS9<01E)Ly9NLN0000e000000001er~&{Y01E(&P6q%00000q000000002d@&EuL z01E(sFa`hs0000a0000000030tN;Ka01E(Ym<0d;0000u000000002@+5rF}01E)b zxds3L0000O000000001&hXDX001E(Y#s&ZY0000)0000000001;sF3601E)5?*;$> z0000`000000001&(E$J=01E)1=LP@(0000e000000000HX8`~r01E(6ss;c60000e z000000001w$p8Q%01E(Q9R>gZ0000i000000002=q5=RS01E(oOa}k}0000K00000 z0002-^#A}O01E)rFa`hs0000m000000002S*#H0{01E)TBnAKg0000S000000001H zs{#Nb01E)bPX_=10001F000000002Y)&Kw^01E&}BL)Bf0000S000000001Od;$O> z01E(IJ_i5*0000S000000001GY5)Kt01E)fZUq1U00017000000002hcme<-01E(I zJqG{)0000K000000001Tp8^0P01E(kN(TS{0000q000000001d-2nh101E)v?FIk< z0002E000000001}KL7wC01E&RZUq1U0000W0000000029D*yl@01E&hT?GID0000O z000000001F4*>uo01E)jI|cv%0000)0000000000Dgpo^01E(k=LP@(0000K00000 z0000&9smF$01E&pMFju=0000e000000001?hynm201E&}F$Vwu0000e0000000016 zTmk?h01E(U69)hQ000170000000014kpKW901E(o=LG-&0000a000000001JHUR)4 z01E&lnFas=0000K000000001x3;_Tl01E(g_yqs}0000K000000001M#Q^{!01E)b z;RXNz0000S000000000r2Lb>h01E(I4F>=K0000S000000001@Yykiw01E&Rtp)%9 z0000m000000000RT>t`01E)%*#!Uq0000q0000000002NdN#M01E(YRs{e60000a000000000w ziUI&401E)LF$Vwu0000W000000000aS^xkd01E&RkOcq$00017000000000UH2?r2 z01E(6Oa%Y{0000W0000000001tO5Wc01E&pPzL}20000u000000002)3IG5i01E*4 zG6ett0000u000000002_^Z@`O01E)T_67g|0000)000000001eV*mgm01E(6mIVL+ z000130000000000+5rF}01E(swgvzI0000K000000002qNB{sL01E&_Rs{e60000e z000000002D_W%GQ01E)LF$Mqt0000a000000001QA^`v*01E)L2nGNE0000e00000 z0001ONC5yM01E(EpauW{0000S000000000O69E7s01E(c{{;X50000K0000000028 zF#-T001E*89R~ma0000K000000000~xB>to01E(^RR;h70000q000000001`YXATu z01E)RR;h7 z0000S000000002yj{*Q901E&FMh5@@0002s000000000;BLDy*01E)nM+E=?0000q z000000002eCISE=01E(+76$+T0001d000000001_3IG5i01E)vG6ett0000W00000 z00005#Q^{!01E)5;RXNz0000W000000002$1ONac01E&VFa-br0001#000000001{ zkN^N801E*4iUj}w0000m000000000XmH_}F01E(g(*^(l0001-0000000000HUa=5 z01E)vBL@Hg0000W000000001Fh5-N~01E(!#RdQX0000S0000000014HUI!301E(c zOa%Y{0000W0000000020fC2y_01E)vJ_i5*0000;0RR910002PiU0s201E){g#`cr z0000e000000000;8UX+z01E(^0tNs80001F000000002(r~&{Y01E&xO$Pt~0000S z000000000=C0000m000000001!T>tS&01E)HDhB`n0000?0000000021 z9RUC$01E)LR0aS50000O000000000$b^rh(01E)Dx&;6L0000O000000000lssI2Y z01E&p{sjO40000a0000000003Q~&@X01E(ghy?%u0002!0RR910000W8~^|!01E&B zR0RM40000;000000002XPyqlU01E&Rr3L^10000m000000002rDF6T>01E(AS_J?A z0000a000000001MMFIdK01E*8DhB`n0000$000000001lDFFZ?01E)DY6buR0000) z000000002f4*>uo01E&RJO%&&0000m000000002!0RjLb01E(2*9HIp0000e00000 z0000a-T(k101E(^CI$ci0000O000000001^-~j+401E)P!3F>T0000;000000002X z1OWgd01E)zH3k3x0000;000000002u)Bpe?01E(QAO-*c00017000000002}RRRDa z01E&VF9!es0000e000000001rumJ!f01E)P+y(#u00017000000002SNdN#M01E)* zdIbOg0000q000000001wodEzM01E(M*#-ar0001}000000001s+W-I}01E&xB?bTh z0000O0000000013mH+@E01E(+jRgPz0000m000000001lJ^%nB01E)fQUw420000y z0000000003CjbDZ01*HP0000000008000000002QHUR)401E&(nFas=0000e00000 z00010{{a9Z01E)*)dm0n0000W000000002h%mDx*01E)jy z02BZK%n1Mh0000O0000000027od5tL01E)r?gan<00017000000000Q&;bA<01E(k z=LP@(0000K000000000Sod5tL01E(^?*#w=0000m000000000}p8^0P01E(AN(TS{ z0000a000000002iQ~>}Y01E)Tr3L^10000S000000002eP5=NR01E)rf&~Bo0001F z000000002_2>}2i01E*8I0gU!0000m000000002GqyPXS01E&}_XPj|0000~00000 z00018fB^s^01E&}SOx$90000W000000000-*Z=?`01E)vBL)Bf0000K000000002G zdjbF=01E&#Ee8Mq0000e000000000+Zvg-z01E)Hum%7C0000K0000000008g#rK~ z01E)fF9!es0000e000000002V0{{Rb01E)jEd>Ao0000~000000000FP5=NR01E)< ze+2*l0000u000000000MegFU>01E&>(ggqj0002c000000002=V*&so01E&FG6w(v z0000e000000001iV*vmn01E)1sRjT50000S000000000lDgXc?01E(kS_J?A0000S z000000002WeEIMJ+0000i000000000JAprm)01E&F2nGNE0000`000000001k0{{Rb01E)jECm1n z00026000000001AngReK01E(sNe2J`0000O000000002aZvp@!01E)9I|l#&0001J z000000000x$pHW&01E(|;|2f#0000S000000002rxBvhm01E)L2nGNE0000e00000 z0000G{Q&?X01E(U1_uBD0000`0ssI20001IG5`P~01E){R0RM40000y000000000o z+5rF}01E)L=>`A*0001-000000001yA^-p)01E)nM+E=?0000q000000001Xw*dem z01E&R-Ua{w0001h000000002&djJ3;01E(E(FFhi0000e000000002^2><{h01E)v zG6ett0000W000000002ceE|R>01E&#zXkvR0000y000000000?*#Q6|01E)*=mr1) z0001R000000000c>i_^E01E&(Dh2=m0001R000000001|ivj>501E(oLI(f<0000W z000000001fkN^N801E)TiUj}w0000y000000000Ch5!H}01E)L+ywvt0000`00000 z0000FHUI!301E(cOa%Y{0000W000000002=;s5|501E&#Ct@h01E*4R0jY60000;000000000>vH<`h01E&> zr3L^10000K000000000CNB{sL01E&ddIbOg00017000000001pu>b%f01E)9ngsv= z0000O000000000}5C8xo01E)vIRyX!0000q0RR910002UB?15<01E)f6$bzS0002U z0000000013i~;~601E&_Lk9o=0000m000000001|3IPBj01E(+IR*d#0000m00000 z0001aI{*M801E)zYXtxR0001B000000000dM*sjK01E(2Zv_AV0000K000000002I z+5i9|01E&x-vs~w0000a000000002*EC2u^01E*4Tm=9C0000e000000002qWC8#p z01E(=G6w(v00017000000001OgaH5|01E(2!Ug~U00017000000000O3jqKk01E(A zItBm$0000a000000000$o&W$M01E)f?*#w=0000e000000000xhXDX001E&J#s&ZY z0001F000000000;(*Xb?01E&J=mr1)0000m000000001$I067701E)9BnJQh0000S z000000002##Q*>z01E)z7zO|U0001>0RR910001-egFU>01E&R(**zk0001700000 z0000-e*yp^01E&_E(ZVr0000O000000002IGyni101E&dOa%Y{0000q000000000E zPyzrV01E&N5C;GN00017000000000SONed01E(kF9!es0000W00000 z0002K#{d8#01E(w90mXY0000a000000002(+yDR~01E(2CI$ci0000O000000001k zm;nGH01E)*)dm0n0000W000000000o>Hq*D01E(I=mh`(0000S000000002+*Z=?` z01E&#BnAKg00013000000002yZ2y9WRO0000W000000000NY61Wv01E(oHwOR!0000)000000001P=KugA01E(M zDFy%l0000;000000001RyZ`_q01E(k69xbP0000q000000002{C;$Kw01E)nvIGDC z0001J0RR910000=yZ`_q01E(QQU?G40000q000000000i76AYv01E&t0R{j70000e z00000000160|Edd01E)z*aiRq0000a000000002=iUI&401E&JLI(f<0000O00000 z0001^1p)vf01E)*3`A*0000)000000002KfB^s^ z01E)rzy<&S0000K000000002pQUCxV01E(^hXnut0001-000000002gh5!H}01E)D z-30&u0000K000000000*MF0RI01E){R0RM40000y000000002#r~v>X01E(k+Xest z0000S000000000*SpWbc01E)Djs*Y!0000S000000001?=>PyC01E&#=mh`(0000e z000000001iVFCam01E)1F$Vwu0000K000000001sB>?~;01E(=UHq*D01E)5=mh`(0000$000000002~3;_Tl01E&t_yqs}0000;000000002o zKL7wC01E(6ZUq1U0001Z000000001r*#Q6|01E(^=>`A*0000S000000001QodEzM z01E)0000a0000000025ga7~{01E&}+64dr0000O000000002@`2YYS01E&J zG6nzu0000m000000000BeE|R>01E)@R0aS50000W000000000<IDD*0000m z000000002eECB!_01E)@f(8Hp0002I1ONa40002C0|Edd01E(s3z01E&-y9EFM0000~000000000s zkO2T901E(UX$AlQ0000a000000001@76AYv01E)1KL!8*0001F0RR910000yIsgD7 z01E(&P6Yq}0000W00000000242><{h01E)PG6ett0000W000000000^uL1xf01E)b zQwIP50000$000000000Y=>Y&D01E*0#s&ZY0000e000000000ws{#Nb01E(cPX_=1 z0000~0000000004ivR#301E)H-~|8x0000O000000000jB>?~;01E&lUj3~F z01E&B^9BF_0000)000000001#F9HA}01E(=8V3LX0000O000000001u@BsiK01E(^ z&ISMg0000K000000001S;{gC701E&d@df|@00013000000000>3jhEj01E&VPXzz~ z0000`000000002F6#)Pu01E&t0R{j70000e000000001%y#W9s01E&-s0IK40000? z00000000208UO$y01E)1Lj?c;0001l000000000-U;qFj01E)@aRmSX0001(00000 z0001nmjD1F01E&#?F9e;0000m0RR910001yvH}1i01E(QQU?G40000q000000000+ z0|Edd01E)z*aiRq0000a000000002Ft^oid01E&pq6Po}0000;000000000_X8-^q z01E(2g#`cr0000W000000001>w*mkn01E(IRR;h70000e000000000o*Z}|{01E(& z=mr1)0000W000000002W5dZ)p01E&(JOuy%0000)000000000Vv;qJj01W^Dy9WRO z0001L000000001(nE?PI01E(sm<9j<0000q000000000ssR95Z01E(2O$Pt~0000S z000000000PPyqlU01E)jqy_*00000)000000000V3;_Tl01E&t_yqs}0000;00000 z00012AOHZN02lxm1_}TG00008000000001aWC8#p01E(E7Y6_U0001x0000000019 z5dr`r01E(U5C;GN0000S000000002WsQ>^X01E(&`~?620001l0RR910000w0RaFa z01E(6GzI_w0000e000000000XUjP6i01E(^XaxWO0000K000000002ACIA2;01E*0 zNCf}@0000K000000000)oB{wM01E(|KnDN-0000O000000002`&;S4;01E&B9|iyb z0000a000000001%M*;vM01E(=D+d4o0000W000000002NVgdjn01E)rF$Vwu0000m z000000000TW&!{r01E(Q83zCW0000e000000000gD*yl@01E&BTm=9C0001300000 z0001D2?78j01E*0+6Djs0000W000000001{PXGWS01E(EgarTq000170000000023 zxB>tn01W^Dy$1jQ0000l000000002CIspJ801E&>n+5;?0000W000000001YIspJ8 z01E&Nn+5;?0000q000000000{IROA701E&lng##>0000e000000002CLjV9G01E(& zR0RM40000u000000002Z`T+nU01E(E0S5p80000`0ssI20000R{Qv+W01E)5?gan< z0000m000000002Sn*jhK01E){)&>9o00017000000001xmH_}F01E&R)CK?m0001- z000000000HvjG4i01E(Ar3L^10000?000000002&3jzQl01E&h4hH}L0000S00000 z0002k9RL6#01E)*LIMJ+0000W000000001;RR91Y z01E)TQU?G40000q000000001P?*RZJ01E(Y^acO`0002s000000000Sr~&{Y01E(k zP6q%00000K000000001$1pxpe01E(cHU?0000?000000001IrUC#W01E)bO$Pt~0000$000000002e zRsaAZ01E(+jRgPz0000m000000001IdI10;01E)1w*~+J0000C0ssI20002st^xod z02Bad%LxDg0000O000000000xECB!_01E°*&l0002I1ONa40000!-~a$301E&> zCk6lj0000m0000000008;{gC701E&d@CE<{h01E)PG6ett0000W00000 z0002zPyhfT01E(Yg#`cr0000~000000000olL7!D01E)fJO=;(0000e000000000M zUI73i01E(!s0IK40000S000000001TM*sjK01E&>RRsV50001N0000000027wgLbm z01E)bQwIP50000$000000000#egOa?01E(czXkvR0001}000000002maRLA$01E(! zJO=;(0000e000000000Et^oid01E(|+y(#u0000S0000000023O#lEQ01E(^eFXpj z0000`0ssI20000j=>PyC01E&ZDh2=m0000W000000002==m7vC01E*0#s&ZY0000e z000000002zqyPXS01E(|_XPj|0000q000000001%qXGaT01E)TOa}k}0000W00000 z00011ivR#301E)f-~|8x0000O000000002#Y5@Qu01E&}tOfu80000W000000000$ zFaZD}01E)Xj|Kn$0000e0ssI20001(i~s;401E&N;spQz0000a000000000j0RR9Z z01E(QDFpxk0000y000000000I-v9t201E)rS&01E)HJO=;(0000O000000000{jQ{{501E(2;spQz0000u00000 z00003=K%mB01E(|@&*6^0000K000000000&asmJ%01E(QDhB`n0000K000000002c znE(JH01E)fjs*Y!0000m000000001L0RR9Z01E)1DFpxk0000S000000000NVgLXl z01E&pY6SoQ0000W000000002wg8={{01E&V!Ug~U0000u000000002ly8!?q01E&Z z-v$5x0000S000000000^NCE&N01E)LD+d4o0000S000000000!5CH%p01E&x`~?62 z0000;000000002H-T?q201E)P?gjt=0000e000000000_0RR9Z01E&-DFpxk0000e z00000000020s;Uc01E)T*9HIp0000$000000000qZvp@!01E&tI|l#&0001d00000 z0000)Z2|xy01E&}ItKs%0000q000000002ctpWfd01E)LQ3n7300013000000001Q z4FLcm01E&lI|cv%00017000000001mC;01E)T4F&)J0000K000000002mC;$Kw z01E&-vIGDC0001#000000002`K>+|F01E(6o(2E_0000e000000001J8Ug?!01E&# z-v$5x0000S0RR9100030xBvhm01E)z2nGNE000080ssI20000HkO2T901E&>X$AlQ z0000e000000002gHUa=501E&hBnJQh00013000000001%CIA2;01E*0NCf}@0000K z000000001^vj6}h01E(sn*{&>0002!000000000N% z01E)P;|2f#0000K000000002oy8r+p01E(M69xbP0000O000000000++yMY001E&N z>jnS-0000)000000001|-v9t201E&ZCk6lj0000e000000002kp#cCQ01E)T+6Djs z0000S000000000BqyYdT01E*0+6Djs0000W000000001*o&o?O01E&hLI(f<00017 z000000002kkpKW901E)1=LG-&0000S000000000K5dZ)p01E(wIRyX!0000~00000 z0000xZU6ux01E)@aRmSX0001(000000001Y9smF$01E(6MFju=0000e000000000= z3;+Nk01E)*GX($u0000$00000000020ssIa01E*8Oa%Y{0001R0RR910001B<^TX9 z01E&xDFy%l0000m000000000cIRF4601E(6YXtxR0000`000000001o7ytkw01E&Z zLj?c;0000a0000000022^8o-N01E(M&;|ei0000;000000001_rT_pU01E(U`UL<0 z000040RR910000_wEzGj01E(|oCN>?0000W000000000!ZUF!y01E)PuLb}B0001d z000000002}kpTcA01E)XZw3GW0000K000000000v+yMY001E)@>IMJ+0000W00000 z0002nvH}1i01E)TQU?G40000q000000000ONdf>O01E)nD+d4o0000W000000001n zEdc-`01E&thz0-v0001p000000002RDFOf@01E&(=LP@(0000$000000000|eE;M2F01E)n++01E)X&;(|;01E(cJqG{) z0000S0000000023r2zmU01E)body5^0000W000000002qNdN#M01E&Zdj$Xh0000e z000000000p9svL%01E)jR0aS50000W000000001VwE_Sk01W^zyaxaP0000V00000 z0000Q6951r01E&ZKLr2)0000)000000000UhyVa001E)9-UR>v000170000000030 zxc~qn01E)54F&)J0000O000000000cr~m*W01E)j`vm|10000O000000000p-~j+4 z01E*0?gjt=0001-000000000Ji~;~601E)@LI(f<00013000000001I(*OV>01E)1 z)CB+l0000K000000002{zyJUu01E)b76t$S0000)000000002FNB{sL01E(YRs{e6 z0000a000000002vDFFZ?01E&FYX$%S0002I1ONa40000JA^`v*01E(=2nGNE0000W z000000000{4FCWl01E*0Gz93kLuI0000K00000 z0000|-vIz301E&>!3F>T0000;000000002m&H(@-01E&V=LP@(0000a000000001m zCIJ8<01E&JVg>*J0000m000000000?2mt^h01E(AI0gU!0000y000000000@Z~y=z z01E)ToCN>?0000?0000000030vH}1i01E&}QwIP50000a000000001fS^xkd01E(Y zkOcq$0000m0000000010K>+|F01E&Fo(2E_0000?000000000u1ONac01E&}E(HJp z0000m000000002869E7s01E)n{{;X50000a000000001@;{X6601E(cCk6lj00017 z000000000rWdQ&p01E(kGzI_w0001F000000001WNB{sL01E&_Rs{e60000e00000 z0002H8vp-01E(QUj_gG z0001N000000000H0{{Rb01E)*D+K@m0000q000000001<3<3Zm01E&-4hH}L0000S z000000002IUjYCj01E)%s0IK40000e000000002fK>z?E01E&BR0RM40000;00000 z000041pojd01E)9Fa-br0001#000000001$F8}}{01E(6UbY0000~000000000A4*>uo01E(s`vm|10000?000000000(L;?UJ z01E(QDhB`n0000K000000001YbO8V&01E*0vIYPE0000$000000001hH2?r201E&p zY6SoQ0000W000000001HH~;`501E)PY6SoQ0000?000000002bJpuqC01E)fCIbY0000`000000002QS^@wf01E)* z5(fYP0000~000000000eqyhjU01E)zOa}k}0000~000000002`egOa?01E)bR|Wt8 z0000W000000000E9{~U&01E(wR|Wt80000$000000002Av;Y7i01E(A1O@;A0000S z0ssI20000>*8u<_02BbY$q4`e0000u000000002f3IPBj01E)XIR*d#0001#00000 z0002ph5-N~01E)5#RdQX0001F000000000IS^)qe01E&_rv?B30000S0000000029 zu>k-g01E&--39;v0000m0000000016PXYiU01E&#Ee8Mq0000e000000000}AC0000K z000000001+IRF4601E(YP6Yq}0000W000000000R3;+Nk01E)*GX($u0000$00000 z00012zW@Lt01E)L6b1kQ0000O00000000162LS*g01E)vHwFLz0000`000000001s z!~g&y01E&BxCH0000i000000002(7XSbv01E&Z zLj?c;0000a000000000KwEzGj01E(|oCN>?0000W0000000004C;|W?01E&>7Y6_U z0000O000000002@X#fBs01E(&nFRm<0000?000000001y6951r01E(IKLr2)0000i z0RR910002bxd8wo01E(+-Ua{w0000`000000000R`~UzV01E&(G6nzu0001700000 z00027S^)qe01E(Mrv?B30000W000000000HXaWEt01E(|H3t9y0000u0000000020 zasmJ%01E(kDhB`n0000S000000001-^#K4P01E&B_XYp}0000u000000002fMgjmL z01E)*301E&N zz6JmQ0000u00000000043jhEj01E*0P6Yq}0000W000000001nbpQY&01E&-xCH0000e0000000008tN{Qb01E*4+Xest0000K z000000000WqXGaT01E(AN(TS{0000a000000000G*8u<`01E&(=LP@(0000$00000 z0001C;?b;0000;000000000Wr2zmU01E)body5^0000W000000002u69NDt z01E&R-Ua{w0001h000000001TcL4w*01E)rvIYPE0000W000000000SjR62601E(w z%?1Df0000a000000002jAprm)01E(=2nGNE0000W000000001uZ23kLuI0000K000000002D-2nh101E&#zy<&S0000K z000000002&z01E&VQwIP50000q000000001mAOHX&01E)DMFju=0001#0000000020 zcme<-01E&ZEC&Dp0000m000000002RDgXc?01E)bS_J?A0000W000000002t?0000q000000002*kpciB01E)zM+X1^0001d z000000000dNdN#M01E(kdIbOg0000a000000001$J^=tC01E(cCk6lj0001700000 z0002q=E01E&-(gpwk0001-000000002g0ssIa01E)LD+K@m0000m z000000001|fdBv^01E(s*aZLp00017000000001QjR62601E)9%?1Df0000a00000 z0002;CIA4Y01*HH0000000004000000001LR004Z01E&_E(ZVr0000O000000002x z2LS*g01E&pI0gU!0000i0000000030egFU>01E(Y(**zk0000a000000001OZ~y=z z01E)ras>bY0000~000000001cg8={{01E)P!3F>T0000;000000002r!vFvx01E(! zw*>$I0000y000000002`YXSfw01E)5IR^j$0000S0000000008ga7~{01E)rd<6gi z0000K000000002*t^fcc01E(k0R{j70001-000000002upaK9Q01E)bMF#)?0000$ z000000001o+yDR~01E){B?bTh00017000000001;`~UzV01E&FGX?+v0001700000 z0002sZvX%y01E(was>bY0000`000000002h9{~U&01E)bR|Wt80000W000000001H zMF9XJ01E&Rp9TN`0000W000000000LDF6T>01E(QPXzz~0001t000000002ru>t@g z02BbI%LxDg0000G000000000gz5xIt01E(6;06Ey0000`0000000018E&>1|01E(& z83zCW0000S000000002<+yMY001E)X>;?b;0000e000000002Ep8^0P01E)DN(TS{ z0000;000000000;K>z?E01E)fZUq1U00017000000001!cmV(+01E&(K?VQ-0000W z000000000W$p8Q%01E&F9R>gZ0001B000000002zL;wIH01E)bR0RM40000i00000 z0000}1ONac01E(kE(HJp0001V000000001c1^@se01E(YP6Yq}0000W000000002u zGy(u301E(!AqM~e0000`0ssI20000i)Bpe?01E)L)CB+l0000;000000002UZUF!y z01E(Ium%7C0000~000000002WWB>pn01E)1YXtxR0000K000000001S6aWCB01W{6 zyaxaP000010000000011kpciB01E(MM+X1^0001d000000001q00ICa01E(Q)&>9o z0000W000000002>!vO#y01E(!;RXNz0000S000000001JEdc-`01E)9hXw!u0001l z000000001L)Bpe?01E*8)CB+l0000)000000002>MF9XJ01E&xp9TN`0000e00000 z0002^ya50r01E&ps0IK40000K0000000013MgRaJ01E&tRRsV50000K000000000R zdjJ3;01E)1&;$_h01E&( zG6nzu00017000000002ZX#oHt01E(os|El70001(000000002!AOHX&01E)5NCf}@ z0000W0000000027{Qv+W01E(gGX?+v0000?000000000jKL7wC01E)fQUw420000y z000000000hN&o;N01E(odj$Xh0000a0RR910002^I{*M801E*0P6Yq}0000W00000 z0002qO8@{O01E&hSOow80000W000000002P(EtD<01E(U9|iyb0000O000000002Z zodN(N01E)LK?eW;0000K000000001{VE_Ok01E&JY6SoQ0000W000000001)-T(k1 z01E)HCI$ci0000K000000001<&;bA<01E)rvIYPE0000W000000000i8vpd0002E000000001}kpTcA01E)n&jtVh0000; z000000001yegOa?01E&#zy<&S0000K000000001`Zvg-z01E)bum%7C0000W00000 z0000bngIYJ01E&F)&>9o0001B0000000017Gy(u301E(6AqM~e0000u000000002! zb^!n)01E&#vjzYF0000;000000000fvjPAj01E&VQwIP50000q000000000%Edl@{ z01E(2=mr1)0000O000000000GO9B8Q01E)94F>=K00017000000000p6aWCB01W`} zyaxaP00001000000002Hrvd;X01E(QP6q%00000K0000000028zySav01E&hsRjT5 z0000K000000001S!TT0000m00000 z00021L;?UJ01E)13kLuI0001R000000000RZ2JO%&&0000O0000000011dIA6<01E)vJqG{)00017000000002U3jhEj01E)X zGX($u00008000000001I2LJ#f01E(kG6ett0000W00000000013;+Nk01E)fGX($u z0000S000000002FC;01E)nXa)cP0000;000000000DQUCxV01E&th6Mls0002o z000000001OYytox01E)rIR^j$0000`000000002nJplkB01E)@oCW{@0000?00000 z0001nG6Dc101E)%9tQvb0000S0000000017Qvd)W01E&hUIhRE0000m000000001Z z9RUC$01E(wR0aS50000m000000001$JOKbA01E(ooCW{@00017000000002WI{^S9 z01E)*n+5;?0001d000000001GcmV(+01E&hwFUqH0000u000000002HYXJZv01E(+ ztOfu800013000000000o5&{4s01E(w5C;GN0000S000000001+O8@{O01E)rd<6gi z0000K000000002dApig(01E(+Rs{e60000W0RR9100012UjP6i01E)DXaxWO0000K z000000002F*8u<`01E(Q=mr1)0000e000000000xCjtN>01E&N7Y6_U0000K00000 z0001VCIA2;01E)bNCf}@0000m000000002KF984|01E(^jRpV!0000e0ssI20001) z&jA1;01E)HvIYPE0000a000000002gTL1te01E(6kp%z%0000e000000001?M*#pL z01E(!p9TN`0002c000000001}PyhfT01E)rgarTq0001F000000000U1pojd01E&- zF$Dks0000m000000001xi~#^501E&>%?1Df0000)000000001bAprm)01E&hSOx$9 z0000e000000002rVgLXl01E)vl?4C*0001B000000000zI{^S901E(Mn+5;?0000) z000000002od;tI=01E&VyaoUO0000y000000000lUjYCj01E)Xs0IK40000W00000 z00018>Hq*D01E(k=mh`(0000O000000001ENdN#M01E(|dIbOg0000e000000002d zNdf>O01E(=4F>=K0000K000000001aBLM&+01E&pS_S|B0002I1ONa40001r^8f%M z01E)5Fa`hs0000m000000002G0ssIa01E&>D+K@m0001V000000000tJpuqC01E(= zCI$I z0000?000000000-b^-t*01E&FJqG{)0000S000000000hV*&so01E&tG6w(v0000O z000000002_i~;~601E)vLk9o=000000RR910001qL;wIH01E)bR0RM40000i00000 z0002xivj>501E)bLI(f<0000e000000000r1pxpe01E&lHU9o0000W0000000015LI40F01E&}R0RM40000a000000002tTLAzf01E&B zs0IK40000e000000001yWdZ;q01E&_GY0?w0000O000000002_%K!i(01E)1&;tk_7+&0000y000000002%j{yK801E(UX$AlQ0000a z000000002Re*pj@01E(kzy<&S0000O000000001$XaE2r01E)LZ3O@T0001700000 z0001R69E7s01E(w{{;X50000?000000000uCIA2;01E)5NCf}@0000W000000000+ zRsjGa01E&hrUn220001h000000001v9s&R&01E)%69)hQ0000S0000000010WC8#p z01E(E7Y6_U0001x000000002>69E7s01E(6Jq7>(000130RR910001{bpZe(01E(| zvjzYF0000e0000000006Bme*+01E&hSOow80000W0000000021QUCxV01E(QhXnut z0000W000000002ddI10;01E&Vx&{CM0001N0RR910001YEdT%_01E)PSp@(90001R z0000000017g#rK~01E(|KnDN-0000O000000002;n*abJ01E(2?*#w=0000e00000 z0000=1Ofme01E&-+6Djs0000K000000000aC;01E&(Vg>*J0001_000000002e zi2?v301E)LK?eW;0000K0000000021CjtN>01E&h7Y6_U0000W000000001n;Q;_5 z01E&B!Ug~U0000K000000001wGyni101E&JY6SoQ0000W000000001+W&i*p01E&( zm<0d;0000q000000002UgaH5|01E)9!Ug~U0000`0ssI200009E&>1|01E(Q83zCW z0000e0000000001fdBv^01E)@(**zk0001R000000000$ivj>501E&hLI(f<00017 z000000000+V*mgm01E)5Y6SoQ0000K000000002)`vCwV01E)%0|x*A0000`0ssI2 z0000{7Xbhw01E&#KL!8*00013000000000+!2kdv01E&x7X|01E(QyaoUO0001}000000001r`~d(W01E&x1_uBD0000u000000000FQvd)W z01E&NUIhRE0000K000000002Mb^rh(01E)bx&;6L0000~000000001^8UX+z01E*8 z0tNs80000e000000001Ea{&M%01E)1KL!8*0001F0RR910000u!2tjw01E&#sRjT5 z0000`000000000jv;Y7i01EO@;A0000W0000000026f&l;`01E&>!3F>T0000; z000000002K(g6S>01E&#vjzYF0000;000000001EJpceA01E*8Pz3-00000u00000 z0001CF#-T001E)j>IMJ+0000W0000000010uK@re01E(cq6Po}0000K000000002v zF8}}{01E*4VFdsH0000a000000000Q)&T$_01E)*vjzYF0000W000000001gvj6}h z01E(An*{&>0000i000000000pUIG9j01E&pF$Vwu0000W000000001LegOa?01E&Z zzy<&S0000S000000001ew*UYl01E(A2nGNE0000K000000000A2m$~i01E(k4F>=K z0000S000000002Cl>z`F01E)1JqG{)0000S000000001H4gdfm01E&#Q3U`10002Q z000000000N+W-I}01E&dB?bTh0000K000000001nfdT*`01E&hKnDN-0000S00000 z0002L6951r01E(!Km`B*0000)000000000Kc>w?-01E(QwgvzI0000S000000001Z zvjPAj01E(YQwIP50000q000000000LgaQB}01E(sKnDN-0000S000000000UF#rG} z01E)*WCZ{K0001F000000002z3jhEj01E)fGX($u0000S000000000++5i9|01E)v zBnAKg0000O000000001B%>e)+01E&(<^})&0000e000000000tj{pE701E(2<^=!% z0000m0RR910001?5&!@q01E)9Jp}*&0000)000000002rx&Qzo01E&p4+a1L00008 z0ssI20000G?g0QI01E)f^9BF_0000i000000002YQ2+oU01E&Zh6Mls0000K00000 z0002-oB;qL01E&l*#-ar0000e000000001)NB{sL01E&dRs{e60000e000000001J zg#iE}01E*4#0CHW0001Z000000001n3;+Nk01E&}Gz9`3G01E)tS&01E)fJO=;(0000e z00000000226afGt01E)TJ_Y~)0000e000000000o{s90Y01E){2nPTF0000`0ssI2 z0001cg8~2|01E&VF9!es0000e000000000GDFFZ?01E(&X$AlQ0000W0RR910000A z+yMY001E&VyaoUO0000y000000002qbpZe(01E&Fv<3hG0002!000000002AjsO56 z01E&F=K0000K000000002%-T?q201E*8zy<&S0000)000000001$EC2u^01E)9T?GID z0000W000000002KXaWEt01E)<9R~ma0000K000000002WBmw{;01E(w;syW!0000a z000000001S+yMY001E(6>jnS-0002E000000002}2i01E)TI0gU!0000W000000001CHUa=501E*4BL@Hg0000e000000000$ zh5`U001E)LKnDN-0001}000000000mkN^N801E(siUj}w0000y000000002*KLG$D z01E(Aody5^0000S000000000G9RUC$01E(sP6hw~000041^@s60002zodEzM01E&J z+6Djs0000S000000001KWB>pn01E(6YXtxR0000`000000000SrvU&W01E(ko(2E_ z0000K000000002s zSOow80000K000000001@Edc-`01E)Lhz0-v0000e0000000027Z2$lw01E(IaRmSX z0001x0000000020tN{Qb01E&N+y(#u0000e000000002Rg8%>`01E)Xd<6gi0000K z000000000p_5lDQ01E&(_XYp}0000`0ssI20002B+yMY001E&J>;?b;0000?00000 z0002tr2+sV01E&tOa}k}0000K0000000001tpWfd01E)1PzL}20000q000000001E z0RjLb01E(g3kLuI0000K000000001^Ap!s*01E(c6bAqR0000W000000000t*#H0{ z01E(&BnAKg0000m0000000003w*UYl01E&V2L=ED0002c000000000heE|R>01E(6 zyaoUO0000K000000002bv;qJj01W_$y9WRO0000f000000000190C9$01E&(69)hQ z0000m000000002KvjPAi02Ba7%n1Mh0000O00000000230000Y01E)5CIMJ+0000W000000000x!~g&y z01E)bw*>$I0000y0000000016vj6}h01E(An*{&>0000i000000001^)d2t^01E)* zvjzYF0000W000000001;4gdfm01E*4Q3U`10000)000000001`j{yK801E&>X$AlQ z0000e000000001{7Xbhw01E&FK?VQ-0000O000000000C;Q;_501E(+?*;$>0000K z000000000QbpZe(01E(ovjzYF0000W000000002183F(z01E(Q5(fYP0000S00000 z0000iTmS$f01E(kkp%z%0001l000000000sy8!?q01E*8-Ua{w0000S000000000< zYXJZv01E(UtOfu80000e000000001;0RjLb01E(!3kLuI0000O000000001o;sF36 z01E*0?*;$>0000e000000002K0000Y01E)rCgZ0000K000000000gssaEa01E)XP6q%00001x000000001!BLV;-01E)j6bAqR z0000u000000000MF9HA}01E&p8V3LX0000)000000000eIspJ801E(^ng##>0000` z000000001AsQ>^X01E(6mIVL+00013000000002MX#xNu01E&#HwOR!0000K00000 z0001Lc>n++01E(s&;d0001t000000002GAOHX& z01E(wNCf}@0000W000000000~g#Z8|01E&(+XVms000000RR910001+AOQd(01E)* zR|Wt80000y000000002_C;|W?01E)<Hz>E01E)*@&*6^0000S z000000000fCjbB<01E)*Nd*7^000220RR9100020lK=oB01E&#=mh`(0000e00000 z0001QO8@{O01E&BSOow80000W0000000001?*ITI01E(oF9rYr0000a000000001i zoB#kK01E(g?*#w=0000a000000001z0RR9Z01E)TDFpxk0000S000000000P6#)Pu z01E)*J_Y~)0000m000000000^wgLbl02BaV%n1Mh0000G000000000^9RL6#01E(= zLHz>E01E(I#|8iZ z0000W0RR910002kE&%`{01E&>iv|Dy0000m000000002O8~^|!01E(YL0002!000000002{%m4r)01E&t9tHpa0000a00000 z0002SHvj-401E)nOa%Y{0000i000000002`h5`U001E(IK?eW;0000e000000002^ zFaiJ~01E)<9R~ma0000K0000000005`v3qU01E)HG6nzu0000a000000002KmH+@E z01E)r>jeM+0000m0RR910000$3jzQl01E&F4hH}L0000S000000002yg#iE}01E(c z#RdQX0000O000000000Af&c&_01E&>)dc_m0000$0{{R30000HlK}uC01E)vf(8Hp z0000K000000000l7y0RR910000mumS)g01E&pR0jY60000)0000000001 z1^@se01E&_G6ett0000q000000000T1ONac01E&}E(HJp0000m000000001B9{~U& z01E)*2L=ED0000W000000002rg#Z8|01E(o+ywvt0000u000000000pA^-p)01E)H zR|Nn70000m000000002+Y5)Kt01E(MZv_AV0001p000000002bE&u=`01E&hUIhRE z0000m000000002rX8-^q01E(=Yy|)S0000`0000000005a{&M%01E(&KL!8*0000K z00000000041ONac01E&hE(HJp0000e000000002A+W-I}01E)f-vs~w0000K00000 z0000{G6Dc101E*89tQvb0000K000000000Ru>k-g01E&V-39;v0000e000000001& z5dZ)p01E&NI|Tp$0000i0RR910000SBLDy*01E&>SOow80000K000000000iO8@{O z01E)Xd<6gi0000K000000000R+W`O~01E)zxds3L0000u000000002-0ssIa01E)* zD+K@m0000q000000002A3;+Nk01E(gGz9(^-01E(QNCf}@0000W000000002_>j3~F01E)v%LV`d0000K z000000000AaRLA$01E&(JO=;(0000e000000001Kivj>501E)zGY0?w0000e00000 z00010NB{sL01E&dRs{e60000e000000001*%K-o)01E)1y02Bbw%LxDg0000O000000000>ga7~{01E&x+64dr z0000O000000002uZ~y=z01E(^o&^8^0000W000000000lTLJ(g01E(+Fb4nt0000q z000000002J?g0QI01E*0^9BF_0001Z000000000|r~v>X01E&p+Xest0000`00000 z0002Mc>(|;01E)bEC&Dp0001R000000002U5&!@p02Ba_$_W4f0000e000000001P zX955s01E&FGzS0x000000RR910001b{{R3Y01E)zGX?+v0000S000000002a0s;Uc z01E)T*9HIp0000$000000001P%m4r)01E*49R>gZ0000K000000002tLI40F01E&} zR0RM40000a000000002}VFCam01E)j6bAqR0000u000000002M)c^n@01E(2AqD^d z0001l0RR910002>s{jBZ01E(I00sa60000)0000000028P5=NR01E(cf&~Bo0001F z000000001NU;+Rl01E(cF$Vwu0000K000000001(^-01E(ASOow80000q000000000W-T?q201E(+?gjt= z0000e000000001vRRI7Z01E)vr3L^10000W000000002vC;|W?01E)<^X01E&R{sjO40000O00000 z0002+A^-p)01E&BSOow80000W000000002XTmS$f01E(6Wd#5L00008000000000} zXaE2r01E&lnFRm<0000$000000001h*Z=?`01E)@BL)Bf0000W000000000a5&!@p z02BbY$_W4f0000e000000000+H30x301E(&9tHpa0000K000000001j0ssIa01E)v zDg^)l0000q000000002wjsgH801E&ZMF#)?0000W000000002sYytox01E&lItKs% z0000a000000001&0|Edd01E(U30s#Ob01E(kGzI_w0001F000000002sSOEYc01E&FF$Mqt0001700000 z0001dxB&nn01E)frUn220000K000000000a@&EuL01E&}Fa`hs0000u000000000y zodN(N01E)DNe2J`0000K000000000C9smF$01E&FMFju=0000a0000000027Hvj-4 z01E)nOa%Y{0000i000000000z4gdfm01E(!H3a|w0000q0RR9100030mH_}F01E)D z)CK?m0001-000000000Wbpik)01E(QD+d4o0000m000000000BD*yl@01E)*S_J?A z0000S0RR910000?4FUin01E(E4hH}L00017000000001EcK`q)01E&-y9EFM0000~ z000000001}tO5Wc01E(MPzL}20000O000000002-D*yl@01E&(T?GID0000a00000 z0001TPyhfT01E&(g#`cr0000K000000001Ze*yp^01E(IE(ZVr0000a000000000W zbN~P%01E&hu>}AC0000q000000001IcmMz*01E*4%>@7e0001R0ssI20002~G6Dc1 z01E(g9|r&c0000~0000000018DFOf@01E(=7zY3V0000u000000002G>;M2F01E)9 zDh2=m0000$0{{R30001DZUF!y01E&#um%7C0000e000000000*aRC4#01E(=u?7GD z0000W000000001q+5i9|01E){BnAKg0000i000000002E1ONac01E)TF9iSq0000e z000000002$R{{Vc01E(IF9!es0000S000000001%Y61Wv01E(2I0pa#000040RR91 z0000vlK=oB01E&V=mh`(0000W000000002VQvv`Y01E)PEe8Mq0001F000000001} zJOBV901E(=Yy|)S0000`000000002(5CH%p01E&x`~?620000;0000000025i2wj1 z01E)f-vs~w0000K000000002%0{{Rb01E&hE(HJp0000e000000002e2?78j01E&V z+Xest0000K0000000025E&u=`01E)*O9cP`0000u000000001TKL7wC01E&FQw0D3 z0000K000000001asR95Z01E(UO$Pt~00017000000001cB>(^-01E(QNCf}@0000W z000000002$^Z)=N01E(+>jeM+0000m000000000{l>h)D01E(MjRgPz0000m00000 z0001QzX1Ru01E)T;06Ey0000S000000001U*8l(_01E(QBL)Bf0000)000000000r zLIMCH01E&-DF*-m0000~000000002l!2tjw01E*0;06Ey00017000000001-hyVa0 z01E&F-vs~w0000i000000001tp8xO%01E(&MFju=0000W000000001deE|R>01E&Ny#@dP00000 z0RR910001cqyYdT01E(+ody5^0000q000000001?Hvs@501E){AO-*c0000;00000 z0002N761Su01E)rK?MK+0000a0000000008D*^x_01E)j7zY3V00017000000000h z(*OV>01E(I)CB+l0000)0000000002PXYiU01E(=4+j7M0000i000000000FApig( z01E&>Mg;%>0001>000000000fEC2u^01E(IT?GID0000S000000001b0000Y01E&J zCyZ`_q01E)D69xbP0000m z000000001y)&T$_01E&Fv<3hG0002!000000000|P5=NR01E&hfCT^m0000`0ssI2 z0002((EtD<01E(Y(**zk0000a000000002Mo&W$M01E(YkOcq$0000m000000002` z6#xJs02Bc5$q4`e0000e000000000gZ0000K000000002urvLyV z01E)bl?4C*0000K000000001Xq5uFQ01E)D^#uR`0000)000000002wwE_Sk01W_` zyaxaP0000T000000000|CIA2;01E)bNCf}@0000m000000002vj{pE701E(siUj}w z0000y000000002j#sB~!01E)18U_FW0000)000000002P2mt^h01E(+I0gU!0000i z000000000&WdHyo01E)fYXtxR0000K000000002)OacHR01E(wEC&Dp0000W00000 z0001wE&u=`01E)*O9cP`0000u000000001%3jhEj01E(sGX($u0000W0000000027 z90C9$01E(6;06Ey0000`000000001-ya50r01E&#-v$5x0000S0RR910000hZ~*`! z01E&Nu?7GD0000m000000002(-~a$301E)jCk6lj0000S000000000QBmn>-01E)* zUIqXF0001h000000002gi2wj101E)z-vs~w0000$0000000017kO2T901E)D&ISMg z0000a0RR910000&odEzM01E(2*#-ar0000K000000000&3IG5i01E)XP6Yq}0000q z000000002p!~g&x02BZi%n1Mh0000O000000001mJOBV901E*4Yy|)S0000i00000 z0002fegXg@01E&dE(ZVr0000e000000001xEdl@{01E(Q=mr1)0000e000000001{ z)Bpe?01E*8)CB+l0000)000000000ekpKW901E(6iv<7x0000u000000002G#{mE$ z01E)z;syW!0000m000000000|?f?KH01E&}F9rYr0000q000000002%5C8xo01E(w zIRyX!0000~000000001M&jA1;01E&(vIYPE0000i000000000_-T(k101E&N;spQz z0000a000000002|v;qJj01W`Ry9WRO0000h000000002~aR2}!01E&-a|HkZ0000a z000000001nhXMd101E)bFb4nt0000e000000001d)Byk@01E(|vjzYF0000e00000 z0002LM*sjK01E&>c?AFf0002o000000001dp#lIR01E)bMF#)?0000$0000000000 zT>$_h01E&-s0IK40000?000000001ss{sHa01E)*+Xest0000K000000000Q4gmln z01E)HI|cv%0000S000000000*OacHR01E(UEC&Dp0000S000000002_Hvs@501E&( zAqD^d0000K000000000#qXGaT01E(+Oa}k}0000i000000000HHvs@501E(MnFas= z0001J000000000QF8}}%01E(I!vp{T0000a1poj50001uO922P01E)jp#}f|00017 z000000001RApig(01E)nRRsV50000S000000000%e*gd?01E(+(**zk0000;00000 z0001@p#lIR01E)TO9ub|0001R000000001-6#xJt01E&dK?MK+0000a000000000) z+W`O~01E)zy9NLN0000u000000000gGXel201E)f9|r&c0000)000000002G=>Y&D z01E)f@&*6^0000S000000001%e*gd?01E)v(**zk0000K000000001Yj{*Q901E&( zMF#)?0000m000000002JX8-^q01E(gYy|)S0000W000000002;asmJ%01E(=DhB`n z0000S000000000IHUR)401E)@9tHpa0000K000000000{EdT%#01E(AxdZ?J0001d z0ssI20002t_5lDQ01E(!`33+00000u000000000@B>(^-01E&_NCf}@0000W00000 z0002DkOBZA01E)*Mh5@@0001d000000000~-2eb001E(QCI$ci0000O000000002( zeE|R>01E&_z6JmQ0002+000000002!7ytkw01E&-Lj?c;0000W000000001$lmY-E z01E&#JqG{)0000e000000002O1pojd01E)9F$Dks0001d000000002B!vFvx01E(2 zw*>$I0000y000000000hKmq_F01E){CkFrk0000`000000002hSpone01E){F9!es z0000$000000001iIsgD701E)DP6Yq}0000K0000000004T>tO%01E(&MFju=0000W000000001hHvj-401E)HOa%Y{0000W00000 z0000?DF6Tx01E)ny959L0001t2LJ#70001HqX7US01E(+ody5^0000q000000000H z@&N!M01E){^#%X{0000)000000000d`2heT01E(^{ssU50000u0000000029QUL%W z01E(Ar3L^10000?000000001`UjP6i01E(glm!3)0000y0RR910001!761Su01E&> zK?MK+0001#000000002XOaK5P01E)(0000y000000002V4*&on01E(cHw6Fy0000a000000000+ z8v+0#01E)*5(fYP0000~000000001bXaWEt01E)IMJ+0000O000000001$eEgZ0000K0000000010rvd;X01E(2P6q%00000O000000002fVE_Ok z01E)bl?4C*0000K000000000>E&%`{01E&Fi3R`w0000e0ssI20002g-T(k101E)b zCI$ci0000~000000000Bu>b%f01E(sngsv=0000e000000001N7y$qx01E(k0R{j7 z0001-000000000&5&-}r01E&p{sjO40000a000000002Po&o?O01E*0Ne2J`0000K z000000000r0|5Xc01E&#H3k3x0000)000000002+P5=NR01E&(g9QKp0000)00000 z0002sIRF4601E)fYXtxR0000K000000001o?EnBG01E&_E(QPq000040RR910002k zBme*+01E&lNCf}@0000W000000002Fs{jBZ01E*0{{;X50001J000000001dtN;Ka z01E)100sa60000m000000000Vi~#^501E&h%?1Df0000W000000000lO#lEQ01E(! zSOow80000K000000001^i~;~601E(gLk9o=0001F000000001}*Z}|{01E)D=mr1) z0000u000000001%%>V!*01E(69tHpa0000e000000002Wj{yK801E&ZX$AlQ0000e z000000001=R{;Pb01E)rFa`hs0000m000000002!3;+Nk01E(!Gz9-01E)nUj_gG z0000~000000002Q8Ug?!01E(s5(fYP0001F000000000)F#!M~01E&Rlm-9*0000e z0ssI20000O1_1yf01E)zGzI_w0000$000000000Cpa1|O01E)vnFRm<0001F00000 z0000Hi2wj101E(A-vs~w0000S000000002?a{&M%01E)HvIYPE0000a000000000z z&jA1;01E&(vIYPE0000i0000000024>;V8G01E&_^9BF_0001l000000000>k^lfA z01E)T=LG-&0000m000000002OFaZD}01E) zOa}k}0000y000000001l*#H0{01E(w-30&u0000e000000002A!~g&y01E&BxCH0002+000000002r*8l(_01E)9BL)Bf0000m z000000001+lK}uC01E)Lhz0-v0000e000000000@?EwHH01E(Q%mx4e0000K00000 z0002GH30x301E)Lm<9j<0000`000000001=Yybcv01E(IaRmSX0001x000000000Z zl>z`F01E)9o z0000S000000002X82|tx01E(ILj?c;0000a000000002!F#rG}01E)XXaxWO0000? z000000001N6#xJt01E*0Km`B*0000e0000000028u>t@g02Ba_%LxDg0000O00000 z0001}IRXG801E)f@&*6^0000S000000002F4FCWk02BZS%LxDg0000e000000001m z3jqKk01E(kItBm$000220000000010kN^N801E*4iUj}w0000m000000000JJOBV9 z01E(gYy|)S0000W000000000`TLAzf01E(srv?B30001h0000000028%>e)+01E(M z<^})&0000a000000000vo&f+N01E&l+6Djs0000O000000002ussR8Z01E)j+Xest z0000O000000002h&;S4;01E)@9tHpa0000K000000002UzW@Lt01E)j6b1kQ0000m z000000000o$N&H$01E)990mXY0000m000000001QE&u=`01E(+O9cP`0000~00000 z0001vVgLXl01E&(mIVL+0000O000000002I@c{rL01E)n&jtVh0000;000000002g zFaQ7|01E)5Vg&#I0000$0ssI20001t_5c7P01E(MF$Mqt0000S000000000st^fcc z01E(knFRm<0000K0000000019(EtD<01E(29|iyb0000S0000000009$^ZZ&01E(+ z9R>gZ0000e000000000VB>(^-01E&_NCf}@0000W000000001k!T|sx01E(6;RXNz z0000S000000001h7Xknx01E)n5eEPO00017000000002;UjhIk01E&>6bAqR0000m z000000002wGXel201E)%?gjt=0000K000000001WY5@Qu01E&VtOfu80000q00000 z0000$MgjmL01E(QD+d4o0000m000000002M1^@se01E)DP6Yq}0000K000000001; zqyPXS01E&#_XPj|0000K0000000005Hvj-401E)HOa%Y{0000W000000001e7XSbv z01E(wLInT-0001#000000000>X#xNu01E&(HU|Iz0002|000000001rumAue01E&l z0|o#90000K000000001gH39%401E*0?*;$>0000e000000001(=l}pB01E&FDh2=m z0000K000000002Y6#xJt01E&>K?MK+0001#000000000S4FCWl01E(|Gz9(|;01E(&JqG{)0000K000000002+RsjGa z01E)1rUn220000e000000001~C;|W?01E(E7zY3V0000K000000002S0s#Ob01E&d zH3k3x0000O000000001b+W-I}01E)1-vs~w0000e000000001|4*&on01E&xHw6Fy z0000$000000001@Kmh4F>=K z0000S0000000029v;qJj01W_ey9WRO0000O000000000yApig(01E)DRRsV50000a z000000001xP5}TS01E(Uqy_*00000m000000002#SO5Sb01E(sjs*Y!0000i00000 z0002!y#N3r01E&>6b1kQ0000O000000000X@BjcJ01E(2>IDD*0000K000000001y zBme*+01E&lNCf}@0000W000000000D!~g&y01E(!w*>$I0000y000000000{FaiJ~ z01E&>8wUUY0000$0ssI20002zR{#Ja01E&Vjs*Y!0000a000000000dECK)`01E&p z83zCW0000K000000001CGywo201E&N9tHpa0000W000000000zSO5Sb01E&(js*Y! z0000a000000002$MF0RI01E&dcm)6e0000a0RR910002OH~;`501E&ZYXtxR0000u z000000001aDggi@01E)rZw3GW0002I1ONa40000oi~s;401E)H;ROHy0001700000 z00015%mDx*01E&(q01E)zGzI_w0000$000000000M zCjbB<01E&}Nd*7^0001-000000000GLI40F01E&lZv_AV0000e000000001LzyJUu z01E(Y6$StR0001N000000002ChyVa001E&x-vs~w0000a000000000$;s5|501E&R zC}2i01E)zI0gU!0000W000000001j1_1yf01E)1 zHU?~;01E)vU zW&!{r01E(!GY0?w0000~0000000008kN^N801E)TiUj}w0000y000000000vCIJ8< z01E(^VFmyI0001R000000002yWB>pn01E)LYXtxR0000K000000002=6#)Pt02BZ) z%LxDg0000u0000000016lmP%D01E&tiv|Dy0000K000000000_E&u=`01E(+O9cP` z0000~000000000SQ2+oU01E)Xg#`cr0000m000000002rzyJUu01E(M76t$S0001F z000000001Bn*abJ01E&x?*#w=0000S000000000+9RdI%01E(U69)hQ0001700000 z0001R0|Edd01E&R3}Y01E)1r3L^10000S00000000266#@Vv01E(25eEPO0000O z000000001edH?_-01E)<&;z`F01E)TJqG{)0000S00000 z0000h4FCWl01E)zGz9<{h01E(^G6ett0000W000000002cl>h)D01E(M>IDD*0000m0RR910001H3jhEj z01E&xGX($u0000m000000001A#sL5#01E(M;syW!0000a000000000VW&r>q01E&Z zss;c60000u000000001|Qvd)W01E&#hy?%u0000$000000002$<^TX901E(=CHz>E01E&d z#|8iZ0000$000000001nFaQ7|01E&>Vg&#I0001F000000001lj{yK801E&ZX$AlQ z0000e000000001&-T?q201E(+zy<&S0000K000000001rbN~P%01E(Uu>}AC0000$ z0RR910002zmjD1F01E){jRgPz0000a000000002#m;eAG01E(Ijs*Y!0000a00000 z0001!`v3qU01E)rG6nzu0000m000000000+Yykiw01E)9o0000`000000000!9|8a(01E*869)hQ0000S0000000022`2heT z01E)n{ssU50000`0ssI20001aQ2_uV01E(oF9rYr0000a000000002^F9HA}01E)D z8V3LX0000u000000002elmP%D01E)1(FOnj0001-000000002xN&)~P01E&ZEC&Dp z0000m000000000sOaTBQ01E(wq6Po}0001l0RR910002iZvg-z01E)*um%7C0000e z000000000+v;Y7i01E)f0|o#90001N000000000z^Z)=N01E)nF9rYr0001700000 z0001P;?b;0001N00000000234gvro01E)X4+j7M0000a000000000xlmGxC01E*4=mh`( z0000a0RR910000VX8-^q01E(AYy|)S0000W000000001ur~m*W01E)*`vm|10000O z000000000sFaiJ~01E)*8V3LX00017000000002gHUI!301E(+Oa%Y{0000W00000 z0001wMF0RI01E(ka0LJW0002w000000000`qyPXS01E&N_XPj|0000e000000001H z0ssIa01E)vDg^)l0000q000000001D!vFvx01E&Bw*>$I0000?000000001>)&Kw^ z01E&ZBL)Bf0000m000000002wjRF8701E&lItKs%0000a000000001VSpfhd01E&p zrv?B30000S000000002!0000Y01E&JDFpxk0000q0000000006vH$=g01E)Xngsv= z0001N000000002)(*OV>01E)L)CB+l0000;000000000K0096Z01E*4GX?+v0000W z000000001tT>=0i01E&NF$Vwu0000S000000002g0|5Xc01E(kH3k3x0000K00000 z0000_wE_Sk01W^LyaxaP0000X000000001=hyeg101E(I#|8iZ0000W0RR910001Z z=m7vC01E)v#s&ZY0000S000000000XvH}1i01E&>QU?G40000a000000002@5dZ)p z01E&(JOuy%0000)000000000*KmY(D01E&xZUq1U0000W000000001IdjS9<01E(s zy9NLN0000q000000000QXaE2r01E)jm<0d;0000S000000001lDgpo^01E(&=LP@( z0000K000000001DVE_Ok01E)Hl?4C*0000K000000001n6#)Pu01E)n00sa60000K z000000002d1ONac01E)*F9iSq0000m000000002N*Z=?`01E&NBnAKg0000e00000 z0000i(EtD<01E&l9|iyb0000e000000001TaRLA$01E(MJO=;(0000e000000002v zp#T6P01E&}@C5(>0001(1ONa40000#IRF4601E)LYXtxR0000K000000002Y8vy_! z01E)bK?VQ-0000?0RR910000hAOHZN02l!11quKF0000m000000001>3IYHk01E)9 z4F>=K00017000000002p4FUin01E)L4hH}L0002s000000002zUH||h01E&_lm!3) z0000m00000000140{{Rb01E(cECm1n00017000000001Ry#N3r01E)z69xbP0001F z000000002;4*&on01E(=Hw6Fy0002+0RR910000EG6Dc101E(A9tQvb0001t00000 z00005RsaAZ01E(6U2mk;g01E(^G6ett0000W000000001x zdjJ3;01E&Z(FFhi0000W000000002RLjeFH01E(=CY&D01E&d#|8iZ z0000$000000000yF984|01E(civ|Dy0000e0ssI20001C5dZ)p01E)LPz3-00000; z000000000WQvv`Y01E)T5C;GN0001Z000000001rX8`~r01E(kss;c60001300000 z0000vfB^s^01E(+zy<&S0000K000000000?qW}OR01E&>_5}a{0000S0000000028 zl>q=E01E)v(gpwk0001-000000000FM*#pL01E(cp9TN`0000O000000002tEdc-` z01E)zhz0-v0000K000000000oBme*+01E&FNCf}@0000W000000002pWB~vo01E)v zsRjT50000W000000001!Q33!W01E(oEe8Mq0000S000000000dn*jhK01E(w)&>9o z0000`000000002xe*gd?01E&Zdj$Xh0000e000000001CvH$=g01E&(0|o#90001Z z000000000fxd8wo01E)zrUn220000?000000001Hx&Qzo01E)n4F&)J000130RR91 z0000jJOKbA01E(MoCW{@0000S000000001L8UO$y01E(sLj?c;0000W000000000k zssR8Z01E)H+Xest0000S000000000?ng9SI01E(o?gan<0000e000000002rjsXB7 z01E(A&ISMg0000)000000001^6#)Pu01E&VKL!8*0000W0000000018m;wMI01E)9 zJ_i5*0000O000000002iasU7#01E&}odo~@000000RR910000beF6X?01E(kJ_i5* z0000m000000000C6#xJt01E)jKm`B*0000e000000000sHvj-401E&}Y6SoQ0000q z000000001TQvm=X01E)nF9rYr00017000000001M^#A}O01E)X>jeM+0000K00000 z00007&H(@-01E(w<^})&0001x000000001DiU0s201E(o-~|8x0000q000000002g z+5rF}01E)Dxds3L0000O0000000009^8o-N01E&#_67g|0000)000000002h4FLcm z01E(sI|cv%0000m000000002=?*RZJ01E(2^#%X{0000q000000000%0s;Uc01E(g z*9HIp0000S000000001q>Hq*D01E(+=mh`(0000K000000002~L;?UJ01E)HDhB`n z0000?000000002vF#-T001E&R9tQvb0000)000000002a;{gC701E(g@df|@0000) z000000002Ik^ulB01E(M&;|ei0000;000000001=1ONac01E(|F9iSq0000W00000 z0000uiU9y301E&N$_4-c0002Y0RR910001YTmb+g01E&JG6nzu0000m000000002% ztpETb01E(QnFRm<0000K000000001JC;|W?01E)<7Y6_U0001R000000001z$^if( z01E(k0000a000000000-JOThB01E)r zB?kZi0002M000000002mMgRaJ01E&>RRsV50001N000000001^HUI!301E(+Oa%Y{ z0000W000000001pjsXB701E)nXa)cP0000;000000000ipaK9Q01E*0N(TS{0002U z000000002l0|Edd01E&>30000S00000 z0001wp8)_O01E)@oCW{@0000?000000001@UI73i01E)5s0IK40000S000000002j zL;(OI01E*0o(2E_0000S000000001Lpa1|O01E&F@C5(>0000)000000000OIsyP9 z01E)vBnJQh0000q000000001ywg3Pk01E)r1_l5C0000W000000000j(g6S>01E)f z=LP@(0000$000000002yO#uKR01E(6qy_*00000O0000000026E&>1|01E)983zCW z0001h000000001<0ssIa01E&ND+K@m0000q000000002d&j0`-01E)19tHpa0000a z000000001RN&x^O01E(Ep#}f|00017000000000@S^@wf01E&xFb4nt0001B00000 z00004ZUO)z01E(oItKs%0000K000000001*j{pE701E&NQU?G40000q000000002| z=K%mB01E)v#s&ZY0000S0000000029cmV(+01E(EwFUqH0000C0RR910001ZX#fBs z01E&xZUq1U0000W000000001KwE+Mk01E)v-39;v0000S000000001$5di=q01E(E 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%0AE^8OH*_>W_503bZKvHNk(F6 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%0AE^8 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 zZf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fyMMXDcWpi|LZ+S^mGG9eSc2ZL_ zUrE^}`HM?*tjGcGUyM@&gVLtip3F*g85Oi4mRSXf^(E;KGR z07pzoLPJp>0000000RU7000000Ek%!00000 z0D#E}0000000RU7000000I*pH000000Eo#60000000RU7000000Ki!X000000FcQE z0000000RU7000000LWPf000000GP=M0000000RU7000000N7av000000000A00000 z00RU7000000000A000000HDbU000000099201W^D00000000000Qmk100000009I5 z01W^D00000000000I10c00000009920I35200000000000Eqty00000009I50I352 z00000000000Is?00000009920LuXY00000000000BHXS00000009I50LuXY00000000000D#H~ z00000009920CfQX00000000000GP@N000000099202=}T00000000000LcCc00000 z009I502=}T000000000000;mI000000099202=}T00000000000HDeV0000000992 z09672000000000005Jav00000009I50967200000000000I13d00000009920QUg^ z00000000000Km!#00000009920A2wA00000000000093900000009I50A2wA00000 z000000LaP-000000099207wG>000000000000{pH00000009I507wG>0000000000 z0MN<_00000009920ObMz00000000000O-mI00000009920FMO#000000000006_l< z00000009I50FMO#00000000000PxBQ00000009920J8%C00000000000KonU00000 z009I50J8%C00000000000QkxY000000099209yk9000000000001(Rw0000000992 z0D}Mk00000000000LaS;00000009920D}Mk00000000000N~3B00000009920D}Mk z00000000000Qk!Z00000009920D}Mk000000000001(Ux00000009920D}Mk00000 z0000004U4}00000009920D}Mk000000000001yBQ00000009920D}Mk0000000000 z02s>&000000099208a)0000000000003gc=00000009920Mi8k0000000000065DD z00000009920DJ@h00000000000C>v@00000009920DJ@h000000000009eZj00000 z009920LlOW00000000000BFkz000000099207n1-01yBG000000FcWG0000000992 z07n1-01yBG000000JzHu000000099207n1-01yBG000000MN?`000000099207n1- z01yBG000000O-pJ000000099207n1-01yBG00000007Jh000000099207n1-01yBG z0000002s^(000000099207n1-01yBG0000005Hr6000000099207n1-01yBG00000 z07%RU000000099207n1-01yBG000000C39*000000099205Spq00000000000D#L0 z000000099204M+e01yBG000000I16e000000099204M+e01yBG000000AS1s00000 z0099204M+e01yBG000000Eo*8000000099209^(E00000000000GP`O0000000992 z0D1%f00000000000I000000099204N6l0000000000 z065GE00000009920DT1j000000000006@$M00000009920BQgL000000000008q>c z00000009920K)+Q000000000009eck00000009920IUQ600000000000BFn!00000 z0099207e1;00000000000MPyk00000009I501^WL00000000000NDNs00000009I5 z0GfF00000009I508Rh^00000000000J#4N00000009I50J8=F00000 z000000KoqV00000009I503ikd00000000000LcFd00000009I50AK*{0000000IO60Okb% z00000000000D#X40000000IO60QUv}00000000000Eo{C0000000IO600RI300000 z000000FciK0000000IO602>AX00000000000GQ7S0000000IO60F40v0000000000 z0HDta0000000IO60C5EX00000000000I1Ii0000000IO60HOo{00000000000I<&q z0000000IO60D%Dj00000000000JzTy0000000IO601*cO00000000000Km@)00000 z00IO60G9#)00000000000Lae?0000000IO60Ad9I00000000000MO3~0000000IO6 z015#B00000000000NBq70000000IO604)Rn00000000000N~FF0000000IO608Rw} z00000000000O-#N0000000IO60R93100000000000PxQV0000000IO60Hgx|00000 z000000Qk=d0000000IO600ssC0000000000007Vl0000000IO60EGbn0000000000 z00__t0000000IO60G9y(000000000001(g#0000000IO607n7<000000000002t5- z0000000IO60QUj_000000000003gr_0000000IO6080e`000000000004UH200000 z00IO60I~xB000000000005H%A0000000IO60Q3L=0000000000065SI0000000IO6 z01yWN000000000006@?Q0000000IO60Qvv`000000000007%dY0000000IO60J8%C z000000000008r2g0000000IO606PQ#000000000009eoo0000000IO60G9&*00000 z000000ASDw0000000IO60Br#P00000000000BFz&0000000IO60DT4k0000000000 z0C3O=0000000IO60I&uC00000000000C>;|0000000IO60F(d#00000000000D#a5 z0000000IO6044$e00000000000Eo~D0000000IO600aO400000000000FclL00000 z00IO602u-R00000000000GQAT0000000IO601yHI00000000000HDwb0000000IO6 z00;p900000000000I1Lj0000000IO6080S?00000000000I<*r0000000IO60KNbK z00000000000JzWz0000000IO608Ih_00000000000Km`*0000000IO600RR600000 z000000Lah@0000000IO60F?v)00000000000MO700000000IO60H6Z^0000000000 z0NBt80000000IO60A~UK00000000000N~IG0000000IO605S&v00000000000O-&O z0000000IO60L1|S00000000000PxTW0000000IO60CEQa00000000000Qk@e00000 z00IO60KfwP0000000000007Ym0000000IO608{}0000000000000_|u0000000IO6 z09^q9000000000001(j$0000000IO60HFf_000000000002t8;0000000IO60HXx} z000000000003gu`0000000IO606hZ$000000000004UK30000000IO60MY;e00000 z0000005H)B0000000IO604)Ik0000000000065VJ0000000IO604o6i0000000000 z06@_R0000000IO600#sB000000000007%gZ0000000IO609*$E000000000008r5h z0000000IO600jU5000000000009erp0000000IO606ql(00000000000ASGx00000 z00IO600sa600000000000BF$(0000000IO60KWhL00000000000C3R>0000000IO6 z0M!Nn00000000000C>>}0000000IO60Qdp`00000000000D#d60000000IO6009O7 z00000000000Ep2E0000000IO601N^E00000000000FcoM0000000IO60CEKY00000 z000000GQDU0000000IO60NMrs00000000000HDzc0000000IO60M!Ek0000000000 z0I1Ok0000000IO608It}00000000000I<;s0000000IO600#g700000000000JzZ! z0000000IO60Cfid00000000000Km}+0000000IO604@Un00000000000Lak^00000 z00IO60J8)D00000000000MOA10000000IO609ghA00000000000NBw90000000IO6 z0O$e$00000000000N~LH0000000IO60CNHW00000000000O-*P0000000IO60I>l8 z00000000000PxWX0000000IO60C@la00000000000Qk`f0000000IO60P+9;00000 z00000007bn0000000IO601yTM000000000000`0v0000000IO60HX!~0000000000 z01(m%0000000IO60F?j$000000000002tB<0000000IO60CWNX000000000003gx{ z0000000IO609FS8000000000004UN40000000IO602~DX000000000005H-C00000 z00IO60N4Zo0000000000065YK0000000IO609*zD000000000006@|S0000000IO6 z00;m8000000000007%ja0000000IO602u`U000000000008r8i0000000IO60B#2W z000000000009euq0000000IO60Hy)}00000000000ASJy0000000IO60Lldb00000 z000000BF()0000000IO60A2(D00000000000C3U?0000000IO60AvFI0000000000 z0C>^~0000000IO60O|t(00000000000D#g70000000IO60NVoq00000000000Ep5F z0000000IO60B!*Q00000000000FcrN0000000IO60A>LI00000000000GQGV00000 z00IO60I>o900000000000HD$d0000000IO605=B!00000000000I1Rl0000000IO6 z02l@U00000000000I<>t0000000IO609OY900000000000Jzc#0000000IO60Ez(s z00000000000Kn1-0000000IO6015*D00000000000Lan_0000000IO602=`S00000 z000000MOD20000000IO602~1T00000000000NBzA0000000IO60DA%e0000000000 z0N~OI0000000IO60PX|;00000000000O-;Q0000000IO601E~H00000000000PxZY z0000000IO60QLm{00000000000Qk}g0000000IO60B{BX0000000000007eo00000 z00IO60QLp|000000000000`3w0000000IO60B8jO000000000001(p&0000000IO6 z0L}pb000000000002tE=0000000IO60K@|00000000IO6 z0AmLL00000000000D#j80000000IO60Pg_+00000000000Ep8G0000000IO60HOc@ z00000000000FcuO0000000IO60J;GH00000000000GQJW0000000IO60C@xe00000 z000000HD(e0000000IO60Hp%}00000000000I1Um0000000IO605}Bz0000000000 z0I<^u0000000IO60IUN500000000000Jzf$0000000IO60G00000000000O->R0000000IO60D}Vn00000000000PxcZ0000000IO603rtf z00000000000Ql1h0000000IO6073x(0000000000007hp0000000IO60LcRY00000 z0000000`6x0000000IO60Mh~h000000000001(s(0000000IO60A~XL0000000000 z02tH>0000000IO601E&B000000000003g%}0000000IO601E^F000000000004UT6 z0000000IO60Q~>}000000000005H@E0000000IO60Kx?T0000000000065eM00000 z00IO60FnRz000000000006^3U0000000IO600RdA000000000007%pc0000000IO6 z0AT|F000000000008rEk0000000IO604N0j000000000009e!s0000000IO607wJ? z00000000000ASP!0000000IO60Ez000000000000EpBH0000000IO609OS700000000000FcxP z0000000IO609XeA00000000000GQMX0000000IO607L@-00000000000HD+f00000 z00IO60J#AG00000000000I1Xn0000000IO601N;C00000000000I<{v0000000IO6 z02&4W00000000000Jzi%0000000IO60J#JJ00000000000Kn7<0000000IO60G z00000000000Lat{0000000IO600smA00000000000MOJ40000000IO60Coic00000 z000000NB(C0000000IO600jjA00000000000N~UK0000000IO60MrBk0000000000 z0O-^S0000000IO60I3B400000000000Pxfa0000000IO60Hy^100000000000Ql4i z0000000IO601W^D0000000000007kq0000000IO60F46x000000000000`9y00000 z00IO60GI**000000000001(v)0000000IO601p8G000000000002tK?0000000IO6 z0F4F!000000000003g)~0000000IO60C)!g000000000004UW70000000IO609XY8 z000000000005H`F0000000IO60DJ)e0000000000065hN0000000IO607e4<00000 z0000006^6V0000000IO603ZSY000000000007%sd0000000IO60Qvy{0000000000 z08rHl0000000IO60EYqq000000000009e%t0000000IO60LlXZ00000000000ASS# z0000000IO602>4V00000000000BF?-0000000IO604xRo00000000000C3d_00000 z00IO60Ivf800000000000C?320000000IO60E-0x00000000000D#pA0000000IO6 z06+l%00000000000EpEI0000000IO606hT!00000000000Fc!Q0000000IO60DS=f z00000000000GQPY0000000IO60G|K=00000000000HD0000000IO60I38300000000000Laz}0000000IO60Qds{ z00000000000MOP60000000IO60Ez+t00000000000NB10000000IO6 z01^NI000000000004Uc90000000IO60HXl_000000000005I1H0000000IO60PO_; z0000000000065nP0000000IO608s$|000000000006^CX0000000IO60JH=E00000 z0000007%yf0000000IO603`+h000000000008rNn0000000IO609pb70000000000 z09e-v0000000IO60Gj~-00000000000ASY%0000000IO6022TJ00000000000BF|< z0000000IO60D}Pl00000000000C3j{0000000IO603-zf00000000000C?9400000 z00IO60I>xC00000000000D#vC0000000IO60Br*R00000000000EpKK0000000IO6 z0Qd#~00000000000Fc)S0000000IO60N?-s00000000000GQVa0000000IO60C@ob z00000000000HD_i0000000IO603`ze00000000000I1gq0000000IO602BcL00000 z000000I=5y0000000IO603QJW00000000000Jzr)0000000IO60H*)|0000000000 z0KnG?0000000IO607wG>00000000000La$~0000000IO606+o&00000000000MOS7 z0000000IO60E+|w00000000000NB?F0000000IO600aR500000000000N~dN00000 z00IO60N@4y00000000000O;2V0000000IO60F?y*00000000000Pxod0000000IO6 z0MY{h00000000000QlDl0000000IO601N{F0000000000007tt0000000IO604f0h z000000000000`I#0000000IO608<43000000000001(&-0000000IO603Zhd00000 z0000002tT_0000000IO600IU8000000000003g^20000000IO605k#s0000000000 z04UfA0000000IO603QSZ000000000005I4I0000000IO604W3j0000000000065qQ z0000000IO60K5VK000000000006^FY0000000IO60M7#e000000000007%#g00000 z00IO602KfL000000000008rQo0000000IO60OG00000 z000000O;5W0000000IO6000F500000000000Pxre0000000IO601gHK0000000000 z0QlGm0000000IO60E7ns0000000000007wu0000000IO60JZ=C000000000000`L$ z0000000IO605Jgo000000000001(*;0000000IO60FDCy000000000002tW`00000 z00IO60D=Yp000000000003g{30000000IO60AvLK000000000004UiB0000000IO6 z038Pa000000000005I7J0000000IO60KotN0000000000065tR0000000IO60CfNW z000000000006^IZ0000000IO60ILN6000000000007%&h0000000IO60Cold00000 z0000008rTp0000000IO60DA-g000000000009e@x0000000IO60FMR$0000000000 z0ASe(0000000IO60J;SL00000000000BG3>0000000IO60Dl7j00000000000C3p} z0000000IO60L%mc00000000000C?F60000000IO607wD=00000000000D##E00000 z00IO602crN00000000000EpQM0000000IO606+u)00000000000Fc=U0000000IO6 z0Mi2i00000000000GQbc0000000IO60CWKW00000000000HE0k0000000IO60Pq9= z00000000000I1ms0000000IO608Rn`00000000000I=B!0000000IO60M-Hk00000 z000000Jzx+0000000IO60O|$+00000000000KnM^0000000IO605Jpr0000000000 z0La-10000000IO60LK6T00000000000MOY90000000IO607eG@00000000000NB|H z0000000IO60HXu|00000000000N~jP0000000IO607(S^00000000000O;8X00000 z00IO606zx+00000000000Pxuf0000000IO607d}-00000000000QlJn0000000IO6 z0FMCx0000000000007zv0000000IO602lxO000000000000`O%0000000IO60FeOz z000000000001(;<0000000IO605k&t000000000002tZ{0000000IO60A&UM00000 z0000003g~40000000IO60DA)f000000000004UlC0000000IO600aX70000000000 z05IAK0000000IO60MY~i0000000000065wS0000000IO609ynA000000000006^La z0000000IO60M!Hl000000000007%*i0000000IO607n4;000000000008rWq00000 z00IO60N()s000000000009e`y0000000IO60E7bo00000000000ASh)0000000IO6 z0Nwxq00000000000BG6?0000000IO60Q3X^00000000000C3s~0000000IO60PX?+ z00000000000C?I70000000IO60Dc4j00000000000D#&F0000000IO60G|Q?00000 z000000EpTN0000000IO60Q&|200000000000Fc@V0000000IO60Q?330000000000 z0GQed0000000IO605b;w00000000000HE3l0000000IO60MG^i00000000000I1pt z0000000IO60Js1E00000000000I=E#0000000IO602u%P00000000000Jz!-00000 z00IO60967200000000000KnP_0000000IO602%-Q00000000000La=20000000IO6 z0Qv*~00000000000MObA0000000IO6073=;00000000000NC0I0000000IO602=@R z00000000000N~mQ0000000IO606PW%00000000000O;BY0000000IO60CfTY00000 z000000Pxxg0000000IO605${w00000000000QlMo0000000IO609*n90000000000 z007$w0000000IO60H6W@000000000000`R&0000000IO602}}S000000000001(>= z0000000IO60Ga>*000000000002tc|0000000IO60JjAI000000000003h2500000 z00IO60PX+)000000000004UoD0000000IO601F2I000000000005IDL0000000IO6 z0OSAw0000000000065zT0000000IO603ZPX000000000006^Ob0000000IO60384T z000000000007%;j0000000IO607C@;000000000008rZr0000000IO60KWtP00000 z0000009e}z0000000IO60Lujc00000000000ASk*0000000IO60JQ=D0000000000 z0BG9@0000000IO602%@S00000000000C3w00000000IO60OA4w00000000000C?L8 z0000000IO606zo(00000000000D#*G0000000IO60MP{i00000000000EpWO00000 z00IO609XS600000000000Fc`W0000000IO607(J>00000000000GQhe0000000IO6 z09FP700000000000HE6m0000000IO60LTIW00000000000I1su0000000IO60JH-D z00000000000I=H$0000000IO603HAU00000000000Jz%;0000000IO60G0p%00000 z000000KnS`0000000IO60I>!D00000000000La@30000000IO60J{VL0000000000 z0MOeB0000000IO60OkS!00000000000NC3J0000000IO603ZYa00000000000N~pR z0000000IO60Hg!}00000000000O;EZ0000000IO60B8aL00000000000Px!h00000 z00IO60Neur00000000000QlPp0000000IO60L=pc0000000000007(x0000000IO6 z0CNQZ000000000000`U(0000000IO603QGV000000000001(^>0000000IO60PzF> z000000000002tf}0000000IO60D1!e000000000003h560000000IO60Q&;~00000 z0000004UrE0000000IO60Kx+R000000000005IGM0000000IO60OJJ!0000000000 z065$U0000000IO605t*t000000000006^Rc0000000IO601E*C000000000007%>k z0000000IO607nA=000000000008rcs0000000IO60ICE4000000000009f1!00000 z00IO60P6(+00000000000ASn+0000000IO605Aps00000000000BGC^0000000IO6 z0M-Kl00000000000C3z10000000IO60N(%r00000000000C?O90000000IO603ieb z00000000000D#;H0000000IO603QMX00000000000EpZP0000000IO6096G500000 z000000Fc}X0000000IO60ImT500000000000GQkf0000000IO60Dl4i0000000000 z0HE9n0000000IO601pBH00000000000I1vv0000000IO60GR z00000000000O;Ha0000000IO60QLa@00000000000Px%i0000000IO605t&s00000 z000000QlSq0000000IO604V_g0000000000007+y0000000IO602u=S0000000000 z00`X)0000000IO60B8pQ000000000001({?0000000IO60GtK@000000000002ti~ z0000000IO60D%Vp000000000003h870000000IO60EGhp000000000004UuF00000 z00IO60Mr5i000000000005IJN0000000IO603iSX0000000000065(V0000000IO6 z0BHgM000000000006^Ud0000000IO605t{x000000000007%^l0000000IO600;yC z000000000008rft0000000IO603rYY000000000009f4#0000000IO60NDTl00000 z000000ASq-0000000IO60G9v&00000000000BGF_0000000IO60D=Jk0000000000 z0C3$20000000IO60Ja7I00000000000C?RA0000000IO60H_5300000000000D#>I z0000000IO60KfnM00000000000EpcQ0000000IO601O5I00000000000Fd1Y00000 z00IO605}E!00000000000GQng0000000IO6044(f00000000000HECo0000000IO6 z0DuAj00000000000I1yw0000000IO60R9F500000000000I=N&0000000IO60Ad0F z00000000000Jz-=0000000IO60Mq~g00000000000KnY|0000000IO60J#7F00000 z000000La}50000000IO60J;DG00000000000MOkD0000000IO608a-10000000000 z0NC9L0000000IO60Bi;T00000000000N~vT0000000IO60A>aN00000000000O;Kb z0000000IO60L%pd00000000000Px)j0000000IO60ObP!00000000000QlVr00000 z00IO6044_j0000000000007 z0000000IO600{yB00000000000Knb}0000000IO6073@<00000000000Lb1600000 z00IO603-ka00000000000MOnE0000000IO602KrP00000000000NCCM0000000IO6 z067H!00000000000N~yU0000000IO60KxzO00000000000O;Nc0000000IO60DuDk z00000000000Px-k0000000IO60BZpN00000000000QlYs0000000IO6044?i00000 z00000007?!0000000IO60O|w)000000000000`d+0000000IO603`qb0000000000 z01)2^0000000IO60G0#*000000000002tp10000000IO60LuXY000000000003hE9 z0000000IO60Cxre000000000004U!H0000000IO60M7&f000000000005IPP00000 z00IO60M-Nm0000000000065dO00000000000ASz=0000000IO609XV700000000000BGO|00000 z00IO60RI9200000000000C3<50000000IO60K5bM00000000000C?aD0000000IO6 z0H^{000000000000D#~L0000000IO60HFl{00000000000EplT0000000IO600Ra9 z00000000000FdAb0000000IO60IdW700000000000GQwj0000000IO60Imf900000 z000000HELr0000000IO60KEVJ00000000000I1*z0000000IO604xCj0000000000 z0I=W*0000000IO60Pp|+00000000000Jz`@0000000IO609gS500000000000Kni0 z0000000IO60P_O?00000000000Lb780000000IO60A&II00000000000MOtG00000 z00IO60LK9U00000000000NCIO0000000IO60N4Tm00000000000N~&W0000000IO6 z0B8XK00000000000O;Te0000000IO607C-+00000000000Px@m0000000IO603`(g z00000000000Qleu0000000IO600IX90000000000007|$0000000IO60R96200000 z0000000`j;0000000IO60PF<-000000000001)8`0000000IO602u@T0000000000 z02tv30000000IO606+r(000000000003hKB0000000IO60EPnq000000000004U)J z0000000IO6009F4000000000005IVR0000000IO60CWWa0000000000065_Z00000 z00IO60FDL#000000000006^gh0000000IO601*KI000000000007&5p0000000IO6 z04M|i000000000008rrx0000000IO606hl)000000000009fG(0000000IO60Dk}g z00000000000AS$>0000000IO60O0000000000 z0D$2M0000000IO60R90000000000000EpoU0000000IO600jX600000000000FdDc z0000000IO60Lugb00000000000GQzk0000000IO603rkc00000000000HEOs00000 z00IO60OAG!00000000000I1;!0000000IO60L%dZ00000000000I=Z+0000000IO6 z0Ga~;00000000000Jz}^0000000IO606YQ!00000000000Knl10000000IO608s(} z00000000000LbA90000000IO60IdN400000000000MOwH0000000IO606hc%00000 z000000NCLP0000000IO60L=ve00000000000N~*X0000000IO60I~)E0000000000 z0O;Wf0000000IO602BiN00000000000Px`n0000000IO60L}sc00000000000Qlhv z0000000IO60JQ@E00000000000080%0000000IO60QCd_000000000000`m<00000 z00IO601^iP000000000001)B{0000000IO60Imc8000000000002ty40000000IO6 z0O0}v000000000003hNC0000000IO605Svs000000000004U-K0000000IO601X8I z000000000005IYS0000000IO604x9i0000000000065|a0000000IO606zu*00000 z0000006^ji0000000IO60Q?02000000000007&8q0000000IO60B;2V0000000000 z08ruy0000000IO609OP6000000000009fJ)0000000IO60Idc900000000000AS(? z0000000IO60OSS$00000000000BGU~0000000IO608aw|00000000000C3_700000 z00IO60NVus00000000000C?gF0000000IO600{;F00000000000D$5N0000000IO6 z0ILQ700000000000EprV0000000IO60M!Bj00000000000FdGd0000000IO60OSP# z00000000000GQ$l0000000IO604)Fj00000000000HERt0000000IO60IvW500000 z000000I1>#0000000IO60Gj{+00000000000I=c-0000000IO602cxP0000000000 z0J!1_0000000IO60MrHm00000000000Kno20000000IO60ImQ400000000000LbDA z0000000IO60Br^U00000000000MOzI0000000IO601X5H00000000000NCOQ00000 z00IO60J{bN00000000000N~;Y0000000IO60PO<+00000000000O;Zg0000000IO6 z0Kf$R00000000000Px}o0000000IO60GR;*00000000000Qlkw0000000IO608In{ z00000000000083&0000000IO60JsDI000000000000`p=0000000IO600aU600000 z0000001)E|0000000IO60DcAl000000000002t#50000000IO608s+~0000000000 z03hQD0000000IO60P6$*000000000004U=L0000000IO60KozP000000000005IbT z0000000IO60BZyQ00000000000660b0000000IO60DJ=g000000000006^mj00000 z00IO60Pz3-000000000007&Br0000000IO60Otk(000000000008rxz0000000IO6 z0PX<*000000000009fM*0000000IO600#pA00000000000AS+@0000000IO60K5hO z00000000000BGY00000000IO60QLg_00000000000C3|80000000IO6051dp00000 z000000C?jG0000000IO60M`Tn00000000000D$8O0000000IO600IF30000000000 z0EpuW0000000IO604@Lk00000000000FdJe0000000IO60G0&+00000000000GQ(m z0000000IO60MrEl00000000000HEUu0000000IO60M-Bi00000000000I1^$00000 z00IO60E+<{900066007hh0000000000008LY2><{900066006oI00000 z00000008jg2><{900066001Hb0000000000008*o2><{900066008g;0000000000 z0002w2><{900066005x|0000000000000Q&2><{900066004*v0000000000000o= z2><{900066001Nd0000000000000=|2><{900066003VB0000000000001E52><{9 z00066004*r0000000000001cD2><{900066008p<0000000000001!L2><{900066 z0031700000000000021T2><{900066001xm0000000000002Pb2><{900066004sq z0000000000002nj2><{900066008s@0000000000002<{900066003kM00000 z00000003Cz2><{900066008y`0000000000003a*2><{900066007ej0000000000 z003y@2><{900066003110000000000004002><{900066000020000000000004O8 z2><{900066004ys0000000000004mG2><{900066008_10000000000004;O2><{9 z00066000aJ0000000000005BW2><{9000660015b0000000000005Ze2><{900066 z003SG0000000000005xm2><{9000660027y0000000000005}u2><{900066005T- z0000000000006M$2><{900066006`T0000000000006k;2><{900066001op00000 z00000006+`2><{900066002Y<0000000000007A32><{900066007Vg0000000000 z007YB2><{900066004&s0000000000007wJ2><{9000660058#0000000000007|R z2><{900066008|30000000000008LZ2><{9000660043U0000000000008jh2><{9 z00066000OF0000000000008*p2><{900066006fH00000000000002x2><{900066 z007GX0000000000000Q(2><{900066001!n0000000000000o>2><{900066000#S z0000000000000=}2><{900066007Yg0000000000001E62><{900066001uq00000 z00000001cE2><{900066005W<0000000000001!M2><{900066002t@0000000000 z0021U2><{900066007no0000000000002Pc2><{900066006840000000000002nk z2><{900066004;v0000000000002<{900066002z^0000000000003C!2><{9 z00066001xr0000000000003a+2><{900066002A&0000000000003y^2><{900066 z004^v0000000000004012><{900066002t_0000000000004O92><{9000660040V z0000000000004mH2><{900066005`}0000000000004;P2><{900066000&T00000 z00000005BX2><{9000660027!0000000000005Zf2><{9000660015a0000000000 z005xn2><{900066004sm0000000000005}v2><{900066003|T0000000000006M% z2><{900066000jL0000000000006k<2><{900066003qM0000000000006+{2><{9 z00066005W)0000000000007A42><{900066001%o0000000000007YC2><{900066 z001)p0000000000007wK2><{900066006B50000000000007|S2><{90006600903 z0000000000008La2><{900066007qm0000000000008ji2><{900066004#p00000 z00000008*q2><{900066000^V00000000000002y2><{900066000aG0000000000 z000Q)2><{900066006880000000000000o?2><{900066000jK0000000000000=~ z2><{900066001-q0000000000001E72><{900066000~W0000000000001cF2><{9 z00066002z`0000000000001!N2><{900066004IY00000000000021V2><{900066 z000*S0000000000002Pd2><{9000660083#0000000000002nl2><{900066001Ng z0000000000002<{900066007(t0000000000003C#2><{900066007(p00000 z00000003a-2><{900066001Wj0000000000003y_2><{900066003(P0000000000 z004022><{900066005W;0000000000004OA2><{900066002t|0000000000004mI z2><{900066006}T0000000000004;Q2><{900066006Q90000000000005BY2><{9 z00066001)t0000000000005Zg2><{900066001ik0000000000005xo2><{900066 z004ym0000000000005}w2><{900066001=r0000000000006M&2><{900066001Kd z0000000000006k=2><{900066005B&0000000000006+|2><{900066003|Y00000 z00000007A52><{900066002G#0000000000007YD2><{900066001Th0000000000 z007wL2><{900066008g-0000000000007|T2><{9000660049V0000000000008Lb z2><{900066004CZ0000000000008jj2><{900066004Ri0000000000008*r2><{9 z00066001Zk00000000000002z2><{9000660074X0000000000000Q*2><{900066 z008R&0000000000000o@2><{9000660015Z0000000000000>02><{900066003$S z0000000000001E82><{900066001)q0000000000001cG2><{900066002)000000 z00000001!O2><{900066008d>00000000000021W2><{900066006ZC0000000000 z002Pe2><{900066008|20000000000002nm2><{900066007ki0000000000002<{900066005o_0000000000003C$2><{900066002h@0000000000003a;2><{9 z00066001@s0000000000003y`2><{900066002V=0000000000004032><{900066 z006iJ0000000000004OB2><{900066007+u0000000000004mJ2><{9000660049Z z0000000000004;R2><{900066003hG0000000000005BZ2><{900066002G*00000 z00000005Zh2><{900066008s>0000000000005xp2><{900066002D&0000000000 z005}x2><{900066002=20000000000006M(2><{900066003160000000000006k> z2><{900066009310000000000006+}2><{900066003VG0000000000007A62><{9 z00066004Xi0000000000007YE2><{900066006`R0000000000007wM2><{900066 z004vn0000000000007|U2><{900066006@R0000000000008Lc2><{900066008j? z0000000000008jk2><{900066001`t0000000000008*s2><{900066001}u00000 z000000002!2><{900066000RD0000000000000Q+2><{900066000vQ0000000000 z000o^2><{900066003bG0000000000000>12><{900066008R%0000000000001E9 z2><{900066004jm0000000000001cH2><{900066005r`0000000000001!P2><{9 z00066002q`00000000000021X2><{900066001rm0000000000002Pf2><{900066 z006xL0000000000002nn2><{900066006-T0000000000002<{900066001ll z0000000000003C%2><{900066002_~0000000000003a<2><{900066001fk00000 z00000003y{2><{900066000I80000000000004042><{9000660040Y0000000000 z004OC2><{900066004Ic0000000000004mK2><{900066002@10000000000004;S z2><{900066004pn0000000000005Ba2><{900066002t{0000000000005Zi2><{9 z00066007wp0000000000005xq2><{900066000#M0000000000005}y2><{900066 z0040U0000000000006M)2><{900066000UH0000000000006k?2><{900066002P* z0000000000006+~2><{900066008L#0000000000007A72><{900066003_U00000 z00000007YF2><{900066007km0000000000007wN2><{900066001-u0000000000 z007|V2><{900066002}30000000000008Ld2><{900066003PF0000000000008jl z2><{900066005H(0000000000008*t2><{900066002A#00000000000002#2><{9 z00066001fn0000000000000Q-2><{9000660021#0000000000000o_2><{900066 z0021v0000000000000>22><{900066008U&0000000000001EA2><{900066004jh z0000000000001cI2><{900066004*t0000000000001!Q2><{900066008>{00000 z000000021Y2><{900066000RC0000000000002Pg2><{900066007$n0000000000 z002no2><{900066001ch0000000000002<{900066003PC0000000000003C& z2><{900066002S+0000000000003a=2><{9000660024w0000000000003y|2><{9 z00066005Z+0000000000004052><{900066007wm0000000000004OD2><{900066 z008^~0000000000004mL2><{900066005f;0000000000004;T2><{900066000&O z0000000000005Bb2><{900066004so0000000000005Zj2><{900066002(~00000 z00000005xr2><{900066000vL0000000000005}z2><{9000660027x0000000000 z006M*2><{900066008p_0000000000006k@2><{900066006%R0000000000006-0 z2><{900066002@00000000000007A82><{900066003D70000000000007YG2><{9 z00066006rK0000000000007wO2><{900066000~V0000000000007|W2><{900066 z001-x0000000000008Le2><{900066004{z0000000000008jm2><{900066008*| z0000000000008*u2><{900066004Uj00000000000002$2><{900066001un00000 z00000000Q;2><{900066008>|0000000000000o`2><{900066003zR0000000000 z000>32><{9000660040W0000000000001EB2><{900066008*}0000000000001cJ z2><{900066005T+0000000000001!R2><{9000660065100000000000021Z2><{9 z00066000^R0000000000002Ph2><{900066000dK0000000000002np2><{900066 z005Z;0000000000002<{900066003(T0000000000003C(2><{900066008v> z0000000000003a>2><{900066005i=0000000000003y}2><{9000660080v00000 z00000004062><{900066007MZ0000000000004OE2><{900066006260000000000 z004mM2><{900066002Ay0000000000004;U2><{900066006Q80000000000005Bc z2><{900066008m?0000000000005Zk2><{900066000aD0000000000005xs2><{9 z00066002b<0000000000005}!2><{900066002Dz0000000000006M+2><{900066 z005-{0000000000006k^2><{900066007Yd0000000000006-12><{900066007qp z0000000000007A92><{900066006K60000000000007YH2><{900066004dg00000 z00000007wP2><{900066008g?0000000000007|X2><{900066005^20000000000 z008Lf2><{900066004#o0000000000008jn2><{900066007+t0000000000008*v z2><{900066008U(00000000000002%2><{900066002G!0000000000000Q<2><{9 z00066001ln0000000000000o{2><{900066004~z0000000000000>42><{900066 z006rI0000000000001EC2><{900066006fE0000000000001cK2><{900066001@x z0000000000001!S2><{9000660083z00000000000021a2><{900066001Ne00000 z00000002Pi2><{900066002b-0000000000002nq2><{900066005@}0000000000 z002<{900066002J#0000000000003C)2><{900066003qL0000000000003a? z2><{900066006520000000000003y~2><{900066002M$0000000000004072><{9 z00066007zn0000000000004OF2><{900066005K$0000000000004mN2><{900066 z002P%0000000000004;V2><{900066005N%0000000000005Bd2><{900066000pM z0000000000005Zl2><{9000660024$0000000000005xt2><{900066004&v00000 z00000005}#2><{9000660077V0000000000006M-2><{900066006E70000000000 z006k_2><{900066003tP0000000000006-22><{900066007nj0000000000007AA z2><{9000660077U0000000000007YI2><{900066000RE0000000000007wQ2><{9 z00066006WA0000000000007|Y2><{900066001Ea0000000000008Lg2><{900066 z008X-0000000000008jo2><{900066002@40000000000008*w2><{900066005K( z00000000000002&2><{900066002w}0000000000000Q=2><{900066005%`00000 z00000000o|2><{900066000~U0000000000000>52><{900066008O*0000000000 z001ED2><{900066005By0000000000001cL2><{900066006%O0000000000001!T z2><{900066004jn00000000000021b2><{900066005r^0000000000002Pj2><{9 z00066004Uc0000000000002nr2><{900066001-r0000000000002<{900066 z001!u0000000000003C*2><{900066002b=0000000000003a@2><{900066004^s z0000000000003z02><{900066002n_0000000000004082><{900066002M+00000 z00000004OG2><{900066005B$0000000000004mO2><{900066000650000000000 z004;W2><{900066003J70000000000005Be2><{900066006K80000000000005Zm z2><{900066004{w0000000000005xu2><{900066007Pe0000000000005}$2><{9 z00066001`x0000000000006M;2><{900066001xo0000000000006k`2><{900066 z002k_0000000000006-32><{900066001fi0000000000007AB2><{900066001fj z0000000000007YJ2><{900066008^}0000000000007wR2><{900066000#R00000 z00000007|Z2><{900066005x^0000000000008Lh2><{900066001Bb0000000000 z008jp2><{900066008s_0000000000008*x2><{900066004Xd00000000000002( z2><{900066004;s0000000000000Q>2><{900066002V(0000000000000o}2><{9 z00066000vM0000000000000>62><{900066001oo0000000000001EE2><{900066 z002k<0000000000001cM2><{900066002Y)0000000000001!U2><{900066002b* z00000000000021c2><{900066007Dc0000000000002Pk2><{900066004Ld00000 z00000002ns2><{9000660052z0000000000002<{9000660089x0000000000 z003C+2><{900066008>}0000000000003a^2><{900066000{Y0000000000003z1 z2><{9000660043V0000000000004092><{900066008Cy0000000000004OH2><{9 z00066001cl0000000000004mP2><{900066006}U0000000000004;X2><{900066 z003?U0000000000005Bf2><{900066008R-0000000000005Zn2><{900066008&^ z0000000000005xv2><{900066006HA0000000000005}%2><{900066008m@00000 z00000006M<2><{900066009360000000000006k{2><{900066000&S0000000000 z006-42><{9000660077Z0000000000007AC2><{900066001cm0000000000007YK z2><{900066003zN0000000000007wS2><{9000660080u0000000000007|a2><{9 z00066002z~0000000000008Li2><{900066002k;0000000000008jq2><{900066 z005){0000000000008*y2><{900066003eE00000000000002)2><{900066007Sd z0000000000000Q?2><{900066002=30000000000000o~2><{900066004Cc00000 z00000000>72><{900066001im0000000000001EF2><{900066002n<0000000000 z001cN2><{900066006=Q0000000000001!V2><{900066000F700000000000021d z2><{900066007hj0000000000002Pl2><{900066000gI0000000000002nt2><{9 z00066000gH0000000000002<#2><{900066002b+0000000000003C-2><{900066 z005u?0000000000003a_2><{900066002n@0000000000003z22><{900066003YC z00000000000040A2><{900066008O&0000000000004OI2><{9000660086z00000 z00000004mQ2><{900066001om0000000000004;Y2><{900066003MC0000000000 z005Bg2><{900066001xq0000000000005Zo2><{900066008F#0000000000005xw z2><{900066004>x0000000000005}&2><{900066007bj0000000000006M=2><{9 z00066008m=0000000000006k|2><{900066004Fa0000000000006-52><{900066 z000OA0000000000007AD2><{900066000;Q0000000000007YL2><{900066000*Q z0000000000007wT2><{900066003PB0000000000007|b2><{900066004vr00000 z00000008Lj2><{900066005u_0000000000008jr2><{900066000pK0000000000 z008*z2><{900066000XD00000000000002*2><{900066000F90000000000000Q@ z2><{9000660024#0000000000000p02><{900066003eJ0000000000000>82><{9 z00066005B!0000000000001EG2><{900066000940000000000001cO2><{900066 z001ck0000000000001!W2><{900066006fF00000000000021e2><{9000660012W z0000000000002Pm2><{900066008I!0000000000002nu2><{900066007Ve00000 z00000002<$2><{900066002q^0000000000003C;2><{900066005H)0000000000 z003a`2><{900066003+O0000000000003z32><{900066001Qf00000000000040B z2><{900066000mJ0000000000004OJ2><{900066000*R0000000000004mR2><{9 z00066001!p0000000000004;Z2><{900066001@t0000000000005Bh2><{900066 z009330000000000005Zp2><{900066002q=0000000000005xx2><{900066007wn z0000000000005}(2><{900066004Fb0000000000006M>2><{9000660086x00000 z00000006k}2><{900066001Ha0000000000006-62><{900066000F80000000000 z007AE2><{900066003440000000000007YM2><{900066003<{900066003130000000000007|c2><{900066002t>0000000000008Lk2><{9 z00066003wP0000000000008js2><{900066006N70000000000008*!2><{900066 z0015Y00000000000002+2><{9000660074V0000000000000Q^2><{900066006`S z0000000000000p12><{900066001in0000000000000>92><{900066000#N00000 z00000001EH2><{900066003VD0000000000001cP2><{900066002w?0000000000 z001!X2><{900066003GA00000000000021f2><{900066005l>0000000000002Pn z2><{900066003eH0000000000002nv2><{9000660083x0000000000002<%2><{9 z00066005l@0000000000003C<2><{900066006T90000000000003a{2><{900066 z000jJ0000000000003z42><{9000660083v00000000000040C2><{900066007Mf z0000000000004OK2><{900066007Ga0000000000004mS2><{900066002z@00000 z00000004;a2><{900066003+P0000000000005Bi2><{900066003JC0000000000 z005Zq2><{900066007<{900066003$P0000000000005}) z2><{900066004ag0000000000006M?2><{900066006=U0000000000006k~2><{9 z00066002+}0000000000006-72><{900066002-00000000000007AF2><{900066 z003780000000000007YN2><{900066002n=0000000000007wV2><{900066000UF z0000000000007|d2><{900066008_00000000000008Ll2><{900066000I700000 z00000008jt2><{900066003eK0000000000008*#2><{900066005K%0000000000 z0002-2><{900066008v`0000000000000Q_2><{9000660089y0000000000000p2 z2><{900066003750000000000000>A2><{900066005K*0000000000001EI2><{9 z00066003?V0000000000001cQ2><{900066004#t0000000000001!Y2><{900066 z003YE00000000000021g2><{900066006)N0000000000002Po2><{900066002(_ z0000000000002nw2><{900066003JD0000000000002<&2><{900066004Rc00000 z00000003C=2><{900066007(u0000000000003a|2><{900066006fJ0000000000 z003z52><{900066005%^00000000000040D2><{900066006TA0000000000004OL z2><{900066006xN0000000000004mT2><{900066002V-0000000000004;b2><{9 z00066006!M0000000000005Bj2><{900066005)~0000000000005Zr2><{900066 z007tn0000000000005xz2><{900066004~u0000000000005}*2><{900066002w| z0000000000006M@2><{900066006uJ0000000000006l02><{900066003$R00000 z00000006-82><{900066005{40000000000007AG2><{900066004IZ0000000000 z007YO2><{9000660074W0000000000007wW2><{900066003$M0000000000007|e z2><{900066008y?0000000000008Lm2><{900066001Kb0000000000008ju2><{9 z00066004mn0000000000008*$2><{900066003hH00000000000002;2><{900066 z000*T0000000000000Q`2><{900066007Ye0000000000000p32><{900066000RA z0000000000000>B2><{900066000gL0000000000001EJ2><{900066008a-00000 z00000001cR2><{900066002J$0000000000001!Z2><{900066005Q&0000000000 z0021h2><{900066008O%0000000000002Pp2><{900066003740000000000002nx z2><{900066003bD0000000000002<(2><{9000660043X0000000000003C>2><{9 z00066003+U0000000000003a}2><{900066006WG0000000000003z62><{900066 z002}600000000000040E2><{900066002+`0000000000004OM2><{900066001}y z0000000000004mU2><{900066002<{0000000000004;c2><{900066007Ab00000 z00000005Bk2><{900066006KA0000000000005Zs2><{900066005i>0000000000 z005x!2><{900066008d*0000000000005}+2><{900066005;10000000000006M^ z2><{900066008F$0000000000006l12><{900066001Tg0000000000006-92><{9 z00066007Pf0000000000007AH2><{900066002?|0000000000007YP2><{900066 z000OB0000000000007wX2><{900066008p@0000000000007|f2><{900066006E6 z0000000000008Ln2><{900066005K)0000000000008jv2><{900066001}#00000 z00000008*%2><{900066002(}00000000000002<2><{900066007DY0000000000 z000Q{2><{900066007wq0000000000000p42><{900066007?w0000000000000>C z2><{900066000UE0000000000001EK2><{900066003MA0000000000001cS2><{9 z00066009350000000000001!a2><{900066001%u00000000000021i2><{900066 z0021x0000000000002Pq2><{900066008C&0000000000002ny2><{9000660052v z0000000000002<)2><{900066001Nc0000000000003C?2><{900066007$o00000 z00000003a~2><{900066001Wi0000000000003z72><{900066001uo0000000000 z0040F2><{900066005~50000000000004ON2><{900066005u{0000000000004mV z2><{900066003PD0000000000004;d2><{900066004Lc0000000000005Bl2><{9 z000660046V0000000000005Zt2><{900066007_v0000000000005x#2><{900066 z001!s0000000000005}-2><{9000660055y0000000000006M_2><{900066002@2 z0000000000006l22><{900066002_}0000000000006-A2><{900066005~000000 z00000007AI2><{900066002b?0000000000007YQ2><{900066005c+0000000000 z007wY2><{900066002|~0000000000007|g2><{900066004*q0000000000008Lo z2><{900066004Og0000000000008jw2><{900066003100000000000008*&2><{9 z00066000CA00000000000002=2><{900066001=u0000000000000Q|2><{900066 z004;u0000000000000p52><{900066003YH0000000000000>D2><{9000660077Y z0000000000001EL2><{900066003410000000000001cT2><{900066003SF00000 z00000001!b2><{900066001}w00000000000021j2><{900066001`w0000000000 z002Pr2><{900066008{~0000000000002nz2><{900066000{W0000000000002<* z2><{900066008Fz0000000000003C@2><{900066006lI0000000000003b02><{9 z000660027$0000000000003z82><{900066004jl00000000000040G2><{900066 z003<{9000660024z0000000000004mW2><{900066005K& z0000000000004;e2><{900066000;V0000000000005Bm2><{900066007kh00000 z00000005Zu2><{900066006@P0000000000005x$2><{900066002M-0000000000 z005};2><{900066006TE0000000000006M`2><{9000660052!0000000000006l3 z2><{900066005E!0000000000006-B2><{9000660015X0000000000007AJ2><{9 z00066003720000000000007YR2><{900066003_W0000000000007wZ2><{900066 z005l?0000000000007|h2><{900066003A30000000000008Lp2><{900066004Rh z0000000000008jx2><{900066003VC0000000000008*(2><{900066005E#00000 z000000002>2><{900066006230000000000000Q}2><{900066006)Q0000000000 z000p62><{900066002e=0000000000000>E2><{900066005u`0000000000001EM z2><{900066004>w0000000000001cU2><{900066006xO0000000000001!c2><{9 z000660000400000000000021k2><{900066005-~0000000000002Ps2><{900066 z005i;0000000000002n!2><{900066002V)0000000000002<+2><{900066007|w z0000000000003C^2><{900066009300000000000003b12><{900066001Ec00000 z00000003z92><{900066007GZ00000000000040H2><{900066000;R0000000000 z004OP2><{900066003VE0000000000004mX2><{900066000660000000000004;f z2><{9000660058$0000000000005Bn2><{9000660055!0000000000005Zv2><{9 z00066000I90000000000005x%2><{900066005c<0000000000005}<2><{900066 z002+~0000000000006M{2><{900066004ai0000000000006l42><{900066002P; z0000000000006-C2><{9000660089$0000000000007AK2><{900066000XG00000 z00000007YS2><{900066007+s0000000000007wa2><{900066000360000000000 z007|i2><{900066005E(0000000000008Lq2><{900066008&_0000000000008jy z2><{900066006!P0000000000008*)2><{900066000yO00000000000002?2><{9 z00066008s?0000000000000Q~2><{900066003D40000000000000p72><{900066 z006ZB0000000000000>F2><{900066007|t0000000000001EN2><{900066000gG z0000000000001cV2><{900066001xp0000000000001!d2><{900066002Y*00000 z000000021l2><{900066001Nh0000000000002Pt2><{9000660058!0000000000 z002n#2><{900066001He0000000000002<-2><{900066006EA0000000000003C_ z2><{900066006NA0000000000003b22><{900066003wN0000000000003zA2><{9 z00066006-O00000000000040I2><{900066001fl0000000000004OQ2><{900066 z003kJ0000000000004mY2><{900066001Qc0000000000004;g2><{900066004yo z0000000000005Bo2><{900066002G&0000000000005Zw2><{900066003G500000 z00000005x&2><{900066003qJ0000000000005}=2><{900066003J60000000000 z006M|2><{900066001Ka0000000000006l52><{900066008I#0000000000006-D z2><{900066008F%0000000000007AL2><{900066007<{9 z00066003M70000000000007wb2><{900066004sp0000000000007|j2><{900066 z007<{900066008a<0000000000008jz2><{900066004ae z0000000000008**2><{900066008v@00000000000002@2><{900066003hF00000 z00000000R02><{900066005Z=0000000000000p82><{900066003P80000000000 z000>G2><{900066008s`0000000000001EO2><{9000660058z0000000000001cW z2><{9000660043Z0000000000001!e2><{900066007_x00000000000021m2><{9 z00066002V*0000000000002Pu2><{900066002`10000000000002n$2><{900066 z001il0000000000002<;2><{900066003S90000000000003C`2><{900066007qk z0000000000003b32><{900066001um0000000000003zB2><{900066005{200000 z000000040J2><{900066000mL0000000000004OR2><{900066002S-0000000000 z004mZ2><{900066004mm0000000000004;h2><{900066008C$0000000000005Bp z2><{900066002q{0000000000005Zx2><{900066002`50000000000005x(2><{9 z00066004Lb0000000000005}>2><{900066005!|0000000000006M}2><{900066 z008;|0000000000006l62><{900066006ZH0000000000006-E2><{900066004ml z0000000000007AM2><{900066007Yh0000000000007YU2><{900066003SC00000 z00000007wc2><{9000660055w0000000000007|k2><{900066001)v0000000000 z008Ls2><{900066003tO0000000000008j!2><{900066001fm0000000000008*+ z2><{900066004gh00000000000002^2><{900066004;x0000000000000R12><{9 z00066007zo0000000000000p92><{900066008j@0000000000000>H2><{900066 z0012V0000000000001EP2><{900066006iF0000000000001cX2><{900066006TB z0000000000001!f2><{9000660021$00000000000021n2><{900066006cF00000 z00000002Pv2><{900066007AW0000000000002n%2><{900066003A90000000000 z002<<2><{900066000sO0000000000003C{2><{900066007<{9000660046Y0000000000003zC2><{900066001Hd00000000000040K2><{9 z00066007Sg0000000000004OS2><{900066001lm0000000000004ma2><{900066 z003VA0000000000004;i2><{900066004mi0000000000005Bq2><{900066007Pd z0000000000005Zy2><{900066007|y0000000000005x)2><{900066003SB00000 z00000005}?2><{900066001!q0000000000006M~2><{900066008*_0000000000 z006l72><{900066004vl0000000000006-F2><{900066003YB0000000000007AN z2><{900066003|S0000000000007YV2><{900066008d=0000000000007wd2><{9 z00066007tl0000000000007|l2><{900066002Y;0000000000008Lt2><{900066 z006550000000000008j#2><{9000660024!0000000000008*-2><{900066007(q z00000000000002_2><{900066001oq0000000000000R22><{9000660012U00000 z00000000pA2><{900066003bC0000000000000>I2><{900066008I)0000000000 z001EQ2><{900066000mK0000000000001cY2><{900066008d;0000000000001!g z2><{900066001ci00000000000021o2><{900066008#`0000000000002Pw2><{9 z00066008;}0000000000002n&2><{900066001ur0000000000002<=2><{900066 z000vP0000000000003C|2><{900066000350000000000003b52><{900066006uL z0000000000003zD2><{9000660080z00000000000040L2><{900066007bf00000 z00000004OT2><{900066000>W0000000000004mb2><{900066003hE0000000000 z004;j2><{900066003SE0000000000005Br2><{900066002t^0000000000005Zz z2><{900066004*s0000000000005x*2><{900066002Az0000000000005}@2><{9 z00066000;T0000000000006N02><{900066006}R0000000000006l82><{900066 z003VF0000000000006-G2><{900066003kG0000000000007AO2><{900066008F! z0000000000007YW2><{900066003?S0000000000007we2><{900066003nG00000 z00000007|m2><{900066000030000000000008Lu2><{900066001}x0000000000 z008j$2><{900066003qH0000000000008*;2><{900066006B600000000000002` z2><{900066003_X0000000000000R32><{900066003bI0000000000000pB2><{9 z00066001rr0000000000000>J2><{900066001EZ0000000000001ER2><{900066 z008X<0000000000001cZ2><{900066001=v0000000000001!h2><{900066004;t z00000000000021p2><{900066005E$0000000000002Px2><{900066004{x00000 z00000002n(2><{900066000CB0000000000002<>2><{900066005!_0000000000 z003C}2><{900066004ah0000000000003b62><{900066001@z0000000000003zE z2><{900066008g>00000000000040M2><{9000660058y0000000000004OU2><{9 z00066004mo0000000000004mc2><{900066001Qd0000000000004;k2><{900066 z000060000000000005Bs2><{900066006@V0000000000005Z!2><{90006600097 z0000000000005x+2><{900066000UG0000000000005}^2><{900066000LD00000 z00000006N12><{9000660024y0000000000006l92><{900066004&t0000000000 z006-H2><{900066003hI0000000000007AP2><{900066006iK0000000000007YX z2><{900066003tI0000000000007wf2><{900066006HB0000000000007|n2><{9 z00066001Ke0000000000008Lv2><{900066006xP0000000000008j%2><{900066 z008^|0000000000008*<2><{900066003?R00000000000002{2><{900066007qj z0000000000000R42><{900066000~Z0000000000000pC2><{900066003wJ00000 z00000000>K2><{900066000ID0000000000001ES2><{900066004Rd0000000000 z001ca2><{900066005x@0000000000001!i2><{900066004LZ00000000000021q z2><{9000660021w0000000000002Py2><{900066000C90000000000002n)2><{9 z00066005!}0000000000002<{900066003zQ0000000000003C~2><{900066 z0058%0000000000003b72><{9000660086!0000000000003zF2><{900066001xn z00000000000040N2><{900066001-v0000000000004OV2><{900066000&P00000 z00000004md2><{900066002q>0000000000004;l2><{900066003zK0000000000 z005Bt2><{900066006lK0000000000005Z#2><{900066005!`0000000000005x- z2><{900066002Y=0000000000005}_2><{900066003YG0000000000006N22><{9 z00066001Wg0000000000006lA2><{900066003bH0000000000006-I2><{900066 z005={0000000000007AQ2><{900066003(R0000000000007YY2><{900066008L$ z0000000000007wg2><{900066004Ib0000000000007|o2><{900066007|u00000 z00000008Lw2><{900066000#O0000000000008j&2><{900066004gm0000000000 z008*=2><{900066005H%00000000000002|2><{900066007Je0000000000000R5 z2><{900066004dh0000000000000pD2><{9000660012Z0000000000000>L2><{9 z00066000vK0000000000001ET2><{900066000^U0000000000001cb2><{900066 z002k^0000000000001!j2><{900066000yR00000000000021r2><{900066003kL z0000000000002Pz2><{900066002${0000000000002n*2><{900066000{U00000 z00000002<@2><{900066005N&0000000000003D02><{900066002A$0000000000 z003b82><{900066001=y0000000000003zG2><{900066007+p00000000000040O z2><{9000660086y0000000000004OW2><{900066002(`0000000000004me2><{9 z00066004Ca0000000000004;m2><{900066007Ja0000000000005Bu2><{900066 z003(M0000000000005Z$2><{900066000LE0000000000005x;2><{900066004ji z0000000000005}`2><{900066001We0000000000006N32><{900066000OD00000 z00000006lB2><{9000660071Y0000000000006-J2><{900066005T;0000000000 z007AR2><{9000660015W0000000000007YZ2><{900066003+N0000000000007wh z2><{900066003tN0000000000007|p2><{900066000XE0000000000008Lx2><{9 z00066006!O0000000000008j(2><{900066000sN0000000000008*>2><{900066 z006}W00000000000002}2><{9000660040T0000000000000R62><{900066002+{ z0000000000000pE2><{900066007Ma0000000000000>M2><{900066007Yj00000 z00000001EU2><{900066002P(0000000000001cc2><{900066008p=0000000000 z001!k2><{900066004If00000000000021s2><{9000660027&0000000000002P! z2><{900066005o?0000000000002n+2><{900066008X*0000000000002<^2><{9 z00066003<{900066003?P0000000000003b92><{900066 z002w_0000000000003zH2><{900066007zp00000000000040P2><{900066005o^ z0000000000004OX2><{900066008*~0000000000004mf2><{900066002P+00000 z00000004;n2><{900066003_Q0000000000005Bv2><{900066005x`0000000000 z005Z%2><{900066005Z)0000000000005x<2><{900066007bk0000000000005}{ z2><{900066002?}0000000000006N42><{900066000aH0000000000006lC2><{9 z00066005!^0000000000006-K2><{900066007Aa0000000000007AS2><{900066 z006cD0000000000007Ya2><{900066006cG0000000000007wi2><{900066007Vc z0000000000007|q2><{900066003D80000000000008Ly2><{900066004&o00000 z00000008j)2><{900066008&}0000000000008*?2><{900066006KB0000000000 z0002~2><{900066003|R0000000000000R72><{900066004{t0000000000000pF z2><{900066003nJ0000000000000>N2><{900066005=|0000000000001EV2><{9 z00066004FX0000000000001cd2><{900066003nK0000000000001!l2><{900066 z0040S00000000000021t2><{900066004~w0000000000002P#2><{90006600033 z0000000000002n-2><{900066008v?0000000000002<_2><{900066008|100000 z00000003D22><{900066005;00000000000003bA2><{9000660015V0000000000 z003zI2><{900066002P)00000000000040Q2><{900066005>20000000000004OY z2><{900066000#Q0000000000004mg2><{900066007+r0000000000004;o2><{9 z000660040Z0000000000005Bw2><{900066003G90000000000005Z&2><{9000LB z003A40000000000005}|2><{9000LB003eG0000000000008}azp4EL0FmAo0F?cE z!KlCkU)BHs0000000000008iNzp1bS0PqolNBIx}Jdq#*AJ!ir1JxfO1JxfO1J$qs z0PqopNBIyUJdq#*AJ(t}0PqotNBIy!Jdq#*AJ(t}0PqoxNBIz9Jdq#*AJ(t}0Pqo# zNBIzfJdq#*AJ(t}0Pqo(NBIzNBI!q zJdq#*AJ(t}0Pqo_NBIx}J&_;+AJ(t}0Pqo}NBIyUJ&_;+AJ(t}0Pqp2NBIy!J&_;+ zAJ(t}0Pqp6NBIz9J&_;+AJ(t}0PqpANBIzfJ&_;+AJ(t}0PqpENBIz zK=}~j2azBGAJ)(U0FV&^LHQ5@2$3KHAJ)(U0FV&|LHQ6O2$3KHAJ)(U0FV(1LHQ6u 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 zf*X+_0w30}0sznvc0>6Pq8pJQ0w30}0sznvdPDgT!W)qw0w30}0sznvena^X;v115 z0w30}0sznvfz*0w30}0sznvibMGjLL8AG0w30} z0sznvjzjqnVjPhm0w30}0sznvl0*3rf*g?`0w30}0sznvmP7dvq8yPR0w30}0sznv znnU>z!W@wx0w30}0sznvoO=VuLLZSJ0w30}0sznv?nC(yVjqzp0w30}0sznv@0w30}0sznvN<{e(LL!kM0w30}0sznvPDJ?-Vj__s z0w30}0sznvQbhR>f+CS10w30}0sznvRz&#_q9TzX0w30}0sznvT15E}!Xl9%0w30} z0sznvUPSp2;v$hC0w30}0sznvVnq260wa+i0w30}0sznvW<>cAA|sI?0w30}0sznv zYDD=ELL-qN0w30}0sznvZbbPIVk40t0w30}0sznvazyzMf+LY20w30}0sznvc0~CQ zq9c(Y0w30}0sznvdPMmU!XuF&0w30}0sznvenj~Y;vO}bvLMM?R z0w30}0sznv?nL6c0w30} z0sznv`b7BO;wX_I z0w30}0sznvB1QQS0x6Lo0w30}0sznvCPn!WA}Ns|0w30}0sznvDn+80w30}0sznvHbwamqA8Ie0w30}0sznv zIz{;q!YPp;0w30}0sznvK1KNu;wh0J0w30}0sznvLPhxy0xFRp0w30}0sznvMn(A$ zA}Wy}0w30}0sznvN=5k)LMo9U0w30}0sznvPDS|;Vk(g!0w30}0sznvQbqX?f+~?9 z0w30}0sznvRz>*`qAHOf0w30}0sznvT1EK~!YYv<0w30}0sznvUPbv3;wq6K0w30} z0sznvVnz870xOXq0w30}0sznvW<~iBA}f&~0w30}0sznvYDM`FLMxFV0w30}0sznv zZbkVJVk?m#0w30}0sznvaz*(Nf-8|A0w30}0sznvc18IRqAQUg0w30}0sznvdPVsV z!Yh#=0w30}0sznvent5Z;wzCL0w30}0sznvf<^fd0xXdr0w30}0sznvhDG@hA}o<0 z0w30}0sznvibeSlLM)LW0w30}0sznvjz#$pVl0s$0w30}0sznvl12Ftf-I3B0w30} z0sznvmPPpxqAZah0w30}0sznvnnn2#!Yq*>0w30}0sznvo<;c(;w+IM0w30}0sznv zqDA=-0xgjs0w30}0sznvrbYP>A}x_10w30}0sznvszvz_LM@RX0w30}0sznvu0{C} zVl9y%0w30}0sznvvPJn2f-R9C0w30}0sznvwnh06qAigi0w30}0sznvx<&aA!Yz>? z0w30}0sznvzD4;E;w_ON0w30}0sznv!bSNI0xppt0w30}0sznv#zpxMA}*020w30} z0sznv%0>AQLN1XY0w30}0sznv&PDkUVlI&&0w30}0sznv(na|Yf-aFD0w30}0sznv z)P7hwLNAdZ0w30}0sznv?nU_!VlR;( z0w30}0sznv@x0w30}0sznvMn?G%A~KO60w30}0sznvN=Eq* zLNbvc0w30}0sznvPDc3{qB4;n z0w30}0sznvT1NR0!ZMK{0w30}0sznvUPk#4;xdsS0w30}0sznvVn+E80yB{y0w30} z0sznvW=8oCA~TU70w30}0sznvYDW1GLNk#d0w30}0sznvZbtbKVl$B-0w30}0sznv zaz^f0w30}0sznvu15I~Vl|N<0w30}0sznvvPSt3 zf;EvK0w30}0sznvwnq67qBW5q0w30}0sznvx<>gB!Znc~0w30}0sznvzDD^F;x&;V z0w30}0sznv!bbTJ0ydE#0w30}0sznv#zy%NA~umA0w30}0sznv%0~GRLN<{g0w30} z0sznv&PMqVVm6T=0w30}0sznv(nk3Zf;N#L0w30}0sznv)<*ddqBfBr0w30}0sznv z+D7>h!Zwj00w30}0sznv-bVQl;x>^W0w30}0sznv;zs!p0ymK$0w30}0sznv=0^Dt zA~%sB0w30}0sznv>PGnxLN}2h0w30}0sznv?ne0#VmFZ>0w30}0sznv@<#a(f;W*M z0w30}0sznv_D1;-qBoHs0w30}0sznv`bPN>!Z(p10w30}0sznv{zmx_;x~~X0w30} z0sznv0!R4}0yvQ%0w30}0sznv21of2A~=yC0w30}0sznv3P<@6LO78i0w30}0sznv z4oCSAVmOf?0w30}0sznv5=Z$Ef;f>N0w30}0sznv7DxFIqBxNt0w30}0sznv8b|pM z!Z?v20w30}0sznv9!L2Q;y95Y0w30}0sznvB1icU0y&W&0w30}0sznvCP(=YA~}&D z0w30}0sznvDo6PcLOGEj0w30}0sznvE=TzgVmXl@0w30}0sznvGDrCkf;o{O0w30} z0sznvHb?moqB)Tu0w30}0sznvI!E~s!a0#30w30}0sznvK1cZw;yIBZ0w30}0sznv zLPz-!0y>c(0w30}0sznvMo0M&B07;E0w30}0sznvN=Nw+LOPKk0w30}0sznvPDl9= zVmgr^0w30}0sznvQb+j^f;y2P0w30}0sznvR!8{|qB@Zv0w30}0sznvT1WX1!a9*4 z0w30}0sycPUPt*5;yRHa0w30}0sycPVn_K90y~i)0w30}0sycPW=HuDB0G^F0w30} z0sycPYDf7HLOYQl0w30}0sycPZb$hLVmpx_0w30}0sycPa!2_Pf;*8Q0w30}0sycP zc1QUTqC1fw0w30}0sycPdPn&X!aI>50w30}0sycPen<{LOqcn0w30}0sycPu1EP0Vm*-{0w30}0sycPvPbz4f<2KS0w30}0sycPwnzC8 zqCJry0w30}0sycPx<~mC!ab270w30}0sycPzDM~G;ysZd0w30}0sycP!bkZK0zQ!- z0w30}0sycP#z*-OB0iBI0w30}0sycP%18MSLOzio0w30}0sycP&PVwWVm^@|0w30} z0sycP(nt9afPPty zLO+op0w30}0sycP?nn6$Vn2}}0w30}0sycP@<;g)fh0w30}0sznvN0w30}0sznvPC)q(VgivM0w30}0sznvQb73- zf&!5s0w30}0sznvRzUd>q5_d10w30}0sznvT0r>_!UB;X0w30}0sznvUO@Q};sTK% z0w30}0sznvVnF#20t1mC0w30}0sznvWP0w30}0sznvvOxI|f(4Nv0w30}0sznvwm|t1q6Lv40w30}0sznvxf;s%i*0w30}0sznv z;z0Qj0tb;G0w30}0sznv=0N!nA_tKm0w30}0sznv>OlDrLI;r`0w30}0sznv?m+nv zVh52R0w30}0sznv@<90zf(MZx0w30}0sznv_CWa%q6d*60w30}0sznv`at;*!UvHc z0w30}0sznv{y_N<;s=o+0w30}0sznv0zvr@0tk^H0w30}0sznv20{4{A_$Qn0w30} z0sznv3PJf0LI{x{0w30}0sznv4ng@4VhE8S0w30}0sznv5<&S8f(Vfy0w30}0sznv z7D4$Cq6m>70w30}0sznv8bSFG!U&Nd0w30}0sznv9zppK;s}u-0w30}0sznvB0>2O z0tt~I0w30}0sznvCPDcSA_Te0w30} z0sznvK0)~q;t7!;0w30}0sznvLP7Zu0t%5J0w30}0sznvMnU-yA_|cp0w30}0sznv zN0w30}0sznvqCxo(0u7NM0w30} z0sznvra}1-A`Ous0w30}0sznvszLb>LJg510w30}0sznvu0i<_VhxcX0w30}0sznv zvO)O}f(?-%0w30}0sznvwn6z2q79KC0w30}0sznvxOuJsLJyH30w30}0sznv?m_twVh@oZ0w30}0sznv@Y9f)J4)0w30}0sznv7DD+Dq7acF0w30}0sznv z8bbLH!Vr-l0w30}0sznv9zyvL;t-J_0w30}0sznvB0~8P0uhlQ0w30}0sznvCPMiT zA`y`w0w30}0sznvDnj`XLJ^T50w30}0sznvE<*VbViA!b0w30}0sznvGD7(ff)SA* z0w30}0sznvHbVIjq7jiG0w30}0sznvIzssn!V!@m0w30}0sznvK0^5r;t`P`0w30} z0sznvLPGfv0uqrR0w30}0sznvMnd@zA`+1x0w30}0sznvN<#S%LK2Z60w30}0sznv zPD1$*ViJ)c0w30}0sznvQbPF40uzxS0w30}0sznvWO%PtLKl%B0w30}0sznv?n3zxVi%Dh0w30}0sznv@0w30}0sznv_Com( zq8E`M0w30}0sznv`a<~-!WWSs0w30}0sznv{zCZ>;un!10w30}0sznv0z>%_0vM4X z0w30}0sznv21EG}A{db%0w30}0sznv3Pbr2LKu-C0w30}0sznv4nz46Vi=Ji0w30} z0sznv5<~eAf*6q?0w30}0sznv7DM?Eq8O1N0w30}0sznv8bkRI!WfYt0w30}0sznv z9z*#M;uw)20w30}0sznvB18EQ0vVAY0w30}0sznvCPVoUA{mh&0w30}0sznvDnt1Y zLK%@D0w30}0sznvE<^bcVi}Pj0w30}0sznvGDG6Pq8pJQ0w30} z0sycPdPDgT!W)qw0w30}0sycPena^X;v1150w30}0sycPfz*0w30}0sycPibMGjLL8AG0w30}0sycPjzjqnVjPhm0w30}0sycPl0*3r zf*g?`0w30}0sycPmP7dvq8yPR0w30}0sycPnnU>z!W@wx0w30}0sycPoO=VuLLZSJ0w30}0sycP z?nC(yVjqzp0w30}0sycP@0w30} z0sycPN<{e(LL!kM0w30}0sycPPDJ?-Vj__s0w30}0sycPQbhR>f+CS10w30}0sycP zRz&#_q9TzX0w30}0sycPT15E}!Xl9%0w30}0sycPUPSp2;v$hC0w30}0sycPVnq26 z0wa+i0w30}0sycPW<>cAA|sI?0w30}0sycPYDD=ELL-qN0w30}0sycPZbbPIVk40t z0w30}0sycPazyzMf+LY20w30}0sycPc0~CQq9c(Y0w30}0sycPdPMmU!XuF&0w30} z0sycPenj~Y;vO}bvLMM?R0w30}0sycP?nL6c0w30}0sycP`b7BO;wX_I0w30}0sycPB1QQS0x6Lo0w30}0sycP zCPn!WA}Ns|0w30}0sycPDn+80w30}0sycPHbwamqA8Ie0w30}0sycPIz{;q!YPp;0w30}0sycPK1KNu;wh0J z0w30}0sycPLPhxy0xFRp0w30}0sycPMn(A$A}Wy}0w30}0sycPN=5k)LMo9U0w30} z0sycPPDS|;Vk(g!0w30}0sycPQbqX?f+~?90w30}0sycPRz>*`qAHOf0w30}0sycP zT1EK~!YYv<0w30}0sycPUPbv3;wq6K0w30}0sycPVnz870xOXq0w30}0sycPW<~iB zA}f&~0w30}0sycPYDM`FLMxFV0w30}0sycPZbkVJVk?m#0w30}0sycPaz*(Nf-8|A z0w30}0sycPc18IRqAQUg0w30}0sycPdPVsV!Yh#=0w30}0sycPent5Z;wzCL0w30} z0sycPf<^fd0xXdr0w30}0sycPhDG@hA}o<00w30}0sycPibeSlLM)LW0w30}0sycP zjz#$pVl0s$0w30}0sycPl12Ftf-I3B0w30}0sycPmPPpxqAZah0w30}0sycPnnn2# z!Yq*>0w30}0sycPo<;c(;w+IM0w30}0sycPqDA=-0xgjs0w30}0sycPrbYP>A}x_1 z0w30}0sycPszvz_LM@RX0w30}0sycPu0{C}Vl9y%0w30}0sycPvPJn2f-R9C0w30} z0sycPwnh06qAigi0w30}0sycPx<&aA!Yz>?0w30}0sycPzD4;E;w_ON0w30}0sycP z!bSNI0xppt0w30}0sycP#zpxMA}*020w30}0sycP%0>AQLN1XY0w30}0sycP&PDkU zVlI&&0w30}0sycP(na|Yf-aFD0w30}0sycP)P7hwLNAdZ0w30}0sycP?nU_!VlR;(0w30}0sycP@x z0w30}0sycPMn?G%A~KO60w30}0sycPN=Eq*LNbvc0w30}0sycPPDc3{qB4;n0w30}0sycPT1NR0!ZMK{0w30}0sycP zUPk#4;xdsS0w30}0sycPVn+E80yB{y0w30}0sycPW=8oCA~TU70w30}0sycPYDW1G zLNk#d0w30}0sycPZbtbKVl$B-0w30}0sycPaz^f z0w30}0sycPu15I~Vl|N<0w30}0sycPvPSt3f;EvK0w30}0sycPwnq67qBW5q0w30} z0sycPx<>gB!Znc~0w30}0sycPzDD^F;x&;V0w30}0sycP!bbTJ0ydE#0w30}0sycP z#zy%NA~umA0w30}0sycP%0~GRLN<{g0w30}0sycP&PMqVVm6T=0w30}0sycP(nk3Z zf;N#L0w30}0sycP)<*ddqBfBr0w30}0sycP+D7>h!Zwj00w30}0sycP-bVQl;x>^W z0w30}0sycP;zs!p0ymK$0w30}0sycP=0^DtA~%sB0w30}0sycP>PGnxLN}2h0w30} z0sycP?ne0#VmFZ>0w30}0sycP@<#a(f;W*M0w30}0sycP_D1;-qBoHs0w30}0sycP z`bPN>!Z(p10w30}0sycP{zmx_;x~~X0w30}0sycP0!R4}0yvQ%0w30}0sycP21of2 zA~=yC0w30}0sycP3P<@6LO78i0w30}0sycP4oCSAVmOf?0w30}0sycP5=Z$Ef;f>N z0w30}0sycP7DxFIqBxNt0w30}0sycP8b|pM!Z?v20w30}0sycP9!L2Q;y95Y0w30} z0sycPB1icU0y&W&0w30}0sycPCP(=YA~}&D0w30}0sycPDo6PcLOGEj0w30}0sycP zE=TzgVmXl@0w30}0sycPGDrCkf;o{O0w30}0sycPHb?moqB)Tu0w30}0sycPI!E~s z!a0#30w30}0sycPK1cZw;yIBZ0w30}0sycPLPz-!0y>c(0w30}0sycPMo0M&B07;E z0w30}0sycPN=Nw+LOPKk0w31m55K9R0syds0szoL06_U;z&nvZ03X&LAOqDOAOqE) z0syc8^hfzX006Y{{{I)i17Fr3AOqE)0sznefB=!90sycffB=y{008Tt002~>0sxR9 z@JIPU006Wg03X)C17Fr3AOqE)0syc8fB=!90sycffB=yp007G&{6mu={6UK${6Uk! z006Y20sxRg_(%C-006W=03X&LAOqFF17Fr3AOqF?d%mgt0|1fp3jq1E0sydJfu0Dw}U0sxQzd`I~o008kp002}00Dw{;8~_r)17FtvLjcj>2LSou2LQR@2SB;t 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�#9 z0|2V?0|Ba_LjjS8_Wzdy000#90|2V?0|Ba_!vc}M?*Eqq000#90|2V?0|Ba_BLb1Z z>i?JE0~D&^0~4wN000y}1OV}10030;0|2To000!V=l_?WI{^7N;ISH z0|2U^!vc}$0|2T40DuzU0|Khk?*Esd!vc{x^#7Oi0|2U^8$kIs^#7OR0|2UE0RWH! zU@(zD0RXT8peK<)0RXT7AU2WX0|5Ew0~D$T0DuzZ0|Kh#0~0Fa6o69V0|Bbx0|2U^ z1%Ohy@c);f!vc|0_Wzd?0Duxn_y3of|Nj^B0|2U^!vc{__Wzdx000#80|2T*_y3my z000#80|2U^;{lP1>i?JE0~4yi`2Uxu=Kq)TQ$nfr8$kK}dqJuH!vm4P17Ftvg9_38 zdjYBaLjaNUQv#{=8vyyBCjj}OBLMlL9{~A)0s!y;h)4MW06_VnM*;Z(0D#gV0Dw}U z1%OiW@&A_q8~_p@0040S0svI*z8~_p@0041-1OQap;ISH0|2U^V*!!q0|2T40DuzU0|Kgc?*EsdV*!!e^Z%Fh0|2U^BS87t^Z%FQ z0|2UE0RYefzyXm!0RXT8peK<)0RXT7063B30|5Ew0~D$T0DuzZ0|Kh#0~0C(7l2aY z0|Bbx0|2U^1%Ogq@c);fV*!!&_5YU>0Duys000!AA3*t_GXVLZGeG$t008j;1OQaB z;ISH0|2U^V*!!q0|2T40DuzU0|Kf}?*EsdV*!!0^Z%FQ0|2UE0RYef zzyXm!0RXT8peK<)0RXT706CH80|TlC0DuzZ0|Kh#0~0Ev7l2aY0|Bbx0|2U^1%OgG z@c);fV*!!U_5YU>0DuyI000!ABS85Q@&A{gHvsto0Dw}UH$eHm>i?G?1OPGM7oQpc z8~_p@0040y1prit;ISH0|2U^V*!!q0|2T40DuzU0|Kff?*EsdV*!zh z^Z%Fi0|2U^BS86w^Z%Fg0|2U3^8c3r06@7v>;ISI0|2UE0RYefzyXm!0RXT8peK<) z0RXT7;5m`w2LSo=0|5Ew0~M+U0DuzZ0|Kh#0~9Jl7=TjZ0|Bbx0|2U^1%Ofo@c);f zV*!z$_5YU>0Duxq000!A;{lNZ0f17WBS85n=>M0X;{lN?_Wzdv8~_pk002?|8~_p@ z0041-1OQZ3;ISH0|2U^V*!!q0|2T40DuzU0|Kh??f;jcV*!y@^Z%Fh z0|2U^BS867^Z%FQ0|2UE0RYefzyXm!0RXT8peK<)0RXT706UT60|5Ew0~D$T0DuzZ z0|Kh#0~0C(8Gusa0|Bbx0|2U^1%Oi5@Bf#eV*!zI_5YU>0Dux4000!A;{lPOGeG&M zi?JG0|2U^V*!!q0|2T40DuzU0|Kgy?f;jcV*!!!^8c6g0|2U^BS87@^8c6P z0|2UE0RYefzyXm!0RXT8peK<)0RXT7fIN}o0|5Ew0~D$T0DuzZ0|Kh#0~0Fa8Gusa z0|Bbx0|2U^1%Og=@Bf#eV*!y2_5YWk;{lPnL}=008me7oQpc8~_p@0040y1pri6 z@c)M0YV*!z%BLR`(0|Bbx0|2Vv0~4z4^Z%D00042|2cH@f z8~_raBLR`L^#7NC0swKK4**m_0Dw}U1%Og>@c)+p8~_p@0042|4gged;{TW90{|*u z0RZp~0s!ma7oQpc8~_p@0040S2>?{TBLMlJ7eM*r z=l_@C0|2U^BS85d00HaZC!ZPs8~_p@0042o0svH@BS86}7eM(<;{TWP0|2U_BS86} z6F~V%;{TW70|2U^BLR`<0|2Vv0~4yC>i?IaBLR`1V*!yN>i?IZBLR`8<^PwUBS858 z1OSnsBLMm1|Nj>T@c)M0YV*!z%BLR`(0|Bbx0|2Vv0~4y8 z^Z%D00042|2cH@f8~_raBLR_P^#7NC0swJ<1prh*0Dw}U1%Of_@c)+p8~_p@0042o z1OQYX;{TW90{|*u0RZp0|Bam0Dw{f0;+PB_5YWm;{cIB0RZp; zKoyao0|Aj3?*Ese0|Aks0sxQzpaGHM0|Ba`0Dw{f0;+O-fi z0|BZb1b|Wj0;+Q7;{TVR0|Ak#^8c5h;{cJr?Eja50s!y=005DI0s!yeV0szne zbVvDw?f;jc;{cH+_5YWm;{cIB0RYeefEbaW0|Aj~?f;jd0|AkM0s!y;fC7=?0|Bam z41iJr0;+P(;{TVR0|Akc^8c5h;{cJS?Eja50s!y=005DI0s!y0|Ajx?f;jd0|AkM0s!y;paPNN0|Ba`41iJr z0;+Pg;{TVR0|AkD^8c5h;{cJ3?Eja50s!y=005DI0s!y%0|Aj9?f;jd0|AkM0s!y;-~y520|BZ*0D@8h0;+O@;{TVR z0|Ajm^8c5h;{cIc?Eja50s!y=005DI0s!y<-~y3=0sznebVvCh?f;jc;{cJu^#7Nl z;{cIB0RYee02+~?0|Ai*?f;jd0|AkM0s!y;00WWY0|BaG0D@8h0;+Oq;{TVR0|AjN z^8c5h;{cID?Eja50s!y=005DI0s!y<00WVL0sznebVvCI?f;jc;{cJV^#7Nl;{cIB z0RYeefEtmY0|Alj?Ejac0|AkM0s!y;AOn%&0|Bam0D@8h0;+OR;{TVR0|Ai}^8c5h z;{cH;IR4 z0s!y=005DI0s!yuR40|Akt z?Ejac0|AkM0s!y;fCG`@0|Bbx0D@8h0;+Nb;{TVR0|Al9@&A{g;{cJ~>;IR40s!y= z005DI0s!yl0|AkU?Ejac z0|AkM0s!y;paYTO0|BZ50fJHi0;+QD;s2MQ0|Ak*@&A{g;{cJx>;IR40s!y=005DI z0s!y%X50|Ak5?Ejac0|AkM z0s!y;zyp!u0|BZb0fJHi0;+P<;s2MQ0|Aki@&A{g;{cJY>;IR40s!y=005DI0s!y< zzypzh0sznebVvDd?Ejab;{cHp^#7Nl;{cIB0RYeeU>=d60|Aj%?Ejac0|AkM0s!y; z-~*B30|BZ*0fJHi0;+Pm;s2MQ0|AkJ@&A{g;{cJ9>;IR40s!y=005DI0s!y<-~*9> z0sznebVvDE?Ejab;{cKR^Z%Ek;{cIB0RYee;2x2n0|Aje?Ejac0|AkM0s!y;00fcZ z0|BaG0fJHi0;+PN;s2MQ0|Aj_@&A{g;{cI*>;IR40s!y=005DI0s!y<00fbM0szne zbVvC=?Ejab;{cK2^Z%Ek;{cIB0RYeepdXQ-0|AjF?Ejac0|AkM0s!y;AOw-(0|BZ5 z0EAKj0;+O};s2MQ0|Ajs@&A{g;{cIi>;IR40s!y=005DI0s!y?Ejac0|AkM0s!y;Km?KE0|BZb0EAKj z0;+Ow;s2MQ0|AjT@&A{g;{cIJ>;IR40s!y=005DI0s!yU0|Alp>;IRb0|AkM0s!y;U<8rk0|BZ*0EAKj0;+OX z;s2MQ0|Aj4@&A{g;{cH_>;IR40s!y=005DI0s!y;IRa;{cJC z^Z%Ek;{cIB0RYee;31Kq0|AlQ>;IRb0|AkM0s!y;fCQ1^0|BZ50ESWl0;+O8;s2MQ z0|Ai$@&A{g;{cHs>;IR40s!y=005DI0s!y;IRa;{cI;^Z%Ek z;{cIB0RYeeU?P#A0|Al1>;IRb0|AkM0s!y;pahZP0|BZb0ESWl0;+N);s2MQ0|Ale z@c);f;{cKU>i?I30s!y=005DI0s!y;IRa;{cIl^Z%Ek;{cIB z0RYeeKqHZ$0|Akz>;IRb0|AkM0s!y;zyy)v0|BZ*0ESWl0;+Nh;s2MQ0|AlF@c);f z;{cK5>i?I30s!y=005DI0s!y;IRa;{cIM^Z%Ek;{cIB0RYee zpd*o>0|Aka>;IRb0|AkM0s!y;-~^H40|BaG0ESWl0;+QJ;QyDP0|Ak>@c);f;{cJ% z>i?I30s!y=005DI0s!y<-~^F?0sznebVvD+>;IRa;{cH|^Z%Ek;{cIB0RYee03?y1 z0|AkB>;IRb0|AkM0s!y;00oia0|Bam0ESWl0;+P_;QyDP0|Ako@c);f;{cJe>i?I3 z0s!y=005DI0s!y<00ohN0sznebVvDj>;IRa;{cHv^Z%Ek;{cIB0RYeeU?h>C0|Aj- z>;IRb0|AkM0s!y;AO(@)0|Ba`0ESWl0;+Ps;QyDP0|AkP@c);f;{cJF>i?I30s!y= z005DI0s!y;IRa;{cHW^Z%Ek;{cIB0RYeeASIEY0|Ajk>;IRb z0|AkM0s!y;Kn0QF0|BbR0ESWl0;+PT;QyDP0|Ak0@c);f;{cI>>i?I30s!y=005DI z0s!y;IRa;{cK8^8c5j;{cIB0RYee;3biu0|AjL>;IRb0|AkM z0s!y;Ui?I30s!y=005DI0s!y< zU;IRa;{cJ)^8c5j;{cIB0RYeeU?!2E0|Ai{>;IRb0|AkM0s!y; zfCZ7_0|BZb0Ekin0;+O$;QyDP0|AjZ@c);f;{cIP>i?I30s!y=005DI0s!y;IRa;{cJh^8c5j;{cIB0RYeeASaQa0|Alv>i?Ia0|AkM0s!y;paqfQ z0|BZ*0Ekin0;+Od;QyDP0|AjA@c);f;{cI0>i?I30s!y=005DI0s!yi?IZ;{cJI^8c5j;{cIB0RYeepd*o>0|AlW>i?Ia0|AkM0s!y;zy*=w0|BaG z0Ekin0;+OE;QyDP0|Ai+@c);f;{cHy>i?I30s!y=005DI0s!yi?IZ;{cI^^8c5j;{cIB0RYee03?y10|Al7>i?Ia0|AkM0s!y;;02N50|Bam0Ekin z0;+N=;QyDP0|Alk@Bf#e;{cHZ>i?I30s!y=005DI0s!y<;02L@0sznebVvEf>i?IZ z;{cIr^8c5j;{cIB0RYeefG3fl0|Ak(>i?Ia0|AkM0s!y;00xob0|Ba`0Ekin0;+Nn z;QyDP0|AlL@Bf#e;{cKB>Hn920s!y=005DI0s!y<00xnO0sznebVvEG>i?IZ;{cIS z^8c5j;{cIB0RYee;3tuw0|Akg>i?Ia0|AkM0s!y;AO?}*0|BbR0Ekin0;+QP-~X4O z0|Ak{@Bf#e;{cJ->Hn920s!y=005DI0s!yi?IZ;{cI3^8c5j z;{cIB0RYeeKq!%*0|AkH>i?Ia0|AkM0s!y;Kn9WG0|Bbx0Ekin0;+Q0-~X4O0|Aku z@Bf#e;{cJk>Hn920s!y=005DI0s!yi?IZ;{cH#^8c5j;{cIB z0RYee;3$!x0|Aj@>i?Ia0|AkM0s!y;UHn920s!y=005DI0s!yi?IZ;{cHc^8c5j;{cIB0RYee zKq--+0|Ajq>i?Ia0|AkM0s!y;fCiD`0|BZb0fHn920s!y=005DI0s!yi?IZ;{cKE@&A{i;{cIB0RYee;3<)y z0|AjR>i?Ia0|AkM0s!y;pazlR0|BZ*0fHn92 z0s!y=005DI0s!yi?IZ;{cJ=@&A{i;{cIB0RYeeKq--+0|Aj2 z>i?Ia0|AkM0s!y;zy^`x0|BaG0fHn920s!y= z005DI0s!yi?IZ;{cJn@&A{i;{cIB0RYeeKq`@-0|Al#>Hn9Z z0|AkM0s!y;;0BT60|Bam0fHn920s!y=005DI z0s!y<;0BR^0sznebVvCB>i?IZ;{cJO@&A{i;{cIB0RYee;3|=z0|Alc>Hn9Z0|AkM z0szne00)uc0|Ba`0fHn920szng005DI0sznf z00)tP0syc8bVvE;>Hn9Y;{cI~@&A{i;{cIB0RXT8U@MWJ0|AlD>Hn9Z0|AkM0szne zAP14+0|BbR0fHn920szng005DI0sznfAP13v z0syc8bVvEl>Hn9Y;{cIx@&A{i;{cIB0RXT8z$=lU0|Ak<>Hn9Z0|AkM0szneKnIcH z0|BZ50*F!p0;+Nt-~X4O0|AlR?*Esd;{cKH=>M010szng005DI0sznfKnIb40syc8 zbVvEM>Hn9Y;{cIY@&A{i;{cIB0RXT8AS{uf0|Akm>Hn9Z0|AkM0szneUM010szng005DI0sznfUHn9Y;{cI9@&A{i;{cIB0RXT8;4G1#0|AkN>Hn9Z0|AkM0sznefCrJ{0|BZ*0*F!p z0;+Q6-v5`N0|Ak!?*Esd;{cJq=>M010szng005DI0sznffCrI)0syc8bVvDv>Hn9Y z;{cH*@&A{i;{cIB0RXT8fGv@r0|Aj}>Hn9Z0|AkM0sznepa+rS0|BaG0*F!p0;+P& z-v5`N0|Akb?*Esd;{cJR=>M010szng005DI0sznfpa+qF0syc8bVvDW>Hn9Y;{cHi z@&A{i;{cIB0RXT8ATE)h0|Ajw>Hn9Z0|AkM0sznezz31y0|Bam0*F!p0;+Pf-v5`N z0|AkC?*Esd;{cJ2=>M010szng005DI0sznfzz30l0syc8bVvD7>Hn9Y;{cKK@c);h z;{cIB0RXT8fG&}s0|AjX>Hn9Z0|AkM0szne;0KZ70|Ba`0*F!p0;+PG-v5`N0|Aj; z?*Esd;{cI!=>M010szng005DI0sznf;0KX_0syc8bVvC(>Hn9Y;{cJ`@c);h;{cIB z0RXT8;4YD%0|Aj8>Hn9Z0|AkM0szne00@!d0|BbR0*F!p0;+O?-v5`N0|Ajl?*Esd z;{cIb=>M010szng005DI0sznf00@zQ0syc8bVvCg>Hn9Y;{cJt@c);h;{cIB0RXT8 zKrfM?0|Ai)>Hn9Z0|AkM0szneAPAA-0|Bbx0*F!p0;+Op-v5`N0|AjM?*Esd;{cIC z=>M010szng005DI0sznfAPA9w0syc8bVvCH>Hn9Y;{cJU@c);h;{cIB0RXT8pf8c2 z0|Ali=>M0Y0|AkM0szneKnRiI0|BZ51Bg-q0;+OQ-v5`N0|Ai|?*Esd;{cH;=>M01 z0szng005DI0sznfKnRh50syc8bVvE^=>M0X;{cJ5@c);h;{cIB0RXT8ATW`j0|AlJ z=>M0Y0|AkM0szneUM010szng z005DI0sznfUM0X;{cI%@c);h;{cIB0RXT8U@(!O0|Ak_=>M0Y z0|AkM0sznefC!P|0|BZ*1Bg-q0;+Nz-v5`N0|AlX?f;jc;{cKN=l_?00szng005DI z0sznffC!O*0syc8bVvES=>M0X;{cIe@c);h;{cIB0RXT8;4qP(0|Aks=>M0Y0|AkM z0sznepa_xT0|BaG1Bg-q0;+Na-v5`N0|Al8?f;jc;{cJ}=l_?00szng005DI0sznf zpa_wG0syc8bVvE3=>M0X;{cIF@c);h;{cIB0RXT8KrxY^0|AkT=>M0Y0|AkM0szne zzzC7z0|Bam1Bg-q0;+QC-T#-M0|Ak)?f;jc;{cJw=l_?00szng005DI0sznfzzC6m z0syc8bVvD#=>M0X;{cH>@c);h;{cIB0RXT8fH9Gv0|Ak4=>M0Y0|AkM0szne;0Tf8 z0|Ba`1Bg-q0;+P;-T#-M0|Akh?f;jc;{cJX=l_?00szng005DI0sznf;0Td`0syc8 zbVvDc=>M0X;{cHo@c);h;{cIB0RXT805XxF0|Aj$=>M0Y0|AkM0szne011)e0|BbR z1Bg-q0;+Pl-T#-M0|AkI?f;jc;{cJ8=l_?00szng005DI0sznf011(R0syc8bVvDD z=>M0X;{cKQ@Bf#g;{cIB0RXT8fHIMw0|Ajd=>M0Y0|AkM0szneAPJG;0|Bbx1Bg-q z0;+PM-T#-M0|Aj^?f;jc;{cI)=l_?00szng005DI0sznfAPJFx0syc8bVvC<=>M0X z;{cK1@Bf#g;{cIB0RXT8ATyDm0|AjE=>M0Y0|AkM0szneKnaoJ0|BZ51c*`r0;+O| z-T#-M0|Ajr?f;jc;{cIh=l_?00szng005DI0sznfKnan60syc8bVvCm=>M0X;{cJz z@Bf#g;{cIB0RXT8pfi!60|Ai==>M0Y0|AkM0szneUM0X;{cJa@Bf#g z;{cIB0RXT805p-H0|Alo=l_?X0|AkM0sznefC-V}0|BZ*1c*`r0;+OW-T#-M0|Aj3 z?f;jc;{cH^=l_?00szng005DI0sznffC-U+0syc8bVvE~=l_?W;{cJB@Bf#g;{cIB z0RXT8pfr)70|AlP=l_?X0|AkM0sznepb3%U0|BaG1c*`r0;+O7-T#-M0|Al$?Ejab z;{cHr=l_?00szng005DI0sznfpb3$H0syc8bVvEx=l_?W;{cI-@Bf#g;{cIB0RXT8 zKsAw|0|Al0=l_?X0|AkM0sznezzLD!0|Bam1c*`r0;+N(-T#-M0|Ald?Ejab;{cKT z=Kq&~0szng005DI0sznfzzLCn0syc8bVvEY=l_?W;{cIk@Bf#g;{cIB0RXT8z%`Me z0|Aky=l_?X0|AkM0szne;0cl90|Ba`1c*`r0;+Ng-T#-M0|AlE?Ejab;{cK4=Kq&~ z0szng005DI0sznf;0cj{0syc8bVvE9=l_?W;{cIL@Bf#g;{cIB0RXT8AU2Vp0|AkZ z=l_?X0|AkM0szne01A=f0|BbR1c*`r0;+QI-2a!L0|Ak=?Ejab;{cJ$=Kq&~0szng z005DI0sznf01A;IRa;{cHY=Kq&~0szng005DI0sznf01J_T0syc8bVvEe=Kq(V;{cIq?*Esf z;{cIB0RXT8;5w0@0|Ak&=Kq(W0|AkM0szneAPbS=0|Bbx1&C4s0;+Nm-2a!L0|AlK z>;IRa;{cKA<^Pv}0szng005DI0sznfAPbRz0syc8bVvEF=Kq(V;{cIR?*Esf;{cIB z0RXT8Ks%A30|Akf=Kq(W0|AkM0szneKns!L0|BZ528dDt0;+QO+y9rK0|Ak`>;IRa z;{cJ+<^Pv}0szng005DI0sznfKnsz80syc8bVvD>=Kq(V;{cI2?*Esf;{cIB0RXT8 zz&nwk0|AkG=Kq(W0|AkM0szneU<;Ar0|BZb28dDt0;+P~+y9rK0|Akt>;IRa;{cJj z<^Pv}0szng005DI0sznfU<;9e0syc8bVvDo=Kq(V;{cH!?*Esf;{cIB0RXT8AUu(v z0|Aj?=Kq(W0|AkM0sznefD4i00|BZ*28dDt0;+Px+y9rK0|AkU>;IRa;{cJK<^Pv} z0szng005DI0sznffD4g;0syc8bVvDP=Kq(V;{cHb?*Esf;{cIB0RXT8pgfVF0|Ajp z=Kq(W0|AkM0sznepbL@W0|BaG28dDt0;+PY+y9rK0|Ak5>;IRa;{cI`<^Pv}0szng z005DI0sznfpbL?J0syc8bVvD0=Kq(V;{cKD?f;je;{cIB0RXT8Ks}M50|AjQ=Kq(W z0|AkM0sznezzdP$0|Bam28dDt0;+P9+y9rK0|Aj%>;IRa;{cIt<^Pv}0szng005DI z0sznfzzdOp0syc8bVvCy=Kq(V;{cJ;IRa;{cIU<^Pv}0szng005DI0sznf z;0uv}0syc8bVvCZ=Kq(V;{cJm?f;je;{cIB0RXT8U_Ozc0|Al!<^PwV0|AkM0szne z01T1h0|BbR28dDt0;+Oi+y9rK0|AjF>;IRa;{cI5<^Pv}0szng005DI0sznf01T0U z0syc8bVvFB<^PwU;{cJN?f;je;{cIB0RXT8AU~0y0|Alb<^PwV0|AkM0syc8APkY> z0|Bbx28dDt0;+OJ+y9rK0|Ai>>;IRa;{cH%<^Pv}0sycA005DI0syc9APkX!0sxQz zbVvE-<^PwU;{cI}?f;je;{cIB0RWHzz(0|o0|AlC<^PwV0|AkM0syc8Kn#)M0|BZ5 z2Z&Mu0;+N_+y9rK0|Alp>i?IZ;{cHe<^Pv}0sycA005DI0syc9Kn#(90sxQzbVvEk z<^PwU;{cIw?f;je;{cIB0RXT8AOMk|0|Ak;<^PwV0|AkM0syc8U<{Gs0|BZb2Z&Mu z0;+Ns+y9rK0|AlQ>i?IZ;{cKGi?IZ;{cJ?i?IZ;{cJpi?IZ;{cJQi?IZ z;{cJ1i?IZ;{cIz z+W(iJ0|Ajk>i?IZ;{cIai?IZ;{cIBi?IZ;{cH-Hn9Y;{cHkHn9Y;{cKMHn9Y;{cJ|Hn9Y;{cJvHn9Y;{cJWHn9Y;{cJ7;IRc;{cIB0RXT8;0TeR0|AjcHn9Y;{cI(;IRc z;{cIB0RXT8UHn9Y;{cIg;IRc;{cIB z0RXT8zzLC{0|Ai<Hn9Y z;{cIH0sxQzbVvCM;IRc;{cIB0RXT8 zU<#3-0|AlnHn9Y;{cH@ z;IRc;{cIB0RXT8;0lqT z0|AlOM0X;{cHq;IRc;{cIB0RXT8U<;9;0|Ak~ zM0X;{cKS;{TU`0sycA z005DI0syc9;0}?10sxQzbVvEX;IRc;{cIB0RXT8fDDnK0|AkxM0X;{cK3;{TU`0sycA005DI z0syc901uIX0sxQzbVvE8;IRc;{cIB0RXT8APteA0|AkYM0X;{cJ#;{TU`0sycA005DI0syc9 zAP;IRc;{cIB0RXT8;0=+W0|Ak9M0X;{cJc;{TU`0sycA005DI0syc9Ko60C z0sxQzbVvDh;IRc;{cIB0RXT8fDVzM0|Aj*M0X;{cJD;{TU`0sycA005DI0syc9U=NXi0sxQz zbVvDIi?Ib;{cIB0RXT8;0}?X0|AjiM0X;{cI<;{TU`0sycA005DI0syc9fDe&?0sxQzbVvC^ zi?Ib;{cIB0RXT8fDe(N0|AjJM0X;{cIm;{TU`0sycA005DI0syc9pbwFN0sxQzbVvCri?Ib;{cIB0RXT8;17|Y0|Ai_n)0|Bam0FY7v0;+O! z*#DQH0|AjX=>M0X;{cIN;{TU`0sycA005DI0syc9zz>mt0sxQzbVvCSi?Ib;{cIB0RXT8U=Wd@0|Alt;{TVS0|AkM0syc8;17}F0|Ba`0FY7v0;+Ob*#DQH z0|Aj8=>M0X;{cH};{TU`0sycA005DI0syc9;17|20sxQzbVvF4;{TVR;{cJG>i?Ib z;{cIB0RXT8zz~t30|AlU;{TVS0|AkM0syc801%Pl0|BbR0FY7v0;+OC*#DQH0|Ai) z=>M0X;{cHw;{TU`0sycA005DI0syc901%OY0sxQzbVvE$;{TVR;{cI?>i?Ib;{cIB z0RXT8KoOCk0|Al5;{TVS0|AkM0syc8AP|w_0|Bbx0FY7v0;+N;*#DQH0|Ali=l_?W z;{cHX;{TU`0sycA005DI0syc9AP|v&0sxQzbVvEd;{TVR;{cIp>i?Ib;{cIB0RXT8 zpb?Rv0|Ak%;{TVS0|AkM0syc8KoF7Q0|BZ50gzGw0;+Nl*#DQH0|AlJ=l_?W;{cK9 z;s2L_0sycA005DI0syc9KoF6D0sxQzbVvEE;{TVR;{cIQ>i?Ib;{cIB0RXT8KoXIl z0|Ake;{TVS0|AkM0syc8U=Wew0|BZb0gzGw0;+QN*Z-HG0|Ak_=l_?W;{cJ*;s2L_ z0sycA005DI0syc9U=Wdj0sxQzbVvD=;{TVR;{cI1>i?Ib;{cIB0RXT8;1ZFb0|AkF z;{TVS0|AkM0syc8fDn=50|BZ*0gzGw0;+P}*Z-HG0|Aks=l_?W;{cJi;s2L_0sycA z005DI0syc9fDn;@0sxQzbVvDn;{TVR;{cHz>i?Ib;{cIB0RXT8pc9dx0|Aj>;{TVS z0|AkM0syc8pb(Mb0|BaG0gzGw0;+Pw*Z-HG0|AkT=l_?W;{cJJ;s2L_0sycA005DI z0syc9pb(LO0sxQzbVvDO;{TVR;{cHa>i?Ib;{cIB0RXT8KopUn0|Ajo;{TVS0|AkM z0syc8zz~t*0|Bam0gzGw0;+PX*Z-HG0|Ak4=l_?W;{cI_;s2L_0sycA005DI0syc9 zzz~su0sxQzbVvC~;{TVR;{cKC>Hn9a;{cIB0RXT8;1rRd0|AjP;{TVS0|AkM0syc8 z;1H4G0|BbR0gzGw0;+P8*Z-HG0|Aj$=l_?W;{cIs;s2L_0sycA005DI0syc9;1H33 z0sxQzbVvCx;{TVR;{cJ;>Hn9a;{cIB0RXT8U=@*|0|Aj0;{TVS0|AkM0syc801=Vm z0|Ba`0gzGw0;+O)*Z-HG0|Ajd=l_?W;{cIT;s2L_0sycA005DI0syc901=UZ0sxQz zbVvCY;{TVR;{cJl>Hn9a;{cIB0RXT802Yy;0|Alz;s2MR0|AkM0syc8AQ6$`0|Bbx z0gzGw0;+Oh*Z-HG0|AjE=l_?W;{cI4;s2L_0sycA005DI0syc9AQ6#(0sxQzbVvFA z;s2MQ;{cJM>Hn9a;{cIB0RXT8pcat;0D%90paTJsCLApyL3Mhw1;9qT>LOKmh=d0YDd#paTJs%HjW)p#uStfC2!J0ALZ3;sXJyAp($6 z0RpOWFW3KLOKmh=d0pJ&rpaTJsvEl!hp#uStfC2!J0DuvZ;sXJyK?0Cc0RpOW z7T5ompaTJs*yjJ2pyL3M?%@BIfC2!J0ssJ!fC2!J0e}&aU;+T}0CY$Bv*G`jpyL3M zRq6kiqT>LOKmh=d0bm%BpaTJsnBo7Ip#uStfC2!J0H6_(;sXJyVFHj+0RpOW{nr1N zpaTJszvlm!pyL3M)!_e^fC2!J0ssJ!fC2!J0iY3)U;+T}0CY$Bn&JPKpyL3MJn8?J zqT>LOKmh=d0pJ*spaTJsf8qa^p#uStfC2!J0KgHE;sXJyfdY_H0RpOWLO zKmh=d0e~5ipaTJsX5s&rp#uStfC2!J0N@dk;sXJyp#qRn0RpOW%hvywpaTJsjpqNC zpyL3Mqu~FSfC2!J0ssJ!fC2!J0pJmlU;+T}0CY$BXyN~tpyL3M3hDosqT>LOKmh=d z0U#QYpaTJsP2vBSp#uStfC2!J000t^;sXJy!2*y{0RpOWvey5XpaTJsbmsq;pyL3M zis1j3fC2!J0ssJ!fC2!J0RR$_U;+T}0CY$BPvQTUpyL3M@#z1TqT>LOKmh=d0l*rO zpaTJsG~xf3p#uStfC2!J03Z^P;sXJy;R29S0RpOWnb!Z8paTJsTju|lpyL3Map3=# zfC2!J0ssJ!fC2!J0U#2QU;+T}0CY$BHsSx5pyL3M*y#V4qT>LOKmh=d0YDp(paTJs z8{z+#p#uStfC2!J06-Fv;sXJy0Rxay0RpOWfY$$)paTJsLgxRMpyL3MSm6JcfC2!J z0ssJ!fC2!J0YDOwU;+T}0CY$B9pV3%pyL3Mzv%y$qT>LOKmh=d0l*uPpaTJs0^$Fc zp#uStfC2!J0ALc4;sXJyAp?+70RpOWXV(9hpaTJsDdzu|pyL3MKj8nDfC2!J0ssJ! zfC2!J0bml5U;+T}0CY$B1mXXepyL3Mrs)5dqT>LOKmh=d0bm@FpaTJs>EQpDp#uSt zfC2!J0Duya;sXJyK?9Id0RpOWPS*dIpaTJs5a$1vpyL3MCgA^)`*FpyL3Mjp+ZEqT>LOKmh=d0pJ{wpaTJs(BS`pyL3Mbm;$=qT>LOKmh=d0e~HmpaTJsx8VPmp#uStfC2!J0KgKF z;sXJyfdi0I0RpOW9M=DrpaTJs-sS(7pyL3M^xyxNfC2!J0ssJ!fC2!J0l*TGU;+T} z0CY$Bx#0hopyL3MTj>9nqT>LOKmh=d0U#ccpaTJsp5XtNp#uStfC2!J0N@gl;sXJy zp#zXo0RpOW1J?hSpaTJs#pVB(pyL3M+u#3}fC2!J0ssJ!fC2!J0pJpmU;+T}0CY$B zpy2LOKmh=d0l*%SpaTJsh2Z~}p#uStfC2!J000w_;sXJy!2^&| z0RpOW>ec_3paTJstmXfgpyL3M!r%XwfC2!J0ssJ!fC2!J0RR(`U;+T}0CY$Bhv5I0 zpyL3MDd_)~qT>LOKmh=d0bn1IpaTJsY~cTwp#uStfC2!J03Z{Q;sXJy;RBFT0RpOW z(bfN#paTJsljZ-HpyL3Mso(#XfC2!J0ssJ!fC2!J0U#5RU;+T}0CY$BZs7lypyL3M z5a|DxqT>LOKmh=d0pK5zpaTJsQ{exXp#uStfC2!J06-Iw;sXJy0R)gz0RpOWxYhrc zpaTJsdgcF@pyL3Mkl+88fC2!J0ssJ!fC2!J0YDRxU;+T}0CY$BRp9@ZpyL3M_vinY zqT>LOKmh=d0e~QppaTJsI^h48p#uStfC2!J0ALf5;sXJyAq0?80RpOWpVj}DpaTJs zVdejqpyL3Mci;b)fC2!J0ssJ!fC2!J0bmo6U;+T}0CY$BJmCMApyL3M-sk_9qT>LO zKmh=d0pK8!paTJsA>jX)p#uStfC2!J0Du#b;sXJyK?IOe0RpOWhSmRR zpyL3MUf=(hfC2!J0ssJ!fC2!J0e};cU;+T}0CY$BBjEp+pyL3M#pnN*qT>LOKmh=d z0YD*LOKmh=d0iYp~ zpaTJs@8AEIp#uStfC2!J0KgNG;sXJyfdr6J0RpOWRMr2NpaTJs7Uln!pyL3MEZ_f^ zfC2!J0ssJ!fC2!J0l*WHU;+T}0CY$B@!$WKpyL3Mljr}JqT>LOKmh=d0bnALpaTJs z*5Ch^p#uStfC2!J0N@jm;sXJyp#+dp0RpOWJJtV}paTJs{pA0bpyL3M6W{-rfC2!J z0ssJ!fC2!J0pJsnU;+T}0CY$B*x&z`pyL3MdguR_qT>LOKmh=d0U#rhpaTJsz2ELOKmh=d0l*`XpaTJsq~HISp#uSt zfC2!J03Z~R;sXJy;RKLU0RpOW3Dy6XpaTJs%jEx;pyL3M;okq3fC2!J0ssJ!fC2!J z0U#8SU;+T}0CY$Brr-aUpyL3MNaz2TqT>LOKmh=d0U#uipaTJsi{Jm3p#uStfC2!J z06-Lx;sXJy0R@m!0RpOW@YMg8paTJsvgH4lpyL3M$lm{#fC2!J0ssJ!fC2!J0YDUy zU;+T}0CY$Bjo<&5pyL3MFX#W4qT>LOKmh=d0iYz2paTJsa^L@#p#uStfC2!J0ALi6 z;sXJyAq9|90RpOW*VO-)paTJsndJYMpyL3MuipQcfC2!J0ssJ!fC2!J0bmr7U;+T} z0CY$Bbl?A%pyL3M7U%z$qT>LOKmh=d0U#xjpaTJsS>OMcp#uStfC2!J0Du&c;sXJy zK?RUf0RpOWzSRGhpaTJsfaL#|pyL3MmfruDfC2!J0ssJ!fC2!J0e}>dU;+T}0CY$B zTi^eepyL3M{pSCdqT>LOKmh=d0l+1ZpaTJsK;QqDp#uStfC2!J0H73+;sXJyVFi#< z0RpOWrPTkIpaTJsXXO8vpyL3Mecu0LOKmh=d0YD~^paTJsC*S{^paTJsPUQcWpyL3MWZwUmfC2!J0ssJ!fC2!J0l*ZIU;+T}0CY$BDc}E>pyL3M z%jW-=qT>LOKmh=d0pKQ)paTJs4&VQmp#uStfC2!J0N@mn;sXJyp#_jq0RpOWbJYKr zpaTJsHRS)7pyL3MOWyyNfC2!J0ssJ!fC2!J0pJvoU;+T}0CY$B5a0iopyL3MvgZGn zqT>LOKmh=d0e~lwpaTJs_1^!Np#uStfC2!J000${;sXJy!3B^~0RpOWTGaoSpaTJs z9OVC(pyL3MGT#4}fC2!J0ssJ!fC2!J0RR<|U;+T}0CY$B_ul`PpyL3MndbkOqT>LO zKmh=d0pKT*paTJs+}{6}p#uStfC2!J03a2S;sXJy;RTRV0RpOWLDc`3paTJs1LXgg zpyL3M8Q%YwfC2!J0ssJ!fC2!J0U#BTU;+T}0CY$B-roP0pyL3Mfad>~qT>LOKmh=d z0e~oxpaTJs!`}awp#uStfC2!J06-Oy;sXJyApnw60RpmeDAfO#paTJs>f`^HpyL3M z0N($XfC2!J0ssJ!fC2!J0YDXzU;+T}0CY$B#oqsypyL3MXXgKxqT>LOKmh=d0U#-n zpaTJss^0&Xp#uStfC2!J0ALl7;sXJyK>(6c0Rpme57hscpaTJs(c}M@pyL3M=iUF8 zfC2!J0ssJ!fC2!J0bmu8U;+T}0CY$Btls~ZpyL3MPUioYqT>LOKmh=d0e~rypaTJs zk>3B8p#uStfC2!J0Du*d;sXJyVE~d+0Rpme_S65DpaTJsxa0qqpyL3M&fWi)fC2!J z0ssJ!fC2!J0e}^eU;+T}0CY$BlivTApyL3MHRk`9qT>LOKmh=d0bnYTpaTJsc;5e) zp#uStfC2!J0H76-;sXJyApn$80RpOW-P8YLOKmh=d0RStJpaTJsU*7+hp#uSt zfC2!J0KgTI;sXJyK>(Ce0RpOW#MA$mpaTJshU5R2pyL3MoZbJIfC2!J0ssJ!fC2!J z0l*cJU;+T}0CY$BVc!3jpyL3M1LpsiqT>LOKmh=d0e~x!paTJsM&AFIp#uStfC2!J z0N@po;sXJyVE~j;0RpOWtJD9NpaTJsZR7u!pyL3MgWdm^fC2!J0ssJ!fC2!J0pJyp zU;+T}0CY$BNZ$XKpyL3M>gE5JqT>LOKmh=d0U#`qpaTJsE#Ci^p#uStfC2!J000(| z;sXJyfdG_J0RpOWlGFc}paTJsROA1bpyL3MYTf^rfC2!J0ssJ!fC2!J0RR?}U;+T} z0CY$BFW&!`pyL3M(dGY_qT>LOKmh=d0iZ0ApaTJs6yE=rp#uStfC2!J03a5T;sXJy zp#YRp0RpOWdDH)wpaTJsJLCVCpyL3MQQiNSfC2!J0ssJ!fC2!J0U#EUU;+T}0CY$B z7T*7t4F&)d^8)~?paTJsF5~}~0ssIM^8)~?pyL3MLf!wD-~$t?q~-sY^8)~?paTJs zCFB2>0ssIM^8)~?pyL3MIo0l^8)~?paTJs-Qxe30ssIM^8)~?pyL3M@!bEH-~$t? zQ|14c^8)~?paTJs)Z+h_0ssIM^8)~?pyL3M=-mI8-~$t?O6C8T^8)~?paTJs%i{l+ z0ssIM^8)~?pyL3M-`xL~-~$t?LFNCK^8)~?paTJs!s7pz0ssIM^8)~?pyL3M*4+P> z-~$t?IOYGB^8)~?paTJsx#Itq0ssIM^8)~?pyL3M&D{T&-~$t?FXjK2^8)~?paTJs zu;Txh0ssIM^8)~?pyL3M#N7Xv-~$t?CguN^^8)~?paTJsr{e#Y0ssIM^8)~?pyL3M zyWIbm-~$t?9p(R*^8)~?paTJsp5p(P0ssIM^8)~?pyL3MvfTfd-~$t?6y^Vy^8)~? zpaTJsmE!-G0ssIM^8)~?pyL3MsoejU-~$t?3+4Zp^8)~?paTJsjN<>70ssIM^8)~? zpyL3MpxpnL-~$t?0_Fdg^8)~?paTJsgW~^}0ssIM^8)~?pyL3Mm)!rC-~$t?`Q-nX z^8)~?paTJsdgA|=0ssIM^8)~?pyL3Mj@377-~$t?pXC3S^8)~? zpaTJsAmaa*0ssIM^8)~?pyL3MG~EA}-~$t?mgN7J^8)~?paTJs7vley0ssIM^8)~? zpyL3ME8PE=-~$t?jpYBA^8)~?paTJs4&wip0ssIM^8)~?pyL3MBHaI%-~$t?gyjF1 z^8)~?paTJs1>*mg0ssIM^8)~?pyL3M8QlMu-~$t?d*uI@^8)~?paTJs{NewX0ssIM z^8)~?pyL3M5ZwQl-~$t?a^(M)^8)~?paTJs^Wp!O0ssIM^8)~?pyL3M2i*Uc-~$t? zY2^Qx^8)~?paTJs>f!&F0ssIM^8)~?pyL3M{@eeT-~$t?VC4Uo^8)~?paTJs;o<+6 z0ssIM^8)~?pyL3M_1piK-~$t?SLFYf^8)~?paTJs*x~<|0ssIM^8)~?pyL3M?A!mB z-~$t?PUQcW^8)~?paTJs&*A@<0ssIM^8)~?pyL3M{v;^8)~?paTJsqT&CS0ssIM^8)~? zpyL3Mw%h-g-~$t?807z#^8)~?paTJsnc@GJ0ssIM^8)~?pyL3Mt=s>X-~$t?59I%s z^8)~?paTJskm3KA0ssIM^8)~?pyL3Mq}%_O-~$t?2IT*j^8)~?paTJshvEO10ssIM z^8)~?pyL3Mo7?}F-~$t?{p0_a^8)~?paTJse&PR@0ssIM^8)~?pyL3MlH326-~$t? z^yB}R^8)~?paTJsb>aV)0ssIM^8)~?pyL3MiQE5|-~$t?>*N2I^8)~?paTJsY~lZx z0ssIM^8)~?pyL3MfZP9<-~$t?;^Y69^8)~?paTJsW8wdo0ssIM^8)~?pyL3MciaD$ z-~$t?+2jA0^8)~?paTJsTH*hf0ssIM^8)~?pyL3MZrlHt-~$t?(BuD?^8)~?paTJs zQQ`lW0ssIM^8)~?pyL3MW!wLk-~$t?$K(H(^8)~?paTJsNa6pN0ssIM^8)~?pyL3M zT-*Pb-~$t?zT^Lw^8)~?paTJsKjHtE0ssIM^8)~?pyL3MQ``TS-~$t?wd4Pn^8)~? zpaTJsHsSx50ssIM^8)~?pyL3MO56XJ-~$t?tmFTe^8)~?paTJsE#d!{0ssIM^8)~? zpyL3MLEHbA-~$t?qvQXV^8)~?paTJsB;o&;0ssIM^8)~?pyL3MINSf1-~$t?n&bbM z^8)~?paTJs8{z+#0ssIM^8)~?pyL3MFWdi@-~$t?k>mfD^8)~?paTJs65;=s0ssIM z^8)~?pyL3MCfom)-~$t?h~xj4^8)~?paTJs3E}^j0ssIM^8)~?pyL3M9ozqx-~$t? zf8+m`^8)~?paTJs0O9|a0ssIM^8)~?pyL3M6x;uo-~$t?cH{q-^8)~?paTJs_u&7R z0ssIM^8)~?pyL3M3)}yf-~$t?ZR7u!^8)~?paTJs?%@BI0ssIM^8)~?pyL3M0^9$W z-~$t?WaIyr^8)~?paTJs<>3F90ssIM^8)~?pyL3M`P%=N-~$t?TjT$i^8)~?paTJs z+~EJ00ssIM^8)~?pyL3M@Y?^E-~$t?Qse)Z^8)~?paTJs)8PM?0ssIM^8)~?pyL3M z=i2|5-~$t?N#p;Q^8)~?paTJs%HaQ(0ssIM^8)~?pyL3M-rE0{-~$t?K;!?H^8)~? zpaTJs!QlUw0ssIM^8)~?pyL3M)!P4;-~$t?H{<`8^8)~?paTJsxZwYn0ssIM^8)~? zpyL3M%-a8#-~$t?F5~}~^8)~?paTJsui*ce0ssIM^8)~?pyL3M!`lCs-~$t?CFB2> z^8)~?paTJsrr`gV0ssIM^8)~?pyL3My4wGj-~$t?9OM6&^8)~?paTJso#6kM0ssIM z^8)~?pyL3MvD*Ka-~$t?6XXAv^8)~?paTJsl;HoD0ssIM^8)~?pyL3MsM`OR-~$t? z3giEm^8)~?paTJsi{Ss40ssIM^8)~?pyL3MpW6SI-~$t?0ptId^8)~?paTJsg5dv` z0ssIM^8)~?pyL3MmfHW9-~$t?_~QSU^8)~?paTJsdEoz-0ssIM^8)~?pyL3MjoSa0 z-~$t?@8bWL^8)~?paTJsaNz%!0ssIM^8)~?pyL3Mgxdd?-~$t?=HmaC^8)~?paTJs zXW;*r0ssIM^8)~?pyL3Md)oh(-~$t?-Qxe3^8)~?paTJsUf}0ssIM z^8)~?pyL3MJlg-4-~$t?p5p(P^8)~?paTJsAK?F&0ssIM^8)~?pyL3MGur=`-~$t? zmE!-G^8)~?paTJs7U2Jv0ssIM^8)~?pyL3MD%$^--~$t?jN<>7^8)~?paTJs4dDNm z0ssIM^8)~?pyL3MA=>|!-~$t?gW~^}^8)~?paTJs1mORd0ssIM^8)~?pyL3M7~21r z-~$t?dgA|=^8)~?paTJs```bU0ssIM^8)~?pyL3M58D5i-~$t?apM1%^8)~?paTJs z^56fL0ssIM^8)~?pyL3M2HO9Z-~$t?XyX5u^8)~?paTJs>EHjC0ssIM^8)~?pyL3M z{n`JQ-~$t?U*i9l^8)~?paTJs;NSn30ssIM^8)~?pyL3M^x6NH-~$t?R^tDc^8)~? zpaTJs*Wdq_0ssIM^8)~?pyL3M>)HR8-~$t?P2&HT^8)~?paTJs&fou+0ssIM^8)~? zpyL3M;@SU~-~$t?MB@LK^8)~?paTJs#ozyz0ssIM^8)~?pyL3M+1dY>-~$t?JL3PB z^8)~?paTJsyx;$q0ssIM^8)~?pyL3M(Aoc&-~$t?GUET2^8)~?paTJsv)})h0ssIM z^8)~?pyL3M$Jzgv-~$t?DdPW^^8)~?paTJss^9;Y0ssIM^8)~?pyL3MzS;km-~$t? zAmaa*^8)~?paTJsq2K?P0ssIM^8)~?pyL3Mwb}od-~$t?7vley^8)~?paTJsnBV`G z0ssIM^8)~?pyL3Mtl9sU-~$t?4&wip^8)~?paTJskKg~70ssIM^8)~?pyL3MquKwL z-~$t?1>*mg^8)~?paTJshTs2}0ssIM^8)~?pyL3Mn%V!C-~$t?{NewX^8)~?paTJs zec%6=0ssIM^8)~?pyL3Mk=g&3-~$t?^Wp!O^8)~?paTJsbl?A%0ssIM^8)~?pyL3M zh}r*_-~$t?>f!&F^8)~?paTJsYv2Eu0ssIM^8)~?pyL3Mf7$<+-~$t?;o<+6^8)~? zpaTJsV&DIl0ssIM^8)~?pyL3McG>@z-~$t?*x~<|^8)~?paTJsS>OMc0ssIM^8)~? zpyL3MZQ1{q-~$t?&*A@<^8)~?paTJsP~ZQT0ssIM^8)~?pyL3MWZD0h-~$t?#^L{$ z^8)~?paTJsN8kUK0ssIM^8)~?pyL3MTiO4Y-~$t?z2X0t^8)~?paTJsKHvYB0ssIM z^8)~?pyL3MQrZ8P-~$t?wBi4k^8)~?paTJsHQ)c20ssIM^8)~?pyL3MN!kCG-~$t? ztKt8b^8)~?paTJsEZ_f^0ssIM^8)~?pyL3MK-vG7-~$t?qT&CS^8)~?paTJsBj5j* z0ssIM^8)~?pyL3MH`)J}-~$t?nc@GJ^8)~?paTJs8sGny0ssIM^8)~?pyL3MF4_N= z-~$t?km3KA^8)~?paTJs5#Rrp0ssIM^8)~?pyL3MCE5R%-~$t?hvEO1^8)~?paTJs z2;cvg0ssIM^8)~?pyL3M9NGVu-~$t?e&PR@^8)~?paTJs|K9(X0ssIM^8)~?pyL3M z6WRZl-~$t?b>aV)^8)~?paTJs_TK-O0ssIM^8)~?pyL3M3fcdc-~$t?Y~lZx^8)~? zpaTJs?cV>F0ssIM^8)~?pyL3M0onhT-~$t?W8wdo^8)~?paTJs;y-~$t?E#d!{^8)~?paTJsuHOHb z0ssIM^8)~?pyL3M!r1?p-~$t?B;o&;^8)~?paTJsrQZLS0ssIM^8)~?pyL3Mx!C`g z-~$t?8{z+#^8)~?paTJsoZkPJ0ssIM^8)~?pyL3Mu-N~X-~$t?65;=s^8)~?paTJs zlivTA0ssIM^8)~?pyL3Mr`Z3O-~$t?3E}^j^8)~?paTJsir)X10ssIM^8)~?pyL3M zp4k7F-~$t?0O9|a^8)~?paTJsf!_a@0ssIM^8)~?pyL3MmDvB6-~$t?_u&7R^8)~? zpaTJsc;5e)0ssIM^8)~?pyL3MjM)E|-~$t??%@BI^8)~?paTJsZ{Gix0ssIM^8)~? zpyL3MgV_I<-~$t?<>3F9^8)~?paTJsX5Rmo0ssIM^8)~?pyL3Mdf5M$-~$t?+~EJ0 z^8)~?paTJsUEcqf0ssIM^8)~?pyL3MaoGQt-~$t?)8PM?^8)~?paTJsRNnuW0ssIM z^8)~?pyL3MXxRUk-~$t?%HaQ(^8)~?paTJsOWyyN0ssIM^8)~?pyL3MU)cYb-~$t? z!QlUw^8)~?paTJsLf-$E0ssIM^8)~?pyL3MR@ncS-~$t?xZwYn^8)~?paTJsIo|)5 z0ssIM^8)~?pyL3MP1ygJ-~$t?ui*ce^8)~?paTJsFy8-{0ssIM^8)~?pyL3MMA-kA z-~$t?rr`gV^8)~?paTJsC*J>;0ssIM^8)~?pyL3MJJ|o1-~$t?o#6kM^8)~?paTJs z9^U_#0ssIM^8)~?pyL3MGT8r@-~$t?l;HoD^8)~?paTJs72f}s0ssIM^8)~?pyL3M zDcJv)-~$t?i{Ss4^8)~?paTJs4Br2j0ssIM^8)~?pyL3MAlUzx-~$t?g5dv`^8)~? zpaTJs1K$6a0ssIM^8)~?pyL3M7uf%o-~$t?dEoz-^8)~?paTJs`rZGR0ssIM^8)~? zpyL3M4%q*f-~$t?aNz%!^8)~?paTJs@!kKI0ssIM^8)~?pyL3M1=#ev65-~$t? zOyK{Q^8)~?paTJs&E5Z(0ssIM^8)~?pyL3M;n)9{-~$t?L*W0H^8)~?paTJs#NGdw z0ssIM^8)~?pyL3M*w_D;-~$t?I^h48^8)~?paTJsyWRhn0ssIM^8)~?pyL3M&)5H# z-~$t?G2s7~^8)~?paTJsvfcle0ssIM^8)~?pyL3M#@GLs-~$t?DB%B>^8)~?paTJs zsonpV0ssIM^8)~?pyL3Mz1RPj-~$t?AK?F&^8)~?paTJspxytM0ssIM^8)~?pyL3M zwAcTa-~$t?7U2Jv^8)~?paTJsm)-xD0ssIM^8)~?pyL3MtJnXR-~$t?4dDNm^8)~? zpaTJsj@|#40ssIM^8)~?pyL3MqSybI-~$t?1mORd^8)~?paTJsh28&`0ssIM^8)~? zpyL3Mnb-f9-~$t?```bU^8)~?paTJseBJ+-0ssIM^8)~?pyL3Mkk|j0-~$t?^56fL z^8)~?paTJsbKU=!0ssIM^8)~?pyL3Mhu8m?-~$t?>EHjC^8)~?paTJsYTf^r0ssIM z^8)~?pyL3Me%Jq(-~$t?;NSn3^8)~?paTJsVcq|i0ssIM^8)~?pyL3Mb=Uuw-~$t? z*Wdq_^8)~?paTJsSl$1Z0ssIM^8)~?pyL3MY}fyn-~$t?&fou+^8)~?paTJsPu>5Q z0ssIM^8)~?pyL3MW7q$e-~$t?#ozyz^8)~?paTJsM&19H0ssIM^8)~?pyL3MTG#)V z-~$t?yx;$q^8)~?paTJsJ>CD80ssIM^8)~?pyL3MQP=;M-~$t?v)})h^8)~?paTJs zG~NG~0ssIM^8)~?pyL3MNZ0?D-~$t?s^9;Y^8)~?paTJsE8YK>0ssIM^8)~?pyL3M zKiB`4-~$t?q2K?PU;+TJ0EkEVp(jB3002PwAOHZ$9{>RHKmY(#fzAJy^9w-v{d>iz zzyn{_{d>Qu{R04z;s2jfAOL_;0O|ji{d>Wvzyn{_|3d)L;0FNtU;+TJ0L(}E0YCte z;0HkY0RRB`A0PwO|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbtR#0R%w#pbJ3x00cn! zKL7yh-~j+spbtR#00cn!002NaAE*FvfB^thpbtR#0t7($pbJ3x00cn!;R67w-~$4x zyW9Vl9{>PxVE_PBAOL_;0ssIM004ke{d>Zwzyn{_|3d)L;0FNt;R68q-~&MU|3d(g zzyn{_|3d)L;0FNt;R68qA0PwO|3d(gzyn{_|3d)L;0FNt;0HkY00=<&9{>RHpa1|= z;0HkY00=<&;0FNt`TzeH;0HkY|3d(gzyn{_|3d)L;0FNt;0HkY01QC+9{>RHpa1|= z;0HkY01QC+;0FNt`TzeH;0HkY|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#9{>QkpbtR# z&)EN$A0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY9|QpT;RitZ;0HkY0SEy3;RitZ;0HkY z0So~7;0HkY9}ocfA0PwO|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#jLiR+{d>Zwzyn{_ z|3d)L;0FNt;0HkY002O_02}}k|3d(gzyn{_004jzzyn{_{d>Hr{R04z^9um^^8*N~ zpf3QqU;+TJ0EkEV0RTYxp&tPG0RVu~0098-0iYL=U;+TJ0N6+Q=mQg~qc1?Y;sXJy z0Rn*1HqQT--~$t?VFCcKA&5u$q8~u{Apk)6K>z{DKL7ynKmY(#<;?$=^9w-v{d>fy zzyn{_{d>Hr{R04z^9um^^8*N~pcer7U;+TJ0EkEV0RTYxp&tPG0RVu~0098-0l*iL zU;+TJ0N6+Q=mQg~qZdH=;sXJy0R({37ta5e-~$t?VFCcKA&5u$q8~u{Apk)6K>z{D zKL7ynKmY(##?1eh^9w-v{d>fyzyn{_|APS0;12-#;R^uy;s*fv;159g;R`_d0RRB` z;159g;RitZ0R#Z~A0PwO|APRLzyn{_|3d)L;0FNt;0HkY002Pw0RTYx;0HkY00cn! zAOHZ09{>RH;0K=?02}}k|3d(gzyn{_|3d)L;0FNt;U54w;2%Ia9{>PxU;zMB;0HkY z002Pw0suhy;0HkY0R%w#;0HkY002PwK>z`&0RRB`3jhEV;0HkY002Pw0suhy;0HkY z00cn!;R7J5;0HkY002PwK>z`Y0RRB`;0HkY|3d(gzyn{_{d>Nt{R04zpbr4~p$h={ zpbJ3x+RFcz02}}k;R66FpbtR#rqBPE{d>Zwzyn{_|APS0;12-#;R^uy;tv41;159g z;R`_d0RRB`;159g;SWH$0SExOA0PwO|APRLzyn{_|3d)L;0FNt;0HkY00=<20t5gN z;RitZA_xGvAN&Au;1{1702}}k9{>Px00970;0HkY9|!=s;0HkY002Pw0U!X8;0HkY z0RRB`A0PwO|3d(gzyn{_|3d)L;0FNt;0HkY00=<20t5h2;RitZA_xGv9{>Px;1{17 z02}}k9{>PxAOQeW;0HkY;Rk?H0SExO;0HkY002Pw0U!X;;0HkY0RRB`A0PwO|3d(g zzyn{_|APS0;0FNt;R68q;0HkY00=<2-~#|E;R8VVAOHZ1;12-#;0HkY0RTYx;159g z0{j4x9{>RHK(K(C0Q^Ri0Pua&Apii2;0HkY0RRB`;159g;R68c02DxyArwH807QY> z;12-#;159g9{>RHDggjg;159g0004z;12-#;0HkY002Pw0U!X;;0HkY0RRB`;159g z;R66F;0HkY0SExOA0PwO|APRLzyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU002Pw zKL7yhAprnX;0HkY0SG|3-~&MU00=<2KL7x0VE_PBAOL_;0ssIM004ke|3d(gzyn{_ z|3d)L;0FNt;R68q;0HkY002Pw;R67w-~&MU002PwAOHZ%0Q^If0pxnq;0HkY00=<2 z-~#|EApii2-~&MU00=<2-~#|EAOHZ%|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#0sw$g z0RVu~hRgq#A0PwO{d>Zwzyn{_{d>Ks{R04zpcer7p%Vc4q8|Xcpcg>-q8~uHp%Xy) zddvTpA0PwO{d>cxzyn{_{d>Hr{R04zpbr4~U;+TJ0EkEV0RTYxp&tPG0RVu~pbtR# z0{}qzpbtR#00=<2Apn5VAt1n-prZhh;sXJy;R6GzP2c~Qpoc=KVgdlLLWoECqaQ%| zLI6PdVgLflUjP8{KmY(#z{~%a{d>fyzyn{_{d>Nt{R04zpbr4~pbtR#wcY=hpbtR# z{d>Zwzyn{_{d>Bp{R04z^HTw-pcer7p(g;jU;+TJ0EkEV0RTYxp)UaW0RVu~pcg>- z00cm(poasgpcg>-quu|Ppoc@Lpoavh0RVu~p(jB3004l}pesQ6^8*2@^aB8@-~$t? z;R6(^VgdlLLWoECqc1@DLI6PdVgLflUjP8{KmY(#mCOH^^HV{o{d>l!zyn{_{d>Nt z{R04zpbr4~pbtR#z107gpbtR#{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCy zN6Y`0pbtR#{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbJ3x-~#~5;R67wpbtR#3)KIY zpbtR#{d>Zwzyn{_{d>Bp{R04z^HTw-pcer7p%Vc4U;+S;0EkEV0RTYxp)UaW0RVu~ zpcg>-00cm(poasgpyL3Mp%Xy)_|yNF00cm(poavh0RVu~p(jB3004l}pesQ6^8*2@ z^aB8@-~$t?;R6(^Vgdk=LWoECqc1@DLI6PdVgLflUjP8{KmY(#Qp^9B^HV{o{d>l! zzyn{_{d>Bp{R04z^HTw-pcer7p%Vc4U;+S;0EkEV0RTYxp)UaW0RVu~pcg>-00cm( zpoasgpyL3Mp%Xy)l!zyn{_{d>Ks z{R04zpcer7p%Vc4q8|Xcpcg>-q8~uHp%Xy)y~_WWA0PwO{d>cxzyn{_{d>Nt{R04z zpbr4~p$h={qYps&pbJ3x0RTYxpbJ3x00=<2;sXFG-~$7yuFC(HA0PwO{d>Zwzyn{_ z{d>Hr{R04zpbr4~U;+S;0EkEV0RTYxp&tPG0RVu~pbtR#0{}qzpbtR#00=<2Apn5V zAt1n-prZhh;sXJy;R6Gzf!_a@prZhhPs#t602}}kVFCbz{D zKL7ynKmY(#^2-00{d>fyzyn{_{d>Nt{R04zpbr4~pbtR#=iL97pbtR#{d>Zwzyn{_ z{d>Nt{R04zpbr4~pbtR#JKg`6pbtR#ea-)upbtR#03ZO7a@qfvA0PwO{d>Zwzyn{_ z{d>Nt{R04zpbr4~pbtR#4$1$QA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#4&VQm zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#(#`*uA0PwO{d>Zwzyn{_{d>Nt{R04z zpbr4~pbtR#LfZeAA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#9{>P3pbtR#03ZO7 z>(~F6pbtR#0N?Zwzyn{_{d>Nt{R04zpbr4~pbtR#0N?Zwzyn{_|3d)L;12+~;R^t{;SWH$;0r*xAOHX=|3d(g zzyn{_|3d)L;12+~;R^t{;SWH$;0r*xAOHXg|3d(gzyn{_|3d)L;12+~;R^t{;SWH$ z;0r*xAOHX=|3d(gzyn{_008jPzyn{_|3d)L;0FNt;0HkY9|!>XA0PwO|3d(gzyn{_ z{d>Nt{R04zpbr4~pbtR#00=<&9{>RH-~a$rpbtR#0|-F*pbtR#p$|a$VgP_rU;sbX zA0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY00=<&9{>RH;1{1702}}k|3d(gzyn{_|3d)L z;0FNt;R68qU;+S;0L(}E0YCte;0HkY0RRB`A0PwO|3d(gzyn{_|3d)L;0FNt;0HkY z|3d(gzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_|3d)L;0FNx;0Hkc0l;7$0098d03aBV z002P!ARu5K;Fq5o02}}k0000|02}}k0000I02}}k|3d(gzyn{_|3d)L;0FNt;0HkY z002Pw|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#06+kdcGv%x{d>Zwzyn{_{d>Hr{R04z z^9um^pdSGFp*H}zq89-9pdUc_7|s8eU;+S;0N_XY0YCtepdUc_0RRB`pdUc_p*KLe z0SExOpdUc_06+kdp%*~;xXS;R1^@sQ^8)~?pdUc_4Bh{i-~$t?GTi@{^9w-v{d>fy zzyn{_{d>Bp{R04z^9um^^8*N~pcer7p(g;jU;+S;0EkEV0RTYxp)UaW0RVu~0098d z06-X#q2mCN=mP<&p%*~;{?GrH0098d0iYO>pyL3Mq5}bu=mP?(l+pi}pd$g1=mP+% zpeI1N4AK9Wp(6p2paTJsqC)|Z=mP?()5iao0098d0l*lMphE$X=mQg~hSC3*A0PwO zphE$Xi`oB|pd$g1iP`^`paTJshuQy^pyL3Mh1vg?A0PwO-~$t?VFCbz{DKL7ynfC2zi5&!@c^8)~?phE$Xc-jA#0ssIM^8)~?pd$g1blLxx0ssIM z^8)~?paTJsaM}Nt0ssIM^8)~?pyL3MY}x;p-~$t?=G*_5&B_0l^9w-v{d>l!zyn{_ z{d>Ks{R04z^9um^pcer7p%Vc4pcg>-p%Xy)0^I+XU;+S;0PIKk0YCtepcg>-0RRB` zpcg>-0w4g9pc6p(03ZO7;R67w-~$4x=FI<>1^@sQ^8)~?pcg>-qTK(N-~$t?$lL#y z^9w-v{d>cxzyn{_{d>Nt{R04zpbr4~U;+S;0N_XY0YCtepbtR#0RRB`pbtR#06+kd ze$xM!pbtR#klg>5A0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#SknKOpbtR#rqTbG z{d>Zwzyn{_{d>2m{R04z^HTw-^aBX0pg#b)p&J1Cq89-9U;+S;0EkEV0RTYxp+^Au z0RVu~pd$g1s@wmUq9Xy30098d0pJ*spko1%?bH94pko1%p@RXD=mP<&p+7*m1kL}K z0098d0U#NXpo0OCqN4$k=mP?(3eo?Upu+)?=mP+%pc_E>qQ?K1p~C@@prZkiqT>OP z=mP?(Nyh(|0098d0bm)CpyL6Nq5}ev=mP?(`_TWFpaTMtp+f697Q@phE$Xyw?Ah;{yPy;sX<^p+7*m-~$w@%h3OqA0PwOphE$Xz{DKL7ynpacL^BLDyt^8)~?paTMt*VzA; z0ssIM^8)~?pyL6N)7bx)0ssIM^8)~?pu+)?&)EN$0ssIM^8)~?prZki%h>;y0ssIM z^8)~?po0OC$Jqau0ssIM^8)~?pko1%!`T0q0ssIM^8)~?pd$g1*V6x&-~$t?Ioto2 z^8)~?phE$Xy4e4h-~$t?G~54|8_EBd^HV{o{d>u%zyn{_{d>Ks{R04zpcer7p(g;j zq7MN1qYD7}pcg>-q6-0RRB`pcg>-p$|a$ z0T2NBA0PwO{d>cxzyn{_{d>Bp{R04z^9um^^8*N~pcer7U;+S;0EkEV0RTYxp)UaW z0RVu~pcg>-00=<&00aP$q2mCN=mP<&%iI5#q2mCN0098d0Du{hq5}bu=mP?(A>03# z0098d0l*oNpaTJsq9Xy3=mP?(d(i)vpcg>-00cn!p+fz{DKL7ynfC2zi5&!@c^8)~?phE$XWZ3_g0ssIM^8)~? zpd$g1VA%hc0ssIM^8)~?paTJsT-g7Y0ssIM^8)~?pyL3MSlIuU-~$t?(%S!*xyb*Q z^9w-v{d>l!zyn{_{d>Bp{R04z^9um^^8*N~pf3Qqp%Vc4U;+S;0EkEV0RTYxp)UaW z0RVu~pyL3M&D#H$qT>LO0098d0RS42pd$g15Yzvcpd$g1p+fz{DKL7ynpaK9?6951d^8)~?phE$X8rc7r0ssIM^8)~?pd$g17TEun0ssIM^8)~? zpyL3MD$@U#-~$t?jN1Q~^8)~?paTJs4cPye-~$t?huZ&_Zpil!zyn{_ z{d>Ks{R04zpcer7p(g;jq7MN1pcg>-q7Oj%p(jAOUeW)TU;+S;0HjCx0YCtepcg>- z0RRB`A0PwO{d>cxzyn{_{d>Bp{R04z^9um^^8*N~pf3Qqp%Vc4U;+S;0EkEV0RTYx zp)UaW0RVu~pyL3MaoYcvqT>LO0098d0bm-Dpd$g1w9@~Vpd$g1p+fz{DKL7ynpaK9?6951d^8)~?phE$XzSsYk0ssIM^8)~?pd$g1y4U}g0ssIM z^8)~?pyL3M&e8vu-~$t?Fxvl@^8)~?paTJsvDg2X-~$t?E872;63G9T^9w-v{d>l! zzyn{_{d>Ks{R04zpcer7p(g;jq7MN1pcg>-q7Oj%p(jAO0@44MU;+S;0F+1h0YCte zpcg>-0RRB`A0PwO{d>cxzyn{_{d>Bp{R04z^9um^^8*N~pf3Qqp%Vc4U;+S;0EkEV z0RTYxp)UaW0RVu~pyL3M725xoqT>LO0098d0iYU@pd$g1SknKOpd$g1p+fz{DKL7ynpaK9?6951d^8)~?phE$XV%Ptd0ssIM^8)~?pd$g1Uf2JZ z0ssIM^8)~?pyL3Ma?$^n-~$t?)Y<=+^8)~?paTJsRoDNQ-~$t?&)NT%w#WaM^9w-v z{d>l!zyn{_{d>Ks{R04zpcer7p(g;jq7MN1pcg>-q7Oj%p(jAOrqKVFU;+S;0BlG3 z0YCtepcg>-0RRB`A0PwO{d>cxzyn{_{d>Bp{R04z^9um^^8*N~pf3Qqp%Vc4U;+S; z0EkEV0RTYxp)UaW0RVu~pyL3Mx!M1hqT>LO0098d0pJ>upd$g1{L%lHpd$g1p+feT<2;sXGxp)WwW-~$t?TGaoSA0PwOpaTJs6W9NjA0PwO-~$t?K>`5q zA&5u$qAx)CApk)6K>z{DKL7ynpaK9?6951d^8)~?phE$X2G{?W0ssIM^8)~?pd$g1 z0@weS0ssIM^8)~?pyL3M7SaEg-~$t?c-jA#^8)~?paTJs`PToJ-~$t?bJ_owTF3vF z^9w-v{d>l!zyn{_{d>Ks{R04zpcer7p(g;jq7MN1pcg>-q7Oj%p(jAOO3?q8Kmq{p z0OUvc0YCtepcg>-0RRB`A0PwO{d>cxzyn{_|3d)L;0FNtKmq{p0I)~-0YCte;0HkY z0RRB`A0PwO|3d(gzyn{_|3d)L;0FNtKmq{p0I)~-0YCte;0HkY0RRB`A0PwO|3d(g zzyn{_{d>Nt{R04zpbr4~pbtR#CC~qtpbtR#JJ0`@{d>Zwzyn{_{d>Ks{R04z^9um^ zpcer7Kmq{p0KiB20YCtepcg>-0RRB`pcg>-00cn!p%*~;Ap}7AApk)6Az%Q}Apk)6 z6955=pcg>-00cn!p%*~;Ap}7AApk)6Az%Q}Apk)60004tBhLSqK>&bKq00Z4;R66F z-~$t?cG&-ypcg>-B-j6!A0PwO^9w-v{d>cxzyn{_{d>Nt{R04zpbr4~pbtR#*UA5v zpbtR#4bT6V{d>Zwzyn{_{d>Ks{R04z^9um^pcer7p%Vc4pcg>--0RRB`pcg>-p%Xy)0R#Z~pc6p(002Pw0AK*o002Pw;R67wpc6p(0004t zG|2y#;R67wpcg>-0SEy31^@sQ^8)~?pcg>-`PToJ-~$t?^Vt8F^9w-v{d>cxzyn{_ z{d>Hr{R04z^9um^pcer7pcg>-00=<&Y03YWpg#b)pg%yl9|Qm~;Q|0upcg>-00cn! zp%*~;Ap}7AApk)6Az%Q}Apk)66955=pcg>-00cn!p%*~;Ap}7AApk)6Az%Q}Apk)6 z0004t(9QpsK>&bKHqQT-;R66F-~$t?BiR3!pg%yl^9w-v{d>fyzyn{_{d>Nt{R04z zpbr4~pbtR#03ZO7ao7KsA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#soDRRA0PwO z{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#03ZO7VAubbA0PwO{d>Zwzyn{_{d>Nt{R04z zpbr4~pbtR#Y{>tYA0PwO{d>Zwzyn{_{d>Eq{R04z^9um^pcer7p%Vc4Kmq{p0EkEV z0RTYxp(gRHKmY(#bH@Ld^9w-v{d>izzyn{_ z{d>Nt{R04zpbr4~p$h={pbJ3x0RTYxpbtR#0RRB`pbtR#0w4g9pbJ3x03ZO7;R67w z-~$4xg~Zwzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCyC))p)A0PwO z{d>Zwzyn{_{d>Ks{R04z^9um^^8*N~pcer7pcg>-;R67w-~$t?&(i;w-~$t?^9w-v z{d>cxzyn{_|3d)L;0FNt;0HkY9{>RPA0PwO|3d(gzyn{_|3d)L;0FNt;0HkYApn5V z0RRB`A0PwO|3d(gzyn{_|3d)L;0FNt;0HkY002Pw9{>RH;1{1702}}k|3d(gzyn{_ z|3d)L;0FNt;R68q;RitZ-~&MUKL7yh;1{1702}}k|3d(gzyn{_|3d)L;0FNt;0HkY z002Pw0R#Y%;0HkY0RRB`;0HkY|3d(gzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Nt z{R04zpbr4~pbtR#EzAFxA0PwO{d>Zwzyn{_{d>Qu{R04zKmq{p0Jul_0Q}zw02}}k z0000I9{>Px;1{1702}}k9{>PxzybhNKmq{p0Jul_li2^49{>Px;0K=?02}}k9{>Px zzySbMKmq{p0K7-}|HS{7Kmq{p0Jul_WXk`SU;+S;0ssJ!Kmq{p0lY`~Kmq{p0O&{g zZP5RhKmq{p0K7-}{d>Wvzyn{_{d>Eq{R04zpcer7p(g;jq7MN1Kmq{p0EkEV0RTYx zp(g-p_2fS9M%7qpdSGFpcg>-dBy*ipd$eJp#uStpyL3Mt;_$H02}}k z9{>Px;Q#-p_2fSuf+eCp$|a$70v&b0ssIMA0PwOKmq{p0EkEVp(jB3002Pw zAOHZ$9{>RHKmY(#!^QuX{d>izzyn{_{d>Eq{R04z^9um^^8*N~pcer7p(g;jKmq{p z0EkEV0RTYxp(g-p_2fS^VI*BpdSGFpcg>-P{se3pd$eJp#uStpyL3M zSkC{K02}}k9{>PxpaB3>paTJs%h&&xp#uSt0098706-g&;sXJy;R67w-~$t?4AB3V zpaTJsQqTXF4FCWXpyL3M+sXfz03ZO7;R67w-~$t?$H@Pe1^@sQ^8)~?paTJsN6-J4 z-~$t?sn`FP-~$t?K>`5qA&5u$q9;K4Apk)6K>z{DKL7ynKmY(#h{gYx^9w-v{d>iz zzyn{_{d>Nt{R04zpbr4~pbtR#5Xt|SpbtR#j@JK|pbtR#03ZO757hscA0PwO{d>Zw zzyn{_{d>Nt{R04zpbr4~pbtR#1IGWCA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR# z@74d8A0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#1J?hSA0PwO{d>Zwzyn{_{d>Nt z{R04zpbr4~pbtR#$ISniA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#3&{VMA0PwO z{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#GtB>&A0PwO{d>Zwzyn{_{d>Ks{R04zpcer7 zp(g;jq7MN1V#@!Qq7Oj%p(jAOFVX*(A0PwO{d>cxzyn{_|3d)L;0FNtA0PwO|3d(g zzyn{_{d>Ks{R04zpdSFap&J0Xp&LNCpdUcF1knGNpf3Qqpf5nV9|Qn#VE_PBAOL_; z0ssIM004ke{d>cxzyn{_{d>Qu{R04zKmq{p0Zd2v0AMRHVFCbDKo)?~3C#bO;sXFGKmq{p0aQo%0H8XNAOJtsLC`zZAOHZ10ssKH zKmq{p0Zd2v0AMWvzyn{_{d=UT{R04z^HTw-^8*N~pcer7p`QRbKmq{p0EkEV0RTYx zq2B=c0RVu~-~$t?AJqSspcg>-9ohev02}}k9{>Px-~a$r0098706-g&;R67w-~$t? zp~(N2NB{s70Rezg00Mwgb=Uuw;R66Fpd$g1;sXIHp%*~;7{vdVpyL3Mj?Dj;q2mCN zpd$g1qMtxH#?Swk0RTYxAz%Q}Apk)60004tnb7~202}}k9{>PxzyJVLpyL3M;R67w z-~$t?BFX=k@c;i8pcg>-OV$6Epd$eJpd&!}9{>RHfB^thpd&!}00aQh;R67wpcg>- zQq%vJ002Nap`SoGKL7x0VE_PBAOL_;0ssIM004ke9{>PxzyJVL0098706-g&;R67w z-~$t?Y{>tYA0PwOpyL3MP1OIFpd$g1)6@T#4gdfY^aB8@pyL3MN7Vn90ssIM^aB8@ zpd$g1%hUgt0ssIM^aB8@-~$t?57+;f-~$w@xz_)e-~$t?K>`5qA&5u$qTfLIApk)6 zK>z{DKL7ynKmY(#n8g2=^HV{o{d?S~zyn{_{d>Ks{R04z^9um^pcer7pcg>-Kg|D^ zpcg>-03ZO7Jk0->pcg>-06+kdwbTEX1^@sQ^8)~?pcg>-A=Lku-~$t?o7VrA^9w-v z{d>cxzyn{_{d>Nt{R04zpbr4~pbtR#06+kd=GOn0pbtR#03ZO76V(5gpbtR#5!C;e zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#<<|d~pbtR#2gm=HpbtR#03ZO7{L=rI zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#eAfS$A0PwO{d>Zwzyn{_{d>Nt{R04z zpbr4~pbtR#WYhnbA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#(8>RoA0PwO{d>Zw zzyn{_{d>Nt{R04zpbr4~pbtR#(9i#uA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR# z03ZO7+tdG-pbtR#+0*}*A0PwO{d>Zwzyn{_{d=pa{R04z^HTw-^aBX0pf3RVp(_CS zq9*|Pqn7~rq?-WwrJn%#rlSD)r>6kN2Kmq{p0EkEV0RTYxp-%w$0RVu~pesQ606YMZ06YMZ0Q^ML0PK9z|6?G_-~#}W z06YMZ0Q^ML0PK9zpgREhphE?bpg#clphE?bphE!ppo0XFphp1t-~@mYppyW(;17Tj zpqBu-qJsdDqvHXQU<5#^Km-7(U<5&_Km-A)po0LBq%T1E;{yPyq9;K4p({Z7pgTbM zfB-+%pl<-Vpl^V=p*ukNGXMaKprZki9oGMsprZki;{yPy;sX<^p*ukN-~$w@`5qA&5u$qEA5iApk)6K>z{DKL7yn009701^@sQ^8)~?prZki zna%%~-~$t?`_=!K;=})!zXJe~^HV{o{d?7@zyn{_{d>Nt{R04zpbr4~pbtR#CC>ks zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#fyw`uA0PwO{d>Zwzyn{_|3d)L;0FNt zA0PwO|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#?A8C5;R67wpbtR#nZ*B>pbtR#d(!`x zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#2h9JMA0PwO{d>Zwzyn{_{d>Ks{R04z z^HTw-pcer7pcg>-697Q@pcg>-6a+x|pcg>-cFX^l;sXGx;R6(^-~$t?mec>2pcg>- z+|U1)A0PwO^HV{o{d>cxzyn{_{d>Hr{R04z^HTw-^8*N~pcer7p%Vc4Kmq{p0EkEV z0RTYxp&tPG0RVu~p%*~;-~$t?!p8rXp%Xy)-~$t?L)QP71^@sQ^aB8@-~$t?C)59z z-~$w@q1FGF-~$t?K>`5qA&5u$q8~u{Apk)6K>z{DKL7ynKmY(#fW!Zn^HV{o{d>fy zzyn{_{d>Hr{R04z^HTw-^aBX0pcer7p%Vc4pcg>-_0#{C^8)~?pc6p(^3(s9U;+S( zpdSGFpcg>-=E?t;;R67wpdUc_9{>UCDFFafpc6p(;K~1&;R67wpdUc_9{>UCXaE3I zAOL_;0ssIM004kepx*#Fpx;0_9{>Px-~a$rq8C8<0RVu~pc6p(8PEThn9Ki{1pojP zp%Xy)pcg>-FwOs$lgs~?;R67w-~$w@=*It--~$w@^HV{o{d>fyzyn{_{d>Ks{R04z z^9um^^8*N~pcer7p%Vc4q8C8<0RVu~pc6p(F4g~+fy@7w;R67w-~$t?*2e#r-~$t? z^9w-v{d>cxzyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU002PwKL7yhVgLYC-~&MU z0ssIM;0HkY|3d(gzyn{_{d>Hr{R04z^HTw-^8*N~pcer7p%Vc4Kmq{J0EkEV0RTYx zp&tPG0RVu~pcg>-bJqWtpc?@B-~$t?%*y|lpc6p(n$!Q6;R67wpc_E>AOHZ1;R67w z-~$t?SjqpFq8mW@p%*~;-~$t?6v6+Op%Xy)-~$t?>CFF^1^@sQ^aB8@-~$t?rPBYG z-~$w@AJzYt-~$t?K>`5KA&5u$q8~u{Apk)6K>z{DKL7ynKmY(#{=)y4^HV{o{d>fy zzyn{_{d>Ks{R04z^9um^^8*N~pcer7p%Vc4p%Xy)pcg>-rq%zKG0Xp#;R67w-~$t? zhQ|Mw-~$t?^9w-v{d>cxzyn{_{d>Ks{R04z^9um^^8*N~pcer7p%Vc4p%Xy)pcg>- zz0CiYAj|)k;R67w-~$t?b;kdf-~$t?^9w-v{d>cxzyn{_{d>Nt{R04zpbr4~pbtR# z002Pw9{>RHfB*ngpbtR#002PwGs*v#A0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY|3d(g zzyn{_{d>Ks{R04z^9um^pcer7p%Vc4vll@5pc6p(qtXAD;R67w-~$t?%*g+jA0PwO z^9w-v{d>cxzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Hr{R04z^9um^^8*N~pcer7 zKmq{J0EkEV0RTYxp&tPG0RVu~pu+%>Ys~+bpcg>-q0#@B;R67wpu+%>=mQg~<<9?? zpu+%>N67z|-~$t?K>`5KA&5u$q8~u{Apk)6K>z{DKL7yn009701^@sQ^8)~?pu+%> zJIMc+-~$t?snq|Mki!3$^9w-v{d>fyzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Ks z{R04z^9um^pcer7p%Vc4vll@5pc6p(jL-j<;R67w-~$t?ZPEXiA0PwO^9w-v{d>cx zzyn{_{d>Nt{R04zpbr4~p$h={pbJ3x0RTYxpbtR#0RRB`pbtR#002Pw9{>RHfB*ng zpbtR#002Pw9?AcgA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbtR#z03cXA0PwO z{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#VbuSZA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~ zpbtR#03ZR8?9u<1pbtR#0Kfo|b;JLcpbtR#Q`G;LA0PwO{d>Zwzyn{_{d>Nt{R04z zpbr4~pbtR#0H6So+RFczpbtR#NXq}0A0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR# z(9HjrpbtR#0w4g9pbtR#002Na;R66F-~$4xIne)?A0PwO{d>Zwzyn{_|3d)L;0FNt z;0HkY|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbJ3x@6rF40RTWbpbtR#0RR9wpbJ3x z03ZO7dBOje;R67wpbtR#Apk)60R#Z~pbJ3xugw3KpbJ3x9{>P3pbJ3x9|QpTpbtR# zsm%YEA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCy>(&34{d>Zwzyn{_ z{d>Nt{R04zpbr4~pbtR#@XY_0{d>Zwzyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU z002PwKL7yh;0K=?02}}k|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCy=fVG% zA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCy4Z{DIA0PwO{d>Zwzyn{_ z|3d)L;0FNt;R68q;0HkY;R8VV0RRB`A0PwO|3d(gzyn{_{d>Bp{R04z^9um^pcer7 zp%Vc4Kmq{J0EkEV0RTYxp)UaW0RVu~p%Xy)pcg>-l+yo~pd$eJpcg>-Wx@ZKpeq3R zp+fPxp#cC?pcg>-w9o&SpaTJs_Qn5~;R67wpd$g1;sXJy zp%Xy)4a@(R02}}k9{>PxU;qGAAOL_;0ssIM004ke9{>PxU;+SCvll@5p#uStphE$X zdCvcrpd$g1p%Xy)8p{8dqT>LOp(6p20097y0Du>f`5KA&5u$qAx)CApk)6K>z{DKL7ynKmY(#kiq|# z^9w-v{d>l!zyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU002PwKL7yh;1{1702}}k z|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#002Pw2habP{d>Zwzyn{_{d>Nt{R04zpbr4~ zpbtR#xWoUKA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#Sk3>JA0PwO{d>Zwzyn{_ z|3d)L;0FNtA0PwO|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#XVm|f;R67wpbtR#e8vBl zpbtR#w$uNYA0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Ks{R04z^HTw- zpcer7p%Vc4pcg>-0R%w#pcg>-00=<&KL7yh00ID1vll@5pcg>-6a+x|pc6p(Le2k| z;sXGx;R6(^-~$t?0>J;5pcg>-00cn!0U!X8pcg>-0R#Z~3IG5Upcg>-63qXX^8)~? zpc6p(GtK{(;sXGx;R6$@pcg>-E5-kpA0PwO^HV{o{d>cxzyn{_{d>Nt{R04zpbr4~ zp$h={pbtR#0R%w#pbtR#00=<&KL7yhzySbMqYps&pbtR#00cn!q6Zwzyn{_{d>Hr{R04zpbr4~Kmq{J0EkEV0RTYxp&tPG0RVu~pbtR#b<6*k zpcer7pbtR#3e*3Wpc?@Bp~C=?prZhhQpEq402}}kK>`5KA&5u$q8~u{Apk)6K>z{D zKL7ynKmY(#@xcF={d>fyzyn{_|3d)L;0FNt;0HkY00cn!;R67w;0HkY002PwAOHZ% z0Q^If|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCyWx@ZK{d>Zwzyn{_{d>Nt z{R04zpbr4~pbtR#qRao6{d>Zwzyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU002Pw zKL7yh;1{1702}}k|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#002Pw2Fw4K{d>Zwzyn{_ z{d>Eq{R04z^HTw-^%DU3pdSGFp&J1CKmq{J0EkEV0RTYxp(g zqQn1}^aB8@pc_E>@4o++;R67wpaTJs=mP+%-~$1w_QC&`paTJs;sXGx;R6(^-~$t? zq0#@BpaTJs$Ho7bpc_E>70dsZ^aB8@pc_E>s?z_L^#cH^pdUc_697Q@pdUc_Wyt@R z;{yPy;sX<^;R6+_-~$w@XvzPV;R67wpdUc_0R#Z~A0PwOKmq{J0EkEVp(jB3002Pw zAOHZ$9{>RHpaB3>3jhEV^8)~?paTJssm1@7-~$t?o6`T6^8)~?pdUc_xXk~T-~$t? zmeT*1eZc>h^HV{o^%Fq({d>izzyn{_{d>Ks{R04zpbr4~Kmq{J0EkEV0RTYxp%(!8 z0RVu~p$|a$po0LB(!~Flpc6p(K>`5KA&5u$q8C8z{DKL7ynKmY(#Wx)TJ z{d>cxzyn{_{d>Ks{R04zpbr4~Kmq{J0EkEV0RTYxp%(!80RVu~pbtR#0U!X8po0LB zyTt#Opc6p(K>`5KA&5u$q8C8z{DKL7ynKmY(#PQd?{{d>cxzyn{_{d>Ks z{R04z^9um^pcer7p%Vc4pcg>-QNsV1697Q@pc6p(PQw3}002Pwe*ysO;0K=?02}}k z^9w-v{d>cxzyn{_|3d)L;0FNt;0HkY002Pw0U!X8;0HkY0RRB`;0HkY|3d(gzyn{_ z|3d)L;0FNt;0HkY002Pw|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCyIK}^$ z{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#O~C(`{d>Zwzyn{_|3d)L;0FNt;R68q;0HkY z0RTYx-~&MU002PwKL7yh;1{1702}}k|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#002Pw zEz19w{d>Zwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Nt{R04zpbr4~p$h={pbJ3x zJjnl-;R67wpbtR#71RHhA0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Nt z{R04zpbr4~p$h={0RVtfpbtR#&cpwgpbtR#fXe@uA0PwO{d>Zwzyn{_{d>Eq{R04z z^HTw-pcer7p%Vc4Kmq{J0EkEV0RTYxp(g-71RHh02}}k9{>PxfB^th zpcg>-Apn3<0RR9wpaTJsApn3-p(8-~0R#Z~pcg>-W6J-Rpcg>-F~a|s z02}}k031M)9{>RH;0K=?02}}k9{>PxfCB(jpcg>-69ho{pyL3M;?e(?q2mCNpaTJs z;sXJyp%Xy)CCdMopaTJs;R67w-~$t?naTf`^8)~?paTJsPS5|BpyL3MWXb=R-~$t? zK>`5KA&5u$q9;K4Apk)6K>z{DKL7ynAP4|dKL7v}00e;2k-`6$^8)~?pcg>-+R*=( z^aB8@pu+%>!_ohjp~C=?pyL3M;sXJy;R6(^2Fm}Jq2mCN0097y0AN3nq5}bu=mP?( z$kG3opaTJs=mQg~;R67wASQrPyTt#OpaTJsDbN3xpyL3MC(r+vpu+%>J<0! zA<6%j-~$t?yTt#O-~$w@fzkh$XutoL^HV{o{d>izzyn{_{d>Ks{R04zpbr4~p$h={ zKmq`;0EkEV0RTYxp%(!80RVu~pbJ3x0RTWbpbtR#0RR9wpbtR#9|QpTpbJ3x?8*O^ zpbtR#002Na9}oa>AO!$a9}oa>2mt_89|!<(paK9?9|!<(XafLL9|Qn#AOQeWKmY&~ z9~b~}zy$zQ9~b~}g9HFn9~=O2Kn4I*IRF3@pbJ3x0R%w#po0LBnA884pbtR#p%Xy) z0R#Z~F#rG*pbJ3x0R%w#po0LB{JZ~`pbtR#p%Xy)0R#Z~DF6TzpbJ3x0R%w#po0LB z{KNm3pbtR#p%Xy)0R#Z~ApigrpbJ3x0U$s*po0LBD9HbppbtR#p%Xy)0R#Z~82|tj zpbJ3x0R%w#po0LBIK%&!pbtR#p%Xy)0R#Z~5dZ)bpbJ3x0R%w#po0LB=+Xa|pbtR# zp%Xy)0R#Z~2><{TpbJ3x00cn&po0LB1j7H9pbtR#p%Xy)0R#Z~A0PwOpbtR#p2`20 zA0PwOKmq`;0EkEVp%*~;002PwAOHZ$9{>RHKmY(#{l5Q~{d>cxzyn{_|3d)L;0FNt z;0HkY002Na9{>Px;1{1702}}k|3d(gzyn{_|3d)L;0FNt;0HkY002Na9|!<(;1{17 z02}}k|3d(gzyn{_{d>Nt{R04zpbr4~pbtR#002Na9|Qn#fB^th9|Qn#g8%?j9|!<( zfB*ng3jhEV004l}3IG5UpbtR#00cn!49@?T1^@sQpbtR#00cn!gv|e!0ssIMAOL{U z{d>Zwzyn{_{d>Bp{R04z^HTw-pcer7p%Vc4Kmq`;0EkEV0RTYxp)UaW0RVu~pcg>- z0Mh@L02}}k9{>PxKmh<$pcg>-K>&bK0RR9wrNRG~;R67wpcg>-0R#Z~pcg>-P|5$7 zpcg>-F1-Jj02}}k031M)9{>RH;0K=?02}}k9{>PxKn4I*pcg>-00cn!;LZP+;R67w zpc6p(9{>UC;5VNd02}}k9{>PxfCB(jpcg>-69ho{pcg>-00cn!RKEY0pdSGFq2mCN zpaTJsu)+VApcg>-00cn!&CUOp;R67wpc6p(0005Y6a)Z~pd$g10RVu~KEMB$pd$g1 z;{yPy;sX?_p(8-~-~$t?q{{!7pd$g1YQq1Qpcg>-00cn!p%Xy)uEGD8K>`4z{DKL7ynpa%d{I{*L_00e;2Xu$uM^8)~?pcg>-vCsdP^aB8@pyL3M zn$Z83q2mCNpaTJs;sXJy;R6(^-N^r!p#uSt0097y06+kdq9Xy3=mP?(pV0r8pd$g1 z=mQg~;R67wASQrPlEeR(pd$g10M7rHpaTJs{>}fFpyL3M6v+RVKmq`;0hmYmKmq`; z0Axq`;sXJy;R67w-~$t?l!zyn{_{d>Hr{R04z^9um^^8*N~pcer7Kmq`;0EkEV0RTYxp&tPG0RVu~ z=mQg~pcg>-tH1x3-~$t?K>`4z{DKL7ynKmY(#D!%`h^9w-v z{d>fyzyn{_004kezyn{_AOL_;zyn{_{d>Eq{R04z^HTw-^%DU3pdSGFp&J1Cp&LN? zpdUc_KL7yhz!m^hWYYha02}}k9{>PxfCd0mFuwnn02}}k0000|02}}k9{>PxzySbM zpdUc_*~R~t^8)~?pc_E>O1%G<;R67w-~$t?OTGV>02}}k9{>PxU;qGAAOL_;0ssIM z004ke9{>PxzybhNpdUc_dAt9YqaQ%|pdUc_0RTYxpdUc_00=<&;sXGxpdUc_002Pw zKmY*C0Q^If;sXGx-~$7yjKu$!pdUc_9{>RPpdUc_9|QpTpdUc_9|!>XpdUc_w8j6I z^8)~?pc_E>CA|Na;R67w-~$t?(!c+gpc_E>(7^wfpd$eJpdUc_9nAli;R67wpd&!} z9{>UC;Fq5o02}}k9{>Pxzy$zQpc_E>NXY+}^8)~?pc_E>-OvA*;{yPy;sX<^p(8-~ zpdUc_RLlRDpeF$NpdUc_697Q@pdUc_6a+x|pdUc_k;VU);sXGx;R6(^-~$t?vCaRN zqaQ%|pdUc_0RTYxpdUc_00=<&;sXGxpdUc_002PwKmY*C0Q^If;sXGx-~$7yP{jY2 zpdUc_p(jB30RRB`pdUc_0RTYxpd&!}0Pua&Apii2pdUc_0SEy3KL7v}pdUc_m%#s* z;R67wpd&!}9{>UC;D?_Y02}}k9{>Px00RJ2pc_E>63G9T^8)~?pc_E>r_cYF^aB8@ zpdUc_V9x)S;sXGx;R6(^-~$t?5X%3T^8)~?pdUc_ZOH$Z^aB8@pdUc_TE+jD;sXGx z;R6(^-~$t?&c*+i9{>Oppc_E>6aYZ^pc_E>697Q@pdUc_bHM+X0Pua&VFCb)pdUc_ z002Pw;sXGx-~$w@IL7~%pc_E>697Q@pdUc_Xu$uM0Pua&a{>U1pc_E>6a+x|pdUc_ z6$C)}pdUc_JjMT);{yPy;sX_`;R6(^-~$t?o5TN?pdUc_0RTYxpd&!}0Pua&Apii2 zpdUc_0R#Z~pdUc_^HV{o^%Fq({d>izzyn{_|3d)L;0FNt;R68q;0HkY0RTYx-~&MU z002PwKL7yh;0K=?02}}k|3d(gzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_|3d)L;0FNt z;0HkY|3d(gzyn{_{d>Hr{R04z^HTw-pdSGFp&J1Cq89-9vmZeDpc_E>NW=e^^aB8@ zpcg>-QOp0A;sXGx;R6(^-~$t?mAn6!^HV{o{d>fyzyn{_{d=yd{R04z^9um^pcer7 zp%Vc4Kmq`;0EkEV0RTYxp^pIh0RVu~pu+%>p%*~;`Mdv@pu+%>p#uSt=mP<&nZo~< zphE$X0RVu~zPtaIqC)|Zp#uStpu+)?BLIL>?Z*F?pu+)?q7y**0RVtfDarqrpu+)? zQ@{V0phE$X9mW5bpaTJs8_)ljpu+%>b;kdfpcg>-K>`4z{D zKL7yn00ID14gdfY^8)~?pu+)?LBIc(0ssIM^8)~?phE$X3B~`HpaTJs2habPpu+%> zVaETL-~$t?6VLyb`n>;_^9w-v{d>}=zyn{_{d>Nt{R04zpbr4~pbtR#s?YzIA0PwO z{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#F2MhnA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~ zpbtR#YQ+DS;R67wpbtR#)4uZwzyn{_|3d)L;0FNt;R68q z;0HkY0RTYx-~&MU0Pua&AOHZ1|3d(gzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Ks z{R04z^HTw-^8*N~pcer7p%Vc4pcg>-@5TR@^aB8@pc6p(?8X0=;sXGx;R6(^-~$t? zyuJUI-~$t?^HV{o{d>cxzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Ks{R04z^9um^ zpcer7p%Vc4vll@5pc6p(Z@&MR;R67w-~$t?tib=5^9w-v{d>cxzyn{_{d>Hr{R04z z^9um^pdSGFp&J1Cq89-9qZ0u6vmZeDq7y**p%*~;pc_E>3C{nQq7y**;R67w-~$t? zQN90{A0PwO^9w-v{d>fyzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_|3d)L;0FNtA0PwO z|3d(gzyn{_|3d)L;0FNtA0PwO|3d(gzyn{_{d>Ks{R04zpbr4~p$h={pbJ3x9{>RH z-~j+spbJ3xMa%z};R67wpbtR#PQCw^pbJ3x#J~TSpcer7p$kCypbtR#?7aV%pcg>- zpbG%`@c;i8A0PwO{d>cxzyn{_|3d)L;0FNt;0HkY00=<&|3d(gzyn{_{d>Nt{R04z zpbr4~pbtR#r^Wx5A0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#chLWrA0PwO{d>Zw zzyn{_{d>Nt{R04zpbr4~pbtR#0RTYxpbtR#00=<&;sXGxpbtR#002PwKmY*C0Q^If z;sXGxpbtR#;llrypbtR#|G@v3A0PwO{d>Zwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_ z{d>Ks{R04zpcer7p%Vc4q7MN1p%Xy)pcg>-2fhE7A0PwO{d>cxzyn{_{d>Nt{R04z zpbr4~pbtR#03ZO70RVs!8PWfj9|Qn#;1{1702}}k9{>PxzybhNpbtR#002Pw06+kd z0RTYxpbtR#AOJtspbtR#05AZN0RVs!3eo?U9|Qn#;1{1702}}k9{>Px-~a$rpbtR# z002Pw0AK)-0RTYxpbtR#AOJtsA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~p$h={pbJ3x z0RTYxpbtR#0RRB`pbtR#03ZO7QO^IDpbtR#0w4g9pbJ3x03ZO7;R67w-~$4x#?Jqj zpbJ3x9{>RPA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR#NXh?~A0PwO{d>Zwzyn{_ z{d>Nt{R04zpbr4~pbtR#Owj+AA0PwO{d>Zwzyn{_{d>Hr{R04z^HTw-^8*N~pcer7 zp%Vc4Kmq`;0EkEV0RTYxp&tPG0RVu~pc6p()XM*t;{yPyq8C8<;R6&Z-~$t?W5@rO z-~$t?K>`4z{DKL7ynKmY(#%DexU^HV{o{d>fyzyn{_{d>Nt z{R04zpbr4~p$h={pbJ3x0RTYxpbtR#0RRB`pbtR#03ZO749@?TpbtR#0w4g9pbJ3x z03ZO7;R67w-~$4xfzJPzpbJ3x9{>RPA0PwO{d>Zwzyn{_{d>Nt{R04zpbr4~pbtR# z03ZO7Apn3Zwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Ks{R04z zpbr4~p$h={Kmq`;0EkEV0RTYxp%(!80RVu~pbtR#V$1)R002Napq~IapbJ3xUd#WN z0RTWbpbtR#0RR9wpq~JdSRHKmY(#fxG{g{d>cxzyn{_{d>Ks{R04zpbr4~p$h={Kmq`;0EkEV0RTYx zp%(!80RVu~pbtR#(7OMZ002Pwpc4T3pbJ3x%)0-V;R67wpbtR#Apk)60RRB`po0LB z#=8HP;R67wpbJ3xApk)60RRB`A0PwOKmq`e0EkEVp%*~;002PwAOHZ$9{>RHKmY(# zUAzC6{d>cxzyn{_{d>Nt{R04zpbr4~pbtR#002Na9|Qn#!2tkNpbtR#00cn!9{>RH zK>+|%0098d0zeFr-~a&d0U!a9-~a&d0N??U;{yV!qJn@@%f0`XpbtR#002Na9|!<( z!2tkNpbtR#00cn!9{>RHK>+|%0098d0zeFr-~a&d0U!a9-~a&d0Kfu~;{yV!!h(QO zy1oCGpbtR#002Na9}EC-!2tkNpbtR#00cn!9{>RHK>+|%0098d0zeFr-~a&d0U!a9 z-~a&d0H6br;{yV!;(~xuslES~A0PwO{d>Zwzyn{_{d>Ks{R04z^9um^pcer7p%Vc4 zpcg>-cf|jfpc6p(VaorP02}}k9{>PxpaK9?pc6p(0|-F*pcg>-p%Xy)LI8kLU;sbX zpc6p(0SrL-pcg>-0So~7pc6p(0SG|(pcg>-0SEy31^@sQ^8)~?pcg>-Ai)2Z-~$t? z8qNQgA0PwO^9w-v{d>cxzyn{_{d>Hr{R04z^9um^pdSGFp&J1Cq89-9qn`jdpdUc_ zp%*~;yt)6EpdUc_A0Pm^pdUc_6QBT*pc_E>(#ijq;R67w-~$t?o45a$pdUc_p`SoG z0e}KIpdUc_p27c@3jhEV^8)~?pdUc_0H6SodBgvg0ssIM^8)~?pdUc_<--4$-~$t? z^UVL3^9w-v{d>fyzyn{_{d>Ks{R04z^HTw-pcer7pcg>-697Q@pcg>-6a+x|pcg>- zro{i3;sXGx;R6(^-~$t?3eNwRpcg>-EYAOzA0PwO^HV{o{d>cxzyn{_{d>Nt{R04z zpbr4~pbtR#0H6Yqp1%K=pbtR#0007!!@~cUpbtR#03ZR8l+FK_pbtR#0Du6IkZwzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>Nt{R04z zpbr4~pbtR#03ZO7q{IK0A0PwO{d>Zwzyn{_{d=RS{R04z^9um^pdSGFq2B;Gq89-9 zKmq`e0EkEV0RTYxq2~bk0RVu~pdUc_+{yo!02}}k9{>PxfDZsvp&vl`pu+=^R=NL| zpdUc_0)Rp}p~C}_phE-7RCRUpx;0_9{>Px-~a$rpdUc_F~R?rA3OkYU;qGAAOL_;0ssIM004ke z9{>PxKnDO+pdUc_0H6Sop#uVu=mP<&A;bTdpaTMt1I_=J^8)~?pdUc_0H6Sop<@A& z=mP<&?alv}pdUc_0H6Sop<@D(=mP<&6vO|QphE$Xg3SMyqC)|Z-~a&d0e}RNpo0OC z#l-)Ypo0OCp`!tj=mP<&;sXGx;Q@eBpdUc_O1%Gpko1%)ye;tphEPxfB^thpaTPu z0Rezg6~6zMpaTPu;R67wpcg>->C69@paTPu3%>uC699lx5C8xapcg>-d$<3W02}}k z9{>PxKmh<$paTPu0RVu~&AR`WpaTPu;R67wpcg>-*~|ZzpaTPu`@R2{GXQ{6phE-qQw7~px;0_9{>Px-~a$rpdUc_y}Px zKnDO+pdUc_0H6Sop`!tj=mP<&t-}A8prZkikIes<^8)~?pdUc_0H6Sop+f6Npo0OCXUYGU zpko1%Wy$}Spd$g1d&B>iphE$XVaflOpaTPu+s6Nw02}}k9{>PxfB^thpko4&0Rezg zp}qf?pko4&;R67wpcg>-b<6*kpko4&m%aa&699lx0ssIMGXQ{6paTPu3dR4Ie+B?? zGynh;^8)~?pu+=^wZZ?F-~$t?!^{7d^8)~?paTPu__qI-0ssIM^8)~?prZkiK*|4? z0ssIM^8)~?po0OCJjwr;0ssIM^8)~?phE$XP{aS1pko1%Hp%~&0ssIM^8)~?phE#phE$XAIblh0ssIM^8)~?paTPu*Tnyq-~$t?mCOH^ zKmq`e0EkEVq31yP002PwAOHZ$9{>RHKmY(#b-DkS^9w-v{d?W0zyn{_{d>Ks{R04z zpbr4~p%;$-pbtR#0RTYx zpo0LBA^?EW3cUZ9A0PwOpo0LB-@yNu4*&oZpo0LB?8pC?pbtR#0RTYxpo0LB6vF?P zpbtR#0RTYxpo0LBA^?EWW4-^EA0PwOpo0LBSib+4A0PwOKmq`e0EkEVp%*~;002Pw zAOHZ$9{>RHKmY(#E4lxd{d>cxzyn{_{d>Eq{R04z^9um^pcer7p%Vc4Kmq`e0EkEV z0RTYxp(g-CCvYq^8)~?pcg>-y1@UJqZ2^+;sXGx;R6$@pcg>-g}48g zpdSGFpcg>-0>uB9pd$eJp#uStpyL3My21aK02}}k9{>PxVF3VCvll@5pdUc_*u(#q z;sXGxp%Xy)-~$t?T*CjC02}}k9{>PxfB*ngpcg>-@5BF>0ssIMpdUc_K>`4fA&5u$ zq9;K4Apk)6K>z{DKL7ynKmY(#^|=3+^9w-v{d>izzyn{_{d>Ks{R04zpbr4~Kmq`e z0EkEV0RTYxp%(!80RVu~pbtR#0U!X8po0LB8qNQgpc6p(K>`4fA&5u$q8C8z{DKL7ynKmY(#-MIgk{d>cxzyn{_{d>Nt{R04zpbr4~p$h={pbtR#p$kCyaJm1N z{d>Zwzyn{_{d>Ks{R04z^9um^pcer7pcg>-^vwU4-~$sX^9w-v{d>cxzyn{_{d>Nt z{R04zpbr4~pbtR#002PwPR9S2{d>Zwzyn{_|APS0;12-#;R^uy;s*fv;0r+c0RTX` z;0HkY002O_KL7x0;3uCN02}}k|APRLzyn{_|3d)L;0FNt;R68q-~&MU0RTYx;0HkY z0RRB`A0PwO|3d(gzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_|3d)L;0FNt;0HkY|3d(g zzyn{_|3d)L;0FNt;0HkY|3d(gzyn{_{d>5n{R04z^HTw-peF$Np(6nKq8|YHqZl*9j*^aB8@pcg>- zCCLAm;{yPy;sX?_;R6$@peI22Ot$}*pfdpZpff=ELB{`=;sXGxp(8-~peI22iM#)o zpoa#jpgTbM9{>RHAOQeWpf^DIp*ukNqccGH;sXJy;R67wpeI22BF6uh2mk;Sp))}F zpeI22;==!zp*KMJpko1%o6P^0pf5oAK>`4fA&5u$qCY_SApk)6K>z{DKL7ynfB^th z3IG5UIl2Frp))}FpeI22(!&3j#m4`a^8)~?>&X9?-~$t?ZOZ?bRJi|_^HV{o{d>r$ zzyn{_{d>Nt{R04zpbr4~pbtR#0Du6IFU0?s{d>Zwzyn{_|3d)L;0FNtA0PwO|3d(g zzyn{_|3d)L;0FNtA0PwO|3d(gzyn{_{d>Ks{R04zpbr4~p$h={pbJ3x9{>RH-~j+s zpbJ3x`ojO0;R67wpbtR#Q@sC|pbJ3xy~O{Qpcer7p$kCypbtR#rNaN0pcg>-pbG%` z@c;i8A0PwO{d>cxzyn{_|3d)L;0FNt;0HkY00=<&|3d(gzyn{_{d>Ks{R04zpcer7 zp%Vc4q7MN1pbtR#8pQvX;sXGxp%Xy)pcg>-lF0v;A0PwO{d>cxzyn{_{d>8o{R04z z^HTw-pdSGFp&J1Cq89-9Kmq`e0EkEV0RTYxp*H~e0RVu~-~a&d0H6es;sXGxApn5V zpdUc_O2hw`peq3RpdUc_$H@Pepd$eJp#uStpu+%>W5WNJpf3RVpdUc_p({Z73%CE5 zpfdpZpff=EpeF$NvmZeDpf5oA0Pua&p))}FGynjLpcg>-?Zf|<;sXGx;R6(^-~$t? zt+xM{zb63spdUc_697Q@pu+%>@VWn&6aYZ^pdUc_t-t@5;{yPyqBB7G;R6(^-~$t? z)U^MXpeF$NpeI2203ZO7peF$Npu+%>;<^8q697Q@pdUc_6a+x|pdUc_oxlH=;{yPy zq9;K4;R6(^-~$t?#I*mHpeF$NpdUc_697Q@pdUc_6a+x|pdUc_k-z_!;sXGx;R6(^ z-~$t?vB&?HqaQ%|pdUc_0RTYxpdUc_00=<&;sXGxpdUc_002PwKmY*C0Q^If;sXGx z-~$7yP`>|{pdUc_p))}F0RRB`pdUc_p(jB30R#Z~pesQ60Pua&p))}FApii2pdUc_ z0SEy3A0PwOKmq`e0EkEVp*KMJ002PwAOHZ$9{>RH-~#|u9RL6ndbt0WpeI229{>RH zK>+|%q8~u{pf5oA0Pua&p))}FAOHZ1;R67w-~$4xYry}P2LJ#RpdUc_T)+R9;sXGx zp(jB3pff=Ee8>NnpdUc_qANi8p))}FB)o#zyn{_{d>Ks{R04zpcer7p%Vc4q7MN1pbtR#004mhf26?wm*N8es-Y7= z`Jfj-`5?dlmmeSl)%|^0k@Hglsh}SK`Jo#C`Jxv9`5*!S@BoNM z`2hex`Jp!e`2hfc(%=99&;XzWk>UdYsv!V?(x4we`KZGGm!K;E`Jf*_`6bBzm!Km6 z`Jn>=k)Xo>k-@?Lm!K~I`Jf*_`JpR7`DwQQm!LBM`JgjE`Jg8N`LiED`JgXA`2g^J z)1fm!`7{6ki=Y=k`FFtom*N8es^J3^s^9|?s-v|3m%k?f`Jf*_`4a#@`Jlr9kxse) zmlOa%`Jf*_`3t}Qm*WEfs-iPM`QZZ;s^9|?sxq|ym!KyA`Jg92`2ZjQk)S64`Jlr9 zkwCfsmlFU$`Jf*_`4j{|`Jf*_`TM^Am*WEfs-h=A`QZZ;s^9|?sv@-im!KyA`Jf*_ z`4a#@`Jf*_`4j{|`Jf*_`R~5}m*N8es^J3^s^9|?st?Eim!ls*`Jf*_`2hex`Jf*_ z`2Yw&`Qifrs-Pc0`2YYw`9J^w%K-dCli~vas^9|ys;<5Nm!Ka&`JppF`2hd``Jf*_ z`JpF3`2hp~`JgL6`2g^J)1fm!`5^!Ri=ZDs`2h$3`5zzy)gS@@@BoNM`Jp#J`2YYw z`5*uQ${zp#@!$ghR2={S6xg@_m!Ky=`5yoP@j(FqRH7e1`JgXA`2g^J)1fm!`5*uQ zi{S$Rs^9|xs>#3qmj?g<6rdkK`MSRUm*N8es-Y)9`JgjE`P#<+m!Ka&`JyX8`JppF z`GURwmr=$4m-7Pvs&~i#m*4{vs`<$Om*BSlm-ACWsr`G$sK5hX*8O|Dsr>^0k)RI% z`5*!S@BoNM`2hex`Jo>G`2hfc(x4AO`2YYw`Jfj7`Jtl#k)Xo>k(0gum!KO!`5^)T z@F9pt`Jx{{`5^#6`9S~y%0B=A@jw6oRK~Xdm;HOhsK5hX*8O|Dsr>^0k)RI%`5*!S z@BoNM`2hex`Jo>G`2hfc(x4AO`2Yk!`Jfj7`Jtl#k)Xo>k$S!Vm!KO!`5^)T@F9pt z`Jx{{`5^#6`9S~y%0B=A@jw6oRIRrEm;HOhsK5hX*8O|Esr>^0k@E`x`Jfj7`Jod4 z`Jfj-`2@lLmlFU$`JfX(`2oTImjD1j`F{cc>);ok8UP#s67vf{`TcvtsK5hX*8O|C zsr>^0k@E`x`Jfj7`Jod4`5*!S@BoNM`2hex`JpEO`2hfc(x4YW`L@Xam-7Pvs-PD@ z`OCQfm!lIv`Qifrs^J3@s-PD@`O>`qm!Ka2`Jfj-`A@=k)Y!Mk$h@mjVC)6rdkK`5^)T@F9pt`JyL4`5^#6`9S~y%0B=A@jw6oRA#pSm-7oi z`TcvvsK5hX*8O|Esr>^0k)RI%`5*!S@BoNM`2hex`Jop8`2hfc(x4AO`2ipRk)VSB zk(^0k)RI%`JfL#`2c_bk#4j9m;HOfsK5hX*8O|Dsr>^0k@E`x`SSw^s-PDD`5*!S z@BoNM`2hex`Jo>G`2hfc(&z&ds-PD@`E$1am*4{vsv!aZ@F9pt`Jx{{`5^#6`9S~y z%0B=A@jw6oR4%svm-7oi`TcvusK5hX*8f8Q(clLF`QQgY`Ts)zk-!6A*8O|Fsr>^0 zk)RI%`JfL#`Psq$mmeSl)%|^0k@E`x`Jf*F`Jo#C`Jxv9`Jf*_ z`Jop;`Te#3m!TU#`Jf*_`F6^0k)Rg<`Jod4`JxX1`J)Q}`JxX%`Jod)`Jfj-`76Qym;HOgsK5hX z*8f8Q(clLF`QZZq`QQUU`2hex`QQgY`2hd``5zzy)&D~Pk-!6A*8f8Q(clLF`QQgY z`Ts)zk-!6A*8O|Csr>^0k@E`x`Jfj7`Jod4`5*!S@BoNM`2hex`JpEO`2hfc(x4YW z`Bt<4m-7Pvs-PD@`A^3Gm!lIv`Qifrs^J3@s-PD@`Od`um!Ka2`Jfj-`3JWDm!Km6 z`Jn>=k)Y!Mkt4tVmjE095+48nabW=fRI?XA`Jf*_`CYvKm*N8es-Y7=`QQT+s(Hfy zmjE095+48naex2-RG=3?`Si8_mjVC)6rdkK`5^)T@F9pt`JyL4`5^#6`9S~y%0B=A z@jw6oRJyhQm-7oi`TcvvsK5hX*8O|Esr>^0k)RI%`5*!S@BoNM`2hex`Jop8`2hfc z(x4AO`2ipRk)VSBk>|Ysm!K0s`5^)T@F9pt`Jxv<`5^#6`9S~y%0B=A@jw6oRHC*2 zm;HOgsK5hX*8O|Fsr>^0k)RI%`JfL#`2c_bkpjm5m;HOfsK5hX*8f8Q(clLF`QQgY z`Ts)zk-!6A*8O|Esr>^0k@Hglsh}4C`Jod4`Jfj-`2hq#`Jfj-`2Yw&`9A;v>i_}( zRI?XA`Jfj-`4j{|`JfX(`6ILcm*N8es^J3^s^9|?syD*_m!KCw`2Yk!`2ipRk)Rhq z`2hp~`3e946rdMC`BT9Em-7Pvs-P1<`4qGNm*N8es^J3@s-PD@`FOtnmmeSl)$>z9 zsr`GysK5hX*8O|Fsr>^0k)RI%`JrC`IiL?f`JrDxIRO9wIiL?f`2ZjQk)dBeIkmz6 zm!J^0k@Hglsh}4C`JtZxIUoW6@BoNM`2hex z`JpEO`2hfc(x9I}IUfuFabN=gR38igamWAwR38KYai9SJR38KYaR>qcR3`uc6dx1- zaexB=R38)oapM92R38`sabN=gR397waexB=R3QKW6h6iOm*E2ds-PD@`2hd``9S~x z6d}0(m*E2ds-PD@`2hd``8)ss6yN{=umC_CkxH`vm*E2ds-PD@`2hd``85Cl6rdMC z`5yoPIWhnM6rdMC`5yoP`7Zzf6rdMC`5yoP`78hc6rdMC`5yoP`6&PZ6rdMC`5yoP z`6d7W6rdMC`5yoP`JkUbIUfK3ao`u98UP#s5&#@Pk{CIT&;cL?k)Q(sk$AuVm!Jayk>~>xs^J3ws(?O#Qh&Ywm!Jay zk)g!@m!RVSk+;78mmmTF@Bw&7`5*!S@BoZQ`Qifss^J3ws^9|?s)xq^mmeSl)gK@O z)gS@@@BoNM`JpF3`2YYw`5*uQ${zp#@xTE9R15$B6!ZfCs-Ob_k&49smjVC)6!ZfC zs-WWlk)FQ)m*4{vsyMp;m*4{ws{Y3Rm*uqom-ACWsr`G!sK5hX*8f8Q(clLF`QQgY z`2YYwIUfW7ao`u98UP#s68}R0k-!6A*8O|Esr>^0k@E`x`Jfj7`Jod4`Lh>5`JfX( z`Ej!Um*E2ds^9|?s*b$>mmeSl)$^0k@E`x`Jfj7`Jod4 z`Lh>5`JfX(`C_vFm*E2ds^9|?suQ*UmmeSl)$^0k)RI% z`JoE{`Jf9x`Bk$2m*E2ds-O=*`2hd``5zzy)%|^0k)RI%`JoE{ z`JfL#`JoFy`82=(mmeSl)%|^0k@E`x`SSw^s-PDD`Jfj-`98A$ zm*E2ds^9|?s^0k@E`x`Jfj7`Jod4`5*!S z@BoNM`2hex`JpcW`2hfc(xDST`Jfj-`F6Yim!Km6`Jfj-`Afn7m!K;E`JqDrk)Q(s zk^jd3mjE095+48naiIYKRG=3?`A)t6m!Jaykvzfwm*E2ds-PnQk>UdZs-Y7=`6t2u zmjE095+48nabN%dR3HF=QUU+~6aWB#QXc>Sao_>~RI?XA`Jn>=k)T5Xk=L{Tm!K0s z`Ki4Bm*E2ds-PnQk>~>es^9|wsszLTm!jhUk)b02k>CITumFG;k>mpcs^bFzs^S9x zs-Y`D`QQT+s!qWFm!Km6`Je*6yN{=&;TF?kqiI;6yN{=&;URNkqH0*6yN{=&;Vct zkp=(&6yN{=&;Wo2kpln#6yN{=&;Y;&k^e&gk-!6A*8O|Fsr>^0k)RI%`JoE{`Jf9x z`8T@%m*E2ds-O=*`2hd``5zzy)%|^0k)RI%`JoE{`Jf9x`MbLR zm*E2ds-O=*`2hd``5zzy)%|^0k)RI%`JoE{`Jf9x`H#Q^0k)RI%`JfL#`JKQ2m;HOfsK5hX*8O|Fsr>^0k)RI%`JoE{`JfL#`2YYw z`62*-(xD4L`GU6pmmeSl)%|^0k@E`x`5*!S@BoNM`2hex`JpEO z`2hfc(x9UNk=eKZm!P8nk)Rs@`Jkf!ks$zp(zL_>m*WEfs-eRGk)Y!Mk>UdZs^J3z zsv^Gsm!RVSk&MFsm*E2ds-U9)k@d&_m!RVSkpTdJ(kit7mjE095+48naX|q9Q~&`0 zkOCk(k>CIT&;cL;k>CIT&;Z~Dk>djbs={c1QWm!Vm!RVSk>J7qm-7Pvs-WWlk;S_I zm!P8nkte(Vm*4{vsv!aZ@F9pt`JyL4`5^#6`9S~y%0B=A@qhsUR0;q96!QZBs-WWl zk+-`4mjVC)6!QZBs-U9)kr%uFm*4{vs*%P2mw2=Pm-7oi`TcvvsK5hX*8O|Esr>^0 zk)RI%`5*!S&;W=>`2hex`Jop8`2hfc(x4AO`2ipRk)VSBk#WcWm!K0s`5^)T&>@IN z`Jxv<`5^#6`9S~y%0B=A@jw6oRA96Jm;HOgsK5hX*8O|Fsr>^0k)RI%`JoE{`Jf9x z`Lx3SmjM7k`JfL#`2hd``5zzy)%|^0k)Rg<`Jod4`JxX1`J)Q} z`5*!S&;W=>`2hex`JpEO`2hfc(x4YW`T4W|m!Ka2`Jv+gk)VSBk@2?wm!Km6`Jfj- z`Tno}m!Ka2`Jm$fk)b0%`69&sm!k_n`JxX%`QZZqs-PD@`K7x5m!KCw`SY*;m!Ka2 z`Jm$fk)b0%`4`0hmmvZG&>@IN`JyL4`5^#6`9S~y%0B=A@jw6oR423lm;HOisK5hX z*8f8Q(clLF`QZZq`QQgY`2hex`QQUU`2g&E(;xr^0k@Hgl zsq+H}s-PDD`5*!S&;W=>`2hex`Jo>G`2hfc(%=IVs=vDbm*E2ws-PD@`5e6emj(a; z6!ZfCs^9|?s-(jIm*4{wsvgDvm*4{vsv!aZ&>@IN`Jx{{`5^#6`9S~y%0B=A@jw6o zRQ^0k)RI% z`JfL#`2YYw`QZZqs-O=*`831-mmeSl)%|^0k)Rg<`Jod4`JxX1 z`JfX(`5yoP@t^^0k)RI% z`JoE{`5*!S&;W=>`2hex`Jop8`2hfc(xD4L`JfL#`D(ELmmeSl)gS@@&;W=>`Jop; z`2YYw`5*uQ${zp#@jw6oRK>FYm;HOgsK5hX*8f8Q(clLF`QQgY`2Yw&`QZZqs^AAe z`2YYw`5*uQ%K-dClm9~ik-!6A*8O|Csr>^0k@E`x`Jf*F`Jo#C`Jxv9`J)p6`Jf*_ z`Jo#?`NFaPm!KyA`Jf*_`FFbim*WEfs-h=A`Jod)`Jfj-`Fgwmm!Ky=`3nF56o0e- zm!Ka&`Jx*@`JpF3`8&D)mkPoEm-7PvsxZU^0k@E`x`Jf*F`Jo#C`Jxv9`Jf*_`PZ@km-7Pvs-PP{`P8xhm!cOy`QZZqs^9|? zs_eY~m-7oi`TcvusK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`Jod)`Jfj-`LV^0k@E`x`Jf*F`Jo#C`Jxv9`Jf*_`A)k3m-7Pvs-PP{`AfS0 zm!cOy`QZZqs^9|?s^75xm-7oi`TcvusK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`J)Q} z`JxX%`Jod)`Jfj-`C7XFm;HOgsK5hX*8O|9sr>^0k@E`x`Jf*F`Jo#C`Jxv9`5*!S z&;W=>`2hex`Jq1m`2hfc(x4ka`B%9Am-7Pvs-PD@`C!2Rm*N8es^J3@s-Pc0`N*^X zm!K;E`JgL6`N^;Um*E2ds-Pc0`F^kem!O9Qsh~4J`5yoP@gM>KRG=?F`JppF`J*d9 z`Qifss^J3ws-Pc0`S-a0m!KyA`5*v*QlK9JIieo{k)b02k)WdiksQGPm!OA6sSN-C z6rn3X`Jf*_`KPk~m!U5}`Jf{Kk!-#Hm%kqYIieo{k)b02k)Wdikq^NCm!OA6sUiXZ z&_aku`J+ET`9c6d`C^0k)RI%`JoE{`Jf9x`5yoP@!$afRG^0k@E`x`Jf*F`Jo#C z`Jxv9`Jf*_`Jo#?`3$xHm!Ka&`2ZjQk)anr`3SZDmj(a;6!QZBs-Pc0`EbGim*4{v zs_Mi4m-7oi`TcvusK5hX*8O|Asr>^0k@Hglsh}4C`Jod4`5*!S&;W=>`2hex`Jp!e z`2hfc(x77jk)abn`P#w%m*E2ds-PD@`9sA2m!O9Psh}%B`5yoP@gM^LRG{Mkk)anr z`TW8Em$N58`LruQ`JfX(`FOMcm*E2ds-WWlk>mpas^bFzs^S9_s^J3@s-PD@`E<1Z zm!Km6`5*v*QlQ@eIilYHk)ZL`9c6d`C^0k)Rg<`Jod4`JxX1`5*!S&;W=>`2hex`Jo>G`2hfc z(xMMQ`Jod)`Jfj-`4z+emmvZG&>@IN`Jx{{`5^#6`9S~y%0B=A@jw6oRC%%gm;HOh zsK5hX*8f8Q(clLF`QQgY`2Y++`Ts)zk-!6A*8f8Q(clLF`QQgY`2Yw&`Ts)zk-!6A z*8O|Fsr>^0k)RI%`JoE{`JoFy`JfL#`Ixl-m!S(l`JfL#`N6~gmmeSl)%|^0k)RI%`JfL#`2oBCm!J^0k)RI%`JoE{`JoFy`JfL#`MtpZmmeSl)%|^0k)RI%`JfL#`5yoP@!$XeRG<$)`2YYw z`2ZjQkpTce`JfL#`5*v4)*m1P)%|^0k@Hglsh}SK`JuxAIieQ; z`J)p6`LiED`JfX(`3S)Om*WEfs-hP_`QZZ;D&PYXs%N?XmmeSl)$>z9sr`GzsK5hX z*8O|Dsr>^0k)RI%`5*!S&;W=>`2hex`Jo>G`2hfc(x4AO`2YYw`Jfj7`Jtl#k)Xo> zk)^}`m!KO!`5^)T&>@IN`Jx{{`5^#6`9S~y%0B=A@jw6oRP3<-m;HOhsK5hX*8O|E zsr>^0k@E`x`Jfj7`Jod4`Jfj-`A59}mlFU$`JfX(`9!?`mjD1j`F{cc>);2U8UP#s z67vf{`TcvtsK5hX*8f8Q(clLF`QQgY`2YYw`2j!xk>CeF`2hd``QQgY`Ts)zk-!6A z*8f8Q(clLF`QQgY`2YYw`Ts)zk-!6A*8O|Dsr>^0k)RI%`5*!S&;W=>`2hex`Jo>G z`2hfc(x4AO`E#)Um!KB_`Jkf!ks$zp(u2hRm!KN}`Jlr9kubpjmmvZG&>@IN`Jx{{ z`5^#6`9S~y%0B=A@jw6oRIsrBm;HOhsK5hX*8O|Fsr>^0k)RI%`JfL#`IWE#mjE09 z5&!@IQUDwP68(F^sK5hX*8f8Q(clLF`QQgY`5yoP`QQgY`5y!T`QQgY`5y=X`5zzy z)&D~Pk-!6A*8O|Esr>^0k@E`x`Jfj7`Jod4`Lh>5`JfX(`E|elm*E2ds^9|?s^0k)RI%`JfL#`2e5* zk^Q{?m*E2dDxeQQ`2ipRxu6d~`2Zk5x&3>>sK5hX*8O|Fsr>^0k)RI%`JfL#`6;gd zmmeSl)%|^0k)RI%`JfL#`2hex`JfL#`2Yw&`Qifrs-O=*`2YYw z`9J^w%i;q7s-O=*`K+-2m!J^0k)Rg<`Jod4`JxX1`Jod)`Jfj-`8u!vmmeSl)%|^0k@E`x`Jf*F`Jo#C`Jxv9`J^0 zk@Hglsh}4C`Jfj-`4a#@`Jfj-`4j{|`Jfj-`5m$Um*N8es^J3^s^9|?s%^3Vm!KCw z`SZ5_mmeSl)$>z9sr`GysK5hX*8O|Fsr>^0k)RI%`JfL#`AWn8mmeSl)%|^0k@E`x`Jfj7`Jod4`5*!S&;W=>`2hex`JrzB`2hfc(x4*(kxRb+m%rZt zIiTM_IRF3vQUDwP5+48nabQLORG=3?`2Zk5xgQh&aR4;{R38)oajXFVR38WcaUd%I zR38Wcaf|=}R38KYaR4p=ROKuROSHy6dxb}ao`yMR39J! zam)Y!R38`saX>BrR397wao`;QRNVmp6dxo2aex2-R3A71alkVGRM-Ik6afH$lAsen z`R=X%mjE095&!@IQUDwP5&#@Pk{~>fsvfxim!M+-kpRN~m-7Pvs-PD@`2e5*k)h)Nk>~>f zs_Mf3m!KCw`2e5*k)gu@k>~>fsu8&Vm!QJ{k$=Jem!iV}k>CITkO4pkk)Q(sk;1wE zm!Jayk)b02k>~>fs^S9xs(}E2QlJ+=`A4z;m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3w zs-O&jQv0_5m!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`Gm9omlGTS5}?BZk&UeXm!Km7 zk=MTem!Jayk=4Hcm!QJ{k?Xksm!RVSk~>fs>iqgm!M+-k*UG|m-7Pvs-PD@`2e5*k)h)Nk>~>fs*}S1m!KCw`2e5*k)gu@ zk>~>fs=BxTm!QJ{kto6cm!iV}k>CITkO6=Pk)Q(sk!!jCm!Jayk)b02k>~>fs^S9x zs(}H3QlJ+=`S7s+m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQlz&3m!ZP~k)Y!M zk>djas^S9xs^J3@s-P1<`7N{mmlGTS5}?BZkv6RVm!Km7k$}Gcm!Jayk$%4am!QJ{ zk(9Xqm!RVSk$S%Wm-PYw6rdvlkpTdJQl`59m!KCw`H;2$m+k@p6afH$lAsen`M9~>fs!_N9m!QJ|ku$;nm-7Pvs-PD@`2e5*k)h)Nk>~>fsvW}rm!KCw`2e5* zk)Z~>fsu;rmm!Sgzk>CITkO1HZk)k63k>~>gs=mPgm*4;ZkO5!_k)R_1k)mS( zk>~>gsu;Ham!M+-k)gu^k>~>fs^J3ws=zXUQm(B3m!ZP~k)Y!Mk>djas^S9xs^J3@ zs-P1<`Ma|JmlGTS5}?BZku0AR1*MzQdR;06d?eBQlJw+`Tw*3mjE095&!@IQUDwP z5&#@Pk{~>fs;svEm!M+- zk&eLsm-7Pvs-PD@`2e5*k)h)Nk>~>fs(8Wwm!KCw`2e5*k)gu@k>~>fs-L$1m!QJ{ zkqyBAm!iV}k>CITkO6=Mk)Q(skx;n*m!Jayk)b02k>~>fs^S9xssR9iQlJ+=`PHxg zm!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQi-+ym!ZP~k)Y!Mk>djas^S9xs^J3@ zs-P1<`4Y1KmlGTS5}?BZksGW3m!Km7k!8LAm!Jaykz>98m!QJ{k$JcOm!RVSkzc+4 zm)ZdU6rdMC`2e5*k)dM&k>~>fs&Tgem!M+-kyF6`m-7Pvs-PD@`2e5*k)h)Nk>~>f zsy)H~m!KCw`2e5*k)gu@k>~>fs${nRm!QJ{kCITkO6=Mk)Q(skrlZA zm!Jayk)b02k>~>fs^S9xssRFkQlJ+=`I@i)m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3w zs-O&jQcku1m!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`PZ@kmlGTS5}?BZk>INTm!Km7 zkt)6am!Jayktn_Ym!QJ{kv_Nom!RVSktDtUm!AOu6u;j9IT8Q>6dxc1)eryx6dxc1 z)eZmv6dxc1)eHat6dxc1)d~Or6dxc1)d&Cp6dxc1)dm0n6dxc1)dTCITkO6=Qk>CITkN|)Qk>djbs)8?oQo67Im!Km8k>tGp zmmmOuQlQ@eIY~>fs^GQ%m!M+-k;1?Km-7Pvs-PD@`2e5* zk)h)Nk>~>fs;t2Om!KCw`2e5*k)gu@k>~>fs?)Xqm!QJ{kwL%zm!iV}k>CITkO3eD zk)Q(sk%YJZm!Jayk)b02k>~>fs^S9xszCvOQlJ+=`3bN8m!Ts8k)Xo?k)p!_k>~>g zs^S9ys^J3ws-O&jQoXeQm!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`9`t-mlGTS5}?BZ zkx#1sm!Km7k(s>zm!Jayk(a#xm!QJ{k*&7>m!RVSk(0dtmkt2{6rdMC`K+`5mmf3$ zao`u98UP#s5+48naUc``RG=3?`K7b}mmd%Sao`7^8UP#s5&#@Pk{~>fs*|<~>fs$anWm!KCw`2e5*k)gu@k>~>fs)n`ym!QJ{k@UX*m!iV}k>CITkO4pkk)Q(s zkvF&hm!Jayk)b02k>~>fs^S9xs(}E2QlJ+=`Mj?Gm!Ts8k)Xo?k)p!_k>~>gs^S9y zs^J3ws-O&jQgF2Ym!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`T4N_mlGTS5}?BZkpim! zm!Km7kxab*m!JaykxIP(m!QJ{kzls}m!RVSkw(1#m%#u46rdMC`2e5*kruQ6m*E2d zs-P1<`FFDamjE095&!@IQUDwP5&#@Pk{~>fsywy-m!M+-ksiPQm-7Pvs-PD@`2e5*k)h)Nk>~>fstCaUm!KCw`2e5* zk)gu@k>~>fsxP(wm!QJ{k)6K(m!iV}k>CITkO6=Pk)Q(sk>Ixfm!Jayk)b02k>~>f zs^S9xs(}H3QlJ+=`DL#Em!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQW>=Wm!ZP~ zk)Y!Mk>djas^S9xs^J3@s-P1<`J%A@mlGTS5}?BZk*lfym!Km7k@dU(m!Jayk@LI% zm!QJ{kqNf{m!RVSk?*_zmudh26rdMC`3STBmu3I}6rdMC`2Zk5xgRV5ao`u98UP#s z5&#@Pk{CIT zkO6=Qk>CITkN|)Qk>djbs)9CvQm(H5m!Km8k=VQcmmmOuQlQ@eIXnOW6rdMC`2e5* zk)dM&k>~>fs?@aqm!M+-k+#17m-7Pvs-PD@`2e5*k)h)Nk>~>fs-VCBm!KCw`2e5* zk)gu@k>~>fs>ihdm!QJ{ku|>mm!iV}k>CITkO2S&k)Q(sk$ATMm!Jayk)b02k>~>f zs^S9xs$l_uQlJ+=`Tec`m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQn9oDm!ZP~ zk)Y!Mk>djas^S9xs^J3@s-P1<`8u%wmlGTS5}?BZkwdBfm!Km7k&V0mm!Jayk&CImjVC)6!QZBs-VLFk%P7Wm!RVSk!idCmy`ei6!QZBs-VLHkr}D~mjVC) z6!QZBs-PnQkzu?4mjVC)6!QZBs-Ob_kzKq0mjVC)6!QZBs-VLFk#V*Em!RVSkypF_ zmx2HQ6!QZBs-VLHk#Dg7mjVC)6!QZBs-R;5kx#q-mjVC)6!QZBs-PnQkxRS(mjVC) z6!QZBs-Ob_kw?4#mjVC)6!QZBs-WWlkwd%xmu>(66!QZBs-VLHk@KkkmjVC)6!QZB zs-PnQkvqHpmjVC)6!QZBs-Ob_kvF^lmjVC)6!QZBs-VLFkxRAzm!RVSkukgfms|h< z6!QZBs-VLHk>RNSmjVC)6!QZBs-PnQktw_XmjVC)6!QZBs-Ob_ktMtTmjVC)6!QZB zs-VLFkvX;hm!RVSksrJNmr4Kt6!QZBs-VLHkR@kmjVC)6!QZBs-Ob_k=?rgmjVC)6!QZBs-VLFk@2+um!RVSk=MHamjVC)6!QZB zs-PnRkrTfEm*4{vs!hHBmo%&Ym-7oi`Tcv&sK5hX*8f8Q(cuFKs^A9z`QQgY`2b)5 zk>UdZs^bFys$c{_sXzn(sbB~|`9KH&`Ts)zk-!6A*8f8Q(clLF`5*y+(*HvMk-!6A z*8O|Asr>^0k@Hglsq+H}s-PDD`5*!SkN}8B`2hex`Jp!e`2hfc(%=IVs>8DXm!KCw z`2fHGk)SI8`JgL6`9iP%m!Km6`JgL6`Af9_m!KyA`Jp2Lk)Q(skvF{mmjE095+48n zaUcZ%RGdjaD&hkGs^J3!s^9|@s+qO_m!M+-k>9WX zm*E2ds^9|?ssOtGmjnO+6ruk>Ip6~ms?@Llm!Jayk)o{sm)QUR7xV)Fs^9|?s(QNr zm*4{ws`R}7mmeSl)!+jYsv!aZkRgai`Jy*K`5^#6`9S~y%0B=A@jw6oRMM*dm-ACW zsr`G$sK5hX*8O|9sr>^0k@Hglsq+H}s-PbL`Jp!exuO>U`5*!SkN}8B`2hex`Jq1m z`2hfc(xAfuk>$Mqm!ZP}k-z`|@BknRk>UdZs^J3ws^9|?swTDnm!QJ|k!-a8m!KCw z`QpC+mjE095&!@IQUDwP5+48nai9VKRKNfL@Bm;6k)fjjk>~>fs-YJ^`J=G^m%so3 z@ByF-k)Wdik)p!^k>~>gsyVX%m!QJ|k>LXXs^9|?s*$Jvm!QJ|kvqEom!P8okvY2m zm%so3@BqLHk>LXXs^9|?s<65Lm!Ka&`2Zk5xgR(HabX4kRG=R~`2e5*kpZ{=m-GVw zs-PnQk+Qu1m!Ts8k)T5Xk>UdZs^J3^s`a%0m%so3@B!cok)T5Xk)mS(k>~>gsu!~V zm!Ka&`2e5*k)eYDk>~>fss_IQm!X3Jk)UG%k)opkk>~>gs#T}|m%so3@Bv^5k)Wdi zk)p!^k>~>gst2LXXs^9|?s$Zx7m!QJ|kqNs0m!P8okq5f}m!N|Ikp;T{ zm!M+-kpsH_m!Lxdkpa5@m!Km7kr%Z8mmB~96rdkK`2Zk5xnrsSm-GVws-S}bk$}Aa zm!X3Jk)Wdik>UdZs^J3^s>8JZm!YEpk-z`|@BknSk)p!^k>~>gs)fA&m!QJ|k>LXX zs^9|?sy(Owm!QJ|k>|Ppm!P8ok>$Dnm!N|Ik^8g%m!LO5xgP)kali`zRG>FNxkjn~ zm-GVws-S}bkz>67m!X3Jk)Wdik>UdZs^J3^s;0F6m!YEpk-z`|@Bm;7k)p!^k>~>g zs%X6bm!QJ|k>LXXs^9|?svxKTm!QJ|k;=LMm!P8ok;u9Km!N|Ik>0camqP#m6!QZB zs-VLGk=nEWm*4{vsyw{^m-GVws-VLGk-fS9mjVC)6!ZfCs-U9*k-545mofkV6!ZfC zs-VLGk+r%1mjVC)6!ZfCs-U9*k+He|mjVC)6!ZfCs-S}bk*&G^mjVC)6!ZfCs-R;5 zk*T@=mjVC)6!ZfCs-Qywk)^r+mjVC)6!ZfCs-PnQk-4+~ml^;76!ZfCs-VLGk)65! zmjVC)6!ZfCs-U9*k(s&wmjVC)6!ZfCs-S}bk*%};mks~`6!ZfCs-VLGk&(IomjVC) z6!ZfCs-U9*k&U_kmjVC)6!ZfCs-S}bk)gBymjVC)6!ZfCs^9|?s)f1#m*4{ws{gzH zmmeSl)!+jYsv!aZkRgai`Jz8S`5^#6`9S~y%0B=A@jw6oRNblnm-ACWsr`G%sK5hX z*8O|Esr>^0k@E`x`Jfj7`Jod4`Jfj-`Jod)`4YVUmmmTFkO1IE`2j!xk)Rhq`2hd` z`JfX(`2h$(xu6$7`2h$3xu6$7`2s)yk)RVm`2auwk>LXXs^9|xs>ZPYmj(a;6!QZB zs-PD@`L4YGm*4{vs?@vxm-7oi`TcvtsK5hX*8O|Fsr>^0k)RI%`JoE{`JfL#`JoFy z`DUyCmmmTFkN~Vl`2j!xk)RJi`2hd``Jf9x`2i3>`JfL#`2i3B`5zzy)%|^0k)RI%`JoE{`JfL#`JoFy`BSU^mmmTFkN|8)`2j!xk)RJi`2hd``5zzy z)%|^0k)RI%`JoE{`JfL#`JoFy`9!P#mmmTFkN~7d`2j!xk)RJi z`2hd``5zzy)%|^0k)RI%`JoE{`JfL#`JoFy`8BKmmmmTFkN}iN z`2j!xk)RJi`2hd``5zzy)%|^0k)RI%`JoE{`JfL#`JoFy`6jFX zmmmTFkO1UI`2j!xk)RJi`2hd``5zzy)%|^0k@Hglsh}SK`Jo#C z`Jxv9`J)p6`Jf*_`5^#+QUTxrIiMdv`2c`IIUfK3aUc!=RGoBQeZu*av*#ln*jV^(*k@26Civa6F>j}OM(o5 zQUH7c8z2AxOCJmXao`33R38igam)Y!R38KYaUcNzR38WcabN@hR7?N>6dw=(aX`Qifss^J3ws^9|?s;j#HmjDES(g~~om-7Pvs-Y7=`QQT+s$snUmmmTFkO728 z`5*!SkN|*3`Qifss^J3ws^9|?s-3$3mjDES()+6am-7Pvs-Y7=`QQT+s>ibbmmmTF zkO7!S`5*!SkN{*y`Qifss^J3ws^9|?s*k$=mjDES((S7Mm-7Pvs-Y7=`QQT+s-dd? zmmmTFkO6o{`5*!SkN}KF`Qifss^J3ws^9|?s)4%ym*4;Z@B#ook-z`|@ByF;k-z`| z@Bp9;k>djbs-i%EQgEyPmjD2OQW^jN6!ZfCs^9|?syD9xm*4{ws{OkEm-GVws^9|? zsxq$sm*4{ws`$G9m-GVws^9|?sx7Ynm*4{ws`I-4m-GVws^9|?swl4im*4{ws_we~ zm-GVws^9|?sw1xdm*4{ws_DA_m-ACWsr`GzsK5hX*8f8Q(clLF`QQgY`2gTSIsZcd zk-!6A*8O|Fsr>^0k)RI%`JoE{`Jf9x`C7C8m!JLXXs^9|xs%X0Zm!J^0k)Rg<`Jod4`J#USIiMFn`Jod)`2hd` z`Jfj-`2ZjQkyo+*m!KCw`5zDf`Jfj-`5&MFIiMFn`JsP6IRT^qIUgVc)%|^0k@E`x`Jfj7`Jod4`5*!SkN}8B`2hex`JrzB`2hfc(x4*(krlW9m%rZt zIiTM_IRF3vQUDwP5+48nabQLORG=3?`2Zk5xgQh&aR4;{R38)oajXFVR38WcaUd%I zR38Wcaf|=}R38KYaR4p=ROKuROSHy6dxb}ao`yMR39J! zam)Y!R38`saX>BrR397wao`;QRNVmp6dxo2aex2-R3A71alkVGRM-Ik6afH$lAsen z`Ix-_mjE095&!@IQUDwP5&#@Pk{~>fs_3x)m!M+-k;=ONm-7Pvs-PD@`2e5*k)h)Nk>~>f zs~>fs@t&tm!QJ{kx9D$m!iV}k-z`|@Bu&vk)Q(sk&Lqc zm!Jayk)b02k>~>fs^S9xs(}E2QlJ+=`4OuBm!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3w zs-O&jQpKdjas^S9xs^J3@s-P1<`D&^EmlGTS5}?BZkyoYvm!Km7 zk)gN$m!Jayk)OB!m!QJ{k+re^m!RVSk(;;wmrMfy6rdMC`2e5*k!!C1m*E2ds-P1< z`82WrmjE095&!@IQUDwP5&#@Pk{~>fs*$k&m!M+-k#oBLm-7Pvs-PD@`2e5*k)h)Nk>~>fs$IMPm!KCw`2e5*k)gu@ zk>~>fs)Vrrm!QJ{k@C6!m!iV}k-z`|@Bx4ak)Q(sku|dam!Jayk)b02k>~>fs^S9x zs(}H3QlJ+=`MRn9m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQf{yRm!ZP~k)Y!M zk>djas^S9xs^J3@s-P1<`4g%CmlGTS5}?BZkpQLtm!Km7kxIA!m!Jaykw~}ym!QJ{ zkzTR?m!RVSkwmxum-PYw6rdvlkpTdJQgE~Xm!KCw`C6|3m+k@p6afH$lAsen`6{db zmjE095&!@IQUDwP5&#@Pk{~>fsvEHXm!QJ|k^Q;~>fs^_}@m!KCw`2e5* zk)Z~>fs^Yr;m!Sgzk-z`|&;Z~Ek)k63k>~>gs))J&m%so3&;eiwk)R_1k)mS( zk>~>gs^YHym!M+-k)gu^k>~>fs^J3ws=zXUQh25Rm!ZP~k)Y!Mk>djas^S9xs^J3@ zs-P1<`Jt%)mlGTS5}?BZk@lAR1*MzQdR;06d?eBQlJw+`I)l+mjE095&!@IQUDwP z5&#@Pk{mjE095&!@IQUDwP5&#@P zk{~>fs&=pcm!M+- zkyyF^m-7Pvs-PD@`2e5*k)h)Nk>~>fszSQ|m!KCw`2e5*k)gu@k>~>fs%fwPm!QJ{ zk=MBYm!iV}k-z`|&;fu1k)Q(sks7i8m!Jayk)b02k>~>fs^S9xssR9iQlJ+=`Jbr& zm!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQd6$~m!ZP~k)Y!Mk>djas^S9xs^J3@ zs-P1<`S_>*mlGTS5}?BZk>#WRm!Km7kuSFYm!JaykuA3Wm!QJ{kwdWmm!RVSktw$S zm)ZdU6rdMC`2e5*k)dM&k>~>fsyna$m!M+-ksZ1Jm-7Pvs-PD@`2e5*k)h)Nk>~>f zst3CNm!KCw`2e5*k)gu@k>~>fsxGhpm!QJ{k({{ym!iV}k-z`|&;fu1k)Q(sk>9ZY zm!Jayk)b02k>~>fs^S9xssRFkQlJ+=`DCd7m!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3w zs-O&jQW&oPm!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`MszAmlGTS5}?BZk*cHrm!Km7 zk@U6ym!Jayk@B_wm!QJ{kqEH=m!RVSk?ytsm!AOu6u;j9IT8Q>6dxc1)eryx6dxc1 z)eZmv6dxc1)eHat6dxc1)d~Or6dxc1)d&Cp6dxc1)dm0n6dxc1)dTdjbs)8?oQiQ1gm!Km8k*>A> zmmmOuQlQ@eIY~>fs;aL4m!M+-k&L+im-7Pvs-PD@`2e5* zk)h)Nk>~>fs&={mm!KCw`2e5*k)gu@k>~>fs-3R?m!QJ{kqfy0m!iV}k-z`|&;cL@ zk)Q(skxsDxm!Jayk)b02k>~>fs^S9xszCvOQlJ+=`O~NWm!Ts8k)Xo?k)p!_k>~>g zs^S9ys^J3ws-O&jQirYom!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`7EdZmlGTS5}?BZ zkr|`^m!Km7kz=+0m!Jaykzuv}m!QJ{k$12Em!RVSkzKX_mkt2{6rdMC`F5=Tmmf3$ zao`u98UP#s5+48naUc``RG=3?`ERWMmmd%Sao`7^8UP#s5&#@Pk{~>fs$H)Cm!M+-kw3Wqm-7Pvs-PD@`2e5*k)h)N zk>~>fswuhum!KCw`2e5*k)gu@k>~>fs!*=~m!QJ{k-oS8m!iV}k-z`|&;dXPk)Q(s zkpZy(m!Jayk)b02k>~>fs^S9xs(}E2QlJ+=`G%+em!Ts8k)Xo?k)p!_k>~>gs^S9y zs^J3ws-O&jQaY{wm!ZP~k)Y!Mk>djas^S9xs^J3@s-P1<`QN7hmlGTS5}?BZk<6n1 zm!Km7kruW8m!JaykrcK6m!QJ{kt(nMm!RVSkr1{2m%#u46rdMC`2e5*k>IQUm*E2d zs-P1<`Khk|mjE095&!@IQUDwP5&#@Pk{~>fss^tAm!M+-k?6Pom-7Pvs-PD@`2e5*k)h)Nk>~>fs?xasm!KCw`2e5* zk)gu@k>~>fs`;(|m!QJ{k!QF6m!iV}k-z`|&;fu4k)Q(sk*cr%m!Jayk)b02k>~>f zs^S9xs(}H3QlJ+=`7fvcm!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQsb=um!ZP~ zk)Y!Mk>djas^S9xs^J3@s-P1<`G}_fmlGTS5}?BZk#(Z~m!Km7k-xP6m!Jayk-fD4 zm!QJ{k<+gKm!RVSk-4=0mudh26rdMC`O>TZmu3I}6rdMC`2Zk5xgRV5ao`u98UP#s z5&#@Pk{djbs)9CvQh2BTm!Km8k)pK!mmmOuQlQ@eIXnOW6rdMC`2e5* zk)dM&k>~>fs-CU?m!M+-k$|`Vm-7Pvs-PD@`2e5*k)h)Nk>~>fs%p6Zm!KCw`2e5* zk)gu@k>~>fs*$b#m!QJ{k^i>;m!iV}k-z`|&;bAjk)Q(skwUNkm!Jayk)b02k>~>f zs^S9xs$l_uQlJ+=`NyXJm!Ts8k)Xo?k)p!_k>~>gs^S9ys^J3ws-O&jQhTibm!ZP~ zk)Y!Mk>djas^S9xs^J3@s-P1<`5>nMmlGTS5}?BZkqx5%m!Km7kyo_;m!JaykyW(+ zm!QJ{k!!C1m!RVSkx{h&mjVC)6fFGz7oZ~ok&UjENmjVC) z6!QZBs-PnQkt?+SmjVC)6!QZBs-Ob_ktekOmjVC)6!QZBs-VLFkvp#cm!RVSks-AI zmx2HQ6!QZBs-VLHkvXaVmjVC)6!QZBs-R;5kr}lAmjVC)6!QZBs-PnQkrlN6mjVC) z6!QZBs-Ob_krA~2mjVC)6!QZBs-WWlkqxx}mu>(66!QZBs-VLHk-ee+mjVC)6!QZB zs-PnQkp;B>mjVC)6!QZBs-Ob_kpZ;-mjVC)6!QZBs-VLFkrl50m!RVSk^8g%ms|h< z6!QZBs-VLHk*lHqmjVC)6!QZBs-PnQk@K_vmjVC)6!QZBs-Ob_k?*trmjVC)6!QZB zs-VLFkpr&(m!RVSk?FJlmr4Kt6!QZBs-VLHk(r_YmjVC)6!QZBs-PnQk>RudmjVC) z6!QZBs-Ob_k=?WZmjVC)6!QZBs-VLFk@2nnm!RVSk=L{TmpA|b6!QZBs-VLHk%yuG zmjVC)6!QZBs-PnQk9QVm!RVS zk;SwBmnHxJ6!QZBs-VLHk#(W}mjVC)6!QZBs-PnQk-fA3mjVC)6!QZBs-Ob_k-4+~ zmjVC)6!QZBs-VLFk^0k@Hglsh}SK`Jo#C z`Jxv9`J)p6`Jf*_`5^#+QURaoBQeZu*av*#ln*jV^(*k@26Civa6F>j}OM(o5 zQUH7c8z2AxOCJmXao`33R38igam)Y!R38KYaUcNzR38WcabN@hR7?N>6dw=(aX-eZmjD6)@Bv^)`2Yd{@BpAk z`Qifss^J3ws^9|?s!Fy0mjDES(x|2Xm-7Pvs-Y7=`QQT+s@${xmjD6)@By?(`2Yd{ z@Bqk1`Qifss^J3ws^9|?sywy-mjDES(we3Jm-7Pvs-Y7=`QQT+s`9q~mjD6)@BxHJ z`2Yd{@Bn~E`Qifss^J3ws^9|?sxGzvmjDES(u}45m-7Pvs-Y7=`QQT+s#vZ6mjD6) z@Bx@d`2Yd{@Bm~-`Qifss^J3ws^9|?svx!hmjDES(tf4?m-7Pvs-Y7=`QQT+sxqbj zmjD6)@Bw&7`2Yd{@BoZQ`Qifss^J3ws^9|?suH#Tm*4;Z@B%;>k-z`|&;g(ek-z`| z&;Xzek>djbs^TGlQURv_mjD2OQW^jN6!ZfCs^9|?s>rDSm*4{ws*bh)m-GVws^9|? zs>7)Nm*4{ws)@D#m-GVws^9|?s=lcIm*4{ws)V)wm-GVws^9|?s=28Dm*4{ws(-cr zm-GVws^9|?s^0k)RI%`JfL#`OLKcmmeSl)%|^0k)RI%`JfL# z`E0KLmmeSl)%|^0k)RI%`JoE{`JoFy`JfL#`BI_(mmeSl)%|^0k)Rg<`Jod4`JxX1`JxX%`Jod)`Jfj-`QotummeSl)%|^0k)RI%`JfL#`PQNTmmeSl)%|^0k)RI%`JfL#`D(EL zmmeSl)%|^0k)RI%`JoE{`JoFy`JfL#`AD_@mmeSl)%|^0k)Rg<`Jod4`JxX1`JxX%`Jod)`Jfj-`K+h^mmeSl)%|^0k)RI%`JfL#`S7m)mmeSl)%|^0k)RI%`JoE{`JoFy`JfL# z`2wi_mmeSl)%|^0k)Rg<`Jod4`JxX1`JxX%`Jod)`Jfj-`F5=T zmmeSl)%|^0k@E`x`Jf*F z`Jo#C`Jxv9`J)p6`2Yd{&;W=>`2hex`JpEO`2hfc(x4ka`5yoP@!$dgRI?vI`Jfv> z`J1r+m!cCu`QZZqs^9|?sw=GjmjE095&!@IQUDwP5+48nao_*|RG=F``Jfj7`Jfv> z`Btz0m!KN}`RxDy7oZzJ`HHRom!KN}`RM=u7oY@IN z`JyL4`5^#6`9S~y%0B=A@jw6oRJfx5m-7oi`TcvvsK5hX*8O|Esr>^0k)RI%`2Yd{ z&;W=>`2hex`Jop8`2hfc(x4AO`ERlRm*E2ds-S}akpQ6omjMC*&>@IN`Jxv<`5^#6 z`9S~y%0B=A@jw6oRG^~&m;HOgsK5hX*8f8Q(clLF`QZZq`QQgY`QZaV`2hd``5zzy z)&D~Pk-!6A*8O|Esr>^0k@E`x`Jfj7`Jod4`Jfj-`Ifc+m-7Pvs-PD@`75gbm!lIv z`Qifrs^J3@s-PD@`Szgym-7oi`TcvtsK5hX*8f8Q(clLF`QQTqD*r^0k@Hglsh}SK`Jo#C`Jxv9`J)p6`Jf*_`T3#$m!KyA`Jfv>`D&v7m-7Pvs-PD@ z`FpMZm-GVws-P1<`3$oEm*fKgs^bF`s^S9^s-Y)9`Jf*_`MRqAm!Ky=`SVjjsr`G! zsK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`JfX(`2hex`Jfj-`2hd``JfL#`BSg|mjM7k z`Jfj-`2hp~`5zzy)%|^0k)Rg< z`Jod4`JxX1`JfX(`9ZJ$mjM7k`Jfj-`2hd``JfL#`8==xmjM7k`Jfj-`2hp~`5zzy z)%|^0k)Rg<`Jod4`JxX1`JfX(`7f{kmjM7k`Jfj-`2hd``JfL# z`2hex`Jfj-`2hp~`5zzy)%|^0k@E`x`Jf*F`Jo#C`Jxv9`2Yd{ z&;W=>`2hex`Jp!e`2hfc(xAftk<7LKm!Km6`LiQH`Jf*_`M9b7mwy5P>);ok8UP#s z5+48nabN@hRG=R~`8}}zmmdHC@!$afRI?vI`Jf*_`8cTmmjD1j`P!`im!cOy`QZZq zs^9|?s$Q%AmjE095+48nabN%dR3HF=QUU+~6aWB#QXc>SaXd`Jf{}`M#|G zm*N8es-YJ^`QQT+szR&(mjE095+48naexN^RG=e3`Jg8N`LiQH`Jf*_`HH0fmjD1j z`F{cc>);ok8UP#s5+48nai9SJRG=R~`GTbXm-7Pvs-Pc0`G2JUm*E2ds-R;5k>UdZ zs^J3@sd`Jf{Kkv*#amjD1j`J1f&m!cOy`QZZqs^9|?svoQW zmjE095+48nai9VKRG=q7`G&0jmmdHC@!%Jq8UP#s5+48naR31TRKF_#`Jy8Mk)cBY zk)UG%k=(BTm!OA5sZ#&|6ruwGk)ZhTm!OA5sZ9U?6rmSD`Jf*_`KhD- zmq`Es6tf>d`Jf{}`FX7Wm!cOy`QZZqs^9|?s{N|}mjE095+48naUcf(RG=e3`Jg8N z`LiQH`Jf*_`N^mMmjD1j`F{cc>);ok8UP#s5+48naXd`Jf{KkwdcomjD1j`B|+0m*N8es-YJ^`QQT+ zs@ zk)cBYk)UG%k(#dmm!OA5sSyAG6rv*mk)b02k)UG%kx--mm!OA5sS5xA6rmSD`Jf*_ z`Ddg5mj?g<6u&C~`JzJsk)ZL`9c6d`C^0k)RI%`2Yd{&;W=>`2hex`Jop8 z`2hfc(x4AO`KPP@m*E2ds-S}ak))pgmjMC*&>@IN`Jxv<`5^#6`9S~y%0B=A@jw6o zR79cwm;HOgsK5hX*8O|Bsr>^0k@Hglsh}SK`Jo#C`Jxv9`J)p6`2Yd{&;W=>`2hex z`JpcW`2hfc(x4ka`5yoP@qq#WRG=R~`O&EVm*E2ds-PD@`5yoQ>%aj3RI?vI`JfX( z`R=a&m-GVws-PD@`S+{;m*N8es^J3^s^9|?s(Y&cmjE095+48nabN%dR3HF=QUU+~ z6aWB#QlLKpIiMdv`2ZjQk>djZs-hP_`Jod)`Jg{RIq9DNm!Ka&`2Z9^`2hp~k)R(y z`2iFF`Jh7qk)abn`9Zb+m!K;^`2hj|&>@IN`JyjC`5^#6`9S~y%0B=A@jw6oR0N^_ zm-ACWsr`G#sK5hX*8O|Fsr>^0k)RI%`JoE{`JoFy`JfL#`8uZmm!S(l`JfL#`6HkI zmmeSl)%|^0k)RI%`JfL#`HQCim;HOfsK5hX*8f8Q(clLF`QQgY z`2Y++`Ts)zk-!6A*8f8Q(clLF`QQgY`2Yw&`Ts)zk-!6A*8O|Bsr>^0k@Hglsr6d| zsh}qS`Jp2K`Jx{H`2Yd{&;W=>`2hex`JpcW`2hfc(x4we`O~cbm-Yhys-Qywk@T|v zm$gFyk+dT~`QZZ;ssI6i($BE}m-7Pvs(%6i@t^`JpdB`2YYw`5*uQ${zp#@qhsUR0;q96!ilDs^J3^s^9|? zs!_E6m-7P^s-Qywk!Gs@m*4{vs>rhcm#?7zm-ACWsr6ezsr`G#sK5hX*8O|Bsr>^0 zk@E`x`Jf*F`Jo#C`Jxv9`2Yd{&;W=>`2hex`JpcW`2hfc(x4we`8J^cm-7Pvs-Pc0 z`HQ3fmtg_`%b*)T`9A;v>)*D|bRG=R~`4*u6m*E2ds-P=C`5yoQ>xlpWRG=R~`4FK0mjVC)6rd|W`2hj| z&>@IN`JyjC`5^#6`9S~y%0B=A@jw6oRBoXEm-7oi`TcvwsK5hX*8O|Esr>^0k@E`x z`Jfj7`Jod4`Jfj-`Ea8DmjD1j`SSw+s-P1<`D~*9mjD1j`CtM7%K-dClk*Ee`Tcvt zsK5hX*8O|Fsr>^0k)RI%`JoE{`Jf9x`5yoP@t^^0k@E`x`Jf*F`Jo#C`Jxv9`J)p6`Jf*_`M;n4m-7Pvs-PP{ z`MjV1m!lIv`Jxv<`QZZqs^9|?s-vm@m-7oi`TcvusK5hX*8O|Csr>^0k@Hglsr3^8 z`Jg8N`Jp2K`Jx{H`Jf*_`CF;~m-Pbxsz9sr3^; z`TcvvsK5hX*8f8Q(clLF`QZZq`QQUU`2hex`QQgY`2hd``5zzy)&D~Pk-!6A*8f8Q z(clLF`QQgY`Ts)zk-!6A*8f8Q(clLF`QQgY`2ZjQk^e&gk-!6A*8O|Csr>^0k@E`x z`Jf*F`Jo#C`Jxv9`J)p6`2Yd{&;W=>`2hex`JpEO`2hfc(x4ka`5yoP@!$dgRI?vI z`Jfv>`E{NDm!cCu`QZZqs^9|?s-3L=mjE095&!@IQUDwP5+48nao_*|RG=F``Jfj7 z`Jfv>`81>dm!KN}`RxDy7oZzJ`K+%0m!KN}`RM=u7oY@IN`JyL4`5^#6`9S~y%0B=A@jw6oRMMaSm-7oi`TcvvsK5hX*8O|Esr>^0k)RI% z`2Yd{&;W=>`2hex`Jop8`2hfc(x4AO`30x{m*E2ds-S}ak&>|gmjMC*&>@IN`Jxv< z`5^#6`9S~y%0B=A@jw6oRJx!4m;HOgsK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`JoR$ z`JfX(`BbI^0k)RI%`JfL#`6H^0k@E`x`SSw^s-PDD z`Jop;`QQT+s>PxIm*4{vs`Cp#`TcvtsK5hX*8O|Fsr>^0k)RI%`JoE{`JoFy`JfL# z`Rb^0k)RI%`JoE{ z`JoFy`JfL#`RAYim!J^0k)RI%`JoE{`JoFy`JfL#`G21Om*E2ds-O=*`2hd``JfL#`2hex`JfL#`2hp~ z`JfL#`2hex`Jf9x`2g^J(;)x=i=Yoc`2h$3`5zzy)%|^0k)Rg< z`Jod4`JxX1`5*v*QlS3;Iie3h`Jod)`Jfj-`7^5jm;HOhsK5hX*8f8Q(clLF`QQgY z`2Yw&`Ts)zk-!6A*8f8Q(clLF`QQgY`2ZjQk^e&gk-!6A*8O|Csr>^0k@E`x`Jf*F z`Jo#C`Jxv9`J)p6`2Yd{umFfh`2hex`JpEO`2hfc(x4ka`5yoP@!$dgRI?vI`Jfv> z`5U1Bm!cCu`QZZqs^9|?s@tpomjE095&!@IQUDwP5+48nao_*|RG=F``Jfj7`Jfv> z`7*Qrm!KN}`RxDy7oZzJ`4Y1Km!KN}`RM=u7oYm!Km+`2hj|upx*? z`JyL4`5^#6`9S~y%0B=A@jw6oR1ly4m-7oi`TcvvsK5hX*8O|Esr>^0k)RI%`2Yd{ zumFfh`2hex`Jop8`2hfc(x4AO`BSq0m*E2ds-S}ak<_ODmjMC*upx*?`Jxv<`5^#6 z`9S~y%0B=A@jw6oRQR6%m;HOgsK5hX*8f8Q(clLF`QZZq`QQgY`QZaV`2hd``5zzy z)&D~Pk-!6A*8O|Fsr>^0k)RI%`JfL#`Rt_sm;HOfsK5hX*8O|Esr>^0k)Rg<`Jod4 z`JxX1`JfL#`G1`Mm*N8es-Y7=`Jfj-`RA_xmmeSl)%|^0k@Hgl zsh}SK`Jo#C`Jxv9`2Yd{umFfh`2hex`Jp!e`2hfc(!c-!kN}_rk>UdYsv!V?(x4we z`46i9m!K;E`Jf*_`HZjsm!Km6`Jn>=k)Xo>ktnJEm!K~I`Jf*_`JpR7`OuyJm!LBM z`JgjE`Jg8N`LiED`JgXA`2g^J)1fm!`7{6ki=Y=k`BI$!m*N8es^J3^s^9|?s%ESI zm%k?f`Jf*_`4a#@`Jlr9k+q=zmlOa%`Jf*_`EsWJm*WEfs-iPM`QZZ;s^9|?s+pVr zm!KyA`Jg92`2ZjQk)S64`Jlr9k*A>lmlFU$`Jf*_`4j{|`Jf*_`C_L3m*WEfs-h=A z`QZZ;s^9|?s)?Kbm!KyA`Jf*_`4a#@`Jf*_`4j{|`Jf*_`BtX?m*N8es^J3^s^9|? zs&=mbm!ls*`Jf*_`2hex`Jf*_`2Yw&`Qifrs-Pc0`2YYw`9J^w%K-dCli~vas^9|y zsuiXGm!Ka&`JppF`2hd``Jf*_`JpF3`2hp~`JgL6`2g^J)1fm!`5^!Ri=ZDs`2h$3 z`5zzy)c^tjumFfh`Jp#J`2YYw`5*uQ${zp#@!$ghR2={S6hEK;m!Ky=`5yoP@j(Fq zRH7e1`JgXA`2g^J)1fm!`5*uQi{S$Rs^9|xsxYVjmj?g<6rdkK`5~tNm*N8es-Y)9 z`JgjE`9ZG#m!Ka&`JyX8`JppF`RSzpm$^0k)RI%`JoE{`JfL#`2YYw`62*-(xD4L`IDsommeSl)%|^0k@E`x`2Yd{umFfh`2hex`JpEO`2hfc(x9UNkt(kLm!P8nk)Rs@ z`Jkf!ks$zp(rK^%m*WEfs-eRGk)Y!Mk>UdZs^J3zs-vg>m!RVSk@2Pfm*E2ds-U9) zk;djbs={c1Qj?(nm!RVSku{+Im-7Pvs-WWlk#4I0m!P8nk?5uWm*4{vssRE3upx*? z`JyL4`5^#6`9S~y%0B=A@qhsUR0;q96!QZBs-WWlkzlI-mjVC)6!QZBs-U9)k=UjG zm*4{vst&OKm-U_hm-7oi`TcvvsK5hX*8O|Fsr>^0k)RI%`JoE{`JfL#`2YYw`62*- z(xD4L`4yu7mmeSl)%|^0k@E`x`Jfj7`2Yd{umFfh`2hex`JpcW z`2hfc(xBr2k%z4Rm!RVSk)R_0`Jm$fks$zp(sG~wm*WEfs-Xh`k)R_1k>UdZs^J3z zsz{#ym!Km7k#?&8m-7Pvs-PD@`OB&Qm*E2ds-WWlk>UdZs^J3@s*0Tdm!Km7kpTdJ z(o?bjmjE095+48naX|q9RKNfL@B#n?k-z`|kO3e8k-z`|kO1HYk>djbs={c1Qahmk zm!Km7kpZXwm-7Pvs-PnQk&dhXm!RVSk<_C9m*4{vssRE3upx*?`JyjC`5^#6`9S~y z%0B=A@qhsUR0;q96!QZBs-PnQk$|iJmjVC)6!QZBs-WWlk;J0^m*4{vs^0k)RI%`JoE{`JfL#`JoFy`ID&sm;HOfsK5hX*8O|F zsr>^0k)RI%`JfL#`6RFZm;HOfsK5hX*8f8Q(clLF`QZZq`QQgY`2hex`QQUU`2YYw z`9A;v>);ok8UP#s68}R0k-!6A*8O|Esr>^0k@E`x`Jfj7`Jfj-`3#`{m*4{vD)S3K z`TcvtsK5hX*8O|Fsr>^0k)RI%`JfL#`2YYw`KF=&m;HOfsK5hX*8f8Q(clLF`QZZq z`QQUU`2hex`QQgY`2hd``5zzy)&D~Pk-!6A*8O|Fsr>^0k)RI%`JfL#`F*ATm;HOf zsK5hX*8f8Q(clLF`QQgY`2YYw`Ts)zk-!6A*8f8Q(clLF`QQgY`Ts)zk-!6A*8O|E zsr>^0k@E`x`Jfj7`Jod4`Lh>5`JfX(`Gl_jmusm1m*E2ds^9|?s+gVsmmeSl)$^0k@Hglsh}qS`Jp2K`Jx{H z`J)>E`J@*B`2Yd{umFfh`2hex`Jq1m`2hfc(x4we`6QkHm-7Pvs-PP{`6a0Tm-GVw zs-PD@`NpjOm*WEfs^S9_s^J3@s-P!8`Kg=#m!LBM`JgjE`Tnf`m*N8es-Yu5`Jg92 z`FgJZm!O9Rsh~SR`5yoP@gM;JRG>FN`Jp>N`J*#H`Qifss^J3ws-P!8`O}^Mmk0m= z6rnRf`Jg92`TwK;m!UU6`JiI~k?5`em!K~|`2hj|upx*?`Jz8S`5^#6`9S~y%0B=A z@qhsUR0;q96xyBtm!UI2`Jg92`R}9umu9Q~m-7Pvs*J7wm*4{vst&LJm-U?gm-ACW zsr`G%sK5hX*8O|Fsr>^0k)RI%`JoE{`JfL#`2YYw`62*-(xD4L`9Y)qmmeSl)%|^0k@E`x`Jfj7`2Yd{umFfh`2hex z`JpcW`2hfc(xBr2kUdZ zs^J3zsu!UDm!Km7kv*#am-7Pvs-PD@`Fg4Um*E2ds-WWlk>UdZs^J3@s->;}m!Km7 zkpTdJ(n_ZPmjE095+48naX|q9RKNfL@B*L{k-z`|kO3e8k-z`|kO1HYk>djbs={c1 zQZ}Fem!Km7ksO=^0k)RI%`JoE{`JfL#`2YYw`62*-(xD4L`B0z# zmmeSl)%|^0k@E`x`Jfj7`2Yd{ zumFfh`2hex`JpcW`2hfc(xBr2k)fdfm!RVSk)R_0`Jm$fks$zp(tND{m*WEfs-Xh` zk)R_1k>UdZs^J3zs+OAnm!Km7k;tF_m-7Pvs-PD@`CYC5m*E2ds-WWlk>UdZs^J3@ zs+g?*m!Km7kpTdJ(#f3vmjE095+48naX|q9RKNfL@B+Xnk-z`|kO3e8k-z`|kO1HY zk>djbs={c1QrVvWm!Km7ku$3Qm-7Pvs-PnQk%XfEm!RVSk?N!Wm*4{vssRE3upx*? z`JyjC`5^#6`9S~y%0B=A@qhsUR0;q96!QZBs-PnQk#?g0mjVC)6!QZBs-WWlk=mpG zm*4{vs#LE3mph#Qm-7oi`TcvwsK5hX*8O|Fsr>^0k)RI%`JoE{`JfL#`2YYw`62*- z(xD4L`CFj>mmeSl)%|^0k@E`x`Jfj7`2Yd{umFfh`2hex`JpcW z`2hfc(xBr2kUdZs^J3z zs-B?#m!Km7kuaVAm-7Pvs-PD@`8}oom*E2ds-WWlk>UdZs^J3@s%V-2m!Km7kpTdJ z(y^oemjE095+48naX|q9RKNfL@B)B1k-z`|kO3e8k-z`|kO1HYk>djbs={c1Qh}cT zm!Km7k!z~|m-7Pvs-PnQkz}a^0k)RI%`JoE{ z`2qld(xD4L`JfL#`R1+vm;HOfsK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`Jfj-`JxX% z`Jod)`46uDmmeSl)%|^0k)RI%`JfL#`Ol#Lm!KB_`Jfj-`2YYw z`5yoP@gM;JRG<$)`E;WHm*N8es-PD@`2YYw`QZZqs^9|xs#>Z4m!KCw`5yoP`5zzy z)%|^0k)RI%`JfL#`GA`Lm;HOfsK5hX*8O|Fsr>^0k)RI%`JoE{ z`JoFy`JfL#`M;k3mmeSl)%|^0k)RI%`JoE{`JfL#`2wB)mjE09 z68(F^sK5hX*8O|Esr>^0k)RI%`JfL#`F5)Rm!KB_`JfL#`J15smmdHC`Jfj-`Tcvt zsK5hX*8f8Q(clLF`QZZq`QQUU`2hex`QQgY`2hd``5zzy)&D~Pk-!6A*8f8Q(clLF z`QQgY`Ts)zk-!6A*8O|Esr>^0k@E`x`Jfj7`Jod4`Jfj-`PHWXmjD1j`SSw+s-P1< z`O&8TmjD1j`CtM7%K-dDlk*Ee`TcvtsK5hX*8O|6sr>^0k@Hglsr3^8`Jg8N`Jp2K z`Jx{H`J)>E`2Yd{kN}8B`2hex`Jq<;`2hfc(x4we`5yoP@jxK}RG=q7`2Yw&`QZZq zs-P!8`2Yk!`5*uQ%K-dDli>pZs-Pc0`5yoQ>u3%DRG>owk)j(w`JpF3`G}$am!Lxe zkw%&Sm!LlY`Jg92`S+Utm!K;E`Jn>=k)T5Xk$0y5m!Lxc`Jg92`2Yk!`JhJt`JqEV z`Jf*_`9A;v>uCl6RG=q7`2hq#`Jf*_`2g&E)8GRD%QFA~i=Zb!`4j{|`Jg92`4t2} z`Jg92`JbKtm*WEfs^S9`s^J3^s^9|?s)noom!Ky=`2hq#`Jf*_`2g&E(;)x=i=Zb! z`2hp~`Je*{`Jo>``Jh8U`7{6k%b+Jf`Es5Am*WEfs-izY`QZZ;s^9|?s@0kQ zm*E2ds-P!8`2hp~`Je*m!Ky=`2hq#`Jh8U`2g&E(;)x=i=Zb!`2hp~`Je*UdYs-Yi1`Jg92`JABtm!LBM`Jg92 z`H`3Zm!K;E`JqDrk)Q(skp-szm!LNQ`Jg92`JppF`O&2Rm!LZU`Jg*M`JgWV`JgvI z`2g&E)1f;+`7;0ji=Zb!`81vXm*WEfs-hb}`Jo>``QQT+s+XDnm%lFn`Jg92`4a#@ z`Je*m*N8es^J3^s^9|?s`Z%v zm!l^@`Jg92`2hex`Jg92`2Yw&`Qifrs-P!8`2YYw`9J^w%K-dDli~vas^9|ys??|d zm!Ky=`Jp>N`2hd``Jg92`JpdB`2hp~`JgjE`2g&E)1f;+`5^!Ri=Zb!`2h$3`6>Va z6!QZBs-Qyxk({ajm*4{vs*0@tmra}hm!K~|`5yoP@j(IrRG>FN`2g&E)1f;+`7;0j zi=j6_`Jf*_`5*uQiva9=)1f;+`7{6ki=Zb!`PQ8Om*N8es^J3^s^9|?s=}E6mj?g< z6rd+S`OlpHm*N8es-Z7H`Jg*M`Ma3^m!Ky=`JyvG`Jp>N`J<=*m%ga~m-7Pvs^qHw zm*4{vs%EVJmmeSl)c^tjkN}8B`Jq=p`2YYw`5*uQ${zp#@jw6oR7INqm-ACWsr3^; z`Tcv#sK5hX*8O|Esr>^0k)RI%`2Yd{kN}8B`2hex`Jop8`2hfc(xDGP`JjUUkv^{f zm!K0s`2hj|kRgai`Jxv<`5^#6`9S~y%0B=A@jw6oR4tnSm;HOgsK5hX*8O|Dsr>^0 zk)RI%`JoE{`2Yd{kN}8B`2hex`Jo>G`2hfc(x4AO`2hex`Jf9x`2g&E(;xrks+@Cm!KO!`2hj|kRgai`Jx{{`5^#6`9S~y%0B=A@jw6oR1li~m;HOh zsK5hX*8O|Esr>^0k@E`x`Jfj7`Jod4`2Yd{kQ2m5`Jfj-`Bkp}m!cCu`QZZqs^9|? zswJrZmmeSl)$^0k@E`x`Jfj7`Jod4`Jfj-`4a>{`Jfj- z`M{z7m*N8es^J3@s-P1<`QWMlm!KCw`Jod)`2hp~`5zzy)$^0 zk@Hglsh}SK`Jo#C`Jxv9`2Yd{kN}8B`2hex`JpcW`2hfc(x4we`RuL#m-7Pvs-PP{ z`RT3ym-GVws-PD@`GT4Mm*N8es^J3^s^9|?s#cr-m!KyA`Jp2Lk)T5XktUx1m!K;^ z`2hj|kRgai`JyjC`5^#6`9S~y%0B=A@jw6oRJob|m-ACWsr`G#sK5hX*8O|Fsr>^0 zk)RI%`JoE{`JoFy`JfL#`ERZNmmeSl)%|^0k@Hglsh}SK`Jo#C`Jxv9`Jf*_`O~HUm-7Pvs-PP{`Ou~Rm-GVws-PD@ z`OT&Om*N8es^J3^s^9|?s;Q{|m-ACWsr`GzsK5hX*8O|Dsr>^0k)Rg<`Jod4`JxX1 z`5*v*QlS3;Iie3h`Jod)`Jfj-`8%cmm;HOhsK5hX*8O|Csr>^0k@E`x`Jf*F`Jo#C z`Jxv9`Jf*_`8}-vm!KyA`Jfv>`GTMSm-7Pvs-PD@`HQFjm*WEfs^S9^s-Y)9`Jf*_ z`NFCHm!Ky=`SS}v`TcvvsK5hX*8O|Esr>^0k)Rg<`Jod4`JxX1`JfX(`G1=KmjM7k z`Jfj-`2hd``JfL#`Cg{~mjM7k`Jfj-`2hp~`5zzy)%|^0k@E`x`Jfj7`Jod4`2Yd{kN}8B`2hex`Jp!e`2hfc(x4YW z`E#rPm!Ka2`Jfj-`G}kUm!Km6`5*v*QlQ@eIiMdv`5yoP@t^_#RG=R~`Jf{J`Lh>5 z`Jf*_`N5X|m*N8es-Y7=`QQT+s_CWwm!RJOIiTM_IUfK3aex2-RG=R~`GcJQmjeI* z6rdkK`TVEmm!OA5sR9B3kV1$@`J*>L z`9c6d`C^0k)RI%`2Yd{kN}8B z`2hex`Jop8`2hfc(x4AO`Ru9xm*E2ds-S}ak-4e=mjMC*kRgai`Jxv<`5^#6`9S~y z%0B=A@jw6oRN^0k@Hglsh}SK`Jo#C`Jxv9`J)p6`2Yd{ zkN}8B`2hex`JpcW`2hfc(x4ka`5yoP@qq#WRG=R~`3{@^m*E2ds-PD@`5yoQ>%aj3 zRI?vI`JfX(`Ae4nm-GVws-PD@`GlPRm*N8es^J3^s^9|?s&J+MmjE095+48nabN%d zR3HF=QUU+~6aWB#QlLKpIiMdv`2ZjQk>djZs-hP_`Jod)`Jg{RIfj=1m!Ka&`2Z9^ z`2hp~k)R(y`2iFF`Jh7qk)abn`R=3tm!K;^`2hj|kRgai`JyjC`5^#6`9S~y%0B=A z@jw6oRH2yvm-ACWsr`G#sK5hX*8f8Q(clLF`QQgY`Ts)zk-!6A*8O|Esr>^0k)Rg< z`Jod4`JxX1`JfX(`J$Zvm*E2ds-PD@`5^#6`2hd``JfL#`PiEOmjM7kIiMFn`2ipR zIUgVc)%|^0k)RI%`JoE{`JoFy`JfL#`Lmb*m!S(l`JfL#`S6whmmeSl z)%|^0k)Rg<`Jod4`JxX1`JfX(`F@`NmjM7k`Jfj-`2hd``JfL# z`CX;|mjM7k`Jfj-`2hp~`5zzy)%|^0k@E`x`Jfj7`Jod4`2Yd{kN}8B`2hex`Jp!e`2hfc(x4YW`O=^Nm!Ka2`Jfj- z`A3`om!Km6`5*v*QlQ@eIiMdv`5yoP@t^_#RG=R~`Jf{J`Lh>5`Jf*_`6!wHm*N8e zs-Y7=`QQT+s_3Num!RJOIiTM_IUfK3aex2-RG=R~`EIKJmjeI*6rdkK`7@gTm!Ka2 z`Rf1w7oj6S`Jf{Kkpi6mm!RK3IUfK3aXL`9c6d`C^0k@Hglsh}qS`Jp2K`Jx{H z`J)>E`J@*B`2Yd{kN}8B`2hex`Jp!e`2hfc(x4+i`5yoP@u30$RG=q7`P7>Km*E2d zs-Pc0`5yoQ>)-(ZRI?{Q`JiI~k)azv`Q)enm-GVws-Pc0`B|R-m*N8es^J3^s^9|? zs&%CQmjE095+48nabN%dR3HF=QUU+~6aWB#QlMV}IiMRr`GA@Km*E2ds-PD@`8lNj zm!LBM`Jg92`2ZjQk>djZs-ho2`JppF`Ji7xIfa$~m!Ky=`2Z9^`2hp~k)S6)`2iFF z`JiI~k)bm{`GK4Nm!K~|`2hj|kRgai`Jy*K`5^#6`9S~y%0B=A@jw6oRG^ptm-ACW zsr`G$sK5hX*8f8Q(clLF`QQgY`Ts)zk-!6A*8O|Esr>^0k)Rg<`Jod4`JxX1`JfX( z`PrfWm*E2ds-PD@`5^#6`2hd``JfL#`PZ5MmjM7kIiMFn`2ipRIUgVc)%|^0k)Rg<`2YZb z|9_zq0QsU10QsXs06E|R0Pp~aNBIE&K>48`0Qms`fYRdw1S+BrK>48)K>45-K>19b z|Ciwb0PrD*NBN>3K=~m6K>0xc0m?rB0P#Qo090g`|CjxH#HhdnU)KG5y{Y{J0Fm2r+|CjRv0IHx9K>3`Z|Ciwd0IJ{v6RIhs|Cb*i1J&~jK>7W9 z!>GUmU)KG5zN!5K0Fj^%0QsQ{0QsN~K>25s|Cb^FfYPB0K>6sX|Cb*i1J(U|!l=Ll zU)KLa0MXzF0QuktK>7be0Fl50U)KG5zN!5K0Fj^%0QsQ{0QsR0K>45xK>0ra0P6q& z092q4K>4n!|Cbe@|CgW-K=}Y50Fj^%0QvU+{}&%11J(U|!l=LlU)KLa0MXzF0Qukn z0Pp~uNBIFj0FmGaK=}ax0Qnyv1J(aS0Fl50U)KG5zN!5K0Fj^%0QsN~K=~h?|CgW- zK>017|CjxH!l=LlU)KG5yQ%#H0Fm=k0jZ!L0QsTA06C%;0QsX60QsOFK=~g40QsOF zK=~6O0Fj^*K=}%$|Ci(g0IH)GK=}dyfYRXu6e{2Y6RHHE|CgX2K=}e70FmGU0Pq0R zNBQ9c0IJ{v0;)Zh|CgXA0QsOFK>493K=}ax0QsOFK=}XwK>6VV0IHxLK=~-9|Cb*i z1J(0WL8<+F#i+moU)KG5zN!5K0Fj^%0QsN~K=}ZG0FhRd|CjxH!l=LlU)KG5ys7;I z0Fj^%0Qukn0Pp~aNBIE&K>48`0Qms`fYP83K=}XwK>45-0QsS#0Fj`>0FjQV|CgW} zK>6VT0PrD*NBN>3K=~m6K>0xc0m?rB0P#Qo094hM|CjxH#HhdnU)KG5ys7;I0Fj^% z0Qukn0Pp~aNBIE&K>48`0Qms`fYP83K=}X!K>45-0QsS#0Fj`>0Fia6|CgW}K>6VT z0PrD*NBN>3K=~m6K>0xc0m?rB0P#Qo093q||CjxH#HhdnU)KLa0MXzF0Qunq0Qukp zK=}axK>6SYK=}ax0Qnyv1J(aS0Fl50U)KLa0MXzF0QuktK>7be0Fl50U)KG5ys7;I z0Fj^%0QsQ{0Qukn0Pp~aNBIE&K>48`0Qms`fYP83K=}axK>45xK=}adeAD0q0Lvf% z0E?g(0QsS#0Fj`>0Fj`o|CgW}K>6VT0PrD*NBN>3K=~m6K>0xc0m?rB0P#Qo0922b z|CjxH#HhdnU)KLa0MXzF0QuktK=}XwK>7be0Fl50U)KG5zN!5K0Fh9n|CgW-0QsN~ zK=~g40P#Tq093#L0MG&e0+FBq0MG#-4UwP#0MGy+4w2&n0;+-!fKvOI|CgW-K=}Xw zK=~g40P&yz092q4K=}XwK=}XwKsf>c02IIlfKvT?!l=LlU)KG5zN!5K0Fj^%0QsN~ zK>5F?|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K=}X+K=~g40P#Tq092q4K>2f+ z|Caz901^NI08#)P01_Vn0C8Xd08}6VfKmbg02BZKfKnd-0CC^|092q4K>48n0MH>| z4v_&U0QtZHfKqJ$02H7PK>2~B|CgW-K=}X=K)D})0C8ad|5Tt4K=}X=K)D|z0CC{{ z|5Tt4K=}X=K)D|%0C8ac|5Tt4K=}X=K)D|@0C7P8095Y({}-SSK=}X=K)E020CAuN z08}670C6k=08}5a0C8Xi08}5a0C5Zf08}3Y05K~G08}3U0CBAd08}4{0CAuP08~T( z02Cjz0CAuP08}5q0C5Wl08}~v02Cj%0db%O08}5i0dWig08}4z0de2~08}5C0de31 z08}4r0dXJ!08}&p02CkW0dYV908}6J0dYV908}5)0dc?q08}ji02BZLfKo6302Dw0 zfKo0102CkrfKn^~02E*WfKn;|02F`$fKn&`02H7BfKny^02H7A0MGy+50N7PfKq}0 zfYRXu0IHx5K>5v=|Cb&B02H7A0MG!S43R?sfKs9WfYRXu0IHx5K>5X&|Cbg302H7A z0MG#71(9O_fKq}0fYRXu0IHx5K>59w|CbH`02H7PK>5y_|Cb8@02H7PK>0_M|Ca~= z02JT>fKmnk02H7PK>48n0MH>o50L>V0QtZHfKvT?!l=LlU)KG5y{Y{J0Fj^<0QsR4 z0QsU10QsO3K=~g40P&yz092qCK>4B%K>48)K=~1&|Cb*i1J(U|!>GUmU)KG5zN!5K z0Fj^%0QsQ{0QsQ{K>45#K>6>K|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K>2r) z|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K>2@}|Cb*i1J(U|!l=LlU)KG5x~csG z0Fm49B0Qms`fYP8BK=~60K>45-K>1>l|CfIP z0PElfpBexh01_Vn0CAuJ092qCK=}Yb0FeOzfKqvy|CgYL1F4|n0Fh#x|CgYL1gW4S z0g<7fKsmaY|Cb5?02H7XK>2r~|CgYL1gW7XK>466K>4GeKsn+A0IHxDK>5I<|Cb*i z1J&RG0Pp~aNBN;IK=}XwK=~j50LmW#0P#Qo091pO|CjR%K>7W9#;CvpU)KG5zN!5K z0Fj^%0QsN~K=}ig|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K=}axK>45#K=}X& zK>6YW0IHx5K=}XwK>0ub0LuXULzChI0IHx5K=}!x|CgW-K>5R^|Cb*i1J(U|!l=Ll zU)KLa0MXzF0QuktK>7be0Fl50U)KG5y{Y{J0Fj^<0QsR40QsU10QsR4K>45-K>2%? z|Cb*i1J(U|!>GUmU)KG5zN!5K0Fj^%0QsN~K>1^y|Cb*i1J(U|!l=LlU)KG5zN!5K z0Fj^%0QsN~K>6dP|CgW-K>4w$|Cb*i1J(U|!l=LlU)KG5x~csG0Fm=k0jZ!D0QsR4 z0Qukn0Pp~aNBIE&K>49B0Qms`fYP8BK=~5@0+FB>K=}Y50Fl?9|Ciwd04kstK=}Zm z0+Hhb0IC82fKuQC6RI4Z|Caz901}|z06Cx+K=}ZG0Fj~JKsoZD|Cb;DfKs3X0Xd)p z0g)mAfKuTD0IHxDK>7cu|CgYL1gW4GK=}e70Fj_00g(V80FmJX0IJ{v0;6{K|Ciwd0IHx9K=~g40qfwGpBexh01^NkK$0H-0P$b|08}6V zfKmbg02BZKfKnd-0CC_008{`3fYRcY|CjRv0IHzl0Fmee0IHx9K>5k1|CgcT0Fj^o z0MGz{50Rn+0g>nf0;(UU|CgWx0g>nf6RP0@0IC2pfKnEd|CgWx0g-^D|CgZS0Fi#A z|Cita0Pq2{NBQ6Z0Pq0FNBQCd0jl8x0IJ{v6RKvW|Cb;DfKuTB0PrD*NBN>JK=~m6 zK>0xc0m?rB0Pz3<08|bD02K5C0IHw^0g-B?|Ca&)02K5C0IHzl0Fh>-|Ca&)02K5C z0IJ{v6RH-P|Citc6sp{&|Chs*|CjSqL8<+F#;CvpU)KG5wyFIC0Fm=k0jZ!D0Qukn z0Pp~aNBIE&K>49h0Qms`fYP8BK=}Y50Fhj!|Cay&K=~g40P)}g092qCK=~5@0+FB> zK=}Y50Fh9i|Cba508yY9K=}Y50Fh9o|Cay&K>6bX0IDJYfKuTD6e{2Y6RMJ(|Caz9 z01^NI08#)P01_Vn0C8Xd08}6VfKmbg02BZKfKnd-0CC^}092qCK=}Y50FgbV|CbX0 zK>45-K=}cn0+FEO0g-5+|CgZS0g>SY0IJ{v6RJq2|CgZS0g-B$|CgW_K=}Y50Fh^x z|Caz901^NI08#)P01_Vn0C7P9093#L0MG&;Es>xA0MG%T3z47z0MG#750T>o0;<9_ zfKvUI|CgW_K=}ZG0Fid1|Caz901^NI08#)P01_Vn0C7P9093#L0MG&;Es>xA0MG%T z3z47z0MGzH5Ru~p0;=LQfKu$1|CgW_K=}Y50Fmva|CgW_K=}ZG0Fe@;|CgW_K=}Y5 z0FghJ|Caz901^NI08#)P01_Vn0C6A!092qCK=}Y50FnQs|Cay&K=~g40P$b}092qC zK=}Y50Fn8m|Cay&K>4?p|Caz901_Vn0C8Xd08}6VfKmbg02BZKfKnd-0C9i?092qC zK=}Y50FmsZ|Cay&K>4BL0Fmee0jl_+|CgW_K=}Y50FmXS|Cay&K>4BL0g>nf0jlYw z|CgcT0g<5N0FfG(|Caz901_Vn0C4~V092sk0FeQa|CfZ3|Caz901_Vn0CC^}092qC zK=}Y50Flz9|CbX0K>4BL0Fj_$0g-Z>|CgX+0g<8O0g>nf0jl8x0IJ{v6RMP$|Ca;+ z02H9(0Fe=)|CinW{}&(tfKuTB0PrD*NBN>pK=~m6K>0xc0m?rB0P#Qo08|r{|CjSq zL8<+F%Ba8tU)KLa0MXzF0QuktK=}Y50g?Yh0Fl50U)KLa0MXzF0QuktK>7be0Fl50 zU)KG5x~csG0Fm49B0Qms`fYPAj0Fj{+K>1Lk z|CgW_K=~5@0+FB>K=}Y50FjrT|Ciwd04kv40FmPZ0IGrjfKuQC6RO>u|Caz901}|z z06Cx+K=}Y50g<8KKsmFY|CgZOKsg@(0C6Az092qCK=}Y50FjBL|Cay&K=~g40P$b| z08}6VfKmbg02BZKfKnd-0CB(q092qCK=}Y50Fi#A|Cay&K=}X!K>48)K>2!_|CjRv z0IHxDK=}cn0+FC20gSY0IJ{v6RL%!|Ciwd0IHxDK=}bU0QsOJ0gJK=~m6K>0xc0m?rB0Pz3;08|D502K2B z0IHzl0FjlK|Citc6ROLl|Ch3p|CjR%K>7W9#;CvpU)KG5x~csG0Fm=k0jZ!D0QsR4 z0Qukn0Pp~aNBIE&K>49B0Qms`fYP8BK=~5@0+FB>K=}Y50FgwV|Ciwd04kstK=}Zm z0+Hhb0IEU&fKuQC6RL@v|Caz901}|z06Cx+K=}ZG0Fj~JKsjHZ|Cc}jfKs3X0Xd)p z0g)mAfKuTD0IHxDK>2K^|CgYL1gW4GK=}e70Fj_00g(V80FmJX0IJ{v0;)ix|CgW_ zK=}Y50Ff!A|Cay&K=~g40P)}g092q8K=~g80I}c)pBexh01^NkK$0H-0Pz3<092qC zK=}Y50FfM||Cay&K>1#g|Ciwd0IHx9K=~g40qfwGpBexh01^NkK$0H-0P$b|08}6V zfKmbg02BZKfKnd-0CC_008{`3fYMKu|CjRv0IHzl0Fmee0IHx9K>0SN|CgcT0Fj^o z0I&d{5Rsw-0g>nf0;-Iq|CgWx0g>nf6RP0@0IC2pfKr2z|CgWx0g>&Z|CgZS0FmpW z|Cita0MG%nNBQ6Z0MG!)NBQCd0jl8x0IJ{v6ROjs|Cb;DfKuTB0MH?bNBN>JK=~m6 zK>0xc0m?rB0Pz3<08|bD02K5C0IHw^0g>0D|Ca&)02K5C0IHzl0Fl$8|Ca&)02K5C z0IJ{v6RLxl|Citc6sk$3|Ccb6|CjSqL8<+F#;CvpU)KG5yQ%#H0Fm=k0jZ!D0Qukn z0MG!4NBIE&K>4930Qms`fYKlUfKs5}06Cx+K=}Y50FlR||Cay&K=~g40P)}lpBexh z01_Vn0CAuM092qCK=~5@0+FB>K=}Y50Fk(z|Cba508yY9K=}Y50Fk((|Cay&K>6bX z0IFgDfKuTD6e{2Y6RP@~|Caz901}|z06C!FKsf*a08#)P01_Vn0CC^}092qCK=}Y5 z0FkJp|CbX0K>45-K=}cn0+FEO0Fl$4|CgZS0FmJX0IJ{v6RNYM|CgZS0Fl*}|CgW_ zK=}Y50Fly_|Caz901^NI08#)P01_Vn0C7P9093#L0I&ieE0Lf80I&g|3z47z0I&ey z50T>o0;)nhfKq6c|CgW_K=}ZG0FmLL|Caz901^NI08#)P01_Vn0C7P9093#L0I&ie zE0Lf80I&g|3z47z0I&c+5Ru~p0;*y>fKpeL|CgW_K=}Y50FhXu|CgW_K=}ZG0Fiy7 z|CgZOKsf*a08#)P01_Vn0C8Xf092qCK=}Y50FkAY|Caz901^NI08#)P01_Vn0C8Xe z092qCK=}Y50Fh;*|Cay&K>0I}|Caz901_Vn0C8Xd08}6VfKmbg02BZKfKnd-0CC^| z092qCK=}Y50FhXu|Cay&K=}X!K>3-a|Cb;DfKuTB0MH?bNBN>BK=~m6K>0xc0m?rB z0P#Qo092%s|CjSqL8<+F#i+moU)KLa0MXzF0QuktK=}YPK>hzi0Fl50U)KG5y{Y{J z0Fj^<0QsO30R5p40QsPU0FeR!fKuTD0IHxDK>0bO|Cb;DfKvT?!>GUmU)KG5zN!5K z0Fj^%0QsR`06Cyv0FeR!fKuTD0IHx5K>3}P|Cb;DfKvT?!l=LlU)KG5y{Y{J0Fj^% z0Qukn0MG!4NBIE&K>48;0Qms`fYQGc0QsPU0FeR!fKuTD0IHx5K>1*j|Cb;DfKuTB z0MH?bNBN=`K=~m6K>0xc0m?rB0P#Qo090#||CjxH!>GUmU)KLa0MXzF0QuktK=}YH zK>7be0Fl50U)KG5zN!5K0Fj^%0QsQ{0QsOp0FeR!fKuTD0IHx5K>1##|Cb;DfKvT? z!l=LlU)KG5zN!5K0Fj^%0QsQ{0Qmv{fKs6gK>45#K>1Ia|Cb;DfKvT?!l=LlU)KLa z0MXzF0QuktK=}YLK>7be0Fl50U)KG5zN!5K0Fj^%0QsQ{0QsOp0FeR!fKuTD0IHx5 zK>2y1|Cb;DfKvT?!l=LlU)KG5yQ%#H0Fj^%0Qukn0MG!4NBIE&K>4930Qms`fYP83 zK>6&K|CgYL0;!-6K=~<^|CgYL1F50o0Fj`h0Fkwr|Caz9021K=0MH?bNBN>BK=~m6 zK>0xc0m?rB0P#Qo08}87|CjxH#i+moU)KG5yQ%#H0Fj^%0Qukn0MG!4NBIE&K>493 z0Qms`fYP83K>7Hd|CgYL0;!;*0Ffa8fYKDB|CgYL1F4|n0Fl+0|Cizc0MJ5+NBN^C zK>0!dK>1<-0?J48`0Qms`fYP83K=}Xw zK>45-0QsS#0Fj`>0Fh9k|CgW}K>6VT0MH?bNBN>3K=~m6K>0xc0m?rB0P#Qo0950V z|CjxH#HhdnU)KG5ys7;I0Fj^%0Qukn0MG!4NBIE&K>48`0Qms`fYP83K=}X!K>45- z0QsS#0Fj`>0FgJL|CgW}K>6VT0MH?bNBN>3K=~m6K>0xc0m?rB0P#Qo094A6|CjxH z#HhdnU)KG5y{Y{J0Fm45(K=~S_|Cay&K>2?H z0PElfpBexh021>HK>7W9!>GUmU)KLa0MXzF0QuktK=}XwK=}a#0FmGaK=}ax0Qukt zK>7be0Fl50U)KLa0MXzF0QuktK=}XwK>7be0Fl50U)KG5zN!5K0Fj^%0QsN~K>4zh z|CjxH!l=LlU)KLa0MXzF0QuktK=}YDK>7be0Fl50U)KLa0MXzN0J-1~K)D|v0CAuO z08}3!0CDUA08}3g0C4~X08}3g0C5Zf08}3Y0CB(r08}3Y0CDUC08}3U0CC^~08~Q& z02Ch(0C4~W08}CX02CiE0CC_208}3^0CCI!08}3+0CAuM08}3+0CCI&08}3U02CiM z0C9i?08}410CDRC08}450C8Xi08}490C9i?08}mj02H7A0I&c65s@tb02H7A0I&c+ z5s@kY02H7A0I&dn5s@bV02H7A0I&eS5s@SS02H7A0I&c65|JSQ02H7A0I&c+5|JJN z02H7A0I&dn5|JAK02H7A0I&d{5|J1H02H7A0I&eS5|I@E02H7A0I&ey5|I)B02H7A z0I&c66Oj)902H7A0I&cc6Ojx602H7A0I&c+6Ojo302H7A0I&dn6Ojf002H7A0I&eS z6OjV|02H7A0I&cc6p{Z!0Fl50U)KG5yQ%#H0Fm=k0jZ!D0QsR40Qukn0MG!4NBIE& zK>4930Qms`fYP8BK=~6O0FfX7fKs6206C!J0FmJX0IHxDK>4JX|CgX60QsN;0g>SY z0IJ{v6RMw||CgW>K=~g80I}c)pBexh01^NkK$0H-0Pz3<092qCK=}Y50FlX||Cay& zK=})g|Ciwd0IHx9K=~g40qfwGpBexh01^NkK$0H-0P$b|08}6VfKmbg02BZKfKnd- z0CC_008{`3fYSVu|CjRv0IHzl0Fmee0IHx9K>6dN|CgcT0Fj^o0I&dn50Rn+0g>nf z0;)Nq|CgWx0g>nf6RP0@0IC2pfKo7z|CgWx0g;-Z|CgZS0FjuW|Cita0MG%nNBQ6Z z0MG!)NBQCd0jl8x0IJ{v6RLos|Cb;DfKuTB0MH?bNBN>BK=~m6K>0xc0m?rB0Pz3< z08|bD02K5C0IHw^0g;5D|Ca&)02K5C0IHzl0Fi*8|Ca&)02K5C0IJ{v6RI$l|Citc z6sq>3|Cim6|CjSqL8<+F#i+moU)KG5zN!5K0Fj^%0QsN~K=}Y50Fhjw|Cb;DfKvT? z!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K=}Y50FiQ`|Cay&K=}X!K>48yK>2Q$|Ciwd z0IHx5K=}a>0Qn#QfKvT?!l=LlU)KG5yQ%#H0Fm=k0jZ!D0QsR40Qukn0MG!4NBIE& zK>4930Qms`fYP8BK=~6O0FgidfKs6206C!J0FmJX0IHxDK=~q<|CgX60QsN;0g>SY z0IJ{v6RI7b|CgW>K=~g80I}c)pBexh01^NkK$0H-0Pz3<092qCK=}Y50Fg(b|Cay& zK>3M||Ciwd0IHx9K=~g40qfwGpBexh01^NkK$0H-0P$b|08}6VfKmbg02BZKfKnd- z0CC_008{`3fYN%B|CjRv0IHzl0Fmee0IHx9K>1;#|CgcT0Fj^o0I&d{5Rsw-0g>nf z0;;#7|CgWx0g>nf6RP0@0IC2pfKslG|CgWx0g)J>|CgZS0Ff4;|Cita0MG%nNBQ6Z z0MG!)NBQCd0jl8x0IJ{v6RQ59|Cb;DfKuTB0MH?bNBN>BK=~m6K>0xc0m?rB0Pz3< z08|bD02K5C0IHw^0g(cr|Ca&)02K5C0IHzl0FnNm|Ca&)02K5C0IJ{v6RNJ2|Citc z6smNh|Cd{k|CjSqL8<+F#i+moU)KG5zN!5K0Fj^%0QsN~K=}Y50Fm0D|Cb;DfKvT? z!l=LlU)KG5y{Y{J0Fj^<0QsO30R5p40QsPU0FmJX0IHxDK>6~a|Cb;DfKvT?!>GUm zU)KG5zN!5K0Fj^%0QsR`06Cyv0FmJX0IHx5K>4Gc|Cb;DfKvT?!l=LlU)KG5y{Y{J z0Fj^%0Qukn0MG!4NBIE&K>48;0Qms`fYQGc0QsPU0FmJX0IHx5K>7cV|Cb;DfKuTB z0MH?bNBN=`K=~m6K>0xc0m?rB0P#Qo08}E7|CjxH!>GUmU)KG5zN!5K0Fj^%0QsQ{ z0QsOp0FmJX0IHx5K>4_i|Cb;DfKvT?!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsQ{K>45# zK>2=^|Cb;DfKvT?!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsOp0FmJX0IHx5K>4?y|Cb;D zfKvT?!l=LlU)KLa0MXzF0Qnyv1J(aS0Fl50U)KLa0MXzF0Qnyv1J(aS0Fl50U)KG5 zzN!5K0Fj^%0QsN~K>5|7|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN`K=}xr z|Cb*i1J(U|!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU10QsO3K>6;M|Cb*i1J(U|!>GUm zU)KLa0MXzF0Qnyv1J(aS0Fl50U)KLa0MXzF0Qnyv1J(aS0Fl50U)KG5zN!5K0Fj^% z0QsQ{0QsN`K>44c|Cb*i1J(U|!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU10QsO3K>5*^ z|Cb*i1J(U|!>GUmU)KLa0MXzF0Qnyv1J(aS0Fl50U)KG5zN!5K0Fj^%0QsQ{0QsN` zK>1If|Cb*i1J(U|!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU10QsO3K>4|s|Cb*i1J(U| z!>GUmU)KG5zN!5K0Fj^%0QsN~K>5j;|CjxH!l=LlU)KLa0MXzF0Qunq0QukpK>7be z0Fl50U)KG5zN!5K0Fj^%0QsN~K>1Ld|Cb>EfYKV3|CjxH!l=LlU)KG5x~csG0Fm=k z0jc#{0;!-c0QsRS0QsUP0QsXM0QsaJ0QsORK>6VV0IC26fYOJb|Cb*C0P&zNK>0kJ z|CjRv0IHxXK=}!s|CjUw0IHxTK>2cy|CjXx0IHxPK>353|Cjay0IHxLK=~A(|Ci(g z0IK5y7OLU{6{_I_6sq6@6RHxA|Cb5?02D}&|CgaFK>46AK>3x8|CiLA|CjRv0IK?* z|Citc6RLcn|CjSqL848; z0Qms`fYP83K=}axK>4790Fj8J|CgW>K>6VT0I(s5NBN=`K=~m6K>0xc0m?rB0P#Qo z08~ql|CjxH!>GUmU)KLa0MXzF0QuktK=}X^K>7be0Fl50U)KLa0MXzF0QuktK=}ZG z0FnPg0Fl50U)KG5y{Y{J0Fj^<0QsR40QsU10QsO3K=~@2|Ca#(K>45-K=}ax0QsN~ zK>014|Ca#(K>45-K=}a#0Qnyv1J(U|!>GUmU)KLa0MXzF0QuktK>7be0Fl50U)KG5 zxvBjF0Fm49J0Qms`fYP8BK=~q~|CgX20QsO7 zK>4?p|CgX60Qn#QfKs5}06Cx^K=~g40P&y#092qKK>45}0Qs{QK>45_K>5&||Cize z0IH!AK>6SU6RKdC|CgZO06C!FKsg@(0C9i-092qKK>3cF|Ca**02H7fK>5R&|CgX2 z0Qu_w{}-VnK>45}0g*1F|CgZOKsg@(0C7M9092qCK>6XF|CgXI0QsR~0g<310g;`T z|Caz901_Vn0CC^|092v_0g<8O0Fj_$0g+~x|CgYLMX4D802H7j0g+ah|Ch5DK>462 zK>4$o|Cgc@K>6VV0IJ{v6RJ0u|Caz901_Vn0CC^|092v_0g<8O0Fj_$0g+Uf|CgYL zMX3h>02IF~0QsUr0g<620g<3%0g-i>|CgYLMXBNe0I))cNBN^SK>0!dK>1<-0?J7W9$Ed&qU)KLa0MXzF0QuktK=}Y*0FnPg0Fl50U)KG5zN!5K z0Fj^%0QsN~K=}XwK>6L5|Ciwd0IHx5K=}ax0QsN~K>7W9!l=LlU)KG5zN!5K0Fj^% z0QsN~K=}XwK>4|o|Ciwd0IHx5K=}ax0QsN~K>7W9!l=LlU)KG5zN!5K0Fj^%0QsN~ zK>5m;|CjxH!l=LlU)KG5y{Y{J0Fm1ah|CjRv0IHx9K=~q^ z|Ciwd0IJ{v6RL-i|Cb*i1J&~jK>7W9!>GUmU)KG5zN!5K0Fj^%0QsQ{0QsN~K>07be0Fl50U)KG5zN!5K z0Fj^%0QsN~K>4|h|Ch{_|CjxH!l=LlU)KG5zN!5K0Fj^%0QsQ{0Qmv{fYPB0K>45# zK>4ni|CjxH!l=LlU)KG5y{Y{J0Fj^%0Qukn0I&dvNBIE&K>48;0Qms`fYP9Y0Fj{& zK=}cf|CgW>K>6VT0I(s5NBN=`K=~m6K>0xc0m?rB0P#Qo0906x|CjxH!>GUmU)KG5 zy{Y{J0Fj^<0QsR40QsU10QsW}0QsU1K>48)K>45-K>0L~|CjxH!>GUmU)KG5zN!5K z0Fj^%0QsN~K>2x#|CjxH!l=LlU)KLa0MXzF0Qunq0QukpK>7be0Fl50U)KG5zN!5K z0Fj^%0QsQ{0QsQ{K>45#K>2#2|Ca!KA5#Dv022Ls!l=LlU)KLa0MXzF0QuktK>7be z0Fl50U)KLa0MXzF0Qunq0Qnyv1J(aS0Fl50U)KG5yQ%#H0Fm4620QsTA0Fj{M0Fh*x|Caz901_Vn0CC^}092qSK>3fM|CjRv0IHzl0FjWN z|Ciwd0IJ{v6RMSu|CgZS0Ff(@|CgXAK=}Y50Fj_40Qv3z{}-SqK=}#)02Jho|CgaB zK>45-K>68@|Cex_|CjRv0IHUr|Citc6RH@X|CjR%K>7W9#i+moU)KG5y{Y{J0Fj^% z0Qukn0I&dvNBIE&K>48;0Qms`fYP83K>6pE|Ciwd0IHya0FlI%|Ciwb0I(s5NBN=` zK=~m6K>0xc0m?rB0P#Qo095FW|CjxH!>GUmU)KLa0MXzF0QuktK=}X&K>7be0Fl50 zU)KLa0MXzF0QuktK=}X+K>7be0Fl50U)KG5zN!5K0Fj^%0QsN~K>7KX|CjxH!l=Ll zU)KLa0MXzF0Qunq0QukpK>7be0Fl50U)KLa0MXzF0QuktK>7be0Fl50U)KG5ys7;I z0Fm1*c|CjRv0IHxHK>6VV0IC21fYQI6|Cb*C0P$b| z094@v6RJ;<|Cb*i1J&~jK>7W9#HhdnU)KG5zN!5K0Fj^%0QsQ{0Qmv{fYPB0K>45# zK>1UP|CjxH!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU10QsO7K>4B%K>48)K>2*1|Cb*i z1J(U|!>GUmU)KG5y{Y{J0Fj^%0QsN~K>2Kp|CgW_0QsO7K=}XwK=~g40P!FJ092q4 zK>1~t|Cize0IHxDK=}XwK>6VV0IJ{v0;(U5|CgW_K=~g40Qnyv1J(U|!>GUmU)KG5 zzN!5K0Fj^%0QsN~K>6K`|CjxH!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsQ{K>45#K>6^Q z|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K>3rI|Caz9022Ls!l=LlU)KG5 zy{Y{J0Fj^%0QsN~K>0V7|CgW_0QsN~K>0X~|Cb*C0QsO7K>7W9!>GUmU)KG5y{Y{J z0Fj^<0QsR40QsU10QsO7K>4B%K>48)K>53#|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^% z0QsN~K>0JB|CgW_0QsO7K=}XwK=~g40P!FJ092q4K>1LZ|Cize0IHxDK=}XwK>6VV z0IJ{v0;=+k|CgW_K=~g40Qnyv1J(U|!>GUmU)KG5zN!5K0Fj^%0QsN~K=~k*|CjxH z!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K=~-2|Caz9022Ls!l=LlU)KG5y{Y{J0Fj^% z0QsN~K>5&_|CgW_0QsN~K=}!s|Cb*C0QsO7K>7W9!>GUmU)KG5y{Y{J0Fm3Q6|CjRv0IHxDK>0J5|Cgf^K>6YW0IJ~w6RMyWK>3EA|CjR%K>7W9 z!>GUmU)KG5y{Y{J0Fj^%0Qukn0I&dvNBIE&K>48;0Qms`fYP83K=}b60Fj`B0FmRJ z|CgW>K>6VT0I(s5NBN=`K=~m6K>0xc0m?rB0P#Qo095*n|CjxH!>GUmU)KLa0MXzF z0Qukp0V@AP0Fl50U)KG5zN!5K0Fj^%0QsN~K=}ZG0Fgb7|CjxH!l=LlU)KG5yQ%#H z0Fm=k0jZ!L0QsRC0QsU90QsX60QsOFK>3D{|CgXA0QsOBK>62<|CjRv0IHxDK>660 z|CjUw0IHx9K>2x`|Ci(g0IK5y6sqC_6RM#nK>45_K>1&a|CgXAK>71iL8<+F#i+mo zU)KG5xvBjF0Fm49J0Qms`fYPAD0Fh3W z|CgX60Qs{cK>45_K>6C1|CfIP0PElvpBexh01_Vn0C8Xh092qKK>3T9|Cb*C0P)}f z093OdK>45_K>3cC|Cay&K>3)E|Cgc{K>6VV0IJ{v6RKR9|Caz901_Vn0C8Xd08}6V zfKmbg02BZKfKnd-0C7M8093y#0QsOFK>2-`|Cize0IH!w0g<3%0g=I(|CgYLMX8bi z02HAYK>45_K>3uQ|Cf#c02H$yK>45}K>2)-|Cize0IH!EK>6SU6RJR&|Caz901_Vn z0C9i^092qOK>4620Qs{cK>45_K>5^^|Cay&K>2?H0PElvpBexh01_Vn0CAuJ092qK zK>5s+|CjRv0IHxLK>5j(|Ciwd0IHy40g>VZ0jl8x6RKE_|CgYLMX7B702H$yK>45} z0g+>w|Cay&K>1ma|Cgc{K>6VV0IJ{v6RI7V|Caz901_Vn0CAuK092qSK>5I$|Cb*C z0P)}#pBexh01_Vn0C4~T093y#0QsUL0g<6Y0g<3%0g-~4|CgYLMX6H&02HDF0g<5t z0g<3%0g*V4|CgYLMX5~y02HAYK>45_K>1Ig|CdPs02H$yK>45}K>0V2|Cgc{K>6VV z0IJ{v6RP`||Caz901_Vn0C6A(092qOK>4620Qs{cK>45_K=~h-|Cay&K>2?H0PElv zpBexh01_Vn0C7M8093y#0QsOFK=~G!|Cize0IH!w0g<3%0g+mn|CgYLMX4(Q02H$y zK>45}0g*kG|Cay&K=~Jt|Cize0IH!EK>6SU6RO*o|Caz901_Vn0CAuK092qOK>2=} z|Cb*C0P)}#pBexh01_Vn0C4~T093y#0QsT=0g<6Y0g<3%0g*tN|CgYLMX3=002HDl z0g<620g<3%0g?8N|CgYLMX3t_02HAYK>45_K=}=z|Ca{<02IF~0QsUr0g<5t0g<3% z0g0!dK>1<-0?J7W9$Ed&q zU)KG5y{Y{J0Fj^%0Qukn0I&dvNBIE&K>48;0Qms`fYP83K=}ch|Ciwd0IHya0Ff$@ z|Ciwb0I(s5NBN=`K=~m6K>0xc0m?rB0P#Qo095LW|CjxH!>GUmU)KG5x~csG0Fm=k z0jZ!L0QsRC0QsU90QsX60Qukn0I&dvNBIE&K>49B0Qms`fYP8FK=~g40P%qW092qK zK>72P|Ciwd0IHxDK=~g40qej4093OdK>45(K>4tn|CjUw0IHxDK>4+g|Cize0IJ~w z6sq6@6RLTb|Caz901_Vn0C8Xd08}6VfKmbg02BZKfKs480Xd)_K=}Y50FmPZ0IH%F zK>48)K>46QK{=0!|CgX2K=}X^K=}a#0Fj^{K=}a_0QsOp0g<5-K>3rL|CgXEK>6VT z0I(s5NBN>JK=~m6K>0xc0m?rB0P#Qo092}r|CjSqL8<+F#;CvpU)KG5zN!5K0Fj^% z0QsQ{0QsQ{K>45#K>6s7|CgZ)K>45#K>6*B|Cb*i1J(U|!l=LlU)KLa0MXzF0Qunq z0QuktK>6VVK=}ax0Qnyv1J(aS0Fl50U)KG5y{Y{J0Fj^<0QsR40QsU10QsO7K>4B% zK>48)K>3uP|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^%0QsN~K>6&E|CgW_0QsO7K=}Xw zK=~g40P!FJ092q4K=~z{|Cize0IHxDK=}XwK>6VV0IJ{v0;(H~|CgW_K=~g40Qnyv z1J(U|!>GUmU)KG5zN!5K0Fj^%0QsN~K>3A}|CjxH!l=LlU)KG5y{Y{J0Fj^<0QsR4 z0QsU10QsN~K=~Ay|Cize0IH!AK>45-K>6s9|Cb*i1J(U|!>GUmU)KG5zN!5K0Fj^% z0QsQ{0QsN~K>5d%|Caz9022Ls!l=LlU)KG5y{Y{J0Fj^%0QsN~K>5Fz|CgW_0QsN~ zK>4(h|Cb*C0QsO7K>7W9!>GUmU)KG5y{Y{J0Fj^<0QsR40QsU10QsO7K>4B%K>48) zK>351|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^%0QsN~K>6Q^|CgW_0QsO7K=}XwK=~g4 z0P!FJ092q4K>19b|Cize0IHxDK=}XwK>6VV0IJ{v0;&q0|CgW_K=~g40Qnyv1J(U| z!>GUmU)KG5zN!5K0Fj^%0QsN~K=~+%|CjxH!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU1 z0QsN~K=}up|Cize0IH!AK>45-K>6Q`|Cb*i1J(U|!>GUmU)KG5zN!5K0Fj^%0QsQ{ z0QsN~K>2Qo|Caz9022Ls!l=LlU)KG5y{Y{J0Fj^%0QsN~K>1pZ|CgW_0QsN~K>4SM z|Cb*C0QsO7K>7W9!>GUmU)KG5y{Y{J0Fj^<0QsR40QsU10QsO7K>4B%K>48)K>4Pc z|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^%0QsN~K>4Db|CgW_0QsO7K=}XwK=~g40P!FJ z092q4K>0V2|Cize0IHxDK=}XwK>6VV0IJ{v0;-XW|CgW_K=~g40Qnyv1J(U|!>GUm zU)KG5zN!5K0Fj^%0QsN~K>06@|CjxH!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K>4qT z|Caz9022Ls!l=LlU)KG5y{Y{J0Fj^%0QsN~K>6E?|CgW_0QsN~K>2u`|Cb*C0QsO7 zK>7W9!>GUmU)KG5y{Y{J0Fj^<0QsR40QsU10QsO7K>4+m|Ciwd0IHx9K=~g40qfwG zpBexh01_Vn0C7M7095sg|CgZ?K>6SU0jdD_f71W}0gC|eebXb8|CjxH!>GUmU)KLa z0MXzF0QuktK>7be0Fl50U)KG5ys7;I0Fm45-K>1sj z|Ciwd0IHzF0FmMY0jl8x0IJ{v6ROpi|Cb*i1J&~jK>7W9#HhdnU)KG5zN!5K0Fj^% z0QsN~K>2`=|CjxH!l=LlU)KG5zN!5K0Fj^%0QsN~K=}=v|CjxH!l=LlU)KG5zN!5K z0Fj^%0QsN~K>41L|Cay&K>7W9!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN`K>6VV0IC23 zfYNW8|Cb*C0P#Qo0953N|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K>0|S|Cb*C z0P)}lpBexh022Ls!l=LlU)KG5ys7;I0Fm=k0jZ!L0QsRC0QsU90QsOFK>48?K=}ax z0QsOFK=}XwK>70n0IHxLK>2-<|CjUw0IHxDK>3=U|Cize0IJ~w6sq6@6RJ*||Cb*i z1J(0WL8<+F#HhdnU)KG5y{Y{J0Fm70n0IHxDK>2Br|Ciwd z0IJ{v6RNV9|Cb*i1J&~jK>7W9!>GUmU)KLa0MXzF0QuktK=}Y50FnPg0Fl50U)KG5 zy{Y{J0Fm2~0|Cay&K>70n0IHx9K>2-{|Cay&K>1(-0LuXU zM3eIiK>7W9!>GUmU)KLa0MXzF0QuktK>7be0Fl50U)KG5ys7;I0Fm1aV|CjRv0IHxHK>1RS|Cgf^K>4B6VV0IJ{v6RIJI|CjR% zK>7W9#HhdnU)KG5ys7;I0Fm321|CjRv0IHxHK>2@} z|Cgc{K>6VV0IJ{v6RLBV|CjR%K>7W9#HhdnU)KG5ys7;I0Fm1*p|CjRv0IHxHK>1ym|Cgc{K>6VV0IJ{v6RItm|Cb*i1J&~jK>7W9#Hhdn zU)KG5y{Y{J0Fj^<0QsR40QsU10QsW}0QsU1K>48)K>45-K>34{|CjxH!>GUmU)KG5 zx~csG0Fm49B0Qms`fYP8JK>6sA|CjRv z0IHxLK>78U|CeC`0L!2oK>0ra0PEl0+B|CgX2K>6yJ z|CjRv0IHxLK>6pG|CgXA0QsTA0Fj_00g;!M|Cay&K>1(-0E?h20QsOFK>6O7|Ciwd z0IHxXK=~g40qf%c092qKK>5g#|Ciwd0IHxXK=~g40qcnX092qKK>5Ov|Ca&)02H7r zK>6VT0FWVwNBN>JK=~m6K>0xc0m?rB0P#Qo092HT|CjR%K>7W9#;CvpU)KG5zN!5K z0Fj^%0QsQ{0QsN`K=~g40P&yz092q4K>48yK>2%_|Ca&)02BZKfYSYY!l=LlU)KG5 zys7;I0Fm6Z||CjRv0IHxHK>6Q_|Cgf^K>4B< zK>6VV0IJ{v6RM7f|CjR%K>7W9#HhdnU)KG5y{Y{J0Fj^<0QsR40QsU10QsR4K>45- zK>06~|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^<0QsR40QsU10QsO3K=~g40P&yz092qC zK>4B%K>48)K>5Ip|Cb*i1J(U|!>GUmU)KG5y{Y{J0Fj^<0QsR40QsU10QsR0K>45( zK>4Ma|Cb*i1J(U|!>GUmU)KG5zN!5K0Fj^%0QsO}0FkAW|Cay&K>7W9!l=LlU)KG5 zzN!5K0Fj^%0QsO}0Fg7W9!l=LlU)KG5ys7;I0Fj^<0QsR40QsU10QtZF z06C%$K>48)K>45-K>5&)|CjxH#HhdnU)KG5zN!5K0Fj^%0QsQ{0QsRq0Fj_$0Fn2P z|Caz901_Vn0C4~T092r30FlO<|CgDZ|Ca!g|CgX+0Fj=I|CjXt{}&%11J(U|!l=Ll zU)KLa0MXzF0QuktK>7be0Fl50U)KG5ys7;I0Fj^<0QsR40QsU10QtZF06C%$K>48) zK>45-K>7cN|CjxH#HhdnU)KG5yQ%#H0Fm4620QsRG zK>45>K>0ra0PBDO092qSK>2f=|Cga3K=~Dt|CgX2K=}Y50Fj^{0QsONK=}Y50Fj_4 z0QvI&{}-SqK=}#)02IrK|CgaBK>45-K>5Il|Cd*n|CjRv0IGeN|Citc6RQ83|CjR% zK>7W9#i+moU)KG5zN!5K0Fj^%0QsN~K>7QH|Cb>EfYN!J|CjxH!l=LlU)KG5yQ%#H z0Fm=k0jc#90QsON0QsRK0QsUH0QsXE0QsOJK>6VV0IC2AfYQ^L|Cb*C0P&zFK>6r} z|CjRv0IHxPK=}=m|CjUw0IHxLK>5y&|CjXx0IHxHK>62}|Ci$f0IK2x6{_I_6sq6@ z6RKW~|Cb5?02G*s|Cga7K>462K=~P)|Cc0}|CjRv0IEuv|Citc6ROOb|CjSqL87W9#i+moU)KG5y{Y{J0Fj^%0Qukn0FVHPNBIE&K>48;0Qms`fYP83K=}a-K>479 z0FmgE|CgW>K>6VT0FWVwNBN=`K=~m6K>0xc0m?rB0P#Qo092cZ|CjxH!>GUmU)KG5 zzN!5K0Fj^%0QsN~K=}XwK>4?k|Ciwd0IHx5K=}ax0QsN~K>7W9!l=LlU)KG5zN!5K z0Fj^%0QsN~K>56d|CjxH!l=LlU)KG5y{Y{J0Fm3%J|CjRv z0IHx9K>2i=|Ciwd0IJ{v6RKH_|Cb*i1J&~jK>7W9!>GUmU)KG5zN!5K0Fj^%0QsQ{ z0QsN~K>3H3|Cb^FfYPB0K>0w0|Cb*i1J(U|!l=LlU)KLa0MXzF0QuktK=}Y50FnPg z0Fl50U)KG5y{Y{J0Fj^%0Qukn0FVHPNBIE&K>48;0Qms`fYP83K=}a-K>4790Ff_@ z|CgW>K>6VT0FWVwNBN=`K=~m6K>0xc0m?rB0P#Qo08~zh|CjxH!>GUmU)KLa0MXzF z0Qunq0QuktK=}axK>6SUK=}XwK>0ra0PElvpBexh022R00Fl50U)KG5zN!5K0Fj^% z0QsN~K=}XwK>1#g|Ciwd0IHx5K=}ax0QsN~K>7W9!l=LlU)KG5y{Y{J0Fm45(K>6>9|Ciwd0IJ{v6RI$b|CjR%K>7W9!>GUmU)KG5x~csG z0Fm=k0jZ!L0QsRC0QsU90QsYX06E|R0FVHPNBIE&K>49B0Qms`fYKBIfKs6!K>45> zK>0ra0PCRv092p@0g*PE|CclXfKs3X0g>SY0IHxDK=~b$|Caz901_Vn0C8Xd08}#o zfKmbg02C7dfKs0V0C8Xd092p@0g<6T^ z|Caz901_Vn0CC^|092tLK>45>K>0ra0PA1?08}6VfKmbg02BZKfKnd-0C9i-091eg z0Pp}{6p45_K>1RS|CgXA0QsU9K=}axfYP8RK>59!|CgXE0QsORK>3o2 z|Cgd0K>48`K=~Jt|CgaBK>466K>6T`|CgXEK>3P_|Ciwb0FWVwNBN>JK=~m6K>0xc z0m?rB0P#Qo094Y4|CjSqL8<+F#;CvpU)KLa0MXzF0QuktK>7be0Fl50U)KG5zN!5K z0Fj^%0QsQ{0QsQ{K>45#K>1UZ|Cb*i1J(U|!l=LlU)KG5y{Y{J0Fj^<0QsR40QsU1 z0QsU1K>48)K>45-K>0_C|Cb*i1J(U|!>GUmU)KG5zN!5K0Fj^%0QsN~K>16T|Cb*i z1J(U|!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K=}XwK=~g40P%nU092q4K=}gzK>45# zK=}XwK=}XwK=}ZG0FeR!K>48yK>6SU1FAp(Kh^>O02BZKfYSYY!l=LlU)KLa0MXzF z0QuktK>7be0Fl50U)KG5x2gRD0Fm=k0jc#{0;!-c0QsRq0Xd>40QsXM0QsaJ0Qukn z0FVHPNBIE&K>49Z0Qms`fYP8ZK=~g40QsPU0g<62K>7Ze|CgYH0g<8O0g>nf0jk=J z|CgZS0g;S||CgXU0QsOJK>2Bn|Ciwd0IHy)0g*bH|ChC+0g<2|K>2Hy|Cjay0IIY* zK>6VV6siCPfYNT4|CjRv0IGii0P&yz094`w7OLR`6{_F^6RHcA|CgYn0g(xf|CgXI zK>49NK=}ax0QsQf0g(X!fYM`#|CgZS0g+XP|CgYH0g(@l|Cb*i1J%F*0Pp~aNBN;g zK=}XwK=~j50LmW#0P%nV08|nH02K8D0IJ~w6sq6@6RPH#|CjRv6{?`40g>;F|Ca&) z02K2B0IHzl0g*q3|Ca&)02K2B0IHya0g?BN|Citc6RK62|Cc<6|CjSqL8022h|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~ zK>1dc|Cb-U199LNpBexh01_Vn0CAuJ092q4K>1IV|Cb-^0&(F0092q4K>16R|Cb;9 z0&!sg08}6VfKmnk02BZKfKmhi02H7PK=~7e|Cb;DfKvT?!l=LlU)KG5ys7;I0Fm48`0Qms`fYP8BK=}X+K=}a#0Fj^0QsO7K=}YrKsg@(0C9i-092qCK=~g~067Z)02H7XK>2i)|Cize z0IEO$K=}axK>6SU0;(VYKi1&`04kstK=}a>0J)$SK=~68K)I=q|CfIP0Bhg}pBexh z01^NkK$0H-0P)}lpBexh01_Vn0C9i;092qCK=~8E0Fj^3K=~m6K>0xc0m?rB0P#Qo093e!|CjR% zK>7W9#HhdnU)KG5ys7;I0Fj^<0QsR40QsU10QsXA0J)$SK=}X=K)In4K=~m6Ksg@( z0c$`3092p=0MG(}1(ARN0MG#-4UvEV0MGy+6_Miu0;45#K>0ra0PA7{092qCK>5&=|Cize04kvqK>45_K=~j50E++sKsjFk0Bhg}pBexh z01^NkK$0H-0P)}lpBexh01_Vn0CC^|092qCK>2|H0MH>o50L>V0QtZHfKmnk02H7f zK=}X!0Fj^{0Quwp{}-SaK)L;U#HhdnU)KG5wyFIC0Fm=k0jc#{0;%_71F89I1gZOT z1*xD%0QsOtK>5#+|CgXgK=}X=K)D}?0C7M8092p=0MG)U36X#R0MG#-4UvEV0MG!S z6_Miu0;<9tfKuv+|CgXgK>3`M|Cay+01+S5198Yr092s>0PrD@9FZVcV7Orb01zO^ zAd3J1AJ(8pK>2|H0MH@e6_Eib0QtZHfKqk>02F`#fKqe<02H7{K>3N3|Cb+_0dZgj z08}5C0dcGW08}5m0CC_008}5m0C9`}08}4{0C8Xf08|D602Ci^0dar=08}4{0dYVB z08{}102Cj{0dZgi08}5y0db4~08}5i0dZgh095(_02Ck40dW8X08}5;0dYVC095q= z02Dz4fKs4GK>2cp|Cjdw02F}>fKs4GK>2Ql|CjRs02JW`fKs4GK>2Eh|CjFo02BcM zfKs4GK>22d|Cj3k02F}%fKs4GK>1>Z|Ci?g02Dz1fKs4GK>1#V|Ci$c02HACfKs4G zK>1pR|CiqY02CnsfKs4GK>1dN|CieU02H7{K>53v|CgYf0J)%>K)Ilo0J)%>K)D|T z05RYfpBexh01^NkK$0H-0P)}e092qyK>2|H0MH?T7Lfrc0QtZHfKns^02HB{K)K-m zno>Ui0Bh|D092uyK)K+5n^Hdj0BdXs092qyK>0D0|Cb+d0de3LpBexh01^NkK$0H- z0P$b}092qyK=~<@|Cb-s0de3LpBexh01^NkK$0H-0P$b|08}6VfKmbg02BZKfKnd- z0C4~Y092qyK>3WA|CgYj0J)%_K)D|T05RYfpBexh01^NkK$0H-0P)}e092qyK>2|H z0MH?T7Lfrc0QtZHfKvAX02HC0K)K+5n^Hdj0BhjapBexh01^NkK$0H-0P#Qq092u$ zK)K-mn^Hdj0BhjKpBexh01^NkK$0H-0P#Qp092rxK)C@_7E_>~K)E3R01E(sgi-*M zzj7b|01Kd(0J$Ro02H7{K>2|H0MH>|7m)!d0QtZHfKu2202H7{K>2|H0MH>|7m)!d z0QtZHfKt){02HB{K)K+5n^Hdj0BhjapBexh01^NkK$0H-0P)}f092uyK)K-mn^Hdj z0BhjKpBexh01^NkK$0H-0P)}e092qyK>2|H0MH?z7?A-e0QtZHfKt2x02H8?K)D|P z0CB4T092uuK)K-kzY;$H0BcPF092p=0MG)U36X#R0MG#-4UvEV0MG!y8Ij`y0;<9+ zfKm^L|CgYbK)E0M0dcGV092uuK)IktK>5Xm|CdSt02H8?K)E0MA92h9092rtK)C>X z22%h88ZzMn04ktIK>53c|CgYbK)C=E01^NI88YDm04ktIK>4+W|Cc%d02HB@K)K-m zpHe>n0BfuQ092rtK)C>X3{wCI8#3Vo04ktIK>4bL|CgYbK)C>X22%hO01^NI88YDm z04ktIK>4GE|CgYbK)C=E01^NI88YDm04ktIK>3}8|Cb^F02H8?K)C>X5>o&S95Uep z04ktIK>3!1|CgYbK)C>X3{wCU01^NI88YDm04ktIK>3e_|CgYbK)C>X22%hO01^NI z88YDm04ktIK>3J;|CgYbK)C=E01^NI88YDm04ktIK>31&|Ca{<02H7{K>2|H0MH?T z8j%4g0QtZHfKprm02EpQ02H7{K>2|H0MH>|8<7Dh0QtZHfKpWf02H7{K>2|H0MH?z z9FYMi0QtZHfKpEZ02H7{K>2|H0MH@e9gzVj0QtZHfKo{T02H7{K>2|H0MH>IACUnl z0QtZHfKo#N02H7{K>2|H0MH>|Advwm0QtZHfKojH02H7{K>2|H0MH?zA&~(n0QtZH zfKoRB02H7{K>2|H0MH@eB9Q?o0QtZHfKo9502H7{K>2|H0MH>IB#{9q0QtZHfKn>~ z02H7{K>2|H0MH>|C6NIr0QtZHfKnv^02H7{K>2|H0MH?zCXoRs0QtZHfKnd;02H7{ zK>2|H0MH@eCy@at0QtZHfKnL&02H7{K>2|H0MH>IDUksv0QtZHfKn3y02H7{K>2|H z0MH>oDv<#w0QtZHfKm+s02H7{K>2|H0MH?TE0F;x0QtZHfKmqm02H7{K>2|H0MH@8 zERg{y0QtZHfKmYg02H7{K>2|H0MH@eEs+5z0QtZHfKvMa02H7{K>2|H0MH=-FOdN# z0QtZHfKv4U02H7{K>2|H0MH>oFp&W$0QtZHfKu-O02H7{K>2|H0MH?TF_8f%0QtZH zfKurI02H7{K>2|H0MH@8GLZo&0QtZHfKuZC02H7{K>2|H0MH=-G?4))0QtZHfKuH6 z02H7{K>2|H0MH>oHIV@*0QtZHfKt~002H7{K>2|H0MH?THjx1+0QtZHfKt%_02H7{ zK>2|H0MH@8H<1A-0QtZHfKtl<02H7{K>2|H0MH=-IgtS<0QtZHfKtT(02H7{K>2|H z0MH>oI*|b=0QtZHfKtBz02H7{K>2|H0MH>|JCOk>0QtZHfKs^t02H7{K>2|H0MH?z zJdpt?0QtZHfKsyn02H7{K>2|H0MH@eJ&^$@0QtZHfKsgh02H7{K>2|H0MH=-Kal|_ z0QtZHfKsOb02H7{K>2|H0PrCo0FePG0QtZHfKs6V02H7{K>2|H0PrC|0g(YH0QtZH zfKr4+V|Cf{i02H7A0FVGcEs>xz0Qo=wfYP8h0QsQ{ zMya4jK>0Y9|Caz901^NI08#)P01^NkK$0H-0P)}lpBexh01_Vn0CB($093#MfKq}0 z02H7A0FVG+Es>x*0QrCbfYP8p0QsQ{N2#DkK=~z>|Caz901^NI08#)P01^NkK$0H- z0P)}lpBexh01_Vn0CAuU093#MfKqP&02H7A0FWD?Es>l6fYRXu8>-?19IBv4K=~7v z|Caz901^NI08#)P01^NkK$0H-0P)}lpBexh01_Vn0CAuS093#MfKpum02H7A0FW8r zEs>f4fYRXu8LHv~8mgd2K=}cd|Caz901^NI08#)P01^NkK$0H-0P)}lpBexh01_Vn z0CAuQ093#MfKp2U02H7A0FW0TE|J&(fYRXu7pmd|7^6>L|Caz901^NI08#)P z01^NkK$0H-0P)}lpBexh01_Vn0CAuO093#MfKoXC02H7A0FV`cE|Jy%fYRXu6{_L` z7OJ2}K>6L3|Caz901^NI08#)P01^NkK$0H-0P)}lpBexh01_Vn0CAuM093#MfKn#_ z02H7A0FV>lE|Js#fYRXu6RP3^6sn*{K>5p+|Caz901^NI08#)P01^NkK$0H-0P)}l zpBexh01_Vn0CAuK093#MfKn9z02H7{K>2|H0PrDT0+9hI0QtZHfKm?t02Ch}1J#H9 z{}&%11J#B7{}&%11J#55{}&%11J!~3{}&%11J!^1{}&%11J!-~{}&%11J!%|{}=O9 zL8|M5+68MXCLJ%Ba8tU)KG5x~csG0Fm49B0Qms`fYP8BK=~?<|CgWufKs480J)$SK=}X=K)D~l0CB(q08}5q0C9`}08}5e z0CAuI08||S02CkO0C8*s08|tJ02H7XK=}X=K)K-q04kstK>7QF|Cb*i1J%F)fKs48 z0J)$SK>6;G|Cb-Y0C9i=08|zL02H7XK=}X=K)K-q04kstK>6;2|Cc8K02H7XK=}X= zK)K-q04kstK>6r{|CcrZ02H7A0MG&e5RrfY0MG#-4UvEV0MG!S43Xml0;(c%fKnoc z|Cb-Y0C5Wf08}630CCI#08|G602H7XK=}X=K)K-q04kstK>5^z|CbE_02H7XK=}X= zK)K-q04kstK>5yt|Cby902H7XK>2|H0PrCI1CaqJ0QtZHfKnv^02H7XK>59q|Cb*W z0dar<08}580dYV908}5i0C7M7092X)02H7XK=}Z`K{??A04kstK>4|Y|Cc8K02H7X zK=}X=K)K-q04kstK>4$S|Cdbw02H7XK>4VV|Cb-+0CCI!08}5q0C6e-08}5i0CAuJ z091tl02Ch-0dW8V08}580dc?q091eg02H7XK=}X=K)K-q04kstK>448|CjCm{}-Sa zK=}Z`K{??A04kstK>3-2|Ca{<02H7XK=}X=K)K-q04kstK>3q{|CcQQ02JT=fKs48 z0J)$SK>3D||Ca#308t+#0CDI5092qCK=}X=K)K-q04kstK>3D)|Ca{<02H7XK>2|H z0MH@81CaqJ0QtZHfKuH602H7XK>2l%|Cb*W0dW8V08}3o0dcGV08{|L08t+#0CDIE z08|7302CjT0dW8U08~o=02H7XK=}X=K)K-q04kstK>2Nh|CjFn{}-SaK=}X=K)K-q z04kstK>25b|Cb*i1J&RFfKs480J)$SK>1pc|Cb-M0C7M808}5e0C9`}08}5W0CB(o z08|$M02Bbg08t+#0C9){08|YC02H7XK=}X=K)K-q04kstK>1RG|Cb*i1J$4xK>0_J z|Ca#308t+#0C9){08|YC02H7XK=}X=K)K-q04kstK>0?4|CbX002H7XK>2|H0MH?T z1d#zK0QtZHfKr_R02H7XK=}X=K)K-q04kstK>0d@|Ca{<02H7XK>2|H0MH?T1(5+L z0QtZHfKrhF02H7XK=~<=|Ca#308t+#0C6Y*092qCK=}X=K)K-q04kstK=~6!{|Chfb0Qnt{|Cb*C0J)$)K)D|j0CAxO092qCK=}Y5 z0g<|m|Ci$f0IHw^0g*xhfKuTD0IJ{v1FB?_|CgXE0QsO7K=}Y50g0ra0P8>j092p=0I&i85RrfY0I&fd4UvEV0MGzn29e_f z0;&R$fKo$+|CjoX|Cay&K)D|P0C7PF092qCK>497K=}bM0QsO7K=}YLK>497K>0ra z0P8^p092p=fKpEY02H70ra z0P8>j092p=0I&i85RrfY0I&fd4UvEV0MGzn29e_f0;&R&fKn8N|Ch^-|Cay&K)D|P z0C8af092qCK>493K=}bI0QsO7K=}YHK>493K>0ra0PA4@093#LfKng;02H7XK=~7( z0g<2=K=}Y50g+ve|Ciwd0IHw^0g>VZ0IJ{v6RO04|CgW_K=}Y50g+XW|CjRv0IHxD zK=}Y50g>^N|CeC`0E?g_K>0ra0P8>j092p=0I&i85RrfY0I&fd4UvEV0MGzn29e_f z0;(dFfKup$|CitZfKtH$0MH?bNBN>JK=~m6K>0xc0m?rB0P#Qo090Fo|CjR%K>7W9 z#;CvpU)KG5y{Y{J0Fj^<0QsR40QsU10QsU1K>48)K>45-K>4GQ|Cb*i1J(U|!>GUm zU)KLa0MXzF0Qunq0Qnyv1J(aS0Fl50U)KG5zN!5K0Fj^%0QsN~K>2Zl|Cb*i1J(U| z!l=LlU)KG5zN!5K0Fj^%0QsN~K>0O*|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~ zK=}X=K=~g40P)}e092q4K=}X=K=}Y50MR3X|CazD0FeR!02BZKfYSYY!l=LlU)KG5 zwW<9B0Fm49p0Qms`fYP8J zK=~60K>45_K>5*r|CfIP0PElfpBexh01_Vn0C7MA092qKK=}Yb0Ffa8fYOYW|CgYL z2&tq;K>4LhK>45_K=}Yb0FeR!K=}g%K>45-K>48?K>3!4|CgYL2dSW=0FlRt|CgYL z38|oC0+FGgKsg_U|CgX2K=}Yb0Ffw$|Cdw%02F`#0MGzH2a)0f0IDGXfYP8JK>3N4 z|CgXA0QsOFK>493K=~nr|CgXE0QsORK>6Z;|Ciwd0IHy40g(a#fKvW{|CgX2K=}ZX z|CgYL2dSas0g<310+B3@|Cgbo0Fj_$0+A_=|CgmNK>4IIK>4FjK>4CmK>49ZK>46c zK>6ka1ghi%0;=Kz0IHxLK>4nN|CgYL2C1N<0g(X!fKsZ4|CgYL2&teW0+Ex5|CgYL z38|oC0+FGgKsoD#|CgX2K>4YT|CgYL38|zvK>4LRK>4CiK>4FnK>45-K>48?K>0n7 z|CgYL2&teSK>1dZ|CgXAK>6T~|Ca#pebb>UK=~m60E?g>K=}a>0QsOFK>6VV0IHy4 z0g(a#K=~p70Qmq2K)E0Y0J)$aK=}Yb0FmJX0IHxP0+9j$K=~p70Qmq2K)E0Y0J$F^ z1J%F*0MG!4NBN;wK=}XwK=~j50LmW#0P#Qo092cS|CjR%K>7W9%c#HuU)KMF0MXzF z0QuktK=}Yb0FeL$K&jvd0jU81fYRX$K=}XwfYRU(K>6YW0jlEz0IJ{v0;=Hy1FHXn z0Fl50U)KG5zN!5K0Fj^%0QsN~K>0U+|Cb*i1J(U|!l=LlU)KG5y{Y{J0Fj^<0QsR4 z0QsU10QsO3K=~g40P&yz092qCK>4B%K>48)K>2Ww|Cb*i1J(U|!>GUmU)KG5zN!5K z0Fj^%0QsQ{0QsQ{K>45#K=~?@|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsN~K>448`0Qms`fYP83K=}Xw zK=~g40P)}i092q4K=}=R|Ciwd0IHx5K=}XwK=~j50LuXULzAEr0QsX2K>45#K=}a> zK>45(K=}ahebe9r0Lvf%0E?m%K>6VV0IJ{v1FA%i|CgYn0Ffet|CgW-K=}Yb0FmJX z0IHy)0FeR!K=~p70Qmq2K)E0Y0J)$KK=}bc0Fj^%K=~p7K=}dy0Qn&ZK)C@30J)$K zK=~gK0Qnyv1J%F*0MG!4NBN;2K=}XwK=~j50LmW#0P#Qo08}J_|CjxH#HhdnU)KLa z0MXzF0QuktK=}X!K>6VV0IJ{zK=}XwK=~j50LuXULzDkQ0Fl50U)KG5yQ%#H0Fm=k z0jc#{0;!-U0QsRu0J)+M0Xd@|0QsONK>7K9|Caz901_Vn0C7M7090Xt|CgXAK=~64 zK>4&MK>45(0g)(`|CjXx0IHx50g+9G|Cjay0IHxLK>418|Ci$f0IK2x7OLR`6{_F^ z6slkXKh^*o021?4L87be0Fl50U)KG5xT*aE z0Fm=k0jZ!L0QsRC0QsW706D+`0MG!4NBIE&K>49R0Qms`fYP8JK=}ZG0FmL3|Caz9 z01^NI08#)P01_Vn0C7P9092p=0I&jp6_J1d0I&g|3z2{T0I&c+5Ru~p0;+;UfKpe3 z|CgX2K=}ZG0Fm^Q|CgYL2C1N<0g)kp|Caz901^NI08#)P01_Vn0C6Az093z20Xe@f z0QsV00g<6Y0g<4i0g)zv|Ch7VMyc)q02H7bK=~Su|Ca#(Kslge0g<1C|CgY@Ksg@( z0CC{~092qKK=~5@0+FB}K=}Y50FhUV|Ciwd04ktk0g>Ya0IH$@fKuQC6RMqw|Caz9 z01_Vn0C8Xd08}6VfKmbg02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b z0QsUr0g<6M0g<4i0g?ZI|Ch7VMybUB02H7fK=}Y50Fics|Caz901_Vn0C6A#092qK zK=~5@K>46!0g-!z|Ciwd0IHy)0g)ts|CgYn0g>SY0IJ{v6RJd#|CgYn0g+~e|Cb;D zfKs400Xd)_K=}XwK>4660QsUr0g<6M0g<4i0g(}f|Ch7VMyaO&02H7fK=}Y50FfY( z|Cay&K=~g40P)}#pBexh01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g=#u|Ch7V zMyZwn02H7fK=}Y50Fe)o|Cay&K>6K$|Caz901_Vn0C7PA092qKK=}Y50Feig|Cay& zK>5Xj|Caz901_Vn0C7P9092p=0I&jp6_J1d0I&g|3z2{T0MG!y2a)3g0;=LjfKt_h z|CgX2K=}Y50Fm~P|Cay&K>5Ud|Caz901_Vn0C7MA092qKK=}Y50FmyH|Cay&K=~5{ zK>46!0g*0*|Ciwd0IJ{v6RIPC|Cb;DfKs400Xd)_K=}Y50FmO5|Cay&K=}X!K=~(u z|CgXE0QsUr0g<6M0g<4i0g=Xp|Ch7VMyXr?02H7fK=}Y50Fl*@|Cay&K>3q`|Caz9 z01_Vn0C7P9092p=0I&jp6_J1d0I&g|3z2{T0MG!y2$ACh0;(cPfKsD^|CgX2K=}Y5 z0g)V!|Caz901^NI08#)P01_Vn0C7P9092p=0I&jp6_J1d0I&g|3z2{T0MGzH36bLi z0;*z4fKrlz|CgX2K=}Y50g*40|CgYL2C1N<0g+sO|CgXY0Xd)_K=}Y50g<$i|CgXY zK{)^b08#)P01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g+vQ|Ch7VMyVqJ02H7f zK=}YTK=~g40P#Tq092p=0I&jp6_J1d0I&g|3z2{T0MG!y36bLi0;+;bfKqOP|CgX2 zK=~6mK>46!0g=*!|Ciwd0IHy)0g-!t|CgYn0g>SY0IJ{v6RMk$|CgYn0g=6f|Cb;D zfKs4C0Xd)_K=}f|0g<6Y0g<4i0g(!S|Ch7VMya4<0g0!dK>1<-0?JrU)KG5zN!5K0Fj^%0QsQ{0QsN~K=}a#K>45#K=}X&K>0ra0PDa3092z7 zK>45#K=}X!K>4BzK>6VV0IJ{v1FE}x|CgW-K=}X!K=}b60Fj^%K=}a#0Qm<102H7P zK>7cR|Cgc*K>6VV0IHx5K>1IM|Cb*i1J(U|!l=LlU)KG5ys7;I0Fj^%0QtZH0MG!4 zNBIE&K>48`0Qms`fYP83K>6;A|CgW_0QsP!0Ffa8fYK_7|CgW}0QsQ90FfJk|Chl5 z0MH?bNBN>3K=~m6K>0xc0m?rB0P#Qo091#6|CjxH#HhdnU)KG5zN!5K0Fj^%0QsN~ zK=}XwKsg@-0CC^|08}3c0C6D!092q4K=}X!K>3}A|Ca{<02H7PK=}X!K>0m=|Ca** z02H7PK>6m8|CjxH!l=LlU)KG5ys7;I0Fj^%0QtZH0I&dvNBIE&K>48`0Qms`fYP83 zK>3D+|CgW_0QsN~K=~tp|CgW}0QsTA0Fj`h0Ff7o|Caz90209g0I(s5NBN>3K=~m6 zK>0xc0m?rB0P#Qo0900g|CjxH#HhdnU)KG5zN!5K0Fj^%0QsN~K=}X!K=}b60MVci zK=}a#0QsU1K>45#K=}X!K>6VV0IJ{v0;*Dm|Cb*i1J(U|!l=LlU)KG5ys7;I0Fm48`0Qms`fYPBCK>6SU6RI|Y|Citc6RPxl|Cb*i z1J&RI6RN=h0I(s5NBN>3K=~m6K>0xc0m?rB0P#Qo08}b}|CjR%K>7W9#HhdnU)KLa z0MXzF0Qunq0QukpK=}axK>6SYK=}ax0QuktK=}b60FmGWK=}Y50FmMY0jlEz0IFaF zK&e0k0I6UIK>0uj0Qnyv1J(aS0Fl50U)KG5ys7;I0Fm48`0Qms`fYPBCK>6SU6RHM-|Citc6RLcS|Cb*i1J&RI6RN=h0I(s5NBN>3 zK=~m6K>0xc0m?rB0P#Qo095*Z|CjR%K>7W9#HhdnU)KG5zN!5K0Fj^%0QsQ{0QsQ{ zK>45#K>1{T|Caz901^NI08#)P022Ls!l=LlU)KG5zN!5K0Fj^%0QsN~K=}XwK=~g4 z0P#Tq092p=0FVNpJduC^0I&f73Xy;S0I&cc3z6dk0;*yqfKp$9|CgW-K=}XwK=}Xw zKsg@-0C9i-08}3c0CC^|08|SA02H7PK=}Y50Ffa8fKoGn|Cb5?02H7PK=}Yb0Ffa8 zfKvX2|Ca>-02H7PK=}Y*0FmZ}|Cb*i1J$4pK>7W9!l=LlU)KG5yQ%#H0Fm=k0jZ!D z0QtZH0I&dvNBIE&K>4930Qms`fYP8BK=}XwK=~g40P#Tq092p=0FVOUIFWz=0I&f7 z3Xy;S0I&cc3z6dk0;<9vfKo7l|CgW_K=}XwK=}XwKsg@-0C9i-08}3c0CB(r08}^t z02H7XK=~6O0Fj^1>e|CgX60QsN;0g>SY0IJ{v6RKg1|Caz901_Vn z0C7P9092p=0FVOUIFWz=0I&f73Xy;S0I&dn3z6dk0;+-_fKm~G|CgW_K=}Y50FkPP z|CazD0Fguh02H7XK=~6u0Fj^0R)|CgX60QsN;0g>SY0IJ{v6RI_a z|Caz901_Vn0C7P9092p=0FVOUIFWz=0I&f73Xy;S0I&dH43Xml0;)nGfKv5<|CgW_ zK=}Yb0Fma6|CcEM02H7XK=}Y*0Fe%o|Caz901^NkK$0H-0P)}lpBexh01_Vn0C9i- z092qCK=}XwK=~X102BZOfYM5U|CjRv0IHzl0Fi%?|CgfU0Fi(I0I&f-4UwP&0g=Lp z|CgWx0g>nf6RP0@0II+mfKuUw|CgWx0g>yC|CgZS0FeQR|Chi40I&gsNBO`30I&dn zNBQCd0jl8x0IJ{v6ROdV|Chl50I(s5NBN>BK=~m6K>0xc0m?rB0P(;908|VB02K5C z0IHw^0g={?|Ca&)02K5C0IHzl0Fmm4|Citc6RL!R|Citc6sk&)|Ccd-|CjSqL8<+F z#i+moU)KG5yQ%#H0Fm=k0jcu?2&$kL0QsR40QtZH0I&dvNBIE&K>4930Qms`fYP87 zK=}XwK>48;K>0ra0PElfpBexh01^NkK$0H-0P%nW08{`3fYJnj|CjRv0IHzl0FgP6 z|CgfU0Fi(I0I&g|4UwP&0g-%&|CgWx0g>nf6RP0@0IEP4fKr=<|CgWx0g4hW|CgW_ zK=}XwKsg@>0C4~c08}3c0C9)_08}3Y0C9i_08~~002Ch_0C9*4092q8K=}Y*0FjcB z|Caz901^NI08#)P01^NkK$0H-0P)}lpBexh01_Vn0C9i=08{`3fYQ%@|CjRv0IHzl z0FeZc|CgfU0Fi(I0I&f-4w0Y(0g*?D|CgWx0g>nf6RP0@0IHxFfKq0K|CgWx0g-Tx z|CgZS0Fj1=|Chi40I&gsNBO`30I&dnNBQCd0jl8x0IJ{v6RK8^|CgW_K=~+=|Caz9 z01_Vn0C4~U092p@0g-Qv|CgW_K=}a#K>45p0g;!6|CgW_K=}a#K>45p0g)mAfYRoH z|CgW_K=~g80QsN;0g>8*|CgW_K=~g406Cx+K>13D|Cc%d02H7XK=}d$K>45(K=}a# zK>6SU0;>Cb|Ce9}0QoWi02H7XK=~8|K>45(K=}bc0Fj^r0g<6SU6sqiy z|CeA20Qn~X02BZOfYOM6|CjRv0IHxDK>5**|CjUw0IHzF0Fknf0;<1{|CgWx0g>nf6RP0@0IFanfKsx8 z|CgWx0g)h$|CgZS0FfSz|CgY{0Fg9@|Chi40I&g=NBO`30I&dLNBQCd0jl8x0IJ{v z6RHG{|Cb*i1J&RI6RN=h0I(s5NBN>BK=~m6K>0xc0m?rB0Pz3?08}Ob02K5C0IHw^ z0g(rd|Ca&)02K5C0IHzl0FfJq|Citc6RNd>|Citc6smiV|CjUw0IHw^0g?QS|Ca&) z02K5C0IHzl0Fe-f|Citc6RN6$|Citc6smBK|CjUw0IHw^0g>^H|Ca&)02K5C0IHzl z0FmvC|Ca&)02K5C0IHzF0FeQQ|Citc6RMkn|Citc6slp5|CdO8|CjSqL8<+F#i+mo zU)KG5zN!5K0Fj^%0QsQ{0QsN~K=~g406Cx!K=~g80QsN`K>0(1|Ciwd0IHx5K>5Uh z|CgW-K>5yx|Cb*i1J(U|!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K>48yK>6&3|Cb*i z1J(U|!l=LlU)KG5zN!5K0Fj^%0QsQ{0QsN~K>48yK>1#a|Cb*i1J(U|!l=LlU)KLa z0MXzF0Qunq0QuktK>6VVK=}ax0Qnyv1J(aS0Fl50U)KG5x~csG0Fm49B0Qms`fYPB8K>45-K>789|CgX60QsO7K>5mv|CgXE0QsRq z0g<2s0g-->|Caz901_Vn0CAxK092qCK>5vu|CgWx0g=0j|Ciwd0IHxP0g>VZ0ji-B zK>4PL|Caz901_Vn0C8Xd08}6VfKmbg02BZKfKnd-0C8Xf093OVK>48q0g<3X0g+aG z|CgX60g<5-K>3S%|CgfU0Fj|10g+$;0Pp~S7m?%x0;=N!0jlBy0IH!YK>6SU6RM4U z|CgX60QsN;0g;-C|CazD0Fl7~0I(s5NBN>JK=~m6K>0xc0m?rB0P#Qo094U@|CjR% zK>7W9#;CvpU)KG5zN!5K0Fj^%0QsN~K=}X!K=}bc0MVciK=}a#0QsU1K>45#K=}X! zK>6VV0IJ{v0;)WV|Cb*i1J(U|!l=LlU)KLa0MXzF0QuktK>7be0Fl50U)KG5xT*aE z0Fm=k0jZ!L0QsRC0QsW706D+`0I&dvNBIE&K>49R0Qms`fYP8JK=}ZG0FkPT|Caz9 z01^NI08#)P01_Vn0C7P9092p=0FVN}7?FSg0FVKo3z2{T0FVGc5Ru~p0;+;UfKniT z|CgX2K=}ZG0Fk|q|CgYL2C1N<0g>u@|Caz901^NI08#)P01_Vn0C6Az093z20Xe@f z0QsV00g<6Y0g<4i0g>-}|Ch7VMyc)q02H7bK>0&{|Ciwd0IHy40g)Jb|CgY@Ksg@( z0CC{~092qKK=~5@0+FB}K=}Y50FfYv|Ciwd04ktk0g>Ya0IH$@fKuQC6RKu~|Caz9 z01_Vn0C8Xd08}6VfKmbg02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b z0QsUr0g<6M0g<4i0g=di|Ch7VMybUB02H7fK=}Y50Fgg`|Caz901_Vn0C6A#092qK zK=~5@K>46!0g*(2|Ciwd0IHy)0g>%`|CgYn0g>SY0IJ{v6RHi4|CgYn0g*3&|Cb;D zfKs400Xd)_K=}XwK>4660QsUr0g<6M0g<4i0g>8(|Ch7VMyaO&02H7fK=}Y50Fmj8 z|Cay&K=~g40P)}#pBexh01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g;(||Ch7V zMyZwn02H7fK=}Y50Fl^?|Cay&K>4P5|Caz901_Vn0C7PA092qKK=}Y50Fls)|Cay& zK>3b-|Caz901_Vn0C7P9092p=0FVN}7?FSg0FVKo3z2{T0I&eS2a)3g0;=LjfKr}* z|CgX2K=}Y50Fl3p|Cay&K>3Y%|Caz901_Vn0C7MA092qKK=}Y50Fk$h|Cay&K=~5{ zK>46!0g?BA|Ciwd0IJ{v6RPZc|Cb;DfKs400Xd)_K=}Y50FkSV|Cay&K=}X!K>6@| z|CgXE0QsUr0g<6M0g<4i0g;b@|Ch7VMyXr?02H7fK=}Y50Fj=I|Cay&K>1vL|Caz9 z01_Vn0C7P9092p=0FVN}7?FSg0FVKo3z2{T0I&eS2$ACh0;(cPfKqIJ|CgX2K=}Y5 z0g>g3|Caz901^NI08#)P01_Vn0C7P9092p=0FVN}7?FSg0FVKo3z2{T0I&c+36bLi z0;*z4fKpq2|CgX2K=}Y50g?EQ|CgYL2C1N<0g)wo|CgXY0Xd)_K=}Y50g-)+|CgXY zK{)^b08#)P01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g)zq|Ch7VMyVqJ02H7f zK=}YTK=~g40P#Tq092p=0FVN}7?FSg0FVKo3z2{T0I&eS36bLi0;+;bfKoSp|CgX2 zK=~6mK>46!0g;=3|Ciwd0IHy)0g*&{|CgYn0g>SY0IJ{v6RKp5|CgYn0g;A(|Cb;D zfKs4C0Xd)_K=}f|0g<6Y0g<4i0g=;s|Ch7VMya4<0g-%v|Citc6RP0@6sp1j0I))c zNBN^aK>0!dK>1<-0?JrU)KLa0MXzF0QuktK>7be0Fl50U)KG5xT*aE0Fm=k0jZ!L0QsRC0QsW7 z06D+`0I&dvNBIE&K>49R0Qms`fYP8JK=}ZG0Ficz|Caz901^NI08#)P01_Vn0C7P9 z091eg0Pq6f9+6-G0Pq2z3z1*|0Pp}n5Ru~p0;+;UfKu#z|CgX2K=}ZG0FjA~|CgYL z2C1N<0g<+O|Caz901^NI08#)P01_Vn0C6Az093z20Xe@f0QsV00g<6Y0g<4i0g=0U z|Ch7VMyc)q02H7bK>34+|Ciwd0IHy40g>2@|CgY@Ksg@(0CC{~092qKK=~5@0+FB} zK=}Y50Fms4|Ciwd04ktk0g>Ya0IH$@fKuQC6RI+V|Caz901_Vn0C8Xd08}6VfKmbg z02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g;q? z|Ch7VMybUB02H7fK=}Y50FeuR|Caz901_Vn0C6A#092qKK=~5@K>46!0g(`Y|Ciwd z0IHy)0g<_R|CgYn0g>SY0IJ{v6RO#a|CgYn0g?ND|Cb;DfKs400Xd)_K=}XwK>466 z0QsUr0g<6M0g<4i0g0Xe@b0QsUr0g<6M0g<4i0g+{T|Ch7VMyZwn02H7fK=}Y50Fk7N z|Cay&K>2cb|Caz901_Vn0C7PA092qKK=}Y50Fj)F|Cay&K>1pI|Caz901_Vn0C7P9 z091eg0Pq6f9+6-G0Pq2z3z2{T0FVH{2a)3g0;=LjfKqCG|CgX2K=}Y50FjG}|Cay& zK>1mC|Caz901_Vn0C7MA092qKK=}Y50Fi@>|Cay&K=~5{K>46!0g=Og|Ciwd0IJ{v z6RNm+|Cb;DfKs400Xd)_K=}Y50Fif#|Cay&K=}X!K>56T|CgXE0QsUr0g<6M0g<4i z0g+pO|Ch7VMyXr?02H7fK=}Y50Fi2o|Cay&K=~+r|Caz901_Vn0C7P9091eg0Pq6f z9+6-G0Pq2z3z2{T0FVH{2$ACh0;(cPfKoVp|CgX2K=}Y50g@||CgXY0Xd)_K=}Y50g*|H|CgXYK{)^b08#)P01_Vn0C6Az z093y>0Xe@b0QsUr0g<6M0g<4i0g>`~|Ch7VMyVqJ02H7fK=}YTK=~g40P#Tq091eg z0Pq6f9+6-G0Pq2z3z2{T0FVH{36bLi0;+;bfKmf}|CgX2K=~6mK>46!0g-2Z|Ciwd z0IHy)0g(`S|CgYn0g>SY0IJ{v6RI$b|CgYn0g+OE|Cb;DfKs4C0Xd)_K=}f|0g<6Y z0g<4i0g<11|Ch7VMya4<0g*_4|Citc6RP0@6sp1j0FXk6NBN^aK>0!dK>1<-0?JrU)KG5xT*aE z0Fm=k0jZ!L0QsRC0QsW706D+`0FVHPNBIE&K>49R0Qms`fYP8JK=}ZG0Fg(D|Caz9 z01^NI08#)P01_Vn0C7P9091eg0Pq69856e|Ca#(K>46!0g=sm|CgY@Ksg@( z0CC{~092qKK=~5@0+FB}K=}Y50Fk|f|Ciwd04ktk0g>Ya0IH$@fKuQC6RHD)|Caz9 z01_Vn0C8Xd08}6VfKmbg02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b z0QsUr0g<6M0g<4i0g+{S|Ch7VMybUB02H7fK=}Y50Fm5$|Caz901_Vn0C6A#092qK zK=~5@K>46!0g>T-|Ciwd0IHy)0g;M$|CgYn0g>SY0IJ{v6RN6<|CgYn0g=po|Cb;D zfKs400Xd)_K=}XwK>4660QsUr0g<6M0g<4i0g-op|Ch7VMyaO&02H7fK=}Y50Fj1@ z|Cay&K=~g40P)}#pBexh01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g*O&|Ch7V zMyZwn02H7fK=}Y50FiZy|Cay&K>0&=|Caz901_Vn0C7PA092qKK=}Y50FiBq|Cay& zK=~_t|Caz901_Vn0C7P9091eg0Pq69846!0g;q_|Ciwd0IJ{v6RL@M|Cb;DfKs400Xd)_K=}Y50Fg+F|Cay&K=}X!K>3Y& z|CgXE0QsUr0g<6M0g<4i0g)_z|Ch7VMyXr?02H7fK=}Y50FgV2|Cay&K>7K5|Caz9 z01_Vn0C7P9091eg0Pq6980Xe@b0QsUr0g<6M0g<4i0g=Oa|Ch7VMyVqJ02H7f zK=}YTK=~g40P#Tq091eg0Pq69846!0g*U;|Ciwd0IHy)0g>T%|CgYn0g>SY0IJ{v6RH7=|CgYn0g)qp|Cb;D zfKs4C0Xd)_K=}f|0g<6Y0g<4i0g-Tc|Ch7VMya4<0g)Mf|Citc6RP0@6sp1j0FXk6 zNBN^aK>0!dK>1<-0?JrU)KLa0MXzF0QuktK>7be0Fl50U)KG5xT*aE0Fm=k0jZ!L0QsRC0QsW7 z06D+`0FVHPNBIE&K>49R0Qms`fYP8JK=}ZG0Fe`j|Caz901^NI08#)P01_Vn0C7P9 z091eg0Pq69A(3DJ0Pq2z3z1*|0Pp}n5Ru~p0;+;UfKrKj|CgX2K=}ZG0Ffq)|CgYL z2C1N<0g+R8|Caz901^NI08#)P01_Vn0C6Az093z20Xe@f0QsV00g<6Y0g<4i0g+gE z|Ch7VMyc)q02H7bK>56Q|Ciwd0IHy40g)+p|CgY@Ksg@(0CC{~092qKK=~5@0+FB} zK=}Y50FjA<|Ciwd04ktk0g>Ya0IH$@fKuQC6ROXF|Caz901_Vn0C8Xd08}6VfKmbg z02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g*9y z|Ch7VMybUB02H7fK=}Y50FkJB|Caz901_Vn0C6A#092qKK=~5@K>46!0gSY0IJ{v6RLKK|CgYn0g;$||Cb;DfKs400Xd)_K=}XwK>466 z0QsUr0g<6M0g<4i0g*#}|Ch7VMyaO&02H7fK=}Y50FhFO|Cay&K=~g40P)}#pBexh z01_Vn0C6Az093y>0Xe@b0QsUr0g<6M0g<4i0g(cD|Ch7VMyZwn02H7fK=}Y50Fgn7 z|Cay&K=}`L|Caz901_Vn0C7PA092qKK=}Y50FgO~|Cay&K>7E2|Caz901_Vn0C7P9 z091eg0Pq69A(3DJ0Pq2z3z2{T0FVH{2a)3g0;=LjfKms0|CgX2K=}Y50Ffw(|Cay& zK>7A{|Caz901_Vn0C7MA092qKK=}Y50FfYx|Cay&K=~5{K>46!0g+&Q|Ciwd0IJ{v z6RK5s|Cb;DfKs400Xd)_K=}Y50Fe}l|Cay&K=}X!K>1mD|CgXE0QsUr0g<6M0g<4i z0g?E8|Ch7VMyXr?02H7fK=}Y50FeiY|Cay&K>5Xb|Caz901_Vn0C7P9091eg0Pq69 zA(3DJ0Pq2z3z2{T0FVH{2$ACh0;(cPfKt_Z|CgX2K=}Y50g+CJ|Caz901^NI08#)P z01_Vn0C7P9091eg0Pq69A(3DJ0Pq2z3z2{T0FVGc36bLi0;*z4fKtSI|CgX2K=}Y5 z0g+*g|CgYL2C1N<0g;Y&|CgXY0Xd)_K=}Y50g>j1|CgXYK{)^b08#)P01_Vn0C6Az z093y>0Xe@b0QsUr0g<6M0g<4i0g;b)|Ch7VMyVqJ02H7fK=}YTK=~g40P#Tq091eg z0Pq69A(3DJ0Pq2z3z2{T0FVH{36bLi0;+;bfKs4(|CgX2K=~6mK>46!0g(iJ|Ciwd z0IHy)0gSY0IJ{v6RORL|CgYn0g>-}|Cb;DfKs4C0Xd)_K=}f|0g<6Y z0g<4i0g*g+|Ch7VMya4<0g>f<|Citc6RP0@6sp1j0FXk6NBN^aK>0!dK>1<-0?J2y|Citc6RHl1|CjZ5|CjSqL8<+F$f&>rU)KG5xT*aE z0Fm=k0jZ!L0QsRC0QsW706D+`0FVHPNBIE&K>49R0Qms`fYP8JK=}ZG0FmT||Caz9 z01^NI08#)P01_Vn0C7P9091eg0Pq69B#~eM0Pq2z3z1*|0Pp}n5Ru~p0;+;UfKpm| z|CgX2K=}ZG0Fn2K|CgYL2C1N<0g)tj|Caz901^NI08#)P01_Vn0C6Az093z20Xe@f z0QsV00g<6Y0g<4i0g)+p|Ch7VMyc)q02H7bK>5ji|Ciwd0IHy40g)Dm|CgY@Ksg@( z0CC{~092qKK=~5@0+FB}K=}Y50FhdP|Ciwd04ktk0g>Ya0IH$@fKuQC6RMzq|Caz9 z01_Vn0C8Xd08}6VfKmbg02BZKfKs440Xd*MK{)^b08#)P01_Vn0C6Az093y>0Xe@b z0QsUr0g<6M0g<4i0g(cC|Ch7VMybUB02H7fK=}Y50Film|Caz901_Vn0C6A#092qK zK=~5@K>46!0g--t|Ciwd0IHy)0g)$m|CgYn0g>SY0IJ{v6RJmv|CgYn0g-8Y|Cb;D zfKs400Xd)_K=}XwK>4660QsUr0g<6M0g<4i0g)7Z|Ch7VMyaO&02H7fK=}Y50Ffhz z|Cay&K=~g40Pz3-fd7Bs7oQpc8~_p@0040y0RU9LHvu`nD**YTLjjSYHvy5LqXCiA zcK?^N(?+S5000!AA3*s4AOMjPi2s)W06_WRbpMwC8~_p@004180svH?A3*s4AOMjH zi2s)W06_W3dH;008g+zz31z0|Khz zNPtqkB6D**YTLjjSYHvy5LqXCi0d;gcS(?+RW000!AA3*s4AOMlrhyRxV06_Vc zdH;008g+zzC7!0|KfdN`O+PdH;008g+ zKnaoK0|KgIN`O+8dH;008g+zzLD#0|KgoOMp^w zdHi2s+y zcK?_2Q$eZyd&sE317FtvLjcj>2LSot2SEA%LjaM$17Fttd$_6n0|1fpQvs=<9{~BG z8vyyDzW_O)0RZp-h)4MW06_VnKLGgw0D#h;007VcKoF7R0|KgoM1WEzdHA3*sN z00NPqA3*s4AOMjjf&Z7`0{|+ZV*!!l0|2U`0Dw~90~4xjfB%;N8~_p@0041d002}V z0Dw{g000yK0Dw}UI{`VMJ3%=B002?|8~_p@0040y0RU9LHvu`nD**YTLjjSYHvy5L zqXCi5b^n*M(?+Sq000!AA3*s4AOMj?dHk9G8~_p@ z004180RU8h007Ve04R}Q007VdpbL>;008g+zz31z0|KhzNPtqLc>kB6A3*s4AOMlY zhX0oU06_VZbN`nB8~_p@004170{~Q@A3*s4AOMlQhX0oU06_T@1VH(qV*!!k9G8~_p@004180RU8h z007Ve04R}Q007VdpbL>;008g+zzC7!0|KfdN`O*wc>kB6A3*s4AOVr;008g+KnaoK0|KgIN`O*fc>kB6 zA3*s4AOVs7i2s+MhX$#jqXCgCbpMy2KLI(QA3*s4AOVqsh5whJKS4PF002?|8~_p@ z0040y0RU9LHvu`nD**YTLjjSYHvy5LqXCgDb^n*M(?+Qy000!AA3*s4I6(Oy008kp z0RU8h007Ve04R}Q007VdpbL>;008g+zzLD#0|KgoOMp^6c>kB6A3*sNI6(QJV*!z& zdH2LSou0|5Ep13>u!06_WR2SE7&008+PAOqF^LjaM$17FtvLjcj> z2LSot2SEA%LjaM$17FtvLjcj>2LSot2SEA%LjaM$17Fttd%LOq0|1fp3jq0`7XbO8 z69D<30RZp-h)4MW06_VnCjj{Y0D#h<7eM&{AOMjIc>k9G8~_p@0040y0svH?7eM(F z06_Vm6F~WZg8!ER06;mQ;{cHbdHkB67eM&{ z06_U*000!A7eM&{AOMlQh5wfT06_VRa{reA8~_p@004180svH?7eM&{AOMlIh5wfT z06_V3cmJ0F8~_p@004180RU8h008g;AO?|O007VdpbL>;008g+zz31z0|KgIC4f?c zcmJ257eM&{AOMl1h5wfT06_V2a{reA8~_p@004170svH?7eM&{AOMk^h5wfT06_T@ z1VH(q6F~V)g8!G{0|2Vv0~4ybasQW~7eM&{AOMk)h5wfT06_Tw1VH)Mb^n(x000!A z7eM&{AOMkzh5wfT06_UkcmJ0F8~_p@004180RU8h008g;AO?|O007VdpbL>;008g+ zzzC7!0|KgICV)~|cmJ257eM&{5J34K008kp0RU8h008g;AO?|O007VdpbL>;008g+ zzzLD#0|KgoCV)~*cmJ257eM(F5J35$6F~VOg8!ER06;mQ;{cJRc>kB6;{cK20|2Vv z0~4xwhX0qK;{cJHc>kB67eM&{5J35%0RZqJh)4ONCqVfj06_Uc00GKB008ko00306 zbpMz03qbk(d&Q{017FtvLjcj>2LSot2SEA%LjaM$17Fttd%mgt0|1er4*>b03jq0` z3qbi-c>kB-0|2U^4?y`GcmJ0kAOqF?d%~!|17Fttd%LOq0|1fp3jq0`7XbO869D<3 z0RZp-h)4MW06_VnCjj{Y0D#h<7eM&{AOMkYcmJ0F8~_p@0040y0svH?7eM(F06_Vm z6F~VzcK?^*0|2U^;{cHwa{rg0;{cK20|2Vv0~4w~hX0qK;{cIhc>kB67eM&{06_U* z000!A7eM&{AOMjfh5wfT06_WhasQV98~_p@004180svH?7eM&{AOMjXh5wfT06_WJ zcK??E8~_p@004180RU8h008g;;0Tdm007VdpbL>;008g+zz31z0|KgIC4f@scK?^4 z7eM&{AOMjGh5wfT06_WIasQV98~_p@004170svH?7eM&{AOMj8h5wfT06_T@1VH(q z6F~V9cK?^*0|2Vv0~4xdh5whJ7eM&{AOMl~g#VWS06_Tw1VH&bb^n(x000!A7eM&{ zAOMl@g#VWS06_V!cK??E8~_p@004180RU8h008g;;0Tdm007VdpbL>;008g+zzC7! z0|KgICV*1DcK?^47eM&{5J34K008kp0RU8h008g;;0Tdm007VdpbL>;008g+zzLD# z0|KgoCV*10cK?^47eM(F5J35$6F~Xpb^n*)0|2U^;{cJmasQW~;{cK20|2Vv0~4y= zh5whJ;{cHWc>kB67eM&{5J35%0RZqJh)4ONCqVfj06_Uc00GKB008ko002}LbpMz0 z3qbk(d&Q{017Fttd%LOq0|1fp3jq0`7XbO869D<30RZp-h)4MW06_VnCjj{Y0D#h< z7eM&{AOMl(cK??E8~_p@0040y0svH?7eM(F06_Vm6F~Vdf&Z7`0|2U^;{cI_h5whJ z;{cK20|2Vv0~4yWh5whJ;{cJ?cmJ257eM&{06_U*000!A7eM&{AOMk=g#VWS06_U> zasQV98~_p@004180svH?7eM&{AOMk&g#VWS06_UpcK??E8~_p@004180RU8h008g; z01lC0007VdpbL>;008g+zz31z0|KgIC4f?1cK?^47eM&{AOMkng#VWS06_UoasQV9 z8~_p@004170svH?7eM&{AOMkfg#VWS06_T@1VH(q6F~X;008g+zzC7!0|KgICV)~jcK?^47eM&{5J34K z008kp0RU8h008g;01lC0007VdpbL>;008g+zzLD#0|KgoCV)~WcK?^47eM(F5J35$ z6F~XTfd7}_0|2U^;{cH)h5whJ;{cK20|2Vv0~4xLh5whJ;{cI%cmJ257eM&{5J35% z0RZqJh)4ONCqVfj06_Uc00GKB008ko002~sbN`p~3qbk(d&Q{017Fttd%LOq0|1fp z3jq0`7XbO869D<30RZp-h)4MW06_VnCjj{Y0D#h<7eM&{AOMkEcK??E8~_p@0040y z0svH?7eM(F06_Vm6F~V5fd7{P06_Vm;{cH!bpMy2;{cK20|2Vv0~4w$h5whJ;{cIN zcmJ257eM&{06_U*000!A7eM&{AOMjLg#VWS06_WNaQ~M88~_p@004180svH?7eM&{ zAOMjDg#VWS06_V~b^n(D8~_p@004180RU8h007VeU<;98006K7pbL>;007Vczz31z z0|KgIC4f@Yb^n*37eM&{AOMl|ga4NR06_V}aQ~M88~_p@004170svH?7eM&{AOMl= zga4NR06_T@1VH(q6F~XdfB%=^0|2Vv0~4y|cK?^47eM&{AOMl$ga4NR06_Tw1VH&H zbpMww000!A7eM&{AOMlvga4NR06_Vgb^n(D8~_p@004180RU8h007VeU<;98006K7 zpbL>;007VczzC7!0|KgICV*0^b^n*37eM&{5J34K008kp0RU8h007VeU<;98006K7 zpbL>;007VczzLD#0|KgoCV*0%b^n*37eM(F5J35$6F~W`fB%;O06_Vm;{cJqbN`p1 z;{cK20|2Vv0~4ysg#VYI;{cKDcK?^47eM&{5J35%0RYe;h)4ONCqVfj06_Uc00GKB z008ko002}1bN`p~3qbk(d&Q{017Fttd%LOq0|1fp3jq0`7XbO869D<30RYedh)4MW z06_VnCjj{Y0D#h<7eM&{AOMllb^n(D8~_p@0040y0svH?7eM(F06_Vm6F~X5a{rg% z0|2U^;{cH)asQW~;{cK20|2Vv0~4yCg#VYI;{cJucK?^47eM&{06_U*000!A7eM&{ zAOMksga4NR06_UtaQ~M88~_p@004180svH?7eM&{AOMkkga4NR06_UVb^n(D8~_p@ z004180RU8h007VeU=WdD006K7pbL>;007Vczz31z0|KgIC4f>&b^n*37eM&{AOMkT zga4NR06_UUaQ~M88~_p@004170svH?7eM&{AOMkLga4NR06_T@1VH(q6F~Wca{rg% z0|2Vv0~4yWbpMy27eM&{AOMkBga4NR06_Tw1VH(obN`nv000!A7eM&{AOMk4ga4NR z06_T=b^n(D8~_p@004180RU8h007VeU=WdD006K7pbL>;007VczzC7!0|KgICV)~P zb^n*37eM&{5J34K008kp0RU8h007VeU=WdD006K7pbL>;007VczzLD#0|KgoCV)~C zb^n*37eM(F5J35$6F~V_a{rg%0|2U^;{cJwaQ~N};{cK20|2Vv0~4x1g#VYI;{cIj zcK?^47eM&{5J35%0RYe;h)4ONCqVfj06_Uc00GKB008ko002~Ya{rg}3qbk(d&Q{0 z17Fttd%LOq0|1fp3jq0`7XbO869D<30RYedh)4MW06_VnCjj{Y0D#h<7eM&{AOMj_ zb^n(D8~_p@0040y0svH?7eM(F06_Vm6F~WCc>kB-0|2U^;{cJif&Z7F;{cK20|2Vv z0~4wig#VYI;{cI3cK?^47eM&{06_U*000!A7eM&{AOMm2g8!EQ06_W3Z~vD78~_p@ z004180svH?7eM&{AOMl_g8!EQ06_V$bpMwC8~_p@004180RU8h007Ve;1ZEw006K7 zpbL>;007Vczz31z0|KgIC4f@EbpMy27eM&{AOMl!g8!EQ06_V#Z~vD78~_p@00417 z0svH?7eM&{AOMlsg8!EQ06_T@1VH(q6F~Vjc>kB-0|2Vv0~4x}hX0qK7eM&{AOMli zg8!EQ06_Tw1VH%|bN`nv000!A7eM&{AOMlbg8!EQ06_VMbpMwC8~_p@004180RU8h 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 z0000%4j`Qbo&!M*9Yo&U3?Bdh000yK003|n00010{r@lk0000%4iHKX001BW004*< z000001mj{r@xo000EXuK)l+4j`Qb zo&!M*9ZKHa3?Bdh000yK007h%001~v{r?mI0000%4iG~Q001Na008V4001;r{r{W* z0000%4ltbto&`Y-9YK=>lmlbl-P69YT``ln0dt0z%&1)zj1r9{?Z#001Z%003NA z{r^}10000%4ltbto&`Y-9aG-j3?Bdh001BW002xG0059!{r_A50000%4ltbto&`Y- z9aP@k3?Bdh001Na003|q0078X{r^M&0000%4ltbto&`Y-9YK=>P2Szp3?Bdh000yK z005X70087z{r@Nc0000%4iHEV000yK006KV008t@{r?yM0000%4iH2R001BW0077t z008t@{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001BW008V6008t@{r?;Q0000%4j`Qb zo&!M*9Yo&U3?Bdh000yK000mg008V*{r@lk0000%4iHKX001BW001Z&000D8{r?~U z0000%4j`Qbo&!M*9Yx;V3?Bdh000yK002xH00014{r?mI0000%4iG~Q001BW003kf z008`0{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh000yK004*@000PC{r?mI0000%4iG~Q z001Na004v&000D8{r@lk000E<0000EbtN;K(4p5y6o(Vw>9YK=_lm`NQ-rdvG3?Bdh001BW008(J007)t{r{)| z0000%4ltbto&`Y-9Rg?G-3%W9000yK000~t003ZI{r@BY0000%4iHBU000yK001-_ z003-U{r@BY0000%4iHBU001BW002xI004Mg{r_YD0000%4j`Qbo&!M*9ai4m3?Bdh z001li002}J006jL{r^A$000C|tN;K(4q%-Oo(n+@9YK={lnDZi-rdvG3?Bdh001Na z005vH0078d{r_YD0000%4nUmmx3?Bdh000mG0077v000DE{r?C6 z00000000mG007(@008)2{r?C600000001Ze008hC008V>{r?aH0000%4p5y6o(Vw> z9YT``ln0dt0>9qf)zj1r9{>~p000~u007Wo{r@lk0000%4iHKX000yK001-`008J= z{r?mI0000%4iG~Q000yK002xJ0087+{r?mI0000%4iG~Q001Na003kh007`&{r^k= z0000%4nUm^ zB%UKd4IM#~B75H5(+nQ~001BW006ig007it{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh z001BW007(^007Wp{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001Na0086_007Kl{r@xo z000E~ssI2%4j`Qbo&!M*9ZKHa3?Bdh000yK001Z*007ux{r@Nc0000%4iHEV000yK z002N8008J>{r?mI0000%4iG~Q001Na003AW0087-{r^k=0000%4ltbto&`Y-9YK=> zlmk!R-P6~p004j;000PM{r?mI0000%4iG~Q001Na005XB000DI{r@-s0000% z4ltbto&`Y-9YK=>O5WYm3?Bdh001Na006)p000zY{r^w^0000%4nUm^$4j`Qbo&!M*9Z}xh3?Bdh000yK007(` z004|*{r?mI0000%4iG~Q001BW008tJ004+%{r@Zg0000%4ltbto&`Y-9Z25Y3?Bdh z001BW000;t0059<{r`{v0000%4j`Qbo&!M*9bw+x3?Bdh001BW002B6008`B{r_A5 z0000%4j`Qbo&!M*9aP@k3?Bdh001BW003Yg001;({r?~U0000%4j`Qbo&!M*9Yx;V z3?Bdh001BW004v^001y#{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001Na005{T001mx z{r`9X0000%4nUmVBX!+3?Bdh001Ze0068R005|F{r{K%000C=rvLy!4nUmlmk%S-P6008i8{r}tm0000%4p5y6o(Vw> z9YK=_bKc$43?Bdh001BW008_U005+I{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW z001B&007)={r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001Na002ZH007)={r@Nc0000% z4ltbto&`Y-9YK=>M&8}i3?Bdh001BW003+v007)={r?~U0000%4j`Qbo&!M*9Yx;V z3?Bdh000yK00598007u+{r@xo0000%4j@Yo000yK005{W008uD{r@Nc0000%4iHEV z000yK006)u000DT{r?mI0000%4iG~Q000yK007t`0001P{r?mI0000%4iG~Q000yK z008hJ008`L{r?mI0000%4iG~Q001li008V8008)H{r@BZ000Dkr2qgy4uAoj5S|Y~ z4IM#~4wMZ7Mc&=h)C?a0001BW001~6008W6{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh z000yK003Mg008K2{r?mI0000%4iG~Q000yK0049&0087}{r?mI0000%4iG~Q001BW z004|5007`_{r_M90000%4ltbto&`Y-9aY}l3?Bdh000yK006Kf0010s{r?yM0000% z4iH2R001BW0077%0010s{r@-s0000%4ltbto&`Y-9ZTNb3?Bdh001li007V&001y= z{r^w`000ELqyPXx4se|go((|_9YK=}lnVlo-rdvG3?Bdh001BW000~$002;N{r@-s z0000%4ltbto&`Y-9ZTNb3?Bdh001li001N%003lh{r^w`000D!qyPXx4se|go((|_ z9YK=}lnVlo-rdvG3?Bdh001BW003|#004w@{r_YD0000%4nUmP2Szp3?Bdh001Na007`5001C#{r}tm0000%4p5y6o(Vw> z9YK=_bKc$43?Bdh001BW000Oj007i<{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW z001l{000bi{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001Na002-W000Pe{r_YD0000% z4nUmmx3?Bdh000yK004L;002aF{r?mI0000%4iG~Q001BW0059B z002OB{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001Ze005XC002C7{r^+|000C-qW}Ow z4nUm{r?mI0000%4iG~Q z001Na001;5004Y-{r}tm0000%4p5y6o(Vw>9YK=_bKc$43?Bdh001BW003Mj001y{ z{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW004j{003xq{r?~U0000%4j`Qbo&!M* z9Yx;V3?Bdh000yK005*W003lm{r?mI0000%4iG~Q001Na006uu003Zi{r{W*0000% z4ltbto&`Y-9YK=>lmlbl-P6{r^A!0000%4j`Qbo&!M*9ZlZd z3?Bdh001li008VC008iI{r~6z000F0p#T6u4p5y6o(Vw>9YK=_lm`NK-rdvG3?Bdh z000yK001~A005|X{r@BY0000%4iHBU001Na002-Y006Xj{r@}w0000%4ltbto&`Y- z9YK=>OWxhn3?Bdh001Na004L=0078%{r@}w0000%4ltbto&`Y-9YK=>OWxhn3?Bdh z001BW005vT007*0{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW006`%008KC{r@Nc z0000%4j`Qbo&!M*9Y@~X3?Bdh001Ze007J&008WG{r@-s000Cup#T6u4ltbto&`Y- z9YK=>O5WYm3?Bdh001Na000yy008)S{r@ll0000%4q%-Oo(n+@9YK={0!ZH7(+nQ~ z000yK002BF0001b{r{){0000%4iIP#001BW002}d005AB{r@lk0000%4j`Qbo&!M* z9ZBBZ3?Bdh001BW004L>005kN{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW005jQ z005|Z{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh000yK006)!006Xl{r@BY0000%4iHBU z000yK007u1006*x{r@BY0000%4iHBU000yK008hP007K-{r@BY0000%4iHBU000yK z000On007u}{r@BY0000%4iHBU000yK001B<0088A{r@Zg0000%4iHHW001BW001~C z008)U{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001BW003Mm008iM{r@lk0000%4j`Qb zo&!M*9ZBBZ3?Bdh001Ze003kn008`Y{r?yN000D_p8x9YK=_0z%&1 z(+nQ~001BW0068h008KF{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW007V_001C- z{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW008tU001m}{r|K80000%4p5y6o(Vw> z9ctd)3?Bdh000yK000;&006vv{r@Nc0000%4iHEV001Ze000yt007K<{r`jj000C7 zp8x~p003Mn001O?{r?yM0000%4iH2R001BW z0049<001O?{r@Zg0000%4j`Qbo&!M*9Z25Y3?Bdh001BW005XO001m~{r@}w0000% z4ltbto&`Y-9ZcTc3?Bdh001BW006uy002aN{r_A50000%4ltbto&`Y-9aP@k3?Bdh z000yK007`B004Y_{r@Zg0000%4iHHW001Ze007)0005AE{r`jj000C_o&W$r4p5y6 zo(Vw>9YK=_UEbZ(3?Bdh001Na001N_008KH{r^Y+0000%4nUm;~0000%4se|go((|_9YK=}lnZ>`-P6P2Szp3?Bdh000yK003Yv005+c{r@Nc0000%4iHEV000yK004L{006Xs{r?yM z0000%4iH2R001BW0059K006Xs{r_wL0000%4nUmcHZ673?Bdh001BW000~> z007W}{r@xo0000%4j`Qbo&!M*9ZKHa3?Bdh001BW002NQ007{E{r?~U0000%4j`Qb zo&!M*9Yx;V3?Bdh001Na002lR007*A{r^k=000Czng9Sn4j`Qbo&!M*9Z=rg3?Bdh z000yK004|H0001k{r?mI0000%4iG~Q001BW005*f008`g{r@Zg0000%4ltbto&`Y- z9Z25Y3?Bdh001Ze0068g000Do{r>;~000EpnE(Jm4nUmlmk%S-P6~p003|>001UEbZ(3?Bdh z001BW001m8003B<{r^k=0000%4j`Qbo&!M*9Z=rg3?Bdh001BW002-i004lS{r@}w z0000%4j`Qbo&!M*9ZcTc3?Bdh001BW0049`005Yq{r@}w0000%4j`Qbo&!M*9ZcTc z3?Bdh001BW005XV006L?{r@}w0000%4j`Qbo&!M*9ZcTc3?Bdh001BW006u(0079F z{r@}w0000%4j`Qbo&!M*9ZcTc3?Bdh001li006`)007{d{r_+R000D%nE(Jm4nUm< zo(Dk<9YK=@lm!Bq-rdvG3?Bdh000yK000m&001DK{r?yM0000%4iH2R001BW001a5 z001DK{r^+|0000%4j`Qbo&!M*9a7%i3?Bdh000yK002xf002;){r@BY0000%4iHBU z001BW003k%003N`{r^+|0000%4ltbto&`Y-9a7%i3?Bdh001Ze003+&004}h{r_kZ z000CgnE(Jm4&VWu9G)9N4IM#~8UvOD-rds-9{?->005XP0079a{r_+R000CZng9Sn z4nUm9YK=_aNgb13?Bdh001BW0077|007Lh z{r_A50000%4ltbto&`Y-9aP@k3?Bdh000yK008VX000EE{r@BY0000%4iHBU001Na z000Cv000oQ{r^Y+0000%4ltbto&`Y-9YK=>PTt+q3?Bdh000yK001mC001zw{r?mI z0000%4iG~Q001Na002Za001ns{r_+P0000%4p5y6o(Vw>9YK=_lm}Se-P6;~0000%4q%-Oo(n+@9YK={eBRyD3?Bdh001Na001~Q004x# z{r^M&0000%4ltbto&`Y-9YK=>P2Szp3?Bdh001BW003Y&005x6{r@-s0000%4j`Qb zo&!M*9ZTNb3?Bdh001Na004wH006YQ{r^w^0000%4nUmh)i4p5y6o(Vw>9YT``ln0dtTi)H()6@(f000yK z007)K001nz{r@Nc0000%4iHEV000yK008ti002C@{r?mI0000%4iG~Q000yK000a) z0020<{r?yM0000%4iH2R001Na001O70020<{r}Ja0000%4p5y6o(Vw>9YK=_aNgb1 z3?Bdh001BW002xl007{-{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW003|}000=g z{r@Zg0000%4ltbto&`Y-9Z25Y3?Bdh000yK005LY001Do{r@BY0000%4iHBU001BW z0068w001n!{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001Na007W9001Ps{r@lk0000% z4ltbto&`Y-9YK=>NZ#Gk3?Bdh001BW008(n001n!{r@Nc0000%4j`Qbo&!M*9Y@~X z3?Bdh000yK00100001z&{r?mI0000%4iG~Q001BW001;O001n!{r^A!0000%4j`Qb zo&!M*9ZlZd3?Bdh001BW003Ay002n5{r_M90000%4j`Qbo&!M*9aY}l3?Bdh001BW z004YB004x%{r@xo0000%4nUm9YK=_aNgb13?Bdh001BW008(o002C_{r_A50000%4ltbto&`Y-9aP@k3?Bdh z000yK00101004Bo{r@BY0000%4iHBU001BW001;P004l!{r?;Q0000%4j`Qbo&!M* z9Yo&U3?Bdh001BW003Az004Ns{r@-s0000%4ltbto&`Y-9ZTNb3?Bdh001li003Y! z004}={r^w`000E9k^lff4se|go((|_9YK=}lnVlo-rdvG3?Bdh001BW0068y006AN z{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001Ze006Wz006kZ{r?yN000Dok^lff4p5y6 zo(Vw>9YK=_0z%&1(+nQ~001BW008_t005-G{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh z001Ze000Cu006MS{r@ll000C=k^lff4q%-Oo(n+@9YK={0!ZH7(+nQ~001BW002xo z006YX{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001BW003}1006YX{r?;Q0000%4j`Qb zo&!M*9Yo&U3?Bdh000yK005Lb006AP{r@lk0000%4iHKX001Na0068z006|n{r@Nc z0000%4ltbto&`Y-9YK=>M&8}i3?Bdh001BW007iG006|n{r?~U0000%4j`Qbo&!M* z9Yx;V3?Bdh000yK008(q006+j{r@Nc0000%4iHEV001BW000m?007Xz{r?;Q0000% z4j`Qbo&!M*9Yo&U3?Bdh000yK001;R0079r{r?yM0000%4iH2R000yK002xp0079r z{r?mI0000%4iG~Q001Na003k>006|n{r^A!0000%4ltbto&`Y-9YK=>Oy1qo3?Bdh z000yK004|U007*<{r?mI0000%4iG~Q001li004+J007v*{r@BZ000EnkN^Nd4uAoj z5S|Y~4IM#~4wMZ7Mc&=h)C?a0001BW007iH007Lw{r@lk0000%4j`Qbo&!M*9ZBBZ z3?Bdh000yK008(r007v+{r?mI0000%4iG~Q001Ze008tg007j&{r@ll000DwkN^Nd z4q%-Oo(n+@9YK={0!ZH7(+nQ~001BW002Ba007v-{r@lk0000%4j`Qbo&!M*9ZBBZ z3?Bdh000yK003Y;0088}{r?mI0000%4iG~Q001Ze003Mz007{_{r@ll000CwkN^Nd z4q%-Oo(n+@9YK={0!ZH7(+nQ~001BW005*t0088~{r@lk0000%4j`Qbo&!M*9ZBBZ z3?Bdh001Ze0068u008jB{r@ll000E}j{pEc4q%-Oo(n+@9YK={0!ZH7(+nQ~000yK z008to008vG{r?yM0000%4iH2R001BW000a=008vG{r@Nc0000%4j`Qbo&!M*9Y@~X z3?Bdh001Na000y>008*K{r@lk000D}j{pEc4ltbto&`Y-9ZBBZ3?Bdh001Na002BU z0002S{r_A5000Dlj{pEc4ltbto&`Y-9aP@k3?Bdh001BW004kK001<`{r?;Q0000% z4j`Qbo&!M*9Yo&U3?Bdh001BW005*u001n;{r@Nc0000%4j`Qbo&!M*9Y@~X3?Bdh z001BW00787001z?{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001BW008Vh001z?{r@lk z0000%4ltbto&`Y-9ZBBZ3?Bdh000yK000m_002D3{r@Nc0000%4iHEV000yK001aI z002zJ{r?mI0000%4iG~Q001Na002Ng002nF{r^M&0000%4ltbto&`Y-9YK=>P2Szp z3?Bdh001xm002xl003mh{r{K*000DcjsO5b4zK~87M>MB4IM(06qFN{5(6Ot-rd#H z)C?a0001BW005jn0079!{r^}10000%4ltbto&`Y-9aG-j3?Bdh001BW006*0008{T z{r_|T0000%4nUmP2Szp3?Bdh001Ze008hf003yq{r^w^000CBjsO5b4ltbto&`Y-9YK=>P~P3s z3?Bdh000yK001~Z004~3{r?;Q0000%4j@Gi000yK002-x005B7{r?mI0000%4iG~Q z001Na003w}004~3{r{W*0000%4q%-Oo(n+@9YK={lnG9YK=_ zQ{LUv3?Bdh001BW002Ni003~z{r^Y+0000%4ltbto&`Y-9Z%lf3?Bdh000yK003k` z005NC{r?mI0000%4iG~Q001Na004YJ005B8{r`jk0000%4se|go((|_9YK=}0$twS z(+nQ~001BW005*x008XG{r_A50000%4ltbto&`Y-9aP@k3?Bdh001Na0078A001P; z{r?030000%4q%-Oo(n+@9YK={lnH&_-P6~p008ho0002b{r?mI0000%4iG~Q z001BW000O=008{X{r^k=0000%4ltbto&`Y-9Z=rg3?Bdh000yK001mP001P<{r?yM z0000%4iH2R000yK002Zn001P<{r?yM0000%4iH2R001BW003M<001P<{r@xo0000% z4j`Qbo&!M*9ZKHa3?Bdh001BW004kO001=4{r^Y+0000%4ltbto&`Y-9Z%lf3?Bdh z000yK005*y003Ce{r?mI0000%4iG~Q001Na006u~0030a{r`jk0000%4se|go((|_ z9YK=}0$twS(+nQ~000yK0087d006Mi{r?yM0000%4iH2R000yK008_#006Mi{r@BY z0000%4iHBU001Ze000z2006wu{r@BZ0000%4se|go((|_9YK=}lnVky-rdvG3?Bdh z000yK002Nk006Yn{r?mI0000%4iG~Q001BW003A+006Mj{r^k=0000%4ltbto&`Y- z9Z=rg3?Bdh000yK004YL007w0{r@BY0000%4iHBU001BW005Lj0089C{r_kH0000% z4nUm zP2Szp3?Bdh001Na00785002PJ{r@lk000CxiU0sX4j`Qbo&!M*9ZBBZ3?Bdh000yK z000a`002nR{r?mI0000%4iG~Q001BW001OJ002bN{r^Y+0000%4j`Qbo&!M*9Z%lf z3?Bdh000yK002lt003yx{r@Nc0000%4iHEV001BW003Y_004N>{r@BY0000%4j`Qb zo&!M*9Y)^W3?Bdh001Na004wU004N>{r{W*0000%4p5y6o(Vw>9YK=_lm}zp-P69YK=_lm`Nc-rdvG3?Bdh000yK005jw002nf{r?yM0000%4iH2R001BW006W| z002nf{r@xo0000%4ltbto&`Y-9ZKHa3?Bdh001BW007uX003Cv{r@lk0000%4j`Qb zo&!M*9ZBBZ3?Bdh001BW008_*003m*{r_YD0000%4ltbto&`Y-9ai4m3?Bdh000yK z001CK005-m{r?yM0000%4iH2R001BW001~i005-m{r@lk0000%4j`Qbo&!M*9ZBBZ z3?Bdh001BW003M`006My{r@Zg0000%4j`Qbo&!M*9Z25Y3?Bdh000yK004kV006k) z{r?yM0000%4iH2R001BW005Xt006k){r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW z006v6006|`{r_+P0000%4p5y6o(Vw>9a-Mp3?Bdh001BW007`g000o-{r_wL0000% z4p5y6o(Vw>9a!Go3?Bdh001BW000C^003Cw{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh z001BW001aT003Cw{r_YD0000%4nUm zP2Szp3?Bdh000yK005Xu008vi{r@Nc0000%4iHEV000yK006K`000Ey{r?yM0000% z4iH2R001BW0078J000Ey{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh000yK008Vt008{q z{r?yM0000%4iH2R000yK000C_008{q{r_MA0000%4iExX4gf3w0000)002be{r{i= z000DNg8%?Q4p5y6o(Vw>9YK=_lm`N2-rdvG3?Bdh001BW002x&006Y){r@BY0000% z4j`Qbo&!M*9Y)^W3?Bdh001BW003}H006Y){r^M&0000%4j`Qbo&!M*9Zufe3?Bdh z001li004MI007kF{r{i=000CJg8%?Q4p5y6o(Vw>9YK=_lm`N2-rdvG3?Bdh001BW z006{G002bh{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001BW008Jq002bh{r@lk0000% z4ltbto&`Y-9ZBBZ3?Bdh001BW000b3002005Nc{r@Zg z0000%4j`Qbo&!M*9Z25Y3?Bdh001BW004MQ005lk{r@Nc0000%4j`Qbo&!M*9Y@~X z3?Bdh001BW005j!005xo{r@Zg0000%4j`Qbo&!M*9Z25Y3?Bdh000yK006*D005}w z{r?mI0000%4iG~Q000yK007ub005-s{r?mI0000%4iG~Q001BW008hz005xo{r?~U z0000%4j`Qbo&!M*9Yx;V3?Bdh001BW000zC005lk{r@BY0000%4j`Qbo&!M*9Y)^W z3?Bdh001BW001~m005lk{r@Nc0000%4ltbto&`Y-9Y@~X3?Bdh000yK003M~005xo z{r?mI0000%4iG~Q000yK004AN005lk{r?mI0000%4iG~Q001BW004|l005Zg{r@BY z0000%4j`Qbo&!M*9Y)^W3?Bdh001BW006K}005Zg{r@Nc0000%4ltbto&`Y-9Y@~X z3?Bdh000yK007iY005lk{r?mI0000%4iG~Q001BW008Vw005Zg{r@BY0000%4j`Qb zo&!M*9Y)^W3?Bdh001BW000n9005Zg{r@Nc0000%4ltbto&`Y-9Y@~X3?Bdh001BW z001;j005lk{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh000yK003A{005Nc{r?yM0000% z4iH2R001BW003}K005Nc{r@BY0000%4j`Qbo&!M*9Y)^W3?Bdh001xm004ML005Nc z{r|uK000CpfB*nN4q%-Oo(n+@9YT`|lnIpxmIrIz-PP99)C?a0001BW0078N001E8 z{r_A50000%4ltbto&`Y-9aP@k3?Bdh000yK008Vx003C${r?yM0000%4iH2R000yK z000C}003C${r?yM0000%4iH2R001BW0010M003C${r^Y+0000%4ltbto&`Y-9Z%lf z3?Bdh000yK002Nw004aF{r?mI0000%4iG~Q001Na003A|004OB{r`jk0000%4se|g zo((|_9YK=}0$twS(+nQ~000yK004kb007kJ{r?yM0000%4iH2R001BW005Xz007kJ z{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW006vC007|V{r@lk0000%4j`Qbo&!M* z9ZBBZ3?Bdh001BW007`m008Xh{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001Ze008Jn z0089Z{r^M&000EregFVL4ltbto&`Y-9YK=>P2Szp3?Bdh001Na000z8008{x{r@lk z000EDegFVL4j`Qbo&!M*9ZBBZ3?Bdh000yK003A}000E({r?mI0000%4iG~Q001BW z003}M0002#{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001BW005Lw008{x{r@Nc0000% z4j`Qbo&!M*9Y@~X3?Bdh001BW006j90002#{r^}10000%4ltbto&`Y-9aG-j3?Bdh z001BW007)j001=U{r@lk0000%4ltbto&`Y-9ZBBZ3?Bdh001BW0000{002Pg{r?;Q z0000%4j`Qbo&!M*9Yo&U3?Bdh000yK001OW0021Y{r?yM0000%4iH2R001Na001CL z0021Y{r@Zg000E5eE9YK=_X5QV?3?Bdh001BW006*I006Y<{r_A50000%4ltbto&`Y-9aP@k z3?Bdh000yK0087s008Xi{r?yM0000%4iH2R000yK008_^008Xi{r?yM0000%4iH2R z001BW000zH008Xi{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh000yK001~r0089a{r?yM z0000%4iH2R000yK002-@0089a{r?mI0000%4iG~Q001Na003xG007|W{r^+|0000% z4nUm3{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW0000}002{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW007)m005Zk z{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001BW0000~005Bc{r@BY0000%4j`Qbo&!M* z9Y)^W3?Bdh001BW001OZ005Bc{r@lk0000%4ltbto&`Y-9ZBBZ3?Bdh001Na002l- z005lo{r^Y+0000%4ltbto&`Y-9YK=>PTt+q3?Bdh001BW003}Q006w|{r_A50000% z4ltbto&`Y-9aP@k3?Bdh000yK005L!008vr{r?mI0000%4iG~Q001BW00691008jn z{r?~U0000%4j`Qbo&!M*9Yx;V3?Bdh001Na007Wb008Xj{r_+P0000%4p5y6o(Vw> z9YK=_lm}Se-P6n-G4ltbto&`Y-9ZBBZ3?Bdh001BW007Wc004yV{r_A50000%4ltbto&`Y-9aP@k z3?Bdh001BW008t=006x2{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001BW000000c|{r@-s0000%4ltbto&`Y-9ZTNb3?Bdh001BW000Oy1qo3?Bdh000yK004wp0012E{r?yM0000% z4iH2R001Na005j>0012E{r^M&0000%4ltbto&`Y-9YK=>P2Szp3?Bdh000yK006{U z0021g{r?mI0000%4iG~Q001Na007)s001=c{r^w^0000%4nUm;~0000%4q%-Oo(n+@9YK={eBRyD z3?Bdh001BW005v`004yY{r@-s0000%4j`Qbo&!M*9ZTNb3?Bdh001Na006{V005Zs z{r^w^0000%4nUmC{r?mI0000%4iG~Q001BW00017 z000#8{r@lk0000%4nUm9YK=_Vcy--3?Bdh001BW002;2004;d{r@BY0000%4j`Qbo&!M*9Y)^W z3?Bdh001li003B3004;d{r{{0000ETasU894p5y6o(Vw>9YT``ln0dtX5QV^)6@(f z001BW005+1000E^{r_A50000%4ltbto&`Y-9aP@k3?Bdh001BW0078b002Dn{r@lk z0000%4j`Qbo&!M*9ZBBZ3?Bdh001BW008V<002nz{r?;Q0000%4j`Qbo&!M*9Yo&U z3?Bdh001Ze008t=002Pr{r^M&000C-asU894ltbto&`Y-9YK=>P2Szp3?Bdh001Na z001CX003C@{r@lk000CVasU894j`Qbo&!M*9ZBBZ3?Bdh000yK003lN003b0{r?yM z0000%4iH2R001BW004Yl003b0{r_A50000%4ltbto&`Y-9aP@k3?Bdh000yK005v} z005Zu{r@lk0000%4iHKX001BW006jM006M`{r@lk0000%4j`Qbo&!M*9ZBBZ3?Bdh z001Na007)w006x7{r@}w0000%4ltbto&`Y-9YK=>OWxhn3?Bdh001Ze000DD007YR z{r^}20000%4q%-Oo(n+@9YK={lnDY--rdvG3?Bdh000yK001yv008{;{r?mI0000% z4iG~Q001BW002l{008*){r@Nc0000%4j`Qbo&!M*9Y@~X3?Bdh001BW003-W008{; z{r@lk0000%4ltbto&`Y-9ZBBZ3?Bdh001BW0059)000Q~{r?~U0000%4j`Qbo&!M* z9Yx;V3?Bdh001BW006XJ000E`{r^}10000%4j`Qbo&!M*9aG-j3?Bdh000yK007ut z0021l{r?mI0000%4iG~Q001xm007ii001=h{r_YE000DQZ~y>74v+zz5}px34IM(0 z5R?y<4wel9RNmdy*3;As9{>~p001Ok003n7{r?yM0000%4iH2R001BW002B+003n7 z{r?;Q0000%4j`Qbo&!M*9Yo&U3?Bdh001BW003ZL003O~{r?~U0000%4j`Qbo&!M* z9Yx;V3?Bdh001BW004wv003C`{r_wL0000%4j`Qbo&!M*9a!Go3?Bdh001Na005|8 z005x({r^k>0000%4nUmMB4IM#~6atFg-O~&o000yK001yy007tv{{KJ#0000%4j@hr001BW002l~ z0000C{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001BW003-Z008_8{{K7x0000%4ltbt zo&`Y-9ZcTc3?Bdh001BW0059-000yW{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh001BW z006XM000;a{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001BW007uw000yW{{Qp<0000% z4nUm9YT``ln0dtmIYqk-PP99)C?a0000yK002Z{002}C{{IvJ z0000%4iG~Q001li002N+002-8{{OrL000CSZ2$m44uAoj5S|Y~4IM#~4wMZ8D*@i! z)6@(f001BW004|)007(({{Mgg0000%4j`Qbo&!M*9bMkt3?Bdh001BW006LJ001}= z{{L(M0000%4nUm!3?Bdh000yK003-b003YU{{K(_0000%4iHif001Na004wz z005X1{{L_Q0000%4nUm!3?Bdh001BW0069G007_<{{Jul0000% z4j`Qbo&!M*9ZBBZ3?Bdh001BW007Wq008V0{{N%^0000%4j`Qbo&!M*9cJF$3?Bdh z001li007ur003+h{{K({000D;YXAU24p5y6o(Vw>9YK=_lm`Nk-rdvG3?Bdh001li z000PG004{@{{N%{000DjYXAU24p5y6o(Vw>9YK=_lm`Ok-rdvG3?Bdh001BW002~E z0000Q{{Kh-0000%4j`Qbo&!M*9Z%lf3?Bdh001BW004Mo001N!{{JWd0000%4j`Qb zo&!M*9Y@~X3?Bdh001BW005k1001Z&{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh000yK z006*b001l+{{JKZ0000%4iHBU001Na007uz001}|{{J8W0000%4q%-Oo(n+@9YK={ z0z}^3(+nQ~001Na0087&001x>{{KV(000EwY5)L14j`Qbo&!M*9Zufe3?Bdh000yK z001au002xI{{IvJ0000%4iG~Q001li001Oj002lE{{OrL000D}Y5)L14uAoj5S|Y~ z4IM#~4wMZ8D*@i!)6@(f000yK003}h007h<{{IvJ0000%4iG~Q001li003-W007V* z{{OrL000DRY5)L14uAoj5S|Y~4IM#~4wMZ8D*@i!)6@(f001li005j`003Mh{{OrL z000C`Y5)L14uAoj5S|Y~4IM#~4wMZ8D*@i!)6@(f000yK008J^008JH{{IvJ0000% z4iG~Q001li0087(0087D{{OrL000COY5)L14uAoj5S|Y~4IM#~4wMZ8D*@i!)6@(f z001li000zU003|;{{OrL000E^X#fC04uAoj5S|Y~4IM#~4wMZ8D*@i!)6@(f000yK z003ZS008_k{{IvJ0000%4iG~Q001li003NH008(g{{OrL000ERX#fC04uAoj5S|Y~ z4IM#~4wMZ8D*@i!)6@(f001Na005|F004wG{{Msk0000%4q%-Oo(n+@9YK={lnGtl z-P6~p008)A z002NY{{JWd0000%4iHEV000yK000nY002-o{{IvJ0000%4iG~Q000yK001aw002xk z{{IvJ0000%4iG~Q001Na002N|002lg{{JWf0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~ z000yK003xb002li{{IvJ0000%4iG~Q001BW004kz002Ze{{Jul0000%4j`Qbo&!M* z9ZBBZ3?Bdh001Na005+C002-q{{JWf0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~001Na z007Kq002-s{{JWf0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~001Na008u7002-u{{JWf z0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~001Na0010l002-w{{JWf0000%4p5y6o(Vw> z9YK=_0*2n*(+nQ~001Na002a2002-y{{JWf0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~ z001Na003-g002-!{{JWf0000%4p5y6o(Vw>9YK=_0*2n*(+nQ~001BW005L|002-$ z{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001Na005j}002xy{{J)p000D$X8-^}4j`Qb zo&!M*9ZKHa3?Bdh001Ze006{c003A;{{K(_000DSX8-^}4ltbto&`Y-9YK=>lmk%S z-P69YK=_lm}Mc-P6P2Szp3?Bdh000yK007Wx003A< z{{JWd0000%4iHEV000yK008J}003x4{{I*N0000%4iH2R001li0087;003x4{{MUc z000D0WdHy{4nUm0000%4nUm{{I{R0000%4j`Qbo&!M*9Yo&U3?Bdh001BW z007);008_({{I{R0000%4j`Qbo&!M*9Yo&U3?Bdh001BW0001N008tx{{J8V0000% z4j`Qbo&!M*9Yx;V3?Bdh001BW001Ox008ht{{J)p0000%4j`Qbo&!M*9ZKHa3?Bdh z001BW002mA0000-{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001BW003-k008_({{J8V z0000%4j`Qbo&!M*9Yx;V3?Bdh001BW0059|008(#{{Kt>0000%4j`Qbo&!M*9Z=rg z3?Bdh001BW006XX001CI{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh000yK007u*001OM z{{IvJ0000%4iG~Q001Na008i8001CI{{Kt>0000%4nUm9YK=_aNgb13?Bdh001BW0001P007)a{{I{R0000%4j`Qbo&!M* z9Yo&U3?Bdh001BW001Oz007iS{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh001xm001m! z007iS{{O%L000CRVgLX^4q%-Oo(n+@9YT`|lnIpxmIrIz-PP99)C?a0001BW004Y$ z003Y}{{LJ60000%4ltbto&`Y-9aP@k3?Bdh000yK005wF005Xs{{I*N0000%4iH2R z001BW006jd005Xs{{LJ60000%4ltbto&`Y-9aP@k3?Bdh001BW007)>007WP{{Kh- z0000%4ltbto&`Y-9Z%lf3?Bdh000yK0001Q008tz{{IvJ0000%4iG~Q001Na000P2Szp3?Bdh001Na z000DO004AK{{Jul000DEU;qF?4j`Qbo&!M*9ZBBZ3?Bdh000yK002mE004YS{{IvJ z0000%4iG~Q001Na003Zc004MO{{Kt>0000%4nUm4p5y6o(Vw>9YT``ln0dtTi)H()6@(f001BW002mF007)d{{JWd0000% z4j`Qbo&!M*9Y@~X3?Bdh000yK003-p007`h{{IvJ0000%4iG~Q001Na004w>007)d z{{Kt>0000%4nUm{{I{R0000%4j`Qb zo&!M*9Yo&U3?Bdh001BW007W&008(({{I{R0000%4j`Qbo&!M*9Yo&U3?Bdh001BW z008uH008hx{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001li008`I008Vt{{Mgg000Dc zUH||=4p5y6o(Vw>9YT``ln0dtTi)H()6@(f001BW002mG002Bo{{JWd0000%4j`Qb zo&!M*9Y@~X3?Bdh000yK003-q002Ns{{IvJ0000%4iG~Q001Na004w?002Bo{{Kt> z0000%4nUm~p0010y007WS{{IvJ0000%4iG~Q001BW z001;~007KO{{NT&0000%4p5y6o(Vw>9b?|z3?Bdh001BW003BZ002Nt{{J)p0000% z4nUm9YK=_lm`M>-rdvG3?Bdh001BW004w`007WU{{M6U0000%4nUmOy1qo3?Bdh001Na001Cz004YX z{{Kh-000DvR{#J(4j`Qbo&!M*9Z%lf3?Bdh001BW003lp005j%{{J8V0000%4j`Qb zo&!M*9Yx;V3?Bdh001BW004-2005Xz{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh001BW z0069c005j%{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001BW007W=005Xz{{J8V0000% z4j`Qbo&!M*9Yx;V3?Bdh001Ze007u>005Lv{{QFz000EmRsaA&4p5y6o(Vw>9YK=_ zcHZ673?Bdh000yK001C*002->{{J8V0000%4iH8T000yK00208003A}{{IvJ0000% z4iG~Q001BW002;W002}_{{J`t0000%4j`Qbo&!M*9ZTNb3?Bdh001Na004A)003xE z{{IXC0000%4ltbto&`Y-9YK=>f8O2G3?Bdh001BW005kN002x;{{I{R0000%4j`Qb zo&!M*9Yo&U3?Bdh000yK006*x002Z${{IvJ0000%4iG~Q001BW007u}002Ny{{Jul z0000%4j`Qbo&!M*9ZBBZ3?Bdh001Ze007`~002x;{{NT&000EtRR91%4nUmP2Szp3?Bdh z001BW002;X007ic{{IXD0000%4q%-Oo(n+@9Rh&f-3%W9000yK004A*006vG{{I*N z0000%4iH2R000yK004}8006vG{{I*N0000%4iH2R001Na005+W006vG{{J`t0000% z4ltbto&`Y-9YK=>O5WYm3?Bdh001BW007K;007KW{{L(N0000%4nUmO5WYm3?Bdh001Ze000zy006XB{{Qd* z0000%4xj;@6rK}74IM#~5|j~m-rdvG3?Bdh000yK002OJ004Mb{{K7x0000%4j@eq z001Ze003Bh005j<{{N@|0000%4uAoj5S|Y~4IM#~4wMaM-rdvG3?Bdh000yK004x2 z000P2Szp3?Bdh001BW002yY008J){{JWd0000%4j`Qb zo&!M*9Y@~X3?Bdh000yK003}+008V;{{I{R0000%4iH5S001BW004-9008h?{{JWd z0000%4j`Qbo&!M*9Y@~X3?Bdh001BW0069j008t`{{KJ#0000%4j`Qbo&!M*9ZlZd z3?Bdh001BW007W{000nN{{J8W0000%4ltbto&`Y-9Rfw(-3%W9001Na008uW000bK z{{Pef0000%4ltbto&`Y-9YK=>ao*k23?Bdh001Na0010;006jM{{OrH0000%4ltbt zo&`Y-9YK=>Yu??{3?Bdh001li001a@002y0{{PGY000ETPXGWx4p5y6o(Vw>9YK=_ zlm`ND-rdvG3?Bdh000yK004A>008J;{{IvJ0000%4iG~Q001Na004}E0087){{MIY z0000%4p5y6o(Vw>9YK=_THf8$3?Bdh000yK006Xs001;#{{IvJ0000%4iG~Q001Na z007K^001yx{{MIY0000%4p5y6o(Vw>9YK=_THf8$3?Bdh000yK008uX004ks{{Jul z0000%4iHKX001BW000bv005X^{{J8V0000%4j`Qbo&!M*9Yx;V3?Bdh001Na001z8 z005L={{KV(0000%4ltbto&`Y-9YK=>P2Szp3?Bdh000yK003Bm006LH{{JKZ0000% z4iHBU001BW003};006vT{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh001BW005MN006vT z{{M&o0000%4nUmP2Szp3?Bdh000yK007{E002B;{{IvJ0000%4iG~Q001li007*3001~){{JKa z000ChP5=Nw4uAoj5S|Y~4IM#~4wMZ7Mc&=h)C?a0001BW001b1001mv{{Kh-0000% z4j`Qbo&!M*9Z%lf3?Bdh001BW002yb002;8{{Kh-0000%4j`Qbo&!M*9Z%lf3?Bdh z001BW003}<004Ai{{Kh-0000%4j`Qbo&!M*9Z%lf3?Bdh001BW005MO005X`{{Kh- z0000%4j`Qbo&!M*9Z%lf3?Bdh001Na006jy006vV{{Nf+0000%4ltbto&`Y-9YK=> zlmlbl-P6~p007{F001y!{{IvJ0000%4iG~Q001Na008)d001mw{{Nf+0000% z4ltbto&`Y-9YK=>lmlbl-P6 zlmlbl-P6lmlbl-P6lmlbl-P6lmlbl-P6lmlbl-P6lmlbl-P6{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh001BW z000n%008J_{{I{R0000%4j`Qbo&!M*9Yo&U3?Bdh000yK001Oy1qo3?Bdh001li003}*008u6{{P?r000EHN&o;s4uAoj5S|Y~4IM(0 z4wMa*40GPy)zj1r9{?Z#006v(005+C{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh001BW z007{I005+C{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh001BW000Ds005+C{{JWd0000% z4ltbto&`Y-9Y@~X3?Bdh000yK001b5005|G{{IvJ0000%4iG~Q001Ze001O_005+C z{{N@|000CNN&o;s4p5y6o(Vw>9YK=_X5QV?3?Bdh001BW003-<001Cp{{I{R0000% z4j`Qbo&!M*9Yo&U3?Bdh000yK005AO000001Ot{{JWd0000%4j`Qbo&!M* z9Y@~X3?Bdh001Na005AQ001ax{{LtI0000%4p5y6o(Vw>9YK=_lm}Mc-P6T;AQ&3?Bdh001Na000P!000bW{{K(_0000%4nUm9YT``ln0dt z0z%&1)zj1r9{?l(007L3000PT{{K(_0000%4nUm9YT``ln0dt zTi)H()6@(f001BW003-_004Mu{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh000yK005AU z004Mu{{JKZ0000%4iHBU001BW005|s004w){{J)p0000%4nUm9YK=_VBX!+3?Bdh001BW00110000DQ{{I{R0000%4j`Qb zo&!M*9Yo&U3?Bdh000yK002Oa008`I{{IvJ0000%4iG~Q001BW003By008)E{{K(_ z0000%4ltbto&`Y-9Z}xh3?Bdh000yK004ZB001Ow{{IvJ0000%4iG~Q001BW005MZ z001Cs{{Kh-0000%4j`Qbo&!M*9Z%lf3?Bdh001BW006j-002a5{{JWd0000%4ltbt zo&`Y-9Y@~X3?Bdh001BW007*M002m9{{K7x0000%4j`Qbo&!M*9ZcTc3?Bdh001BW z0001w003ZX{{LJ60000%4ltbto&`Y-9aP@k3?Bdh001xm000Px005Y4{{NH!000D+ zLI40k4p5y6o(Vw>9YT``ln0dtmIYwm-PP99)C?a0001BW003Bz008)F{{I{R0000% z4j`Qbo&!M*9Yo&U3?Bdh001BW004ZC008i7{{Jih0000%4j`Qbo&!M*9Z25Y3?Bdh z001BW005wm008)F{{JKZ0000%4j`Qbo&!M*9Y)^W3?Bdh001BW006{~008)F{{JWd z0000%4ltbto&`Y-9Y@~X3?Bdh001BW008KZ008`J{{JKZ0000%4j`Qbo&!M*9Y)^W z3?Bdh001Ze008ia008`J{{N5w000ELK>z?j4nUm~p z0020U003ZY{{JKZ0000%4j@Mk000yK002;s003-k{{KJ#0000%4iHWb000yK003x^ z005M1{{IvJ0000%4iG~Q000yK004lH0059|{{IvJ0000%4iG~Q001BW005Yf004|^ z{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh001BW006v@0059|{{KJ#0000%4ltbto&`Y- z9ZlZd3?Bdh001BW007{S0069P{{Jul0000%4ltbto&`Y-9ZBBZ3?Bdh000yK000D$ z006jb{{IvJ0000%4iG~Q000yK00113006XX{{I*N0000%4iH2R001BW001lmlbl-P6O5WYm3?Bdh001BW005kl006XY{{J8V z0000%4j`Qbo&!M*9Yx;V3?Bdh001BW006*}006LU{{J8V0000%4j`Qbo&!M*9Yx;V z3?Bdh000yK0088Y0069Q{{KV(0000%4j@ks001Ze008`w007u+{{OfD0000%4v+zz z5}px34IM#~5R?yU-rdvG3?Bdh001BW001bH003le{{Kt>0000%4ltbto&`Y-9Z=rg z3?Bdh001BW002yr004|`{{L(M0000%4p5y6o(Vw>9a!Go3?Bdh001BW003~4007i( z{{JWd0000%4j`Qbo&!M*9Y@~X3?Bdh001Na005Me007u-{{Kh-0000%4nUmlmlbl-P6~p005kn004M!{{IvJ0000%4iG~Q z001Na006X<004Aw{{K(_0000%4nUm{{L720000%4ltbto&`Y-9aG-j3?Bdh001Na002Oh006jg{{KV( z0000%4ltbto&`Y-9YK=>P2Szp3?Bdh001BW003x}007i+{{J`t0000%4j`Qbo&!M* z9ZTNb3?Bdh00000fd79K0001tl>h+fasK}l00000K@Jc@4gdfo0001_l>h+basK~M z00000K@LEj2%ZN)4IM#~22kGJ(+nQ~0000W0002Yl>h(?a{m7y00000K@K3D1fByy z4IM?^-3%W90000K0002+l>h(;a{m7)00000K@Jc|4gdfY00008mH+@4a{m7m00000 zK@Jc@4gdfY0000WmH+@0a{m7q00000K@Jc^4gdfY0000umH+@0a{m7u00000K@Jc_ z4gdfk0000`mH+@4a{m7u00000K@K3D1fByy4IM<@-3%W90000a0001VmH+?{a{m8B z00000K@KpT2A%~$4IM#~1Wn%E(+nQ~0000W0001-mH+@Oa{m8>00000K@KpT2A%~$ z4IN(I-3%W90000W0002MmH+^Za{m7;00000K@KpT2A%~$4IN0{-3%W90000W0002w zmH+^ha{m8#00000K@LEj2%ZN)4INwF-3%W90000a00008mjD3ha{m9|00000K@L!z z3Z4l;4IM#~2z1`v(+nQ~0000W0000mmjD2ubN>G{00000K@KpT2A%~$4IN6}-3%W9 z0000a0000~mjD2;bN>Hu00000K@L!z3Z4l;4IM#~2$Tm{-rdvG3?Bd_0001dmjD3x zbN>HC00000K@KpT2A%~$4IM#~1Wn%E(+nQ~0000a0001_mjD11bpHQD00000K@KpT z2A%~$4IM#~1Wn%E(+nQ~0000a0002YmjD1TbpHQD00000K@KpT2A%~$4IM#~1Wn%E z(+nQ~0000a0002=mjD1vbpHQD00000K@KpT2A%~$4IM#~1Wn%E(+nQ~0000W0000S zm;eB1bpHQ100000K@KpT2A%~$4IN9~-3%W90000i0000akpKXEbpHQP0ssI6qd5Qo zK@M=84xSA`4IM#~43rB3klx+X)C?a00000W0001Rm;eBrcK-i300000K@KpT2A%~$ z4IN9~-3%W90000i0001ZkpKX&cK-iR0ssI6cR2t6K@M=84xSA`4IM#~43rB3klx+X z)C?a00000W0002Qm;eCKc>e!500000K@KpT2A%~$4IN9~-3%W90000i0002YkpKYX zc>e!T0ssI6OE~}lK@M=84xSA`4IM#~43rB3klx+X)C?a00000W0000OnE(I;d;b48 z00000K@KpT2A%~$4IN9~-3%W90000i0000Wk^lf0d;b4W0ssI6A2|R3K@M=84xSA` z4IM#~43rB3klx+X)C?a00000W0001NnE(Jdeg6MA00000K@KpT2A%~$4IN9~-3%W9 z0000i0001Vk^lfqeg6MY0ssI6^EdziK@M=84xSA`4IM#~43rB3klx+X)C?a00000W z0002MnE(K6fByeC00000K@KpT2A%~$4IN9~-3%W90000i0002Uk^lgJfByea0ssI6 z$2b50K@M=84xSA`4IM#~43rB3klx+X)C?a00000W0000Kng9Txf&TwE00000K@KpT z2A%~$4IN9~-3%W90000i0000SlK=p;f&Twc0ssI6n>YXfK@M=84xSA`4IM#~43rB3 zklx+X)C?a00000W0001Jng9UQgZ}?G00000K@KpT2A%~$4IN9~-3%W90000i0001R zlK=qdgZ}?e0ssI6Z#Vz|K@M=84xSA`4IM#~43rB3klx+X)C?a00000K0002Ing9R@ zhW`H)00000K@Jc@4gdfk0002gng9Rn*ac0hW`Ih00000K@KpT2A%~$4IM#~1W?}H(+nQ~0000K z0002Un*acehW`H)00000K@Jc@4gdfo0002sn*acahW`It00000K@LEj2%ZN)4IM#~ z220001Vod5u&hyMR800000K@K3D1fByy4IN0{-3%W90000W0001( zod5u=hyMR000000K@K3D1fByy4IM__-3%W90000W0002Iod5u=hyMR400000K@KpT z2A%~$4IM|`-3%W90000a0002sod5u^hyMRu00000K@LEj2%ZN)4IM#~22pi2naD00000K@KpT2A%~$4IN3|-3%W90000a0002^p8x>#i2nav00000K@LEj z2%ZN)4IM#~22Op00008q5uGhivIr; z00000K@Jc@4gdfk0000Wq5uGdivIr~00000K@K3D1fByy4IM?^-3%W90000K0000) zq5uGZivIr?00000K@Jc^4gdfs0000$n*acSivItQ000043o!ryK@KpT2A%~$4IM#~ z1Yq9X(+nQ~0000e0001Nn*adhivIs_00004^e_MbK@LEj2%ZN)4IM#~23X$R(+nQ~ z0000K0002Aq5uFWi~j!<00000K@Jc@4gdfk0002Yq5uFSi~j#800000K@K3D1fByy z4IM|`-3%W90000W0002+q5uFWi~j#O00000K@KpT2A%~$4IN9~-3%W90000W0000K zqW}Ori~j#y00000K@KpT2A%~$4INb8-3%W90000K0000uqW}POi~j!<00000K@Jc@ z4gdfk0000`qW}PKi~j#800000K@KpT2A%~$4IM|`-3%W90000W0001VqW}POi~j#8 z00000K@K3D1fByy4IM|`-3%W90000W0001(qW}PSi~j!{00000K@K3D1fByy4IM<@ z-3%W90000i0001>oB#lDi~j$B00004&@TW0K@L!z3Z4l;4IM(02$Tnv23y|U)zj1r z9{>O(0002&qW}QFi~j#a00000K@KpT2A%~$4IM#~1Wn%E(+nQ~0000W0000KqyPZi zi~j#800000K@K3D1fByy4IM|`-3%W90000K0000uqyPZmi~j!@00000K@Jc^4gdfk z0000`qyPZmi~j#O00000K@KpT2A%~$4IN9~-3%W90000W0001VqyPZ)i~j#y00000 zK@KpT2A%~$4INb8-3%W90000i0001dod5tVjQ;;X0ssI611|soK@M=84xSA`4IM#~ z43rB3jNaYT)C?a00000e00022od5tlj{g5p00004`z`0001dr2qivj{g4~ z00000K@K3D1fByy4IM<@-3%W90000K0001>r2qinj{g4?00000K@Jc@4gdfk0002E zr2qijj{g5p00000K@KpT2A%~$4INS5-3%W90000K0002or2qg3kN*D@00000K@Jc@ z4gdfo0002=r2qf~kN*Eu00000K@LEj2%ZN)4IM#~29yO+-rdvG3?Bd#0000SrT_pi zkN*Ee00000K@K2K4gdfs0000qrT_q3kN*F-00000K@N}sof4iAK@A;2lMs{-YTn(` z)C?a00000a0001BrT_rwkN*FR00000K@M=84xSA`4IM#~43rCB-rdvG3?Bd>0001p zrT_p;kpBNT00000K@KpT2A%~$4IN9~-3%W90000i0001xp8x=0kpBNr0ssI68!Z3; zK@M=84xSA`4IM#~43rB3klx+X)C?a00000W0002orT_qdlK%f700000K@K3D1fByy z4IM?^-3%W90000W00000rvLzalK%fF00000K@K3D1fByy4IM|`-3%W90000W0000a zrvLzelK%f#00000K@KpT2A%~$4INY7-3%W90000W0000;rvL!7lK%fN00000K@KpT z2A%~$4IN3|-3%W90000W0001NrvL!JlK%f300000K@K3D1fByy4IM<@-3%W90000K z0001xrvL!BlK%e`00000K@Jc@4gdfY0001}rvL!7lK%fR00000K@Jd04gdfk0002M zrvL!ZlK%f#00000K@KpT2A%~$4INY7-3%W90000a0002wrvLy1lm7om00000K@LEj z2%ZN)4IM#~22S4H(+nQ~0000W0000Cr~m*Ylm7oG00000K@K3D1fByy4IM|`-3%W9 z0000m0000Kp#T6Vlm7p}00004zbgO$K@MP@44w-?4IM(03X}YyK000047b^e&K@L!z3Z4l;4IM(02$Tnv23y|U)zj1r9{>O(0000asQ>^_l>Yxv z00000K@LEj2%ZN)4IM#~22kGJ(+nQ~0000a0000?sQ>_Yl>Yxz00000K@LEj2%ZN) z4IM#~22tMK(+nQ~0000a0001VsQ>_^l>Yxz00000K@LEj2%ZN)4IM#~22tMK(+nQ~ z0000a0001-sQ>`bl>Yxz00000K@LEj2%ZN)4IM#~22tMK(+nQ~0000a0002QsQ>`{ zl>Yxz00000K@LEj2%ZN)4IM#~22tMK(+nQ~0000i0002cq5uFWmHz*L00004D=Gj0 zK@L!z3Z4l;4IM(02$Tnv23y|U)zj1r9{>O(0000SssI3ZmHz)!00000K@LEj2%ZN) z4IM#~22tMK(+nQ~0000K0000)ssI3_mHz(}00000K@Jc@4gdfk00017ssI3>mHz)6 z00000K@K3D1fByy4IM<@-3%W90000W0001hssI3(mHz)600000K@K3D1fByy4IM<@ z-3%W90000W0001_ssI3xmHz)s00000K@LEj2%ZN)4INP4-3%W90000a0002UssI4E zmHz)g00000K@KpT2A%~$4IM#~1WexD(+nQ~0000W0002+ssI4cmHz)I00000K@K3D z1fByy4IM|`-3%W90000W0000Ks{jDhmHz)Q00000K@K3D1fByy4IN3|-3%W90000W z0000us{jDtmHz)A00000K@K3D1fByy4IM?^-3%W90000W00017s{jDpmHz)600000 zK@K3D1fByy4IM<@-3%W90000W0001hs{jDhmHz)A00000K@K3D1fByy4IM?^-3%W9 z0000W0001_s{jDdmHz)I00000K@K3D1fByy4IM|`-3%W90000W0002Us{jDhmHz)Q z00000K@K3D1fByy4IN3|-3%W90000W0002&s{jDtmHz)A00000K@K3D1fByy4IM?^ z-3%W90000W0000GtN;MqmHz)600000K@K3D1fByy4IM<@-3%W90000W0000qtN;Mi zmHz)A00000K@K3D1fByy4IM?^-3%W90000K00013tN;MemHz)A00000K@Jc`4gdfk z0001RtN;MmmHz*500000K@LEj2%ZN)4INqD-3%W90000W0001#tN;Kcmj3@J00000 zK@K3D1fByy4IM|`-3%W90000W0002EtN;Kgmj3@B00000K@K3D1fByy4IM?^-3%W9 z0000W0002otN;Kcmj3@700000K@K3D1fByy4IM<@-3%W90000W00000tpETVmj3@B z00000K@K3D1fByy4IM?^-3%W90000a0000atpETRmj3@_00000K@LEj2%ZN)4IM#~ z236kO(+nQ~0000W0000?tpEU2mj3@J00000K@K3D1fByy4IM|`-3%W90000K0001R ztpEU6mj3@300000K@Jc^4gdfY0001ptpEU6mj3@F00000K@Jc{4gdfo0001>tpEUI zmj3^g00000K@L!z3Z4l;4IM#~2w~pc(+nQ~0000W0002UtpEVfmj3@J00000K@K3D z1fByy4IM|`-3%W90000W0002&tpEVjmj3@B00000K@K3D1fByy4IM?^-3%W90000W z0000Gt^fegmj3@700000K@K3D1fByy4IM<@-3%W90000W0000qt^feYmj3@B00000 zK@K3D1fByy4IM?^-3%W90000a00013t^feUmj3@R00000K@KpT2A%~$4IM#~1W4Z9 z(+nQ~0000W0001ht^fecmj3@J00000K@K3D1fByy4IM|`-3%W90000W0001_t^feg zmj3@h00000K@K3D1fByy4ING1-3%W90000W0002Ut^fe+mj3@>00000K@K3D1fByy z4INe9-3%W90000W0002&t^fcim;V1W00000K@LEj2%ZN)4IN6}-3%W90000W0000G zuK)lzm;V1K00000K@K3D1fByy4IM|`-3%W90000W0000quK)l%m;V1C00000K@K3D z1fByy4IM?^-3%W90000W00013uK)lzm;V1800000K@K3D1fByy4IM<@-3%W90000W z0001duK)lrm;V1C00000K@K3D1fByy4IM?^-3%W90000K0001>uK)lnm;V1K00000 zK@Jc|4gdfY0002EuK)l%m;V1000000K@Jc@4gdfk0002cuK)lzm;V1800000K@K3D z1fByy4IM<@-3%W90000K0002=uK)lrm;V1000000K@Jc@4gdfk0000CumAuom;V1C z00000K@K3D1fByy4IM?^-3%W90000W0000mumAukm;V1S00000K@K3D1fByy4IN3| z-3%W90000K0000~umAuwm;V1K00000K@Jc|4gdfY0001NumAu=m;V1400000K@Jc^ z4gdfo0001lumAu=m;V1y00000K@KpT2A%~$4IM#~1W?}H(+nQ~0000W00022umAvT zm;V1;00000K@KpT2A%~$4INb8-3%W90000a0002cumAw0m;V1$00000K@LEj2%ZN) z4IM#~22tMK(+nQ~0000K0002^umAwim;V1400000K@Jc^4gdfY0000Gu>b(jm;V10 z00000K@Jc@4gdfY0000eu>b(fm;V1400000K@Jc^4gdfo0000$u>b(fm;V1$00000 zK@LEj2%ZN)4IM#~22tMK(+nQ~0000K0001Ju>b)0m;V1K00000K@Jc|4gdfo0001h zu>b%FnEw9&0RR91K@MP@44w-?4IM#~3Vhz((+nQ~0000W0001}u>b(znEwA*00000 zK@KpT2A%~$4INY7-3%W90000a0002Yu>b%Rng0Jk00000K@KpT2A%~$4IM#~1WexD z(+nQ~0000W0002=u>b%png0Jc00000K@K3D1fByy4IN9~-3%W90000K0000OvH$=; zng0J200000K@Jc@4gdfo0000mvH$=)ng0J!00000K@LEj2%ZN)4IM#~22kGJ(+nQ~ z0000e00013vH$>Nng0L$00000K@NZcoe-W6K@A;2lMa*(d*0pC)C?a00000K0001l zvH$=yn*RS300000K@Jc@4gdfk0001-vH$=un*RSZ00000K@LEj2%ZN)4IN6}-3%W9 z0000K0002MvH$=;n*RSp00000K@K2K4gdfo0002kvH$>Vn*RTc00000K@M=84xSA` z4IM#~43rCB-rdvG3?Bd}00000vj70ln*RR;0RR91K@NZcoe-W6K@A;2lMa*(ecs*E z)C?a00000a0000ivj707oBsb)00000K@LEj2%ZN)4IM#~22tMK(+nQ~0000W0000~ zvj70poBsbC00000K@K3D1fByy4IM<@-3%W90000K0001Zvj70hoBsb400000K@Jc@ z4gdfk0001xvj70doBsb$00000K@KpT2A%~$4INS5-3%W90000K0002Avj70}oBsbK z00000K@Jc{4gdfk0002Yvj6}9oc{kb00000K@LEj2%ZN)4IN6}-3%W90000K0002+ zvj6}Poc{k500000K@Jc@4gdfo00008v;Y7Moc{lu00000K@MP@44w-?4IM#~3X}0000mv;Y8roc{lO00000K@KpT2A%~$4INzG-3%W90000a0000~v;Y9u zoc{l400000K@L!z3Z4l;4IM#~2$Tm_-rdvG3?Bd>0001dv;Y7Yo&NtQ00000K@K3D z1fByy4IM|`-3%W90000W0001>v;Y7co&NtQ00000K@K3D1fByy4IM|`-3%W90000W z0002Qv;Y7go&NtQ00000K@K3D1fByy4IM|`-3%W90000W0002!v;Y7ko&NtQ00000 zK@K3D1fByy4IM|`-3%W90000K0000CwEzGpo&NtA00000K@Jc^4gdfY0000awEzGp zo&NtQ00000K@Jc|4gdfY0000ywEzG(o&Nt600000K@Jc@4gdfk0000~wEzG#o&NtE z00000K@K3D1fByy4IM<@-3%W90000K0001ZwEzGto&Nt600000K@Jc@4gdfY0001x zwEzGpo&NtQ00000K@Jc|4gdfY0001}wEzG(o&Nt600000K@Jc@4gdfk0002MwEzG# zo&NtE00000K@K3D1fByy4IM<@-3%W90000K0002wwEzGto&Nt600000K@Jc@4gdfk z0002|wEzGpo&NtE00000K@K3D1fByy4IM<@-3%W90000W0000Wwg3Pio&NtE00000 zK@K3D1fByy4IM<@-3%W90000a0000)wg3Pao&Nt^00000K@L!z3Z4l;4IM#~2vgqO z(+nQ~0000K0001Nwg3Q3o&NtQ00000K@Jc|4gdfk0001lwg3QJo&NtE00000K@K3D z1fByy4IM<@-3%W90000a0001}wg3QBo&NtY00000K@KpT2A%~$4IM#~1W4Z9(+nQ~ z0000K0002cwg3QJo&NtA00000K@Jc^4gdfY0002!wg3QJo&NtA00000K@Jc^4gdfs z0002wuK)mCo&Ntw0RR95BOL$$K@L!z3Z4l;4IM#~2m(&t-O~&o0000W0000iw*UZm zp8o$F00000K@K3D1fByy4IM<@-3%W90000W0000`w*UZep8o$F00000K@K3D1fByy z4IM<@-3%W90000K0001Vw*UZWp8o$R00000K@Jc|4gdfk0001tw*UZmp8o$F00000 zK@K3D1fByy4IM<@-3%W90000K00026w*UZep8o$B00000K@Jc^4gdfs00022umAvX zp8o%+00004dmI1&K@L!z3Z4l;4IM#~2xi{h(+nQ~0000K0002=w*Ua_p8o$R00000 zK@Jc|4gdfk0000CxBvkBp8o$F00000K@K3D1fByy4IM<@-3%W90000K0000mxBvk3 zp8o$700000K@Jc@4gdfY0000;xBvj~p8o$700000K@Jc@4gdfo0001BxBvj`p8o$p z00000K@KpT2A%~$4IM#~1WexD(+nQ~0000K0001pxBvhIpZ@xBvhIpZ@<`00000K@KpT2A%~$4IM#~1XJGK(+nQ~0000W0002UxBvh+pZ@x&Q#E zp#J|r00000K@KpT2A%~$4IM#~1WexD(+nQ~0000i00022vj70Vp#J~h00004ml*&6 zK@NZcoe-W6K@A;3lMa*(l?-#<-PP073?Bd>0002^x&Q!hq5l7T00000K@KpT2A%~$ z4INzG-3%W90000W0000Sy8r;lq5l7T00000K@KpT2A%~$4INzG-3%W90000W0000$ zy8r+nqW=GU00000K@KpT2A%~$4INzG-3%W90000W0001Fy8r-qqW=GU00000K@KpT z2A%~$4INzG-3%W90000K0001py8r;tqW=FB00000K@Jc@4gdfY0001>y8r;pqW=FB z00000K@Jc@4gdfY0002Ey8r;lqW=FB00000K@Jc@4gdfk0002cy8r;hqW=F_00000 zK@LEj2%ZN)4INY7-3%W90000K0002=y8r zr2hXD00000K@Jc@4gdfo0001xy#N3-r2hXr00000K@KpT2A%~$4IM#~1WVrC(+nQ~ z0000K0002Ey#N46r2hXD00000K@Jc@4gdfk0002cy#N42r2hXb00000K@KpT2A%~$ z4IN0{-3%W90000W0002=y#N4Ar2hXP00000K@K3D1fByy4IM?^-3%W90000a0000O zz5oD7r2hX@00000K@LEj2%ZN)4IM#~29yO+-rdvG3?Bd>0000$z5oDpr2hXL00000 zK@K3D1fByy4IM<@-3%W90000W0001Fz5oDhr2hXL00000K@K3D1fByy4IM<@-3%W9 z0000a0001pz5oDZr2hY000000K@L!z3Z4l;4IM#~2vgqO(+nQ~0000W00026z5oE2 zr2hXv00000K@KpT2A%~$4ING1-3%W90000a0002gz5oEUr2hX%00000K@LEj2%ZN) z4IM#~22S4H(+nQ~0000K0002|z5oE!r2hXH00000K@Jc^4gdfY0000KzW@N#r2hXD z00000K@Jc@4gdfY0000izW@Nxr2hXD00000K@Jc@4gdfk0000)zW@Ntr2hXj00000 zK@LEj2%ZN)4IN6}-3%W90000e0000?xBvj$r2hYq000042NeJSK@LEj2%ZN)4IM#~ z29yP0-rdvG3?Bd>0001#zW@M0rT+gQ00000K@K3D1fByy4IM?^-3%W90000a0002E zzW@L{rT+g^00000K@LEj2%ZN)4IM#~29yO+-rdvG3?Bd>0002szW@MerT+h900000 zK@LEj2%ZN)4INhA-3%W90000W00004zyJWKrT+go00000K@KpT2A%~$4IN9~-3%W9 z0000K0000ezyJWerT+gI00000K@Jc^4gdfY0000$zyJWerT+gE00000K@Jc@4gdfY z00013zyJWarT+gE00000K@Jc@4gdfk0001RzyJWWrT+gk00000K@LEj2%ZN)4IN6} z-3%W90000e0001Zxc~sfrT+h500004^Ai97K@KpT2A%~$4IM#~1XSML(+nQ~0000i z0001_xc~t8rT+hb00004*AoB$K@L!z3Z4l;4IM(02$Tnv23y|U)zj1r9{>O#0002+ zzyJV9rvCp}00000K@LEj2%ZN)4INY7-3%W90000W0000K!2ke!rvCpl00000K@K3D z1fByy4IN6}-3%W90000W0000u!2ke^rvCpV00000K@K3D1fByy4IM__-3%W90000W z00017!2ke^rvCpl00000K@K3D1fByy4IN6}-3%W90000W0001h!2kf9rvCpV00000 zK@K3D1fByy4IM__-3%W90000W0001_!2kf9rvCpl00000K@K3D1fByy4IN6}-3%W9 z0000W0002U!2kfPrvCpV00000K@K3D1fByy4IM__-3%W90000W0002&!2kfPrvCpl z00000K@K3D1fByy4IN6}-3%W90000W0000G!TFDTL1tAClUYvK@L!z z3Z4l;4IM#~2m|;Q-rds-9{>O#0001}!To1lR%qlmVOp$N~WP0t5g600030{{b0T1ONbN1h4`C zqyYo~0PFz-!~y`o0vG@Q|Nj9@P_zL60N4TqfC&JI0|Wp7m;(g#2>|>9r~$kQ0Qdz2 zlnDUf1_Znb0JsMPs0jev2L!wc0FVd-NV@B;+c1OU_o7ytnO{{ajX1ONaa1T+9d1ONd4o0I_ohXFWD005u? zIN%NdtO5kk3joXl5S$GIkOKsO4Fl){1mFt;yaWV*4Fi+~1oR67*aZZD4Flu_FzgHi zoCXAl3;?p!3um|2= zEC2xH2n6g20K5qV+z9~82?Xp30Eh|%000000et|ZP5}V_{{b~nOaK7H0Tj3f0PFz- zhz01egW@hy)b41^}=G1gHi8*aV~jxCQ{o1_S^A|Nj9H=m7)(0GI*< z$N~V^0t5g6|Nj91|Nj91|Nj91|Nj9DGz0(uKm0|49uQ~&_~{{a&)1ONbF1jqpZa0Ivk0O$b(009600RaF1 z0RaF10SH6{Yyf-&009600TCnw002k?cmP}kWB`Z(1ONd4{{aC1{{dG>1ONbN1jGjb zfB|rz2mqV{1c(R#xB>+D2LRXt1n36<^a2Ff2LQYS1fU22&;)S&2mtH_1mp++hz11I z2mq)C1jGmc#0CVk2mp)+1pEj9)Car)009600RRC1n;iiZWCQ>Ja6s?@0e}JogaQDN z0t5g60RR9100030nyQQ1dsv5Bmk@i1gszc$OZ(QAOPqF1dJd6ga-ut9{|7ym;%Hk z0O$z>gdqTc3Iy~Z0GJ8{>;eSb1pxd41k42h+yey6 z1_1N}1iS_Sgaibv1_00m1pEd7=mZ4p1_1a31l$Gys0H`|009600SH_KWB_yo00960 z0XWbB1b_qp@Bst>0Ehwvlmq~%0t5g6zybuQ1OVUy1ONc|0tCDS0GI;=006K91keNk z&;yhK009600iXiV0n`D+BmmF@1mqt8>;nYU9{`L51jHWzs00MG9{}(KkO9Ob0IUWC ztRMi$1_YcS0O$q;j35An2L${d0Kf;B0>mT$=m`XbApn311oR*Pm6q5d`cZ0NfD-+#vv*6MzE5Bml@21k@q`jT*BLLJS1ONd4{{cAA0R(^q0Pq0> z004*r1e62-r~(840KftSs00Au0t5g6_yPpH1OS)=1ONcA0|d|n0MG-J0RRC1{{aec z1fT%`zySmR0RR612uuW20B8gN00030nJa6s?@0e}JogaQDN0t5g60RR9100030{{as?1dIXzd<6Uf0Gt8@00960 z0S`O`i~<0B1pEO2oB{*@0RR614?F~n0swpj`~d)*0t5g6|Nj91|Nj9100030n=t_> zcmx0dfC8ujzy|=x1TX*qtObAp)CU3727mzo0H6po)Cd6J2m}BC0RR9100030{{aC1 z{{aC1{{aC1{{aC1{{aC1{{aC1{{aC1{{aC1{{b6RSO5UP0tDm(0N4Tq)B^zQ0tCbZ z0GtC{009600S_<)003Ns0ki@D!~z5W0RR618&p^T0KftSK@7*Z~Cm0s!y<1ndF;gaQQI0syoETmS(7{{b6B7ytm+0R;R40Pq0> z>;eFU0tDOw0JH*J00030n;8KSgaHJM0Rfx=1fT%`tN{c70096100030{{aC1{{aC1 z{{aC1n;8KQR0MbdgaHVQ0RWf*1ONa50000000030{{aC1{{aC1{{aC1{{aC1{{aC1 z{{aC1n-u{KJOpF`a0qw+gaHHq0096100030n;8KQa0GY(hyetQ0RWf*1ONa500000 z00030{{aC1{{aC1{{aJfB`V@0Reyl1cU+rkOBk%0096100030{{aC1{{ah(0R)r*0H^^300030n;8KQ zC(K0096100030n;8KQR0MbdgaHVQ0RWf*1ONa50000000030{{ah( z0R)r*0H^^300030n-u{KSOj1Ja0GM!fB^&m0096100030{{ajf1ONay1V8{#1ONd4 z{{aY01XKWM1ONd4{{e*)OauS`gaHJkhXDYb0R)tX0RZFy1jvU00Q><2xQ77%!~z8D zhXDZG0tDQL0RW@}1dxaU0KfwTfQSJAhy(<*hyehk1O%jr0RZd-1lWiH0Eh(y$cO;| z&;EO^$Pfhdi~#`T5Cr6m z0RXHK1elEh0LT#ph>ZaNkP-yEjR63x5(KP`0RZ$81mKMU0FV;|(2W5A*b@YVjsXDl z69n{)0RX%d1gMSy0N4}+n2rGepcMqnjsXC?6$HGF0RV&+1n`al0H78G;En+R=oSQ& zj{yLL7X*Zl0RYSw1h|g@0O%J4sE+{vuowi~j{yM87zE6Z0RWU41b~nM0I(SZ@Q(oi z_!$JGkO2Uc8U&P(0RY?@1jvv90QedNxR3z=z#9bYkO2VP8wA{t0RW^N1dx#d0Kgms zfROjT*kpTeg9t7->0RXfg1fY@u z0MH)>kik^um;AOy6M0Ra3U1n80h0GJ^J*pdMN;2{KzlK}wyAq4!A0RY4z z1hA6<0N^47ppyXrs3Qc_lK}w4BLu{g0RW671o)Ey0H`Dc=#v2e@FWDBlmP&YB?OF= z0RYq`1i+L50PrOQu#^D+xF!VTlmP(LCIr-!0RWsQ1c;RZ0JtXv_>=(vfG7m4l>q>p zCq?cDFoz|0RXHj1elfq0LUr?h?W5WkShed zmH_~)D+H{T0RZ$X1mKnd0FW#M(3SxJ*enEumjM9uEClqH0RX%$1gMt*0N5=An3n+n zpe_W=mjM90E(E-n0RV(A1n`#u0H7}f;Fkda=r076m;nHUFa(5{0RYS}1h|+10O&9T zsF(o&urUPOm;nIHF$Bz*0RWUT1b~?V0I)Iy@R$Jr_%Z~fnE?QlGX#{G0RY@H1jv~I z0QfTmxS0U}z%&HxnE?RYGz8q40RW^m1dy5m0Khc_fSLgSh&BYYngIZ$HUy-a0RZea z1lXDZ0EjmP$eIBF&^HA9ngIapHw5gO0RXf(1fZJ%0MIxDkedMjm^lQ*n*ji{IRvzu z0Ra3t1n8Rq0GK)i*qZ?W;5r11oB;s*It2Wi0RY511hAX|0N^_Wpqv2!s5}JJoB;sD zJOsp?0RW6W1o)f*0H{3#=$run@I3^aodE!hJ_L-N0RYrK1i+mE0PsEpu$=(_xIYBs zodE#UKLpgB0RWsp1c;si0JuN|_?-a&fI$STo&f-yK?Izh0RZGd1kj!V0DwXSz@7mB z$U+44o&f;lLImWV0RXH+1el)z0LViGh@SxfkVFK$p8)`@Luu25np#cEQN(9WI0RWUs z1c0Ie0I*90@SyYqX7Wy zPz3Cw0RXg71fZk=0MJnckfZ?sm{J79qyYf5QUtW50Ra3`1n8sz0GLw**rWjf;8O&Q zr2zo^Qw02^0RY5Q1hAz60N_*vprru-s8s~ir2zoMRRqMP0RW6v1o))^0H{_3=%oPw z@KywzrU3wqR|Jfv0RYrj1i+>N0Pt4?u%-b3xL5?_rU3xdSOnCj0RWs?1c;{r0JvEM z_@)5>fLa8srvU(*S_GV@0RZG$1kk4e0DxNrz^4HK$Xf*TrvU)uTLk2%0RXIA1emA+ z0LWYfh^PSokX;14r~v@1T?DMC0RZ$}1mLIv0FYh;(5L|b*j@yLsR01=UIg^00RX&T z1gNP20N7syn5h8(pkM^dsR01IU$gBYX&}jtxtN{S*X$0)70RXgW1fZ<}0MKd#kgWj# zm}>;YtpNbEYXr2d0Ra4K1n8{+0GMn9*sTEo;A{kpt^ol2Yy|wR0RY5p1hB3F0N`x| zpsoP`sBQ$*t^okVZUn@x0RW6|1o*B20H|*S=&k_(@NWd1uK@sza0HC60RYr+1i-HW z0Pt`Gu&)6CxN!vJuK@tmaRk(_0RWtG1ckNP zz<&hnv;hFze+1mL0RW_c0R)h>0RX^&0R(`x0RV`B0R*(Q0RW_d0R*JA0RZfQ0R-5! z0RV`C0R+gk0RYf~0R;TD0RZfR0R-%|0RXgv0R*770RYg00R)h?0RWhU0R+Uh0RXgw z0R*(R0Ra4j0R-r_0RWhV0R-5#0RZ5I0R)V<0Ra4k0R;TE0RY5?0R*tO0RZ5J0R*78 z0RXgz0gx~N0RR6100000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000026umk`A0002&Cj|fi0001Jumk`A0001p zSqA_B00026SqA_B0002MSqA_B0002USqA_B0002kSqA_B00000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000001000000002>xB>tG0000100000 z00000xdH$H00001000000000CxdH$H00001000000000SxdH$H00001000000000h zxdH$H00001000000000rxdH$H00001000000000(xdH$H00001000000000@xdH$H z0000E000000001ExdH$H0000C000000001BPy_$~0000D000000002YRR;h70000P z000000001B$q4`e0000R000000000G000000000Q000000001R$q4`e0000S00000 z00008000000002>{{L?P0000e0ssI200005000000001>>i_@%000060000000026 zHUIzs0000A000000002oxdH$H0000B000000000O0000000003000000002+&Itej z00002000000002sjsO4v0000K0000000007000000000N000000001h!2f00000)Kv!n000002mk;85C8xG00961M?oY3Ghs0R z%vA>f00000%vA>f000002mk;85C8xG00961M?oY3Ghs0RY)}LM00000bWj8U00000 z2mk;85C8xG00961M?oY3Ghs0R)Kv!n00000+*Jnv0000000000000000000000000 z000000000000000000000{{U400IC2000000000000000000000{{X5C;|Wg00000 z0000000000000000{{a6ur>ey000000000000000000000{{d7pz8nt0000000000 z00000000000{{g8e5C^b000000000000000000000{{j9khB8;000000000000000 z000000{{mAfVBev000000000000000000000{{pBfWZR*00000000000000000000 z0{{sCU{C}A000000000000000000000{{vDfKUVg000000000000000000000{{yE z;I9M#000000000000000000000{{#F%vA>f000000000000000000000{{&G;8h0z z000000000000000000000{{*HFuex=000000000000000000000{{;IcJgsunx000000000000000000000{{^KV95yp0000000000 z00000000000{{{LV95yp000000000000000000000{{~MaLEY(000000000000000 z000000{|2Nc*zL>000000000000000000000{|5OaLfq+00000000000000000000 z0{|8P@XiSU000000000000000000000{|BQ000UA000000000000000000000{|ER zAOH#g000000000000000000000{|HS00000000000000000000000000{|KTAO;Em z0000000000000000RR911OV~>00000000000000000000KL7v#000XB;I9M#00000 z0000000000LI3~&0sspD;I9M#000006aWAK00000KL7v#000R9U{C}A0000000000 z00000KL7v#000aC%vA>f000000000000000PXGV_1OV~>00000000000000000000 zKL7v#000R9Y)}LM000000000000000KL7v#000aC)Kv!n000000000000000jQ{`u z1OV~>00000000000000000000KL7v#000XB_^$*2000000000000000m;e9(0sspD z_^$*2000000000000000ng9R*0sspDD6j+o000000000000000tpET3000*N000UA z000000000000000umAu60sspDXs`qT000000000000000#sB~S0RR{PAOH#g00000 z0RR9100000tpET3000vJaLEY(000000000000000)c^nh0RR&KaLEY(0000000000 z00000`~Uy|0sspDu&@LG000000000000000tpET3000sIV95yp000000000000000 z2mt^90RR#JV95yp000000000000000tpET3000jFjOqsf000000000000000tpET3 z000;OAOH#g000000000000000NLl~@1OV~>00000000000000000000tpET3000dD z;8h0z000000000000000CjkHe0RRmE;8h0z000000RR9100000KL7v#000XB2q*;r z000000000000000KL7v#000XBFen88000000000000000KL7v#000XBq$mXd00000 z0000000000KL7v#000XByeI_#000000000000000KL7v#000XB)F=f20000000000 z00000KL7v#000XB2q^^s000000000000000KL7v#000XBJShbL000000000000000 zKL7v#000XBWGMvz000000000000000KL7v#000XBpeY3a000000000000000KL7v# z000XByeS0$000000000000000KL7v#000XB*eL}7000000000000000tpET3000yK zpvegU000000000000000LID5(0RR*LpvegU000002mk;800000KL7v#000XBw6FvK z000000000000000a{&MV0sspDw6FvK00000AOHXW00000i~#@u0sspD)UX5q00000 zFaQ7m00000v;hDB0sspD1hE7F00000FaQ7m00000)&T$j0sspDG_eE#00000JOBUy z000001Ofm60sspDaIpjc00000FaQ7m00000ECK)k0sspDps@r100000OaK4?00000 zTmk?90sspD?6Cv@00000Pyhe`00000KL7v#000XB;3)+F000000000000000KL7v# z000XBTq*?s000000000000000h5`Tp0RRmE_*Dl0000000RR9100000n*sm;0RRmE z09FS8000000RR9100000KL7v#000XB*eV48000000000000000KL7v#000XB3@Zfy z000000000000000KL7v#000XBKr00R000000000000000KL7v#000XBv?~Pw00000 z0000000000KL7v#000XB@EcW000000000000000KL7v#000XB3@-%$ z000000000000000KL7v#000XBoG%3c000000000000000KL7v#000XBye|a+00000 z0000000000KL7v#000XB^%hl000000000000000 zKL7v#000XB7(WF7000000000000000KL7v#000XBTt5W>000000000000000KL7v# z000XBh(HAZ000000000000000-U0vs0RR*LsL2Tc000002mk;8000001Oos70RR*L zu*nGk000002mk;800000KL7v#000XB%s>SI000000000000000KL7v#000XB^gsmw z000000000000000KL7v#000XB96<#D000000000000000KL7v#000XBKtTln00000 z0000000000KL7v#000XB)IkLR000000000000000KL7v#000XB_(25#0000000000 z00000KL7v#000XBghB-X000000000000000KL7v#000XB7()dB000000000000000 zKL7v#000XBJVONl000000000000000KL7v#000XBTtfu_000000000000000KL7v# z000XBfI|fU000000000000000KL7v#000XBphE=!000000000000000KL7v#000XB zBt!)O000000000000000KL7v#000XBY(xbB000000000000000KL7v#000XBltcvp z000000000000000KL7v#000XB$V3GI000000000000000KL7v#000XBg&000001ONa400000 zTLb_A0RR{PPyh-5000000RR9100000dISIf0RRmE=vD^+000001ONa400000jRXJy z0RR{PSO5wD000000RR9100000s{{Z50RRmE>{bT=000001ONa400000!~_5U0RR{P zU;qjL000000RR9100000=L7%%0RRmE@Ky%^000001ONa400000`~(010RR{PXaEWT z000000RR91000008wCIW0RRmE^i~G|000001ONa400000E(HJp0RR{PZ~zJb00000 z0RR9100000Oa%Y{0RRmE_*Mr1000001ONa400000W(5EM0RR{PcmN6j000000RR91 z00000iUj}w0RRmE{8k45000001ONa400000s|5f60RR{PfB*^r000000RR9100000 z)&&3n0RRmE09OY9000001ONa400000_XPj|0RR{PhyV%z000000RR9100000A_f2e z0RRmE1Xl+D000001ONa400000MFs!>0RR{PkN^q*000000RR9100000as~hZ0RRmE z2v-LH000001ONa400000lm-9*0RR{Pm;ed@000000RR9100000zy<&S0RRmE3|9vL z000001ONa400000)&>9o0RR{Ppa2R0000000RR9100000_67g|0RRmE5LX8P00000 z1ONa4000004hH}L0RR{Pr~nE8000000RR9100000Fb4nt0RRmE6juiT000001ONa4 z00000O$Pt~0RR{PumB1G000000RR9100000bO!(c0RRmE7*_`X000001ONa400000 zk_P|)0RR{PxBvLu00000 z0RR91000003JCxJ0RRmEELR5r000001ONa400000E(rht0RR{P-~b8$000000RR91 z00000TnPXG0RRmEFjofv000001ONa400000eF*>n0RR{P=l}`;000000RR9100000 zs0jc70RRmEG*<@z000001ONa400000&Nr0RR{P009aB000000RR9100000t_lDE0RRmEKvxF< z000001ONa400000#tHxc0RR{P2muNJ000000RR9100000=n4P;0RRmEL{|p@00000 z1ONa4000002MYiI0RR{P5CIAR000000RR9100000Fbe4000001ONa400000+6w>x z0RR{PC;00000 z0RR9100000`V0U70RRmEU{?nK000001ONa40000084Umc0RR{PNC64}000000RR91 z00000LJa@_0RRmEWLF0O000001ONa400000Xbk`W0RR{PPyq@6000000RR9100000 zm<<2`0RRmEXjcaS000001ONa400000w+#RQ0RR{PSOE$E000000RR9100000;0*u( z0RRmEY*z;W000001ONa4000000}cQH0RR{PU;zpM000000RR9100000Fb)6!0RRmE za90Na000001ONa400000Qw{(C0RR{PXaNcU000000RR9100000fDQlv0RRmEbXNxe z000001ONa400000rw#xB0RR{PZ~+Pc000000RR9100000*bV>y0RRmEcvlAi00000 z1ONa400000{0;yB0RR{PcmWCk000000RR9100000Dh~hv0RRmEd{+km000001ONa4 z00000OAi150RR{PfB^~s000000RR9100000b`Jmm0RRmEfL8|q000001ONa400000 zl@9;_0RR{Phye-!000000RR9100000z7GHZ0RRmEgjWXu000001ONa400000;|~A; z0RR{PkO2w+000000RR91000005)c3Y0RRmEh*t*y000001ONa400000GY|j(0RR{P zm;nj^000000RR9100000UJw8P0RRmEj8_K$000001ONa400000jSv6;0RR{PpaBX1 z000000RR9100000#t;Ai0RRmEkXHu)000001ONa400000_7DI70RR{Pr~wK900000 z0RR9100000FcAO%0RRmElvf7;000001ONa400000UJ(EQ0RR{PumK7H000000RR91 z00000mJt8|0RRmEm{$h?000001ONa400000#}NPk0RR{PxB&_P000000RR9100000 z0ulfK0RRmEoL2_`000001ONa400000FcJU&0RR{PzyS&X000000RR9100000Xc7Pb z0RRmEpjQU~000001ONa400000m=XX00RR{P$N>rf000000RR9100000(h>jw0RRmE zq*n(3000001ONa4000000TTcK0RR{P&;ben000000RR9100000Iuif@0RRmEs80RRmE$X5pd000001ONa4000000u}%O0RR{P7y=3a000000RR91 z00000E*1a)0RRmE%vT2h000001ONa400000QWgLJ0RR{PAOZ>i000000RR9100000 zfEEA%0RRmE&{qcl000001ONa400000pB4ZB0RR{PC;|!q000000RR9100000$QA$q z0RRmE)K>=p000001ONa400000=@tM00RR{PFainy000000RR91000006c+#h0RRmE z*jEPt000001ONa400000I~M=|0RR{PI06a)000000RR9100000Y!?6k0RRmE+*bzx z000001ONa400000krw~}0RR{PKmrN?000000RR9100000z!v}j0RRmE;8zC#00000 z1ONa400000+7|!-0RR{PNCFA~000000RR9100000{uclM0RRmE{kZ>000001ONa400000(ii{$ z0RR{PU;+vN000000RR91000003>g3b0RRmE@K*-_000001ONa400000G#LN@0RR{P zXaWiV000000RR9100000W*Gng0RRmE^j8M}000001ONa400000i5UO@0RR{PZ~_Vd z000000RR9100000wiy5b0RRmE_*Vx2000001ONa400000(is2%0RR{PcmfIl00000 z0RR9100000_!$5I0RRmE{8tA6000001ONa40000078(Em0RR{PfC35t000000RR91 z00000J{kZ30RRmE09XeA000001ONa400000Vj2Jd0RR{Phyn@#000000RR9100000 zkQx900RRmE1Xu?E000001ONa400000vl;*Z0RR{PkOB$-000000RR9100000;2Hn` z0RRmE2v`RI000001ONa400000{~7=Q0RR{Pm;wp_000000RR9100000C>sC(0RRmE z3|I#M000001ONa400000P#XXM0RR{PpaKd2000000RR9100000f*Sw;0RRmE5LgEQ z000001ONa400000s2czP0RR{Pr~(QA000000RR9100000*c$)<0RRmE6j%oU00000 z1ONa4000003LF3c0RR{PumTDI000000RR9100000MjQYD0RRmE7+41Y000001ONa4 z00000c^m)$0RR{PxB?0Q000000RR9100000wj2Ne0RRmE99Rbc000001ONa400000 z-5dY_0RR{Pzyb;Y000000RR91000004jljh0RRmEAXo{U+0RRmEELaBs000001ONa400000Qyu^S0RR{P-~tK&00000 z0RR9100000h#mj{0RRmEFjxlw000001ONa400000s~!LV0RR{P=mH7=000000RR91 z00000*d71?0RRmEG*|}!000001ONa400000{~iDU0RR{P@B#_|000000RR9100000 zFdqN_0RRmEI9LY&000001ONa400000XCD9n0RR{P_yP(5000000RR9100000s2>0T z0RRmEJXi++000001ONa400000(jNc-0RR{P00RmD000000RR91000001|R?c0RRmE zKv)L=000001ONa400000BOm|(0RR{P2m=ZL000000RR9100000N+19L0RRmEL|6v^ z000001ONa400000ZXf^v0RR{P5CaMT000000RR9100000oFD)I0RRmENLU8|00000 z1ONa400000!yo_v0RR{P7y}9b000000RR9100000^dJBL0RRmEOjrj1000001ONa4 z00000DIov=0RR{PAOi{j000000RR9100000XdwUq0RRmEP*?{5000001ONa400000 znjruH0RR{PC<6)r000000RR9100000)*%1@0RRmER9FW9000001ONa4000005F!8o z0RR{PFartz000000RR9100000R3ZQX0RRmESXc)D000001ONa400000n<4-J0RR{P zI0Fg*000000RR9100000>>>aF0RRmETv!JH000001ONa4000007b5@w0RR{PKm!T@ z000000RR9100000Od|jQ0RRmEU|0tL000001ONa400000X(Ipt0RR{PNCOH000000 z0RR9100000kRt#90RRmEWLO6P000001ONa400000u_FKg0RR{PPy-48000000RR91 z00000+#>)00RRmEXjlgT000001ONa400000`y&7V0RR{PSOW?G000000RR9100000 zBqRU;0RRmEY*+^X000001ONa400000JR|@B0RR{PU;_#O000000RR9100000UL*hj z0RRmEa99Tb000001ONa400000bR+-(0RR{PXafoW000000RR9100000lq3KE0RRmE zbXW%f000001ONa400000z9awu0RR{Pa03be000000RR9100000@+1HN0RRmEcvuGj z000001ONa400000A0+?)0RR{PcmoOm000000RR9100000RwV!c0RRmEd{_qn00000 z1ONa400000eI)<@0RR{PfCCBu000000RR9100000t|b5f0RRmEfLI3r000001ONa4 z00000)+GP{0RR{Phyw}$000000RR91000002qpjk0RRmEgjfdv000001ONa400000 zGbR840RR{PkOK+;000000RR9100000XeIyv0RRmEh*$>z000001ONa400000jwS#A z0RR{Pm;(v`000000RR9100000z9s+w0RRmEj93Q%000001ONa400000?j`^L0RR{P zpaTj3000000RR9100000C?@~_0RRmEkXQ!*000001ONa400000RVM%d0RR{Pr~?WB z000000RR9100000j3)p90RRmElvoD<000001ONa400000wkH4p0RR{PumcJJ00000 z0RR9100000>L&mI0RRmEm{000000RR9100000QYrud0RRmEv{(lK000001ONa4 z00000bSeM<0RR{P@B<0}000000RR9100000peg_W0RRmExL5}O000001ONa400000 z#VP;*0RR{P_yY<6000000RR9100000^eO-V0RRmEyjTYS000001ONa400000BP##^ z0RR{P00asE000000RR9100000Tq^(o0RRmEz*q+W000001ONa400000h${d90RR{P z2m}fM000000RR9100000zAFF#0RRmE#8?La000001ONa400000@+$xU0RR{P5CjSU z000000RR9100000Ff0H70RRmE$XEve000001ONa400000V=Mpw0RR{P7z7Fc00000 z0RR9100000pez6Y0RRmE%vc8i000001ONa400000(JTM}0RR{PAOs2k000000RR91 z000003@rcv0RRmE&{zim000001ONa400000J}m$M0RR{PCDs0RR{PFa!z!000000RR9100000_ALMa z0RRmE*jNVu000001ONa400000EiM260RR{PI0Om+000000RR9100000ZY}@-0RRmE z+*k(y000001ONa400000p)LRb0RR{PKm-Z^000000RR9100000-Yx(D0RRmE;8+I$ z000001ONa4000006E6S&0RR{PNCXN1000000RR9100000QZE1i0RRmE{tf?000001ONa400000 zbua(`0RR{PU<3*P000000RR9100000t}p-q0RRmE@K^@`000001ONa400000-Y@_F z0RR{PXaouX000000RR91000007%>0<0RRmE^jHS~000001ONa400000N-+Qc0RR{P za0Chf000000RR9100000hA{vD0RRmE_*e%3000001ONa400000y)gg)0RR{PcmxUn z000000RR9100000{xJXm0RRmE{8$G7000001ONa400000G%^4H0RR{PfCLHv00000 z0RR9100000bTR+{0RRmE09gkB000001ONa400000o-zOc0RR{Phy)4%000000RR91 z00000(lP)50RRmE1X%|F000001ONa40000012X^s0RR{PkOT?<000000RR9100000 zJ~IFS0RRmE2w4XJ000001ONa400000a5De^0RR{Pm;?#{000000RR9100000tTO-r z0RRmE3|R*N000001ONa400000+cN+F0RR{Ppacp4000000RR91000006f^(;0RRmE z5LpKR000001ONa400000NHhQd0RR{Ps00cC000000RR9100000hBN>G0RRmE6j=uV z000001ONa400000xikO(0RR{PumlPK000000RR9100000_A~$h0RRmE7+D7Z00000 z1ONa400000EHwZC0RR{PxC9CS000000RR9100000Y&8G?0RRmE99ahd000001ONa4 z00000p)~*i0RR{Pzyt~a000000RR9100000;57gM0RRmEAXx_h000001ONa400000 z5jFq-0RR{P$OH-i000000RR9100000Of~=j0RRmEBv}Ul000001ONa400000e>MOB z0RR{P&;$wq000000RR9100000yfy#;0RRmEC|L&p000001ONa400000@HPMd0RR{P z*aQjy000000RR9100000E;j%G0RRmEELjHt000001ONa400000VK)E(0RR{P-~000001ONa400000d^rFB0RR{P2n7lN000000RR9100000wmAR*0RRmE zL|F#_000001ONa400000=s5rY0RR{P5CsYV000000RR9100000Bsu^90RRmENLdE} z000001ONa400000RyqIx0RR{P7zGLd000000RR9100000k~#nY0RRmEOj!p200000 z1ONa400000$vOZ40RR{PAO#8l000000RR91000003OfJ*0RRmEP+126000001ONa4 z00000Hah?S0RR{PCQ000000RR9100000 z^gRFo0RRmEa9IZc000001ONa400000B|ZQE0RR{PXax!Y000000RR9100000U_Jl< z0RRmEbXf-g000001ONa400000mOcOg0RR{Pa0Lng000000RR9100000);<6L0RRmE zcv%Mk000001ONa4000004nF_@0RR{Pcm)ao000000RR9100000P(J_w0RRmEd|3wo z000001ONa400000g+BlQ0RR{PfCUNw000000RR9100000#6JK40RRmEfLR9s00000 z1ONa400000`#%5x0RR{Phy@A&000000RR9100000KL7v#000XB2uTG10000000000 z00000tpET31^^KN00000000000000000000tpET31^^KN2mk;8000000000000000 zKL7v#000XBNJ#|%000000000000000KL7v#000XB000000000000000JU{>d0RR*Lc*zL>000002mk;800000U_bx>0RR*L zfXN8}000002mk;800000fIt8M0RR*Lh{*{6000002mk;800000oj?Ep0RR*LkjV)E z000002mk;800000zCZu~0RR*Ln8^tM000002mk;800000+du#S0RRmE;8_O%00000 z2mk;800000_doyu0RR{PkOc|=00000Pyhe`00000BS8QF0RR{P-~|c*000002mk;8 z00000Q9%Fz0RRmE;EM+U000001poj500000dqDsI0RRmE=!*vc000005dZ)H00000 z-9Z2V0RRmE0E`C!000005dZ)H00000KL7v#000XBkV^#s000000000000000KL7v# z000XBox1000004gdfE00000tpET3000mG zaIgpf000000000000000M?wGq0RRmEaG(bO000004FCWD00000KL7v#000XB983iO z000000000000000KL7v#000XBP)r2?000000000000000KL7v#000XBa7+aN00000 z0000000000KL7v#000XBkW2*t000000000000000KL7v#000XBuuKI20000000000 z00000KL7v#000XB&`bpY000000000000000enJ2M0RRmE5Vr>a000006aWAK00000 zKL7v#000XB{7eM^000000000000000KL7v#000XBY)%CL000000000000000KL7v# z000XBj7|jr000000000000000KL7v#000XBtWE_0000000000000000KL7v#000XB zz)l4K000000000000000KL7v#000XB^iBl;000000000000000KL7v#000XB6i)>J z000000000000000KL7v#000XBWKRVE000000000000000KL7v#000XB@J|H*00000 z0000000000KL7v#000XBv`_^A000000000000000KL7v#000XB{7?k|0000000000 z00000KL7v#000XBG*JZr000000000000000KL7v#000XB_)!G_000000000000000 zKL7v#000XBJW>S!000000000000000KL7v#000XBfKmkj000000000000000KL7v# z000XBv{D5C000000000000000KL7v#000XB$WjFW000000000000000KL7v#000XB z1XBe7000000000000000KL7v#000XB7*hoR000000000000000KL7v#000XBuu}y9 z000000000000000KL7v#000XB#8U+T000000000000000KL7v#000XB08|A400000 z0000000000KL7v#000XBNK^#?000000000000000KL7v#000XBY*YmR0000000000 z00000KL7v#000XBj8p{x000000000000000KL7v#000XB#8d?U000000000000000 zKL7v#000XB@Kgl=000000000000000KL7v#000XBEL8;n000000000000000KL7v# z000XBKve|*000000000000000KL7v#000XBtW^a7000000000000000KL7v#000XB z&{YKh000000000000000KL7v#000XB>{SH-000000000000000KL7v#000XB999JY z000000000000000KL7v#000XBL{1F000000000000000KL7v# z000XBv|I%M000000000000000KL7v#000XB_*?}5000000000000000KL7v#000XB zAYBCj000000000000000KL7v#000XBI9&w*000000000000000KL7v#000XBTwMhK z000000000000000KL7v#000XBcwGem000000000000000KL7v#000XBs9gmB00000 z0000000000KL7v#000XB$Xx{h000000000000000KL7v#000XB++76#0000000000 z00000KL7v#000XB3|<8Q000000000000000KL7v#000XBAYKIk000000000000000 zKL7v#000XBP+kQ9000000000000000KL7v#000XBP+$cB000000000000000KL7v# z000XB_+bSA000000000000000KL7v#000XB9AX6k000000000000000KL7v#000XB zKw<>|000000000000000KL7v#000XBq+$gC000000000000000KL7v#000XBk000000000000000KL7v#000XB3~2=b000000000000000KL7v# z000XB2x~RGE00000 z0000000000KL7v#000XBgmMJ{000000000000000KL7v#000XB)N%y?0000000000 z00000KL7v#000XBD02k>000000000000000KL7v#000XBJaYvA000000000000000 zKL7v#000XBU~>fk000000000000000KL7v#000XB9C!r)000000000000000KL7v# z000XBKzRiK000000000000000KL7v#000XB9C`%+000000000000000KL7v#000XB zczOi@000000000000000KL7v#000XBoO%TS000000000000000KL7v#000XB#Cin) z000000000000000KL7v#000XB z000000000000000KL7v#000XB@P!2c000000000000000KL7v#000XB7={G^00000 z0000000000KL7v#000XBEQSRD000000000000000KL7v#000XB2!{m#0000000000 z00000KL7v#000XBWQPR+000000000000000KL7v#000XBgogzH000000000000000 zKL7v#000XBn1=-b000000000000000KL7v#000XBG>8QN000000000000000KL7v# z000XBbch82000000000000000KL7v#000XBT#5w%000000000000000KL7v#000XB zfQkhG000000000000000KL7v#000XByovTfs00000 z0000000000KL7v#000XBh>HaP000000000000000KL7v#000XBxQqn=0000000000 z00000KL7v#000XBV2uR;000000000000000KL7v#000XBkc|ZZ000000000000000 zKL7v#000XBz>Ng}000000000000000KL7v#000XB@Qnok000000000000000KL7v# z000XB6pjS|000000000000000KL7v#000XBIF1DX000000000000000KL7v#000XB zT#f|*000000000000000KL7v#000XBfQ|(K000000000000000KL7v#000XBtd0c$ z000000000000000KL7v#000XB$c_a7000000000000000KL7v#000XB_>Kht00000 z0000000000LPG!m0RRmE$c_g900000GXekr00000KL7v#000XB5Re4`0000000000 z00000KL7v#000XBY>)*2000000000000000KL7v#000XBoR9?o000000000000000 zKL7v#000XBP>}@y000000000000000KL7v#000XBc##DF000000000000000KL7v# z000XB{E-C!000000000000000KL7v#000XB6p{r1000000000000000KL7v#000XB zK#~Oj000000000000000KL7v#000XBe3AtK000000000000000KL7v#000XB*pdYR z000000000000000KL7v#000XB1d{~-000000000000000KL7v#000XBh?4~X00000 z0000000000KL7v#000XB(31rK000000000000000KL7v#000XB{F4O$0000000000 z00000KL7v#000XBM3e;p000000000000000KL7v#000XBbd&`E000000000000000 zKL7v#000XBu$2V>000000000000000KL7v#000XB#FYgA000000000000000KL7v# z000XB*p&qU000000000000000KL7v#000XBIFi000000000000000KL7v#000XBK-C2R000000000000000KL7v# z000XBfY=29000000000000000KL7v#000XB+}H&G000000000000000KL7v#000XB z;MoNL000000000000000KL7v#000XB6xsy<000000000000000KL7v#000XBFxmwG z000000000000000KL7v#000XBNZJJe000000000000000KL7v#000XBVA=%$00000 z0000000000KL7v#000XBINJpP000000000000000KL7v#000XBINSvQ0000000000 z00000KL7v#000XBeB1>9000000000000000KL7v#000XBwA=*%000000000000000 zKL7v#000XB1ljMA)00000KL7v#000XB1nmU?0000000000 z00000KL7v#000XBH0=cd000000000000000sz?9;0RRmEAf5*R00000N&)}?00000 zKL7v#000XBWbOq3000000000000000KL7v#000XBeC`DR000000000000000KL7v# z000XBr0xX(000000000000000KL7v#000XB)b0fU000000000000000KL7v#000XB zFz*Eb000000000000000KL7v#000XBOz#B%000000000000000KL7v#000XBbngWK z000000000000000KL7v#000XBnC}Gu000000000000000KL7v#000XB$nOOJ00000 z0000000000KL7v#000XB@b3ix000000000000000KL7v#000XB1n>m_0000000000 z00000KL7v#000XBNbm&!000000000000000KL7v#000XB;PeFm000000000000000 zKL7v#000XBIQ0bp000000000000000KL7v#000XBtn~!|000000000000000KL7v# z000XB@bv`%000000000000000KL7v#000XBK=uUy000000000000000KL7v#000XB zT=oS3000000000000000KL7v#000XBaP|cN000000000000000KL7v#000XB4EF^9 z000000000000000KL7v#000XBH1`Dn000000000000000KL7v#000XBNcRN*00000 z0000000000KL7v#000XBoc9F)000000000000000KL7v#000XB(DwxZ0000000000 z00000KL7v#000XBEcgWg000000000000000KL7v#000XBbod1T000000000000000 zKL7v#000XBi1-Bn000000000000000KL7v#000XB4EhBC000000000000000KL7v# z000XBX!->J000000000000000KL7v#000XBZ2JWO000000000000000KL7v#000XB zfcpgi000000000000000KL7v#000XB%=-lZ000000000000000KL7v#000XBDzb000000000000000KL7v#000XBjQj-v0000000000 z00000KL7v#000XB5dH-K000000000000000KL7v#000XBDE000000000000000KL7v# z000XB`~n65000000000000000KL7v#000XBBm)Kj000000000000000KL7v#000XB zI0FU%000000000000000KL7v#000XBumc7F000000000000000KL7v#000XB$O8rd z000000000000000B1r%M0RRmEfS?Be00000b^rhX00000KL7v#000XBGz10!00000 z0000000000KL7v#000XBR0IY9000000000000000KL7v#000XBa0Uhd0000000000 z00000KL7v#000XBtOf=E000000000000000KL7v#000XB)CL9s000000000000000 zKL7v#000XB^ach1000000000000000KL7v#000XB6bA+X000000000000000KL7v# z000XB000000000000000KL7v#000XBKokZ500000 z0000000000KL7v#000XBSQG{T000000000000000KL7v#000XBh!h3@0000000000 z00000KL7v#000XBv=jya000000000000000KL7v#000XB%oGLy000000000000000 zKL7v#000XB{1gTN000000000000000KL7v#000XBY!wCo000000000000000KL7v# z000XB*cAo<000000000000000KL7v#000XB{1pZO000000000000000KL7v#000XB zU={`d000000000000000KL7v#000XB#1;ks000000000000000KL7v#000XB2p0wb z000000000000000KL7v#000XBFc$^@000000000000000KL7v#000XBNEZeG00000 z0000000000KL7v#000XBWETbi000000000000000KL7v#000XBd=~})0000000000 z00000KL7v#000XB+!zJ`000000000000000KL7v#000XBd>RG-000000000000000 zKL7v#000XBpc)1M000000000000000KL7v#000XB>dUH000000000000000KL7v#000XB03QYb z000000000000000KL7v#000XBBp(I<000000000000000KL7v#000XBOdkdS00000 z0000000000KL7v#000XBXdeau000000000000000KL7v#000XBfFA|`0000000000 z00000KL7v#000XBq#p(V000000000000000KL7v#000XBWFQ6r000000000000000 zKL7v#000XBz#s+y000000000000000KL7v#000XB*dPV~000000000000000KL7v# z000XB@E`^N000000000000000KL7v#000XBI3WfA000000000000000KL7v#000XB zOd$pU000000000000000KL7v#000XB&>{u^000000000000000KL7v#000XB=pqIH z000000000000000KL7v#000XB7$XJ%000000000000000KL7v#000XBNFxRS00000 z0000000000KL7v#000XBWFrOu000000000000000KL7v#000XBs3Qgd0000000000 z00000KL7v#000XB*dqo2000000000000000KL7v#000XB>>~yM000000000000000 zKL7v#000XB3?v2s000000000000000KL7v#000XBG$aN9000000000000000KL7v# z000XBj3fpC000000000000000KL7v#000XByd(wy000000000000000KL7v#000XB z*dzu3000000000000000KL7v#000XB@FWHR000000000000000KL7v#000XB93=(- z000000000000000KL7v#000XBFeL^6000000000000000KL7v#000XBNF@dU00000 z0000000000KL7v#000XB@FfNS000000000000000KL7v#000XBOeO{Z0000000000 z00000KL7v#000XBWF`gx000000000000000KL7v#000XBd?p3}000000000000000 zKL7v#000XBm?j1Q000000000000000KL7v#000XBuqFlo000000000000000KL7v# z000XB#3lv+000000000000000KL7v#000XB7$*h*000000000000000KL7v#000XB zKqm$O000000000000000KL7v#000XBa3=-;000000000000000KL7v#000XB%qIo_ z000000000000000KL7v#000XB=qCmM000000000000000KL7v#000XB5GV!!00000 z0000000000KL7v#000XBG$;lD000000000000000KL7v#000XBWGDsz0000000000 z00000KL7v#000XBlqd!O000000000000000KL7v#000XB@F)fV000000000000000 zKL7v#000XB3@HWx000000000000000KL7v#000XBFewHA000000000000000KL7v# z000XBU?~Ow000000000000000KL7v#000XBs3`^j000000000000000KL7v#000XB z1S$pq000000000000000KL7v#000XB7%Bz;000000000000000KL7v#000XBI4TAJ z000000000000000KL7v#000XBs44~k000000000000000KL7v#000XB=q&~S00000 z0000000000KL7v#000XBL@ovZ000000000000000KL7v#000XBNG}Ee0000000000 z00000KL7v#000XBd@lw7000000000000000KL7v#000XBpf3gh000000000000000 zKL7v#000XB&@To6000000000000000KL7v#000XBEHDND000000000000000KL7v# z000XBNH7Kf000000000000000KL7v#000XBfG`FC000000000000000KL7v#000XB zq%Z~m000000000000000KL7v#000XB)G!7B000000000000000KL7v#000XB1Th8x z000000000000000KL7v#000XBU@-;&000000000000000KL7v#000XBd@%+900000 z0000000000KL7v#000XBv@r$%000000000000000KL7v#000XB*f9nG0000000000 z00000KL7v#000XB2r>o$000000000000000KL7v#000XBI5GwR000000000000000 zKL7v#000XBlrjbY000000000000000KL7v#000XBurdY!000000000000000KL7v# z000XB)G`JD000000000000000KL7v#000XB1TzKz000000000000000KL7v#000XB zU^4~)000000000000000KL7v#000XBbTbA3000000000000000KL7v#000XBz%vE_ z000000000000000KL7v#000XB+%pCM000000000000000KL7v#000XB_%j9o00000 z0000000000KL7v#000XB7&Ha|000000000000000KL7v#000XBP&5Vr0000000000 z00000KL7v#000XBcr*q8000000000000000KL7v#000XB+%yIN000000000000000 zKL7v#000XB95n_2000000000000000KL7v#000XBG&KeQ000000000000000KL7v# z000XBcr^w9000000000000000KL7v#000XBj5P)T000000000000000KL7v#000XB z+%*OO000000000000000KL7v#000XBBsK;B000000000000000KL7v#000XBa5e@2 z000000000000000KL7v#000XBpf&~o000000000000000KL7v#000XBpf?5p00000 z0000000000KL7v#000XB*f$0M000000000000000KL7v#000XBC^!ZH0000000000 z00000KL7v#000XBR5%6z000000000000000KL7v#000XBkT?ba000000000000000 zKL7v#000XByf_8`000000000000000KL7v#000XB+&BgR000000000000000KL7v# z000XB{5S>x000000000000000KL7v#000XBEI9@M000000000000000KL7v#000XB zd^rXH000000000000000KL7v#000XBkU0hb000000000000000KL7v#000XBz&Qp0 z000000000000000KL7v#000XBR5}I#000000000000000KL7v#000XBcsd3E00000 z0000000000KL7v#000XBBs&HG000000000000000KL7v#000XBfI9{N0000000000 z00000KL7v#000XBusa3-000000000000000KL7v#000XB%sU1E000000000000000 zKL7v#000XB5IhC|000000000000000KL7v#000XBKs*Kj000000000000000KL7v# z000XBSUd&*000000000000000KL7v#000XBv^)j?000000000000000KL7v#000XB zt2000000000000000KL7v#000XBP(20! z000000000000000KL7v#000XBs6GY&000000000000000KL7v#000XBygmj100000 z0000000000KL7v#000XB000000000000000KL7v# z000XB96<&E000000000000000KL7v#000XBI6(#g000000000000000KL7v#000XB zSV0B=000000000000000KL7v#000XB#6boC000000000000000KL7v#000XB5JLt4 z000000000000000(MkXS0RRmEV4(*9000001pxp600000KL7v#000XB@IwXw00000 z0000000000WlI160RRmEXrc!I00000mjD0&00000tpET3000dDB)10u0000000000 z00000Tlu000002mk;800000=}Q0r0RRmESc?Y$000005C8xG00000 z?n?jw0RRmEXp08`000005C8xG00000^Gg5#0RRmEc#8)B000005C8xG00000_)7o) z0RRmEh>HgR000007ytkO00000{YwA<0RRmEpo<3p000007ytkO000000!#n^0RRmE zxQhn>000007ytkO00000KL7v#000XBfKCPg0000000000000002TT9}0RRmE0Hg;1 z00000mjD0&00000KL7v#000XBgj5Cq000000000000000KL7v#000XBv{VKF00000 z0000000000KL7v#000XB%v1&d000000000000000KL7v#000XB>{JE-0000000000 z00000KL7v#000XB3{?gI000000000000000KL7v#000XBOjQN|000000000000000 zKL7v#000XBgjWUt000000000000000KL7v#000XB#8(CY000000000000000KL7v# z000XB000000000000000K1~1s0RRmED6a000000000000000<4^zq0RRmE zFsTOs00000%K!iX00000KL7v#000XB*n$QC000000000000000KL7v#000XB?1BaW z000000000000000kx>8u0RRmE0ICN700000#Q*>R00000KL7v#000XBsD}ms00000 z0000000000KL7v#000XBEQkgG000000000000000KL7v#000XBw1@@(0000000000 z00000KL7v#000XB+=vDM000000000000000KL7v#000XB@Q4Ng000000000000000 zKL7v#000XB1c?R!000000000000000K2iVx0RRmEh_MF%00000tN;K200000KL7v# z000XBEQfw100000 z00000000006jT5J0RRmE*s=!z00000p#T5?00000KL7v#000XB=#d5h0000000000 z00000tyBO20RRmE7_fV00000s{jB100000KL7v#000XBIF<$g000000000000000;8g$s z0RRmEXtf6b00000r2qf`00000KL7v#000XBV3-B~000000000000000KL7v#000XB zfS3jV000000000000000KL7v#000XBw3r3}000000000000000KL7v#000XB1epc^ z000000000000000KL7v#000XBB$);P000000000000000KL7v#000XBIGF|j00000 z0000000000KL7v#000XBV3`I0000000000000000KL7v#000XB$e9KJ0000000000 z00000KL7v#000XBB$@^Q000000000000000KL7v#000XBOqvD&000000000000000 zKL7v#000XBe3}LT000000000000000KL7v#000XBn3@Iv000000000000000KL7v# z000XB=$Zxq000000000000000KL7v#000XB44Vc3000000000000000KL7v#000XB zK$`{t000000000000000KL7v#000XBV4DU2000000000000000KL7v#000XBq?-l+ z000000000000000KL7v#000XB%$o)P000000000000000KL7v#000XBYT000000000000000KL7v#000XB zh_VI%000000000000000KL7v#000XBu(AdK000000000000000KL7v#000XB)UpNu z000000000000000KL7v#000XB^s)v3000000000000000004mhe?I^K0000B05r1( z00000000000000006zc#0000B0DQ9s00000000000000006zc#0000B0GzW100000 z000000000006zc#0000B0K~Hf00000000000000006zc#0000B0OYd<0000000000 z0000006zc#0000B00guK00000000000000006zc#0000B0PM5|000000000000000 z06zc#0000B01UMT00000000000000006zc#0000B03fvn00000000000000006zc# z0000B09dsK0000000000000000C`pb0096E0QjH>000000Am0E0000006zc#0000B z0A#iX00000000000000006zc#0000B0D!gz00000000000000006zc#0000B0F<@{ z00000000000000006zc#0000B0K~Qi00000000000000006zc#0000B09>~Q00000 z000000000006zc#0000B0HC)90000000000000000P$7;0096E005&0000000BQgL z000000CHCV0096E0MLsE0000001yBG0000006zc#0000B0IazN000000000000000 z06zc#0000B0K~Zl00000000000000006zc#0000B0Nl9-00000000000000006zc# z0000B02I0g0000000000000000C!ga0096E0C1xR000000Ez$r0000006zc#0000B z0D!v&00000000000000006zc#0000B0JOUX00000000000000006zc#0000B0NlF< z00000000000000006zc#0000B02I6i00000000000000006zc#0000B08qRJ00000 z000000000006zc#0000B0A#!d00000000000000006zc#0000B01Ukb0000000000 z0000006zc#0000B01Unc00000000000000006zc#0000B07Sk9000000000000000 z06zc#0000B05rb_00000000000000006zc#0000B0C2ws00000000000000006zc# z0000B02sgq00000000000000006zc#0000B05re`00000000000000006zc#0000B z07$?F00000000000000006zc#0000B0C>O#00000000000000006zc#0000B0Fb~2 z00000000000000006zc#0000B0HnYM00000000000000006zc#0000B0Mx(+00000 z000000000006zc#0000B0O-I500000000000000006zc#0000B0Q|rP0000000000 z0000006zc#0000B06@V800000000000000006zc#0000B0Eoc`000000000000000 z06zc#0000B0Jy;h00000000000000006zc#0000B006=U00000000000000006zc# z0000B02IOo00000000000000006zc#0000B08GLL00000000000000006zc#0000B z0I0$S00000000000000006zc#0000B0QkfP00000000000000006zc#0000B0C2?y z00000000000000006zc#0000B0Eoo~00000000000000006zc#0000B0HnnR00000 z000000000006zc#0000B00_ng00000000000000006zc#0000B0Bptv0000000000 z0000006zc#0000B0I0000000000000000FGDy0096E0I;kF000000BZmM0000006zc#0000B08q&W z00000000000000001jCI0096E03fXg000000BHaK0000006zc#0000B01V0o00000 z00000000000E}4x0096E0FbQ*000000HXi^0000006zc#0000B0NBe00000000000 z0000006zc#0000B0PM>K00000000000000006zc#0000B0A$Pt000000000000000 z06zc#0000B0C>y>00000000000000006zc#0000B0PxHP00000000000000006zc# z0000B03gi<00000000000000006zc#0000B06@(K00000000000000006zc#0000B z0EEp300000000000000006zc#0000B0I1Cd00000000000000006zc#0000B0L;w> z00000000000000006zc#0000B094Kf00000000000000006zc#0000B0GQ4O00000 z000000000006zc#0000B0Ibdi00000000000000006zc#0000B0MO3{0000000000 z0000006zc#0000B02t5)00000000000000006zc#0000B0ASDt000000000000000 z06zc#0000B0I1Lg00000000000000006zc#0000B0PxTT00000000000000006zc# z0000B0F2QF00000000000000006zc#0000B0HDzZ00000000000000006zc#0000B z06fwL00000000000000006zc#0000B0NBz700000000000000006zc#0000B0Cdv^ z00000000000000006zc#0000B01(s$00000000000000006zc#0000B0Ibvo00000 z000000000006zc#0000B07%sa00000000000000006zc#0000B0OZvM0000000000 z0000006zc#0000B00h00000000000000006zc#0000B04UoA0000000000 z0000006zc#0000B0C?L500000000000000006zc#0000B0F>JX000000000000000 z06zc#0000B0I=Hz00000000000000006zc#0000B0LS00000000000000006zc#0000B0QlPm00000000000000006zc#0000B z01Vs)00000000000000006zc#0000B05seN00000000000000006zc#0000B0G!+g z00000000000000006zc#0000B0Jz)+00000000000000006zc#0000B02JK@00000 z000000000006zc#0000B06g6W00000000000000006zc#0000B0Bqd`0000000000 z0000006zc#0000B0KDA>00000000000000006zc#0000B0NC9I000000000000000 z06zc#0000B0QB7k00000000000000006zc#0000B01(~=00000000000000006zc# z0000B0Fd4W00000000000000006zc#0000B0N~yR00000000000000006zc#0000B z0Q}wt00000000000000006zc#0000B02to}00000000000000006zc#0000B05snQ z00000000000000006zc#0000B08rot00000000000000006zc#0000B0HELo00000 z000000000006zc#0000B0KDJ^00000000000000006zc#0000B0NCIL0000000000 z0000006zc#0000B0QBGn00000000000000006zc#0000B08rru000000000000000 z06zc#0000B0Bqp~00000000000000006zc#0000B0EpoR00000000000000006zc# z0000B0Homt00000000000000006zc#0000B0L0-200000000000000006zc#0000B z0N~*U00000000000000006zc#0000B0AS(<00000000000000006zc#0000B0EFTO z00000000000000006zc#0000B0I1>y00000000000000006zc#0000B0NmmR00000 z000000000006zc#0000B01V>>00000000000000006zc#0000B0G#6n0000000000 z0000006zc#0000B0J!4@00000000000000006zc#0000B0L$m00000000000000006zc#0000B0L1~00000000000000006zc#0000B0LbzN z00000000000000006zc#0000B0Oaxp00000000000000006zc#0000B008p_00000 z000000000006zc#0000B07UZ!00000000000000006zc#0000B0Lb$O0000000000 z0000006zc#0000B0QB<)00000000000000006zc#0000B0BrOI000000000000000 z06zc#0000B08I4;00000000000000006zc#0000B0D$!d00000000000000006zc# z0000B0Pyt&00000000000000006zc#0000B05tXn00000000000000006zc#0000B z0C@HW00000000000000006zc#0000B0KE1F00000000000000006zc#0000B008#} z00000000000000006zc#0000B066ys00000000000000006zc#0000B0Eqbp00000 z000000000006zc#0000B0KoYM00000000000000006zc#0000B01*5J0000000000 z0000006zc#0000B07(1>00000000000000006zc#0000B0GR#;000000000000000 z06zc#0000B0MPyh00000000000000006zc#0000B03ZPe00000000000000006zc# z0000B09XMB00000000000000006zc#0000B0H^~800000000000000006zc#0000B z0N?`$00000000000000006zc#0000B05Apz00000000000000006zc#0000B0B8mW z00000000000000006zc#0000B0JsPT00000000000000006zc#0000B0PqM000000 z000000000006zc#0000B06+@|00000000000000006zc#0000B08|SH0000000000 z0000006zc#0000B0CWon00000000000000006zc#0000B0Ei0*000000000000000 z06zc#0000B0H6y800000000000000006zc#0000B01ylZ00000000000000006zc# z0000B06+`}00000000000000006zc#0000B0B8&c00000000000000006zc#0000B z0Due!00000000000000006zc#0000B0MHBv00000000000000006zc#0000B0OSk@ z00000000000000006zc#0000B06+}~00000000000000006zc#0000B09*|R00000 z000000000006zc#0000B0C)`t00000000000000006zc#0000B0F(^}0000000000 z0000006zc#0000B0H_TI00000000000000006zc#0000B00a&P000000000000000 z06zc#0000B03Z$r00000000000000006zc#0000B06Y!{00000000000000006zc# z0000B09XzO00000000000000006zc#0000B0JIJV00000000000000006zc#0000B z0F)0000000000000000006zc#0000B0Kg9i00000000000000006zc#0000B0OSt` z00000000000000006zc#0000B01OZZ00000000000000006zc#0000B0B8^g00000 z000000000006zc#0000B0E7?+00000000000000006zc#0000B0H6>D0000000000 z0000006zc#0000B0K5w00000 z000000000006zc#0000B0FV|300000000000000006zc#0000B01Oug0000000000 z0000006zc#0000B03a6!00000000000000006zc#0000B06-T9000000000000000 z06zc#0000B09Y3X00000000000000006zc#0000B0O%J700000000000000006zc# z0000B09Y6Y00000000000000006zc#0000B0Bjfs00000000000000006zc#0000B z0F)R900000000000000006zc#0000B0L&N%00000000000000006zc#0000B04Ny; z00000000000000006zc#0000B06ZB700000000000000006zc#0000B0Av{l00000 z000000000006zc#0000B0E`(200000000000000006zc#0000B0H_%U0000000000 z0000006zc#0000B04N#<00000000000000006zc#0000B0Bjlu000000000000000 z06zc#0000B0F)XB00000000000000006zc#0000B0IV7Z00000000000000006zc# z0000B0OT4600000000000000006zc#0000B06-fD00000000000000006zc#0000B z0Dv6_00000000000000006zc#0000B0MH!=00000000000000006zc#0000B0O%bD z00000000000000006zc#0000B0Q?;X00000000000000006zc#0000B01zGr00000 z000000000006zc#0000B08}0a00000000000000006zc#0000B0N@@60000000000 z0000006zc#0000B0Q?>Y00000000000000006zc#0000B01zJs000000000000000 z06zc#0000B0AL>n00000000000000006zc#0000B0CXP*00000000000000006zc# z0000B0LUK)00000000000000006zc#0000B01O}p00000000000000006zc#0000B z0K^~%00000000000000006zc#0000B08k+Z00000000000000006zc#0000B0Ei(6 z00000000000000006zc#0000B0N5i300000000000000006zc#0000B0Qe&Z00000 z000000000006zc#0000B03aj>00000000000000006zc#0000B0C*$^0000000000 z0000006zc#0000B0H`Df00000000000000006zc#0000B0K_B*000000000000000 z06zc#0000B0N5l400000000000000006zc#0000B01PDu00000000000000006zc# z0000B0AwWx00000000000000006zc#0000B0IVek00000000000000006zc#0000B z0MsQ100000000000000006zc#0000B0F)*N00000000000000006zc#0000B0LUf> z00000000000000006zc#0000B001Wk00000000000000006zc#0000B05~TH00000 z000000000006zc#0000B0B|P<00000000000000006zc#0000B0PrUV0000000000 z0000006zc#0000B06-`Q00000000000000006zc#0000B0F)>P000000000000000 z06zc#0000B0O%+O00000000000000006zc#0000B06ZxN00000000000000006zc# z0000B0FWsM00000000000000006zc#0000B01zq%00000000000000006zc#0000B z0Awl$00000000000000006zc#0000B0C*|~00000000000000006zc#0000B0F){R z00000000000000006zc#0000B0I(_t00000000000000006zc#0000B0Q@Qk00000 z000000000006zc#0000B06Z%P00000000000000006zc#0000B0Awo%0000000000 z0000006zc#0000B0F)~S00000000000000006zc#0000B0JJLy000000000000000 z06zc#0000B0MIK300000000000000006zc#0000B0PrgZ00000000000000006zc# z0000B02nL>00000000000000006zc#0000B07xtc00000000000000006zc#0000B z0B9@+00000000000000006zc#0000B0E8?D00000000000000006zc#0000B0HiDj z00000000000000006zc#0000B0K_Z@00000000000000006zc#0000B05mNJ00000 z000000000006zc#0000B09-8x00000000000000006zc#0000B0DLV60000000000 z0000006zc#0000B0GKTY00000000000000006zc#0000B0Jtp&000000000000000 z06zc#0000B030p{00000000000000006zc#0000B07Nba00000000000000006zc# z0000B09-By00000000000000006zc#0000B0DvwB00000000000000006zc#0000B z02D6=00000000000000006zc#0000B06Z@T00000000000000006zc#0000B09-Ez z00000000000000006zc#0000B0C+D400000000000000006zc#0000B0GKZa00000 z000000000006zc#0000B0LU)~00000000000000006zc#0000B0Prsd0000000000 z0000006zc#0000B05C8I00000000000000006zc#0000B0FW>T000000000000000 z06zc#0000B0K_l{00000000000000006zc#0000B0PHXa00000000000000006zc# z0000B01Pn)00000000000000006zc#0000B04OmB00000000000000006zc#0000B z07x+h00000000000000006zc#0000B0B|t}00000000000000006zc#0000B0E96I z00000000000000006zc#0000B0H84k00000000000000006zc#0000B0JJd&00000 z000000000006zc#0000B0Ms!D00000000000000006zc#0000B00c4z0000000000 z0000006zc#0000B04y>G00000000000000006zc#0000B07Nne000000000000000 z06zc#0000B0F*KZ00000000000000006zc#0000B0Pr#g00000000000000006zc# z0000B07Nqf00000000000000006zc#0000B09-Q%00000000000000006zc#0000B z0B|!000000000000000006zc#0000B0EjaO00000000000000006zc#0000B0NgVN z00000000000000006zc#0000B00cA#00000000000000006zc#0000B00cD$00000 z000000000006zc#0000B09-W(00000000000000006zc#0000B0Gu@k0000000000 z0000006zc#0000B0Ms=H00000000000000006zc#0000B0O&Ob000000000000000 z06zc#0000B05~=W00000000000000006zc#0000B05mrT00000000000000006zc# z0000B07y3n00000000000000006zc#0000B0DLzG00000000000000006zc#0000B z0Khi~00000000000000006zc#0000B08BUs00000000000000006zc#0000B08lvx z00000000000000006zc#0000B0Hiqw00000000000000006zc#0000B0Khp100000 z000000000006zc#0000B0Mt1L00000000000000006zc#0000B0300000000000000006zc#0000B0B}7A00000000000000006zc# z0000B0E|5c00000000000000006zc#0000B0H8ew00000000000000006zc#0000B z0K7d100000000000000006zc#0000B0N6bT00000000000000006zc#0000B05m=a z00000000000000006zc#0000B09-x?00000000000000006zc#0000B0C+wJ00000 z000000000006zc#0000B0H{6(00000000000000006zc#0000B0Kh&60000000000 z0000006zc#0000B0N6eU00000000000000006zc#0000B03bjI000000000000000 z06zc#0000B06ahk00000000000000006zc#0000B09Zf=00000000000000006zc# z0000B0DwRT00000000000000006zc#0000B0GvPv00000000000000006zc#0000B z0JJ~{00000000000000006zc#0000B09-)_00000000000000006zc#0000B0E9sY z00000000000000006zc#0000B0H8q!00000000000000006zc#0000B0JK2|00000 z000000000006zc#0000B0LVcH00000000000000006zc#0000B00=?{0000000000 z0000006zc#0000B03bpK00000000000000006zc#0000B0DM9R000000000000000 z06zc#0000B0GvVx00000000000000006zc#0000B0K`HE00000000000000006zc# z0000B0PI2s00000000000000006zc#0000B07OFv00000000000000006zc#0000B z0CYnK00000000000000006zc#0000B0N6tZ00000000000000006zc#0000B0N6wa z00000000000000006zc#0000B0PI8u00000000000000006zc#0000B02oCF00000 z000000000006zc#0000B060Yl00000000000000006zc#0000B0BA)A0000000000 z0000006zc#0000B0FXro00000000000000006zc#0000B0IWp^000000000000000 z06zc#0000B0K`QH00000000000000006zc#0000B00c${00000000000000006zc# z0000B0OUpo00000000000000006zc#0000B0ANQ400000000000000006zc#0000B z0Nh6h00000000000000006zc#0000B09Z%|00000000000000006zc#0000B0Mtka z00000000000000006zc#0000B0O&{u00000000000000006zc#0000B0Q^V?00000 z000000000006zc#0000B01!zB00000000000000006zc#0000B0BA`E0000000000 z0000006zc#0000B0Dwsc00000000000000006zc#0000B0GLS!000000000000000 z06zc#0000B0IW#|00000000000000006zc#0000B0KiEH00000000000000006zc# z0000B0N6G400000000000000006zc#0000B08~l`00000000000000006zc#0000B0C-9V z00000000000000006zc#0000B0IW&}00000000000000006zc#0000B0Q5=+00000 z000000000006zc#0000B0K7{F00000000000000006zc#0000B04z)g0000000000 z0000006zc#0000B0600000000000000006zc#0000B0BB7I00000000000000006zc#0000B0K`oP z00000000000000006zc#0000B00d4400000000000000006zc#0000B08CB?00000 z000000000006zc#0000B0Ax-F00000000000000006zc#0000B0C-LZ0000000000 z0000006zc#0000B0E|ut00000000000000006zc#0000B0KiTM000000000000000 z06zc#0000B08mc{00000000000000006zc#0000B0B}zS00000000000000006zc# z0000B0K`uR00000000000000006zc#0000B04Pug00000000000000006zc#0000B z0ANrD00000000000000006zc#0000B0C-Rb00000000000000006zc#0000B0E|!v z00000000000000006zc#0000B0H9C@00000000000000006zc#0000B0Mt+i00000 z000000000006zc#0000B05nkt00000000000000006zc#0000B0JKpD0000000000 z000000IdK30000K0JzBs0000000000000000IdK30000K0Px8P000000000000000 z0IdK30000K02s;%0000000000000000IdK30000K06@wK00000000000000006zc# z0000B01Q$G00000000000000006zc#0000B060000000000 z000000IdK30000K0I16e0000000000000000IdK30000D0Jysc000000000000000 z0IdK30000K0JzHu0000000000000000IdK30000D0O-310000000000000000IdK3 z0000K0MN?`0000000000000000IdK30000D00_JX0000000000000000IdK30000K z0O-pJ0000000000000000IdK30000D05H4<0000000000000000IdK30000K007Jh z0000000000000000IdK30000D08qRK0000000000000000IdK30000K02s^(00000 z00000000000IdK30000D0C>Cy0000000000000000IdK30000K05Hr60000000000 z000000IdK30000D0GPZ70000000000000000IdK30000K07%RU000000000000000 z0IdK30000D0Jyvd00000000000000000~+E00ICD0Q}1Y000000PtG?000000IdK3 z0000D0PwsA0000000000000000IdK30000D0QkHI00000000000000006zc#0000B z0K`)V00000000000000006zc#0000B00dMA00000000000000006zc#0000B04P)k z00000000000000006zc#0000B0BlqT00000000000000006zc#0000B0Qgh~00000 z000000000006zc#0000B06{{R3000000 z00000000000IdK30000F0D!It00000000000000009jf90096G0D!It0000000000 z000000000000aQ>{{R300000000000000000B2eN0000E05H7=000000000000000 z0D4*g0096O01yBQ0000000;m8000000HRs|00saN000000000000000000000JK^F z0096O0000A0000000000000000Kr-S0096O02lxY0000000;m8000000Nq*u00ICE z0L)bf0000000000000000OMK!00ICB0ANrA0000000000000000O?u)0098;|8UF+ z0000000000000000Pg0000000000 z0000006tp)03rYj0DzkX000000O$Y!000000LWVa03rYj01O}p000000Js1E00000 z02f>U03rYj0L)Yd0000003ZMW000000DfEm03rYj01Q03rYj0PxTT000000Gt2-0000002y8Y03rYj0Ni2* z0000008jz|000000DE2l03rYj01UAP0000005AXm000000MK3l03rYj0Av{l00000 z04M+e0000003=@k03rYj0KC@*0000006+i$0000007+i}03rYj0Qf-#000000E_?t z000000C`^k03rYj0Ps%*000000K@T0000005kvq000000M%ds03rYj0DzhW0000004M+e0000008(K9 z03rYj0Q61;0000003ZMW000000BvCa0Hy#D00;m80000000;m8000000Dxft03rYj z00=1s0000005kvq000000IFdC03rYj0PN}p0000003ZMW000000JmWP01^NI00000 z0000000000000000MTIp03rYj0OSV-0000003ZMW0000007hZ}03rYj0Myn700000 z02}}S000000Doct03rYj0JPi%0000008jt`000000L5Ye03rYj0OT_T0000006+i$ z000000N-K&03rYj0H6>D0000002}}S000000JUQP03rYj0F+t<0000005AXm00000 z0RLkE03rYj0B8mW0000008jz|000000Gwn103rYj0F)>O0000009*h70000003c-m z03rYj0JIJV000000N?-s000000Ptl103rYj02IOo0000005|{u000000C{Er03rYj z0MHBv0000002BZK000000L*3p03rYj02mYp0000004M+e000000AXhU03rYj08Hiu z0000005Aan000000K{hi03rYj0Cb22000000O$b#0000004!(#03rYj0H{6&00000 z02BZK000000HbIC03rYj0Awl$0000002BZK0000001IgV03rYj08k+Z0000005|{u z000000Fh|`03rYj094-v0000002}}S000000ODx?03rYj01(~=000000Du4h00000 z0CQ>p03rYj0N6PN0000005kyr000000J&-a03rYj06?1t0000003ZMW0000000V0P z03rYj06Y!{0000002}}S000000I_QT03rYj0EqYn000000E7Vm0000004{6*03rYj z0JO0N0000002BZK000000DWu#03rYj0K`uR000000Av6F0000002plm03rYj0H_TI z0000009*h7000000Jv=c03rYj0NCvY000000Js1E000000P}4C03rYj0BlnS00000 z05kvq0000002pon03rYj0E9UO0000008{_~0000006}g503rYj02sRk0000003-ka z000000GMt703rYj0B9cu0000002lxO000000K#qn03rYj0O)@O0000005|{u00000 z00nOV03rYj07yv%000000Gt2-0000001$5g03rYj0DNi%0000004M+e0000002^BX z03iSr0O-pJ0000002lxO0000004#3+03rYj031OE0000002}}S000000I6>P03rYj z09-=_0000003-ka0000000?jZ03rYj04xCp0000004M+e0000007Gy901^NI00000 z00000000000000008wxN03rYj0I=W%0000002lxO000000HbgK03rYj032ck00000 z03-ka000000QGPH03rYj02Go10000004x9i0000002FZm03rYj01!L|0000005AXm z000000Do}+03rYj06e<|0000008{_~000000Pk@C03rYj01WyC0000009*h700000 z0Bv#r03rYj0PxlZ0000009*h7000000J?Gj03rYj06-@O0000005AXm000000BLgo z03rYj0GOZ#000000KfnM0000009bSY03rYj0L&Bz0000005|{u000000L*j%03rYj z0MO3{0000007w7;0000003me%03rYj03-03rYj0DPPV0000009*h7000000B3gq03rYj0ASe$000000H^=}00000 z0Kazt03rYj0Khi~000000E_?t0000001bEm03rYj05re`0000002BZK000000Cso) z03rYj0B9@+0000002}}S0000003Ue(03rYj0O;%n0000007w7;0000006TdA03rYj z0QA}h0000003ZMW000000IPWb03rYj0DQ;>000000Mq~g0000002F!v03rYj0N6eU z0000007wA<000000PuPM03rYj0Eoo~0000002}}S000000BL&w03rYj0PNER00000 z0B`^R0000001tcs03rYj0C?mE0000004M+e000000EK)201^NI000000000000000 z000000MvW{03rYj01Rmb000000Q>*|000000403@01^NI00000000000000000000 z06%>I03rYj0IW_00000002BZK000000Bn5#03rYj0QfQm0000005|{u000000D^r0 z03rYj0MIW60000009*h700000055(303rYj0N|(w0000004M+e000000JDAo03rYj z0MK6s0000008{_~0000000n;l03rYj07xtc0000003ZMW000000GfXQ03rYj00d44 z0000007w7;000000Lgy<03rYj0607a0000007L))000000QP?X03rYj0K_B*00000 z02BZK000000GWUQ03rYj02I6i0000006YKy000000LXv<03rYj0OTtL0000005kvq z000000O)`K03rYj030<20000002lxO0000009Szk01^NI00000000000000000000 z0Cs@@03rYj09dsK0000001N>D000000M~&403rYj0AQyE0000003ZMW000000Cs`^ z03rYj04yE`0000003-ka0000001<-#03rYj07Nne0000008jt`000000CNS03rYj0PH;l0000004xCj000000B?o>03rYj0GvVx0000004M+e00000 z0E~tJ03rYj0E|ur0000003ZMW000000MUj303rYj0ASDt0000007w7;00000049e3 z03rYj062vO0000002BZK0000009=Ov03rYj0NBe00000002BZK0000001=1)03rYj z0K}CA0000002BZK0000009A+p03rYj06+}~0000002}}S0000003?Y301^NI00000 z0000000000000000Az^(03rYj06e<|0000008{_~000000Mv;903rYj01PVy00000 z05kvq000000Pu+b03rYj0Ne-$0000000;sA000000C9={03rYj0CbcE0000006YNz z00000027M<03rYj0Dw*g0000000agA000000DFr703rYj04O*H0000004x9i00000 z0OE@P03rYj005{40000004M+e000000C03rYj06@|O000000MGyc000000PT(d03rYj07&-* z0000008{_~0000002+?~03rYj0ALda0000002lxO000000EmwO03rYj0CY1300000 z089V?0000004b0F03rYj0NAMp0000003ZMW000000D+JI03rYj0Ce&O0000004M+e z0000000WT#03rYj09a)O0000001yKJ0000003wk903rYj0Guxc0000003ZMW00000 z06UQY03rYj0MKX#0000007w7;000000Fsda03rYj00dMA0000003-ka0000000WW$ z03rYj01(~=000000Du4h000000F;sd03rYj05~cJ000000B`^R000000DqGJ03rYj z0GKTY0000003ZMW0000006mld03rYj0Q?;X0000002BZK000000AZ8>03rYj0GL$= z0000005kvq000000J@X_03rYj06G400000089V?000000Ed_W01^NI z000000000000000000000K=F703rYj0MH!=0000002lxO000000Oyzh03rYj0APIu z0000005|{u0000004$jR03rYj09?03rYj0D#a10000003ZMW000000MDEN03rYj z0B|-20000005AXm0000008*U*03rYj0FYJ%0000003ZPX000000E3+X03rYj0HEXs z0000006YKy000000NtGc03rYj06+`}0000004M+e000000Q;Q)03rYj03d0000003ZMW0000004JdU03rYj07Nqf0000002lxO000000JEV003rYj0IUWE z0000004M+e000000L!5O03rYj0DRm90000005|{u000000QjK*03rYj0N@@600000 z02}}S0000004AaU03rYj0F*KZ0000009*h7000000Cb`N03rYj0ANQ4000000DJ%d z0000001cx603rYj0AL>n0000002BZK0000004bvY03rYj0JKyF0000002lxO00000 z09c~{03rYj01Oug0000002BZK000000LY^N03rYj0HjC-0000003ZMW000000OF$n z03rYj0PG$H0000002BZK0000000*Q103rYj02n_70000007L))0000005GHg03rYj z0Jy;h0000007w7;000000GXr!01^NI000000000000000000000P>^&03rYj05m@a z0000009XJ30000007s<&03rYj0L(iE0000007L))000000Jfz703rYj0Q`{!00000 z02lxO000000L`TU03rYj09^J30000002BZK0000003W6R03rYj0Mt+i000000AK(B z000000DPtZ03rYj0D!v&0000005kvq000000Oh6t03rYj0I1Cd0000003-ka00000 z0D7kY03rYj08BUs0000000aR5000000N|$p03rYj0Q^V?0000002BZK000000GX%& z03rYj04!An0000002BZK0000002`?Q03rYj01Q$G0000005kvq0000006?h#03rYj z0Q|rP0000007L))000000H>({03rYj01WE}0000007L))000000Me-d03rYj05s?Y z0000004M+e000000As2E03rYj08Hox0000002lxO000000J5q803rYj01V0o00000 z0L%dZ0000002r$P03rYj06+@|0000002BZK000000H3P>03rYj05l{90000009XJ3 z000000OqRz01^NI000000000000000000000Qsu`03rYj0DvC`0000003-ka00000 z086X@03rYj00a&P0000002}}S000000Qal_03rYj04zHP000000DJ%d000000FkW# z03rYj0Av{l0000004M+e000000OhR!03rYj06Z}T0000005AXm0000000yoA03rYj z03d(`0000008jz|000000A{WL03rYj0PG_M0000003ZMW000000Ew;u03rYj0OTtL z0000005kvq000000I9A303rYj0MJzh0000002}}S000000NJhp03rYj0AQI000000 z0B8UJ000000BNrP03rYj06Z%P0000004M+e0000002ikQ03rYj z0L&}}000000I&c60000005!7!03rYj095h@0000003ZMW000000Lrrf03rYj08DuX z0000002BZK000000ROW903rYj0C*$^0000005AXm000000Fkr+03rYj0Kkt100000 z04M?g00000028$U03rYj0K`ZI0000005AXm0000005!D$03rYj0OYd<0000003ZMW z000000IanD03rYj0FX-s0000008{_~000000L--j03rYj0QfQm0000005|{u00000 z0OGX(03rYj08ncM0000008jt`000000QM z0000002BZK0000008+RB03rYj0F37b0000002BZK000000M@tw03rYj07O;=00000 z04M+e000000Q$H901^NI0000000000000000000002jFc03rYj0I*C20000003ZMW z0000007$t203rYj08|SH0000003ZMW000000GPP|03rYj0OSk@0000009*h700000 z09(2M03rYj0CYnK000000Av6F000000I|9N03iSr007Jh0000002lxO000000NT0$ z03rYj0Fdtn0000002BZK00000093mG03rYj0OT460000009*h7000000B^eh03rYj z08nKG0000000;m8000000I0hF03rYj0Ei(60000008jz|0000007bk203rYj04OmB z0000003ZMW000000NK0%03rYj0H8kx000000Av9G000000BpSg03rYj0OaTf00000 z0B`^R000000E)c;03rYj0MJYY0000004x9i000000H3`803rYj0BlwT0000003-ka z000000K~lj03rYj00@T#0000009*h70000001>_b03rYj05tXn0000007L))00000 z0JOdU03rYj0IV7Z0000005|{u000000P?;703rYj0F0gn00000089V?000000EoW; z03rYj0C3+00000005AXm000000M)+$03rYj09>~Q0000007L))0000005re=03rYj z0KD1;0000002}}S000000PDa203rYj08lvx0000008{_~000000B*qm01^NI00000 z0000000000000000F=Q103rYj09c>~0000002}}S0000001(0e03rYj060Mg00000 z03ZMW0000005HM;03rYj0BB7I0000009*h7000000O7&_03rYj0Qiap0000005AXm z0000001CqZ01^NI0000000000000000000006W6~03rYj0C1fK0000003ZMW00000 z0Pe#803rYj09-By0000003-ka000000E@%`03rYj0Axr70000003ZMW000000J+2f z03rYj08rot0000008jt`0000008YgK03rYj0JJd%0000003-ka000000Pe*A03rYj z0HEIm0000004M+e000000RP1R03rYj0B{Bd0000006YKy0000004~M=03rYj05EO^ z0000003ZMW000000Aj`f03rYj0Awfz0000005AXm000000PV&A03rYj031vO00000 z05kvq0000008hsN03rYj063Th0000005kvq000000Mo|+03rYj0K~Hf0000003ZMW z0000003*l%03rYj05quv0000008jt`000000K~`u03iSk0Jyvd0000005kvq00000 z0Q|@R03rYj0K``Y0000003ZMW0000008PmN03rYj0Homt0000003ZMW000000JF&e z03rYj0DOZ5000000Nelo0000002|5x03rYj0CevK0000003-ka000000Jh2i03rYj z03cWe0000003ZMW000000OHC303rYj0Mz6K0000005AXm000000C&p(01^NI00000 z0000000000000000HVtP03rYj0O*(n0000006YKy000000O!j903rYj0FcuK00000 z07w7;0000006fe903rYj00`&?0000005AXm000000NKm{03rYj0IVek0000004M+e z0000007T6I03rYj037NC0000005AXm000000N%|203rYj03cok0000005AXm00000 z04dG@03rYj0B}qN0000003ZMW000000CUa&03rYj0Ibdi0000003-nb000000E*85 z03rYj0N9xY000000Av6F000000O-#E03rYj0N6tZ0000000031000000AkPp01^NI z000000000000000000000FTfB03rYj00_ng000000Av6F000000PD~I03rYj07NbZ z0000000aR5000000JhNp03rYj00=S$0000005AXm0000006)?I03rYj02D6=00000 z04M+e000000NK(203rYj0MJYY0000004x9i000000PfNN03rYj0Dz|k000000Du4h z000000Dsc}03rYj0MP#h0000003-ka000000K(G%03rYj0Hl}&0000004M+e00000 z0Nc|503rYj0NiT@000000AK(B0000009w=l01^NI000000000000000000000C>~@ z03rYj0JP}_000000Gt2-000000H@Rd03rYj0F03rYj0Kl3B000000BisN00000043G{03rYj0H6y800000 z0B`^R000000C?5_03rYj0F(#@0000003ZMW000000H@Xf03rYj05A~-0000005Ado z0000003_D{03rYj09-W(0000006+i$000000D;#403rYj08o|%0000009XJ300000 z0H)Uf03rYj01PDu0000009XJ3000000AAPt03rYj0PM5|0000003ZMW000000O{BO z03rYj02EUP0000005kvq0000002A2&03rYj0LbSC0000006+i$000000HoOf03rYj z0F)~S0000003ZMW0000009@Jt03rYj0DQ9s0000003ZMW000000O;BP03rYj0Ce~T z0000002BZK0000009M-o03rYj0F*KY0000002}}S000000NdLD03iSk0Jysc00000 z04o3h0000001Dgy03rYj0NmmR0000005AXm000000D{~A03rYj03cWf0000004M+e z000000N>mI03rYj0EBV{0000008jt`000000QlSh03rYj0O*01*HH0000000000000000000005;tK03iSr0JzHu0000002lxO0000009xGu z03rYj0N5i30000003ZMW000000K44)03rYj0NlF<0000005|{u0000005IMF03rYj z0Fb){000000B8~b000000L0z^03rYj0Duw)000000Av6F0000007l;c03rYj08C8> z0000002}}S000000EyoK03rYj08|JD0000002BZK0000000ZCv03rYj0OVu^00000 z0Av6F0000009fDv03rYj0Q^h^000000B`{S000000Gr?d03rYj0Mvv9000000Av6F z000000NUUH03iSr0BFkz0000002lxO0000007&5g01^NI00000000000000000000 z0E6KG03rYj0Q5-*0000002BZK000000Jq@)03rYj0Hp5*0000008jt`0000006pRW z03rYj0EFTO0000003-ka000000HERk03iSk006rO000000BQgL0000001o2-03rYj z0Qk)X000000B`~T000000Gi_f03rYj0PM>K000000C)fZ0000002$-}03rYj0FbN( z0000009XJ3000000Hovq03rYj08lgr0000004M+e0000005#Tn03rYj05re`0000002BZK000000J7%*03rYj0OXqn000000DJ%d000000N3XL z03rYj0K``Y0000003ZMW0000004V4H03rYj0C2?y0000002lxO000000H){w03rYj z0Q@)x0000005AXm000000MqCI03rYj0I(_t00000089V?0000006^&g03rYj0B8sX z0000004x9i000000I2Bz03rYj0C+D40000003ZMW0000008Q!u03rYj07x_i00000 z04x9i000000A%U_03rYj01PAs0000004M+e000000F&wf03rYj01OZZ0000009*h7 z0000009)$-03rYj006iJ0000006YKy000000EFuR03rYj06-K60000005AXm00000 z0RHO$03rYj007wr0000003-ka0000008i`y03rYj037B80000005AXm000000K@D6 z03rYj0DQIu000000E7Sl000000O{-i03rYj00iv?0000005AXm0000009)+<03rYj z02EIJ0000008jt`000000Cw#F03rYj090570000005kvq000000KM%103rYj0Pt!C z0000002BZK000000P^hs03rYj03cok0000005AXm0000006p#i03rYj00}0000004M+e000000LAeD03rYj01TT3 z0000005kvq0000000i;?01^NI0000000000000000000008H`#03rYj08G~g00000 z04M+e000000A}(403rYj0K503rYj0Pu(g00000 z02BZK000000DkuX03rYj04V+i0000003-ka000000ND2c03rYj04(?g0000007w7; z0000007>`&03rYj0C+wJ0000005AXm000000QmR-03rYj09Zi=000000BisN00000 z09^S103rYj062~X0000003-ka000000J8Z203rYj0Hm7+0000004M+e000000Py($ z03rYj0DwaU0000003ZMW0000005JLh03rYj002}40000007w7;000000B!mJ03rYj z05m8D0000005AXm0000002})N01^NI000000000000000000000B-vL03rYj0HEIm z0000004M+e000000Dt=c03rYj01Unc0000005|{u000000IK@{03rYj06-fD00000 z06+o&0000000jI103rYj0K`-U0000004x9i000000AlZ0000007L))000000Ehno03rYj0K`)T z0000006YKy000000PX((03rYj01V>>000000FVFx000000DJ%e03rYj0GOTy00000 z03ZMW000000F?j%03rYj0BC3h0000005AXm000000N(%s03rYj01!L}0000004M+e z0000007n4<03rYj09=X%0000003-ka000000Ga^-03rYj07yCq0000005kvq00000 z038AW03rYj01Pn)0000002}}S000000K@_T03rYj0C+V90000002BZK0000006hZ% z03rYj0NBz7000000Gt2-000000IUN603rYj0HDzZ000000Gt2-00000038GY03rYj z08rWn0000008jt`000000M`To01^NI000000000000000000000PzF?03rYj0K8HM z0000005kvq0000002KuR01^NI0000000000000000000006+x+03rYj0En^%00000 z04M+e000000ICH603iSr05Ho50000005|{u000000OAD!03rYj08rot0000008jt` z000000Cxrf03rYj00b%q0000002BZK0000001O8K01^NI00000000000000000000 z08R%103rYj0K}aJ0000003ZMW000000NV!v03rYj0IW_00000002BZK0000000;;H z03rYj0Mt+i000000AK(B000000A&aP03rYj0FXro0000002}}S000000Fej*03rYj z0MH@^0000002lxO000000OJS&03rYj0JKpD0000009XJ300000067T(03rYj02o6B z0000003-ka000000GbH_01^NI000000000000000000000Kf?W03rYj09-Q%00000 z02BZK0000002B%V03rYj07OUy0000003ZMW000000741@03rYj0HEgv0000004M+e z000000N4rv03rYj0AM@^0000004M+e0000006+@?03iSr02s^(0000002lxO00000 z0AvdR03rYj0D#d20000005AXm000000O<<>03rYj08IV`0000003-nb000000F(>? z01^NI000000000000000000000J01L03rYj0KiEH0000002lxO0000002d7b03iSr z0JzEt0000004M+e0000006+}^03rYj0Q58k0000003ZMW000000A>vV03rYj0Pr#g z0000008{_~000000Lu*l03rYj04UoA0000008jt`000000AdaS03rYj06;+n00000 z0F(d#000000FVv=03rYj08mT?0000003ZMW000000P+q203rYj0LX3y0000009*h7 z000000DTVu03rYj0QA}h0000003ZMW000000PPO}03rYj03=`r000000B`^R00000 z080=703rYj00?3R0000005AXm000000I?7O03rYj0Qimt0000002l!P0000002>hj z03rYj00<}r0000004M+e00000051^%03rYj04Q1o0000004x9i0000008SAB03rYj z03@0Q0000004M+e000000HP5A03rYj09=j*0000003-ka000000QeCB03rYj04#_G z000000Ehqp0000002C4d03rYj06;tj0000002lxO000000AmsX03rYj0BlqR00000 z03ZMW000000E!X;01^NI000000000000000000000KyUh03rYj0Kh&60000002lxO z0000009O+M03rYj0GKib0000003ZMW000000J#$Z03rYj06^6R0000006+r(00000 z06-K003rYj0Bn#20000005AXm0000001OoY03rYj0C)`t0000002}}S000000NoV< z03rYj0Oaxp0000002}}S0000008$nK03rYj02nj|0000005|{u000000Nxe>03rYj z06;4R000000CWHV000000QeRG03rYj0K~Ti0000006YKy0000003a6u03rYj08o(y z0000004M+e000000C*Px03rYj07w!C0000002}}S00000067=|01^NI0000000000 z00000000000803rYj0L-KY0000007L))000000F4>} z03rYj0H7}h0000005AXm0000006`l803rYj03etJ0000002lxO000000KXdn03rYj z0K6#$0000002}}S000000OuP403rYj0GLt-0000003-ka0000001X@g03rYj062pM z0000007L))0000009zaZ03rYj0AMi&0000002}}S000000P-9G03rYj0KljQ00000 z03ZMW000000Dm0;03rYj0Eo8*0000006YKy000000IeMX03rYj05IeR0000007w7; z0000003aR#03rYj0H8ew0000002}}S000000B9Zo03rYj0I>1~0000002lxO00000 z0N)+~03rYj0K5E701^NI0000000000000000000008=CZ03rYj00c4z0000004M+e000000JJ0l z03rYj0O-I50000002BZK0000004*f}03rYj0Cb=R0000003-ka000000L3K%03rYj z0Cdv^000000Gt2-0000005m2603rYj05~TH0000005|{u000000L&%<03rYj00i&_ z0000007L))000000Bk1#03rYj04$3J0000002BZK000000OKbC03iSr07%RU00000 z02lxO0000002?R)0Hy#D000000000000aO40000004yj003rYj0GwC_000000Gt2- z000000AeTs03rYj0EpoR0000002}}S0000002(O)03rYj0I1#t0000009*h700000 z0GKHO03rYY000000000000000000000JA9p03rYj031OD0000003-ka000000OKhE z03rYj0PIu-0000003ZMW0000000Sxk03rYj0Q3e10000003ZMW00000030d-03rYj z08rru0000002}}S000000MaS}03iSr0N~0A0000004M+e000000QM>Y03rYj03bpK z0000009*h70000003Ry>01^NI000000000000000000000BI`$03rYj0MP#h00000 z03-ka000000IVwk03rYj0NmsT0000009*h70000001_+#03rYj0Ps`=0000006YKy z0000009-5q03rYj05pgN0000006+i$000000Jtmx03rYj0L-BV0000009*h700000 z0AVcw03rYj02EpV0000002BZK000000M{)603rYj06$m0000005|{u0000008lak03rYj0BrjO0000002BZK z000000KhT<03rYj06cRA0000003-ka0000004y^B03rYj0DwCN0000005AXm00000 z0C6(`03rYj0BkV@0000006YKy000000HQMi03rYj0Mu^=000000K5bM0000005~)O z03rYj02Gb|0000003-ka000000FE>P03rYj0O))L000000AK(B000000P-{e03rYj z03d0000003ZMW z000000LD8303rYj0619%000000Du4h000000PH&f03rYj00h#J0000008{_~00000 z0JBB`03rYj0LU)~0000004M+e0000000&0_03rYj0AS_@0000003-ka0000009;1_ z03rYj00cA#0000000031000000EI^Z01^NI000000000000000000000HH?#03rYj z04N#<0000007L))000000PIHr03rYj0C<@N0000002BZK0000005?bh03rYj0Ax}J z0000005kvq0000009{A{03rYj090%R0000003ZMW000000F6ii03rYj0L+*L00000 z02}}S000000LDlG03rYj02JK@0000004M+e000000A5J}03rYj05B*8000000CWHV z000000Cq_M03rYj08I4;0000005kvq0000001rw503rYj0F>JX0000002}}S00000 z0HR6(03rYj0Kkm}0000005AXm000000Q*V-03rYj05CTN0000006+i$0000003AyK z03rYj08|SH0000003ZMW000000BuVF03rYj01Ph$000000FVFx000000ESBe03rYj z0OYU+0000004M+e000000NYCe03rYj0F37b0000002BZK000000AEZ203rYj03baF z0000002BZK000000Q5`&03rYj0H9L`0000003-ka0000002xgI03rYj06+@|00000 z02BZK000000H93)03rYj0PrUV0000008jt`0000003=QU01^NI000000000000000 z0000007Fgz03iSk0O-310000003ZMW000000B24C03rYj07w@G0000002}}S00000 z0D(>c03rYj0K`QH0000006+i$000000H;m?03rYj0EDRq0000002}}S000000Ao)9 z03rYj03Z$r0000002}}S0000002NRH03rYj0018b0000003-ka0000007p;(03rYj z0N~*U000000Du4h000000L)MU01^NI0000000000000000000000~h603rYj0KhW_ z0000002}}S000000HRR=03rYj04#%{01*HH000000000000000000000EJQk03rYj08E7i0000003ZMW00000 z0FzPy01^NI000000000000000000000H{&{03rYj0DL?J0000004xCj000000M$|f z01^NI000000000000000000000RK_}03rYj0MHQ!0000009*h7000000IpL303rYj z0JNkA0000002lxO00000031{S03rYj09-)_0000004M+e000000H{;}0HFXF02l@e z0000000;m8000000M=9i03rYj0AwQu0000007L))00000076v(03rYj02pfp00000 z05|{u000000H##|03rYj0C=hf0000009XJ30000003TKX03rYj03fLb0000002BZK z000000Hsy|01^NI000000000000000000000LE4U0HFXF0O$n@0000005AXm00000 z0PC0000002BZK000000FGG!03rYj0QBGn z0000009*h700000061C!03rYj03aj>0000009XJ3000000K{4W03rYj0OZ>S00000 z02BZK0000006|*;03rYj0MrHs0000003ZMW000000Ge9?03rYj01%W00000004M?g z0000003BQb03rYj0F*=p0000005kvq000000C8La03rYj0LUK)0000007L))00000 z0HRz003rYj08mT?0000003ZMW0000000dnD03rYj02DO^000000CWHV0000004ZGo z03rYj0B}qN0000003ZMW000000CQad03rYj0Aw8o0000004x9i000000PS4?03rYj z00c1x0000009*h7000000D)cs03rYj063Wj0000004M+e000000M1?k03rYj03fCY z000000Du4h000000C-;k03rYj07(1>0000008jz|0000002E*W03rYj0DLzG00000 z07L))0000007YN{03rYj0PI2s0000009XJ3000000E%D%03rYj0N5i20000002BZK z000000K;Gb03rYj0MM=m000000CWHV00000032Zf03rYj0PrLR0000004x9i00000 z08e2703rYj05EO^0000003ZMW000000E1xx03rYj06f|T0000002BZK0000003u=m z03rYj0LW_v0000002BZK000000DfWt03rYj0C1uP0000002BZK0000002gBc03rYj z0362#0000006+i$000000D)rx03rYj0MxPu0000003ZMW000000QO@603rYj0H}us z000000E7Sl0000002E{a03rYj0Jv%e00000089V?000000B~dh03rYj0IU-R00000 z05AXm000000PAD{03rYj0GvPv0000002lxO0000009R!J03rYj0H8Jo0000000031 z000000Ka7c03rYj04Pug0000005|{u000000A^+Z03rYj0BC6j0000003-ka00000 z0E}h<03rYj0DwRT0000002}}S0000004rw!03iSk0C>Cy0000003ZMW0000008eKD z03rYj0MHEv0000009XM4000000LW(n03iSr0Px8P0000004M+e000000QF}903rYj z0PIx-0000005AXm00000048Vw03rYj095P-000000BisN0000007Ga203rYj0Ax=E z000000E_?t000000D5Qv03rYj0PsTw000000FVj*000000ODu?03rYj05m-Z00000 z04M+e000000B~sm03rYj01*5J0000005|{u000000QG4B03rYj0E|=x0000005|{u z0000008(lJ03rYj0KA+900000089V?000000CH*p03rYj0L0-20000002}}S00000 z0O4u@03rYj0E|Bd0000002BZK0000006%L103rYj05nkr000000K@W0RSQZ3jowL2LJ#7000yK00000005790RSQZ3jic-1poj50058x00000 z007i^0RSQZ3jjp(1^@s6004vl000000047(0RSQZ3jm;{1^@s6000~S00000001g` z0RSQZ3jjFL1poj5001BW00000004%20RSQZ3jm}I1^@s6000;O00000008ZK0RSQZ z3jhR(1^@s6001Zg00000004S?0RSQZ3jk;n2LJ#7003M700000000<$0RR#J00000 z000000000000000001|A0RSQZ3jnws1^@s6001li00000006Rm0RSQZ3jj!-1poj5 z002+`00000000Yq0RSQZ3jkP12LJ#7004Xd00000006Ci0RSQZ3jp-S1^@s6001Ze z00000007&50RSQZ3joLi1^@s6003+N00000002pU0RSQZ3jlmA1poj5002+`00000 z003)$0RSQZ3jna;1poj5003M700000007Z{0RSQZ3jk!i1^@s6005`}00000000Jn z0RSQZ3jmBx1poj5001BW00000002vX0RSQZ3jk1F1poj50000200000005tW0RSQZ z3jjcp1poj5002Ay00000007Z|0RSQZ3jpvh2LJ#7002M$00000002pW0RSQZ3jo-u z1^@s6001BW00000005zZ0RSQZ3jjnz2LJ#7001xm00000008WP0RR#J3jkEP1ONa4 z004Xf00000000t#0RSQZ3jmC11^@s6001BX00000004%90RSQZ3joyX1poj5001xn z00000008xZ0RSQZ3ji$m1poj5002k;00000003r#0RSQZ3jic<1poj5001Ze00000 z006Lq0RSQZ3jk=G1poj5001-q00000000(*0RSQZ3jk#31^@s6001Ze000000057K z0RSQZ3jo|R1^@s6000~S00000001e40RSQZ3jk>P1poj5000C500000007B_0RSQZ z3jl=O1poj5001Ze00000000Yy0RSQZ3jla71poj50049V00000001S10RSQZ3joAa z1poj5001li00000004uA0RSQZ3jlmf2LJ#7000yK00000006Is0RSQZ3jnlS1poj5 z002Y)00000008`k0RSQZ3jlzM1poj5002Ay00000001F}0RSQZ3jo-h1^@s6000yK z000000082L0RSQZ3jll?1^@s6001Na00000003Bs0RSQZ3jkO^2LJ#7001Ze00000 z008rd0RSQZ3jpwi1poj5001Ze000000011poj5001Ze00000005_t0RSQZ3ji3<1^@s6 z002k;00000008`t0RSQZ3jo+R1^@s6002+`00000004%N0RSQZ3jn;S1^@s6000~S z00000002ah0RSQZ3jk;n2LJ#7003M7000000082V0RSQZ3jp}31^@s6001BW00000 z002>v0RSQZ3jlb`1^@s6004LZ00000007>S0RSQZ3joya1poj5003M700000003>1 z0RSQZ3jhq_1poj5001Na00000006g>0RSQZ3jm-)1poj5004vl00000007{V0RSQZ z3jn+%1^@s6000~S00000003Z=0RSQZ3jlQS1^@s6002Y)000000001$0RR#J00000 z000000000000000000`50RSQZ3jj!A1^@s6002+`00000004iL0RSQZ3jp8~2LJ#7 z000~S00000001wR0RSQZ3jlnY1^@s6000~S00000003T=0RSQZ3jkyh2LJ#7003+N z00000008xt0RSQZ3jjne2LJ#7000;O00000001VJ0RSQZ3jo+E1poj5001-q00000 z002Ul0RSQZ3jo}?1^@s6001}u00000003l{0RSQZ3ji=B1^@s6000;O000000051b z0RSQZ3jka#2LJ#7001BW00000002su0RSQZ3joNm1^@s6003|R00000004}b0RSQZ z3jkDD1poj5001-q00000007gN0RSQZ3jo;01^@s6000~S00000002*!0RSQZ3jj#) z1poj5005W-000000082d0RSQZ3jpvd2LJ#7001Ze00000003{A0RSQZ3jow52LJ#7 z006)M00000003W`0RSQZ3jm-q1poj5001BW00000004NK0RSQZ3jl;U1poj5002|~ z00000005zz0RSQZ3jl-=2LJ#7000~S00000004WO0RSQZ3jjEl1poj5000;O00000 z007LK0RSQZ3jh#F2LJ#7003A300000005Ys0RSQZ3jho|1poj5001lj00000007IK z0RSQZ3jj2;1^@s6002k;000000032<0RSQZ3jp|01poj5002Y)00000004`g0RSQZ z3jl}<2LJ#7000;O00000007pW0RSQZ3jjFL1poj5001BW00000001(d0RSQZ3jmNy z1poj5002|~00000002^-0RSQZ3jiq61poj5000;O00000004nn001EX6aX;H2><{9 z000;O00000005q!0RSQZ3jpv^2LJ#7001Na00000006?D0RSQZ3jpLV1poj5001xm z00000007&c0RSQZ3jnY(1^@s6001Na00000003#A0RSQZ3jhcx1poj5001Ze00000 z004cU0RSQZ3jhS&1poj5004jh00000006z90RR#J00000000000000000000007jW z0RSQZ3jmZi1poj5008g-00000000%C0RSQZ3jjdP1^@s6002Y)00000005z(0RSQZ z3jh?`1^@s6000yK00000007vb0RSQZ3jn-|1poj5002Ay000000001@0RSQZ3jko4 z1^@s6001BW00000005<;0RSQZ3jkOF2LJ#7002+|00000002Rw0RSQZ3jnzB1^@s6 z001}u00000006V20RSQZ3jpM71poj5000yK00000008Kt0RSQZ3joX~1^@s6000~S z00000005Ju0RSQZ3jmlV1^@s6000;O00000006$E0RSQZ3jpLx1poj5001}u00000 z007>k0RSQZ3jj3t1poj5000yK00000008@>0RSQZ3jm0RSQZ3jlcN1poj5 z000;O00000001AY0RSQZ3jj#01^@s6001BW00000004ij0RSQZ3jknH2LJ#7000;O z00000005w^0RSQZ3ji<|1^@s6000;O00000007*r0RSQZ3jh>T2LJ#7001-q00000 z000KA0RSQZ3jj z0RR#J00000000000000000000003{V0RSQZ3jkD`1poj5001li00000005J(0RSQZ z3joMn1poj5000yK000000073X0RSQZ3jolQ1poj5001li000000014Z0RSQZ3jpL= z1poj5000~T00000002C&0RSQZ3jheD1^@s6000;O00000007jm0RSQZ3jlO%1poj5 z001BW00000008!|0RSQZ3jn;=1^@s6002M$00000000}Y0RSQZ3jm}a1^@s6006)M z000000070Y0RSQZ3jj1e2LJ#7001Ze00000004Qi0RSQZ3ji?f1^@s6005`}00000 z006kM0RSQZ3jieA1^@s6000;O00000002$10RSQZ3jlZl1^@s6005i-00000007#v z0RSQZ3jjE>1^@s6001li00000000QI0RSQZ3jky)2LJ#7000yK00000003~b0RSQZ z3jl=X1^@s60058x00000008u~0RSNY6abLR2><{9000;O00000001Gi0RSQZ3jplu z1^@s6001BW00000001tv0RSQZ3jpXM1^@s6001xm00000003IG0RSQZ3jiEe1poj5 z001Ze00000004Tm0RSQZ3jka{1poj5001lj00000005}90RSQZ3jpvS1^@s6002k; z000000002C0RR#J00000000000000000000000xV0RSQZ3jiD?1^@s6000yK00000 z003pS0RSQZ3jpBW1^@s6000~S00000001Vp0RSQZ3jkQ51^@s6003M7000000064D z0RSQZ3jj=-1^@s6001xm000000092C0RSQZ3jn+?1poj5001Ze00000000-b0RSQZ z3jmB%1poj5001}u00000004Bj0RSQZ3jjc^1^@s6001BW00000000KL0RSQZ3jmB6 z2LJ#7000~S00000003FJ0RSQZ3jml&2LJ#7000yK00000008;90RSQZ3joa91^@s6 z000;O00000005%80RSQZ3jnZJ1poj5001xm00000007gv0RSQZ3jp|32LJ#7002k; z00000003XR0RSQZ3jmle2LJ#7001xm00000008g10RSQZ3jl=T1^@s6001Na00000 z002_F0RSQZ3jiRo1poj5001-q00000006wa0RSQZ3jovx1^@s6001BW00000000%e z0RSQZ3jq9+1poj5002k;00000001(*0RSQZ3ji=T1poj5002M$000000030I0RSQZ z3jkOb2LJ#70058x00000004Ns0RSQZ3jmNz1poj5001BW000000061I0RSQZ3jl;1 z1^@s6001Na000000014n0RSQZ3jmPr1^@s6001Ze00000005M}0RSQZ3jkC~2LJ#7 z001Na00000006VT0RSQZ3jplr1poj5001Ze00000001n%0RSQZ3jn}{1poj5001xm z00000005i60RSQZ3jom31poj5001Ze00000007Xx0RSQZ3jh?n1^@s6002Ay00000 z0095L0RR#J00000000000000000000001Sx0RSQZ3jh>91^@s6001BW000000029{ z0RSQZ3jpLs2LJ#7004Xd00000007#+0RSQZ3jlyp1poj5001-q00000000xg0RSQZ z3jk!91poj5000yK00000003UW0RSQZ3joBk1^@s6001BW00000006GR0RSQZ3jm-& z2LJ#7000yK00000002qC0RSQZ3jm-{2LJ#7001-q00000004Bt0RSQZ3jl~&1^@s6 z004{t000000005Q0RSQZ3jko81^@s6000~S00000003#j0RSQZ3jjPX2LJ#7001BW z00000000fd0RSQZ3jh=~1poj50049V00000001(?0RSQZ3jj!-1poj5002+`00000 z004``0RSQZ3jpwq1poj5001Na00000007~{0RSQZ3jl=T1poj5002+|00000002M5 z0RSQZ3jk=O1^@s6001xm00000006JW0RSQZ3jnP31poj5002Y)00000003FW0RSQZ z3jnZ81poj5001BW00000004@{0RSQZ3jj!11^@s6001BW00000005W90RSQZ3jkCB z1^@s6001Na00000007d)0RSQZ3jjb>1poj5003+N00000001Ay0RSQZ3jn-K2LJ#7 z001BW00000006Pa0RSQZ3jnyU1^@s6004Xd00000007m;0RSQZ3jiR^1^@s6001BW z00000002hF0RR#J00000000000000000000004u?0RR#J00000000000000000000 z005!L0RSQZ3jm~Q1poj5000yK00000007v?0RSQZ3jlB|1poj5003M7000000008X z0RSQZ3jpL=1poj5000~T00000001G$0RSQZ3jlbY1^@s6000yK00000006m z0RSQZ3jnM|2LJ#7000;O00000001Z80RSQZ3jowP2LJ#7002+`00000005fc0RSQZ z3jj0`2LJ#7000;O00000001uG0RSQZ3jlDR1^@s6000;O00000006+@0RSQZ3joMO z1poj5000~S00000008#k0RSQZ3jkz?1poj5001BW00000001cB0RSQZ3jowX1poj5 z001Na000000036v0RSQZ3jk!+1^@s6001BW00000007G30RSQZ3jhR}1^@s6001BW z00000008^q0RSQZ3jkbI2LJ#7001Ze000000039x0RSQZ3jiPi2LJ#7001}u00000 z007+M0RSQZ3jo+82LJ#7001-q00000003Cz0RSQZ3jjFx1^@s6002+|00000000K% z0RSQZ3jlQT1^@s6001Ze00000004;P0RSQZ3jmm!1^@s6002+`00000006h;0RSNY z4FH(D2LJ#70012T00000007wK0RSQZ3jnl)1poj5001BW00000001H80RSQZ3jlEc z1poj5000yK00000004RB0RSQZ3jnlh1poj5000yK00000007nI0RSQZ3jj1X2LJ#7 z000yK000000005!0RSQZ3joOH1^@s6002M$00000005Hb0RSQZ3jjzX1^@s6000~S z00000008&r0RSQZ3joAZ1poj5002Ay00000003R+0RSQZ3jnO$1poj5000yK00000 z005up0RSQZ3ji=P1poj5001xm00000006b<0RSQZ3jlET1poj5005i-00000001HB z0RSQZ3jjFW1poj5002Y)00000004pM0RSQZ3jl!o1poj5002w?00000007(R0RR#J z00000000000000000000008^x0RSQZ3jj2T1poj5002M$000000039&0RSQZ3jh@6 z1^@s6001Na000000061#0RSQZ3jlC}1poj5003kF00000007DA0RSQZ3jpBR1poj5 z001-q00000001)U0RSQZ3jn0<1poj5001xm00000007AA0RR#J000000000000000 z000000080Z0RSNY6adi62><{9000;O00000000K;0RSQZ3jnAj2LJ#7000~S00000 z005Wl0RSQZ3jiGC1^@s6000yK00000008&w0RSQZ3jn0(1poj5002M$000000012A z0RSQZ3jm-C2LJ#7003|R00000003|80RSQZ3jo;Q1^@s6000~S00000001HG0RSQZ z3ji3=1poj5001BW00000004dN0RSQZ3jj1N2LJ#7001Ze00000001!W0RSQZ3jnA) z2LJ#7003wJ00000000E=0RSQZ3jla<1poj50086w00000003X`0RR#J3jkch1ONa4 z001Nf00000004&Y0RSQZ3jjn`1poj5001Ze000000064+0RSQZ3jkQr1poj5001Ze z00000001xX0RSQZ3jkbM1^@s6001li00000004~f0RSQZ3jmDK1^@s6000yK00000 z006#60ss;K00000000000000000000000H@0RSQZ3ji?u1poj5002k;00000003U{ z0RSQZ3joOS1^@s6000~S00000007SN0RSQZ3jj>n1^@s6000yK00000008^)0RSQZ z3jmNQ2LJ#7004jh00000004gT0RSQZ3jpNR1^@s6001BW00000008du0RSQZ3jn;} z1^@s6000~S00000004jV0RSQZ3ji?M1poj5000;O000000086k0RSQZ3jpvS1^@s6 z002k;00000002An0RSQZ3jpj?1^@s6001BW00000003L{0RSQZ3jiQM2LJ#7000~S z00000000Q~0RSQZ3jkPz1poj5003M700000003<{9000mG00000002k<0stZa3jmPl1poj5000yK00000004dg z0stZa3jn}Q2LJ#70058x00000002P(0stWZ4FE8_2LJ#70018V00000003kH0stZa z3jom11^@s6002k;00000006lH0stZa3jloJ1poj5001-q00000000^T0ss;K3jjQ_ z1ONa4005K#000000027!0stZa3jmPU1^@s6000;O00000003tL0stWZ6ac8p2><{9 z000mG00000005Q)0ss*J00000000000000000000006WD0stZa3jj1V1^@s6002Y) z00000002`20stZa3jpv`1poj5002Ay00000005l?0stZa3jmb11^@s6001xm00000 z006%P0stZa3jl;v1^@s6001xm00000008m?0stZa3ji?R1poj5001Na00000002z| z0stZa3jjFV1poj50000100000004Le0stZa3jk~}1poj5002Ay00000005~40stZa z3jjbU2LJ#7002|~00000001in0stZa3jmP71^@s6000yK00000002)00stZa3jjQG z1poj5001Na00000006rN0stZa3jjzi1poj5001xm00000007no0stZa3joBn1^@s6 z005W(00000001`!0stZa3jhd71poj5002M$00000002n`0stZa3jpwq1poj5001Na z00000005r{0stZa3jibo1^@s6000yK00000001Be0stZa3jp-*1^@s6001Ze00000 z005x~0stZa3joL_2LJ#7001}u000000021&0stZa3joaJ1^@s6000~S000000043c z0stZa3jny|1^@s6000yK00000008U>0stZa3jj>l1^@s6001Ze00000000IG0stZa z3jq8c2LJ#7000yK000000027*0stZa3jk1^@s6001}u00000008U`0stZa3jpje2LJ#7001BW00000004gv0stZa z3jky(1poj5002Ay00000005y60stZa3jnw>1poj5001BW00000008R`0ss;K00000 z0000000000000000093F0stZa3jn}51^@s6005K#00000002Y~0stZa3joO91poj5 z000yK00000003za0stZa3jkDF1poj5001Na00000006lV0ss;K000000000000000 z00000007w#0ss;K00000000000000000000000yb0stZa3jpY>1^@s6001Ze00000 z003|i0stZa3jh=c1^@s6007Vc00000005B@0stZa3jqAy1^@s6000~S00000001-+ z0stZa3jk#91poj5000;O00000006}j0stZa3jk1H1poj5005`~00000000vc0stZa z3jka}2LJ#7001Ze00000005s80stZa3jnmC1^@s6000;O00000001}?0stZa3jiGO z1^@s60000100000005yB0stZa3jh?_1poj5000~S00000007w(0stZa3jpjM1^@s6 z000yK000000090J0stZa3jjb^1poj5000yK00000001f#0stZa3jox71poj5000yK z0000000300000005d50stZa3jp}&1poj5001Nb00000 z006KS0ss*J000000000000000000000074p0stZa3jpMu1^@s6001BW00000001}_ z0stZa3jjcA1^@s6001Ze00000003PV0stZa3jka_2LJ#7000yK00000004;>0stZa z3joOS1^@s6000~S00000008+H0stZa3jl~%1poj5000yK00000001%=0stZa3jo;0 z1^@s6000~S00000006ES0stZa3jn;`1^@s6000~S00000004*?0stZa3jo+M1poj5 z001BW00000007b%0ss*J00000000000000000000000LX0stZa3jmn@1^@s6001}u z00000004{{0stZa3jicY1poj5001BW00000007e(0stZa3jknq1poj5006uM00000 z0021~0stZa3jm}!2LJ#7000~S000000068T0stZa3jmyu1poj5006WA00000001@| z0stZa3jnOS1^@s6000;O00000003DW0ss;K00000000000000000000006Qa0stZa z3jk1_1^@s6001Ze00000003Ma0stZa3jkC~2LJ#7001Na00000004U(0stZa3joBO z1^@s6001BW00000000Oc0stZa3jlQ21^@s6000~S00000001){0stZa3jpLx1poj5 z001}u00000002`S0stZa3jlmM1^@s6000yK00000003|v0stZa3jmaC1poj5002+` z00000005F60ss;K00000000000000000000006HZ0stZa3jowG1^@s6001xm00000 z002rK0stZa3jmy)1poj5001BW00000004L&0stZa3jk1V1poj5004LZ00000007}1 z0stZa3jko71^@s6002Y)00000001u_0stZa3ji<%2LJ#7001}u00000006Zh0stZa z3jo|q2LJ#7002|~00000001T-0stZa3jlP81poj5008I#00000005350stZa3jj>Q z1^@s6003M700000008MB0stZa3jmNz1poj5001BW00000000^y0stZa3joMG2LJ#7 z001Ze00000007A%0stZa3jlcM1^@s6000yK00000002!R0stZa3jlB@1^@s6003M7 z00000008wP0stWZ4FCYW2LJ#7001ul00000001Z?0stZa3joAI2LJ#7001Ze00000 z0034b0stZa3jjDW1^@s6003M700000007t|0stZa3jkyn1^@s6000;O00000002iN z0stZa3joOT1^@s6001li00000008tQ0stZa3jhS31^@s6002w?00000005aL0stZa z3jm0d1poj5002k;00000008wS0stZa3jpLD1^@s6000yK00000004p~0stZa3jnkT z1^@s6001Ze00000005#V0stZa3jh>71^@s6002Ay000000015+0stZa3jl0H1poj5 z001Ze00000003kt0stZa3jo0E1^@s6001Ze00000005FG0stZa3jj#k1poj5000;O z00000008wU0stZa3jlCW2LJ#7002|~00000001E=0stZa3jj1N2LJ#7001Ze00000 z007h}0stZa3jio{1poj5000yK00000000Rp0stZa3jokZ1poj5001-q00000003wz z0stZa3jnCl1^@s6002k;00000006xz0stZa3jpL-1^@s6002Ay00000001>B0stZa z3jkCE1^@s6000~U00000005OM0stZa3jnl12LJ#7000yK00000008|f0stZa3jpva z1^@s6000~S00000004w60stZa3jnCX1^@s6002+|00000001N{0stZa3jhS)1poj5 z001li00000002HM0stWZ6aawB2><{9000mG00000003Go0stZa3jnCl1^@s6002k; z00000006Ho0stZa3jj>&1poj5000yK00000002%d0stZa3jj>w1poj5001}u00000 z0056J0stZa3jidU1^@s6000yK00000008SQ0stZa3jh@81poj5001BW00000003Ms z0stZa3jl=H1^@s6002+`00000006=-0stZa3jmG0stZa z3jkm<1^@s6000yK00000007-E0stZa3jmBx2LJ#7001-q00000002!f0stZa3jhFE z1poj5001BW00000004P00stZa3ji2<1poj5001Ze000000071@0stZa3jn-61^@s6 z001Ze00000001*G0stZa3jlB@2LJ#7004jh000000074_0stZa3jmPb1^@s6002+` z00000003<>0stZa3jlzd1poj5008I!00000008$h0stZa3joY51poj5002|~00000 z000>@0stZa3joA02LJ#7001Ze00000005*k0stZa3jl~f1poj5002Y)00000007K1 z0stZa3jhSP1^@s6008I!00000002uh0stZa3jl;y1^@s6002M$00000003q+0stZa z3jq931poj5001}u00000004Y70stZa3jl1>1poj5001Na00000006!<0stZa3jjDg z1poj5002Y)00000008SX0stZa3joAO1poj5001xm00000000d(0stZa3jiRb1^@s6 z001xm00000004b90stZa3jjD`1^@s6005)_00000007=L0ss;K000000000000000 z00000008nf0stZa3jm1poj5001BW00000004D8 z0stZa3jnk$1poj5001xm00000005Fb0ss;K00000000000000000000006u_0stZa z3jmBB1^@s6000yK00000001yP0stZa3jo}v1^@s6002w?00000007oL0stZa3jpx( z1^@s6000yK000000037%0stZa3jkC&1^@s6002Ay00000007QE0stZa3jmz61^@s6 z001Ze00000000I+0stZa3jk!91poj5000yK00000002=y0stZa3jhpW1poj5000yK z00000005pq0stZa3jo+e2LJ#7000yK00000000j`0stZa3jomm1^@s6002+|00000 z0065&0stZa3jmmn1^@s6001Zg00000001pQ0stZa3jjdD1^@s6002k;00000005Oj z0ss;K00000000000000000000006N<0stZa3jjbA2LJ#7001xm00000001jP0stZa z3jky&1^@s6001xm00000006c_0stZa3joAT2LJ#7002M$00000004DF0stZa3ji!I z1^@s6000~S00000001RL0stZa3jk2s1^@s6002+`00000007@b0stZa3jk2b1^@s6 z006uI00000002ft0stZa3jj1e2LJ#7001Ze00000008<%0stZa3jlDx1^@s6005`} z00000001RN0stZa3jjbt1poj5005K#00000002`*0stZa3jiF)1^@s6002M$00000 z006y50ss;K00000000000000000000007fR0stZa3jhR@1poj5004vl00000001;d z0stZa3jm;e1poj5001BW00000003l20stZa3jio;1poj5001BW00000005Cl0stZa z3jk!Y1^@s6001Na00000008?)0stZa3jq8o2LJ#7002M$00000001IM0stZa3jicK z2LJ#7001Na00000004$b0stZa3jicK2LJ#7001Na00000008Pq0stZa3jmxz2LJ#7 z000;O000000034>0stZa3jkaV2LJ#7000~S00000001jX0stZa3jp*=2LJ#70077U z000000072I0stZa3joND1poj5001xm00000002Tv0stZa3joM#1poj5000yK00000 z005p$0stZa3jk0a1^@s6001Ze000000022n0stZa3jnN+1poj5000~S00000006E{ z0stZa3jo~M1poj5000C500000001*i0stZa3jo+)1^@s6003|R00000004nb0stZa z3jjFf1^@s6005K#00000008_>0stZa3jipK1poj5001Ze00000000(G0stZa3jky# z2LJ#7002k;00000005>>0stZa3jl!F1poj5003M700000000S40stZa3jpxU1^@s6 z001xm00000004ea0ss;K00000000000000000000005Ox0stZa3jpXB2LJ#7003|R z00000007od0stZa3jk2+1^@s6001li00000008q)0stZa3jn}52LJ#7000yK00000 z003@L0stZa3jmZT1^@s6003M700000008n)0stZa3jo+L1^@s6001xm00000004|q z0stZa3jnyD1poj5003wb00000001dd0stZa3jkDX1poj5001BW00000003E20stZa z3jl0|1poj5002|~00000004kf0stZa3jiz<2LJ#7000~S000000028w0stZa3jl!o z1poj5002w?00000005O#0stZa3jk1S1poj5002+`00000006F30stZa3jjDF1^@s6 z000yK00000000A30stZa3jmyY1poj5001Ze000000022v0stZa3jmBB1^@s6000yK z00000006C30stZa3jh#q1poj5001BW00000007}t0stZa3jj#K1^@s6001xm00000 z003K70stZa3jkOc2LJ#7000yK00000005O%0stZa3jn0R1^@s6001xm000000078V z0stZa3jiE=1poj5001Nb00000001^u0stZa3jmm;1^@s6000~S00000007}v0stZa z3jnk+2LJ#7001BW00000001#q0stZa3jnNW1poj5000yK00000004hj0stZa3jnaN z1^@s6000yK00000007=t0stZa3jka`2LJ#7000~S00000005R*0stZa3jmnT1^@s6 z000yK00000007xp0stZa3jmNf1^@s6001li00000003rM0stZa3jjne2LJ#7000;O z00000005U-0stZa3joaO1^@s6001BW00000008J(0stZa3jn|%1^@s6000;O00000 z001*v0stZa3jlx}2LJ#7002+`00000003ND0stZa3jk1-1poj5003A300000004no z0stZa3jj=21^@s6001}w00000006jK0stZa3jn-|1poj5002Ay00000007`y0stZa z3joAH1^@s6002w@00000002K+0stZa3jkD0stZa3jnA-2LJ#7000;O z00000007)(0stZa3jjPR1poj5001Ze00000008%90stZa3jlC22LJ#7000yK00000 z0044l0stZa3jjzl2LJ#7001Ze00000000PR0stZa3jhR21poj5001BW00000003ub z0stZa3jk1y1poj5001}u00000005Y10stZa3jlmA2LJ#7000~S00000003uc0stZa z3jhSP1^@s6008I!00000008D`0stWZ4FHI{2LJ#7001cf00000000we0stZa3jnau z1poj5001BW00000001Fs0stZa3jloT1^@s6000;O00000002g60stZa3joAL2LJ#7 z002M$00000003-i0stZa3jmL0stZa3jk;k2LJ#7000~S00000001R#0stZa z3jhe11poj5000;O00000005+K0ss;K3jjE@1ONa4000~X00000008!H0stZa3jiGP z1^@s6003A300000002{P0stZa3jj1x2LJ#7004jh00000008%J0stZa3jka%2LJ#7 z000~S00000006CV0stZa3jmxo2LJ#7001}u00000007u=0stZa3jnlI1poj5000yK z00000002XB0stZa3jicU1poj5002k;00000005|R0stZa3ji?h1poj5000~S00000 z002630stZa3joNO1^@s6003M700000004z^0stZa3joM&1poj5003M700000000nl z0stZa3jpBY1poj5007Vc00000005kH0stZa3jpNR1^@s6001BW00000000bi0stZa z3jhQ?2LJ#7000~S00000006&r0stZa3ji=P1poj5001xm00000007l>0stZa3jhRD z1poj5000yK00000000Yi0stZa3jq8S1^@s6003|R00000001d=0stZa3jl201^@s6 z002+`00000008KA0stZa3jjQt1poj5002Y)00000004D&0ss;K000000000000000 z00000004(~0stZa3jiEU1poj5001-q00000008NC0stZa3jj!+1poj50000100000 z005SF0stZa3jmNg1^@s6001xm00000006>x0ss;K00000000000000000000007%~ z0stZa3jj2~1^@s6002Ay00000008)S0stZa3jiQ41poj5001Ze00000000qr0stZa z3ji1t2LJ#7001Ze00000005?W0stZa3jlC42LJ#7000;O00000007o`0ss;K00000 z000000000000000000|$0stZa3jo|S1^@s6002M$00000004!00stZa3jj>F1poj5 z002Ay00000006Ig0stZa3jp*^1poj5001BW00000007E*0stZa3jhQ`1^@s6000;O z00000005AC0stZa3jlzQ1poj5001li00000008WJ0stZa3jknm1poj5004*p00000 z005zU0stZa3jl181poj5001xm00000003=$0ss;K00000000000000000000005GG z0stZa3jnND1poj5001Na000000072)0stZa3jkOb2LJ#70058x00000008QJ0stZa z3jlmC1^@s6001Na00000003})0stZa3ji#e1poj5001Ze00000008)Y0stZa3jjPZ z1poj5001xm00000000?(0stZa3jjD>1poj5001Na00000002>c0stZa3jnmc1^@s6 z001Ze00000004o10stZa3jok)1^@s6002k;00000007v30stZa3jpx%1poj5000yK z00000003Bk0stWZ6aWaz2><{9001Ze00000004P_0stZa3jko41^@s6001BW00000 z0016=0ss;K3jlz~1ONa4004Xg00000003Zt0stZa3jnl;1^@s6001Ze00000005tX z0stZa3jmOf1poj5001xm00000000Go0stZa3jjFh1^@s6002M$00000002OO0stZa z3jln31poj5001Nb00000000q#0stZa3jnwX2LJ#7001}u00000005SQ0stZa3jpK* z1^@s6002k;000000072=0stZa3jnl;1^@s6001Ze00000000Gq0stZa3jnYK1^@s6 z000;O00000004r70stZa3jna&1^@s6000~S00000001_H0stZa3jmZV2LJ#7000~S z00000004M}0stZa3jq8b2LJ#7000yK00000005kY0stZa3jn}Q1poj5001-q00000 z0091l0stZa3jhGC1^@s6000yK00000003Tw0stZa3jkEH1poj5000yK00000004Q0 z0ss;K000000000000000000000054L0stZa3jnCs1^@s6000yK00000006{>0stZa z3jo9*2LJ#7004{t000000091m0ss;K00000000000000000000000$-0stZa3jk<) z1poj5000yK00000002~n0stZa3jjPT2LJ#7001Ze000000007r0stZa3jmz*1^@s6 z000yK00000004xD0stZa3jkzJ2LJ#7000yK00000008BP0stZa3jo*^1^@s6001Na z00000000Gv0stZa3jjEl1^@s6001Zg00000004)H0stZa3jjQ*1^@s6002w?00000 z000|`0stZa3jpL^1^@s6004jh00000004lB0stZa3jnZ{1poj5000yK00000006{_ z0stZa3jnAw1poj5004Xd000000088Q0stZa3jnl12LJ#7000yK00000002yj0stZa z3jpLv1poj50068300000003-@0stZa3jj=S1poj5000yK00000006g(0stWZ6aYZV z2><{9001Ze00000007&I0stZa3jnOT1poj5000;O00000003Kz0stZa3ji!K2LJ#7 z000;O00000006y=0stZa3jioZ1poj5001Ze00000008og0stZa3jmZD2LJ#7001}u z00000003Hz0stZa3jpXX1^@s6003M700000000Ay0stZa3jo-j1^@s6000~S00000 z005DW0stZa3jhe(1^@s6000~S000000085T0stZa3jhGZ1^@s6000yK00000003T( z0stZa3jnym1^@s6002k;00000007620stZa3jmZ22LJ#7000yK00000002&q0stZa z3jp|R1poj5001li00000004220stZa3jk=W1^@s6001Ze000000085V0stZa3jh!w z2LJ#7002+`00000000q@0stZa3joYi1^@s6001BW00000004NA0stZa3jl!71poj5 z001BW00000008Zg0stZa3jhS=1poj5000;P00000003~30stZa3jm}j1poj5000;O z00000004NB0stZa3jloX1poj5001Ze00000008!q0stZa3jo9>1^@s6002|~00000 z001F z1poj5002Ay00000004KD0stZa3jj0(1^@s6001BW00000005Ac0stZa3jjPo2LJ#7 z000~S00000002Ff0ss;K00000000000000000000004iM0stZa3jlmE1^@s6001}u z00000000x00stZa3jpvu2LJ#7000yK00000005_#0stZa3jpkb1^@s6006uM00000 z002Fh0stZa3jla32LJ#7000~S00000004!U0stZa3jiqo1poj5001Na00000007^Z z0stZa3jlaD1^@s6003kF00000003H<0stZa3jpx-1poj5002+`00000004%W0stZa z3jlnp1^@s6005W(00000001tU0stZa3jlaJ1^@s600682000000079E0stZa3jn-5 z2LJ#7000~S00000000V`0stZa3jm}@1poj5001BW00000001PL0stZa3jioo2LJ#7 z002Y)00000005tx0stZa3jkoP1^@s6003|S00000000r30stZa3jpK?1^@s6001BW z00000004%Z0stZa3jp|~1^@s6001Ze00000008@(0stZa3jiRs1^@s6001}u00000 z001eS0stZa3jmBY1^@s6002+`00000005_*0stZa3jlC81poj5001Na00000007CI z0stZa3jo~T1poj5002M$00000008}+0stZa3jnw+2LJ#7003kF00000005qz0stZa z3ji?U1poj5000~S00000007vY0stZa3jo+M1poj5001BW00000001JN0stZa3joOA z1poj5000;O000000045I0stZa3jnA-2LJ#7000;O00000008};0ss;K0000000000 z0000000000000Z10stZa3jko+1poj5007tk00000002#(0ss;K000000000000000 z00000003y90stZa3jokZ1poj5001-q000000076J0stZa3jma01^@s6002Y)00000 z001YU0stZa3jiqF1^@s6002+`00000006$B0stZa3jj3S1^@s6003wJ00000005Dq z0stZa3jjb;2LJ#7001Na00000006e40ss;K00000000000000000000007dW0stZa z3jiph1^@s6002k;00000003^I0stZa3jp-S1^@s6001Ze00000005k$0stZa3jl;H z2LJ#7001BW00000001(i0stZa3jk0stZa3joA02LJ#7001Ze00000001$i0stZa3jkza1^@s6003+N z000000051p0stZa3jn;O1^@s6000~S00000002d%0stZa3jmm51^@s6003|R00000 z005Du0ss;K000000000000000000000066|0stZa3ji1+1^@s6001xm00000007sf z0stZa3ji=B1^@s6000;O000000001|0stZa3jnY@2LJ#7000;O00000001JV0stZa z3jiph1^@s6002k;00000006$H0stZa3jmlh1poj5001BW00000001DU0stZa3jl1G z1poj5001}u00000002;^0stZa3jlyp1poj5001-q00000004=o0stZa3jhFI1poj5 z003A300000005|{0stZa3jn0y1^@s6001BW00000000iD0stZa3jla}1poj5001Na z00000002s<0stZa3jo+81^@s6000;O000000051t0ss;K00000000000000000000 z006G30stZa3jjP)1poj5002Y)000000088v0stZa3jnk+2LJ#7001BW000000010stZa z3jnx`1poj5005`}00000002F<0stZa3jkc`1poj5000~S00000003yV0stZa3ji1= z1^@s6001Ze000000095C0stZa3jl=H1^@s6002+`00000003pT0stZa3jn|~1poj5 z000O800000004xy0stZa3jlZ%1^@s6001-q00000000TN0stZa3jj!J1poj5001-q z00000002|C0stZa3jkb>1poj5001Na000000061D0stZa3jlyF2LJ#7005K#00000 z003^e0stZa3jl0H1poj5001Ze00000006YP0stZa3jp-*1^@s6001Ze00000001?* z0stZa3jlB@1^@s6003M700000007;(0stZa3jk!y1^@s6000yK00000005x70stZa z3jjDl1^@s6001BW00000006+d0stZa3ji!k2LJ#7000yK00000002h30stZa3jnAp z1^@s6002M(00000000xc0stZa3jmCs1^@s6002w?000000061I0stZa3jjFg1^@s6 z001Ze00000008^F0ss;K00000000000000000000002b30stZa3jnB>1poj5003YB z00000003;h0stZa3jm0p1^@s6007Vc000000020@0stZa3jpLD1^@s6000yK00000 z0070m0stZa3joZU1^@s6000;O00000000EQ0stZa3jhH31^@s6001}u00000005i7 z0stZa3jlaZ2LJ#7001-q00000007y*0stZa3jhQN1^@s6002+`00000002P20stZa z3ji3<1^@s6002k;00000005Q20ss;K00000000000000000000006DQ0stZa3jm<0 z1^@s6000~S00000002wE0stZa3jpK{2LJ#7003M700000000id0stZa3jp;01poj5 z003wJ00000002tE0stZa3jnAo1^@s6003M700000007y;0stZa3jnC%1^@s6001-q z00000003LW0stZa3jpLk1^@s6001xm000000079u0stZa3jn0(1poj5002M$00000 z008a80stZa3jj0%1^@s6003kF00000002tG0stZa3jhRb1^@s6006uM00000007{{ z0stZa3jlD71^@s6001Zg00000003gf0stZa3jln!1poj5004vl00000004-_0stZa z3jqAo1poj5002Y)00000006|s0stZa3jpYE1poj50058x00000006MZ0ss;K00000 z000000000000000006_s0stZa3jl201^@s6002+`00000004r>0stZa3joBr1poj5 z002|~00000007R&0stZa3jlb)1^@s6000;O00000002VC0stZa3jjbD2LJ#7000;O z00000005@R0stZa3jmz61^@s6001Ze00000007>}0stZa3jj!+1poj50000100000 z004{10stZa3jh?l1^@s6003+O00000000on0ss*J00000000000000000000001+~ z0stZa3jh?31poj5001Na00000004>00stZa3jj3V1^@s6000~T00000008C70stZa z3jm~I1poj5002M&00000001w{0stZa3joMc1poj5002Ay00000004B%0stZa3jnm3 z1^@s6002+`00000007L)0stZa3jiP&2LJ#7001BW00000001S;0stZa3jpk#1^@s6 z002w?00000007_30stZa3jj<`2LJ#7000;O00000002eK0stZa3jlza1^@s6001-q z00000007d?0stZa3jk102LJ#7001BW00000001A)0ss;K00000000000000000000 z002JE0stZa3jmCn1poj5002w?00000006Ad0stZa3jnAC2LJ#7001}u00000001%2 z0stZa3joAg1poj5001BW00000004K;0stZa3ji>m1^@s6001Ze00000008~a0stZa z3ji1_1poj5003A300000001S?0stZa3jkOS2LJ#7003M700000006ep0stTY00000 z000000000000000007d_0stZa3jipK1poj5001Ze00000008XK0stZa3jo|R2LJ#7 z001Ze00000001h|0stZa3jjPr1poj5001BW00000003;#0stZa3joxD1poj5003kF z00000004^80stZa3jm-o2LJ#7000yK00000000Kl0stZa3jmP71^@s6000yK00000 z001h}0stZa3jhQ&1^@s6003M700000005}d0stZa3jo9{2LJ#7003|R00000002JJ z0ss;K000000000000000000000036h0stZa3jio;1poj5001BW00000004v30stZa z3jp}r1^@s6000yK00000001S`0ss;K00000000000000000000002ML0stZa3jjQ9 z1poj5000;O00000005}f0stZa3jo|S1^@s6002M$00000000u!0stZa3jm-V1^@s6 z001Na00000005NM0stZa3jjbA1^@s6000;O00000000En0stZa3jnlG1poj5002k; z000000027I0stZa3jhG~1^@s6002Y)000000073<0stZa3jpN%1poj5000;O00000 z001o50stZa3jjzo1poj5001li00000002YS0stZa3jipn1^@s6000yK000000080G z0stZa3jlO81^@s6002w?00000004s70stZa3jkyi2LJ#7000~S00000002MQ0stZa z3joZR1poj5000~S00000004N}0stZa3jn+g1^@s6000yK00000006Ao0stZa3jl0R z1poj5001BW00000008mY0stZa3jhR21poj5001BW00000002P1poj5002+`00000 z0095o0stZa3jmN52LJ#7000~S00000006Mv0stZa3jjc31poj5003kF000000092o z0stZa3jhde1poj5001BW00000001lA0stZa3jn<51poj5001xm00000005xg0stZa z3jnaP1^@s6001Na00000001H10stZa3jmD#1poj5004vm00000004&H0stZa3jj3V z1^@s6000~T000000083O0stZa3jo0R1^@s6002+|00000004mC0stZa3jkm<1poj5 z001BW00000005fc0ss;K00000000000000000000006q+0stZa3jn~41poj5001xm z00000000x=0stZa3jl;d1poj5005K#00000002(m0stZa3jo|S1poj5000;O00000 z004C10stZa3jj2*1^@s6001Ze00000007$I0stZa3joM32LJ#7001Ze00000001uH z0stZa3jjn&1poj5001BW00000003O#0stZa3jiQp1poj5000;O00000005fe0stZa z3jm0stZa3jjPR1poj5001Ze00000004pH0stZa3jm0y1^@s6000~S z00000000f;0stZa3jkC)1^@s6001Na00000004UB0stZa3jo9{2LJ#7003|R00000 z000o?0stZa3jmNh2LJ#7005i-00000006M&0stZa3jidU1poj5002M$00000008pl z0stZa3jh!d2LJ#7001xm00000000^10stZa3jj3e1poj5001Ze000000064z0stZa z3jjEd1poj5001Na000000002!0stZa3jkay1poj5004Xd00000000o^0stZa3jlaB z1poj5001BW00000004^U0stZa3jmm&1poj5001BW00000005)t0stZa3ji=p2LJ#7 z000~S00000008Xh0stZa3jiQk1poj5001BW00000000>20stZa3jmPo1poj5001xm z00000005ck0stZa3ji?R1poj5001Na00000008vq0stZa3jjRb1^@s6001xm00000 z004~Y0stZa3jnNY1^@s6002Y)00000008Ui0stZa3jkcl1^@s6001BX00000002+x z0stZa3jn-Q2LJ#7001-q000000049A0ss;K00000000000000000000005Nh0stZa z3jkbk1poj50058x000000018B0stZa3jky$1^@s6000;O00000004&U0stZa3joBh z1^@s6001BW00000006h_0stZa3jmxn1poj5002M$00000007490stZa3jm}n2LJ#7 z001BW000000033(0stZa3ji2H1poj5001Na00000006e_0stZa3jj!c1poj5000;O z00000000E;0stZa3jo9u2LJ#7000~S00000006G;0stZa3joX*2LJ#7003M700000 z002Di0stZa3jpK~2LJ#7001Ze00000007bN0stZa3jkn^1poj5001xm00000002<% z0stZa3jnN22LJ#7002k;00000006}B0stZa3jmmh1poj5005i-00000008#z0stZa z3jjo?1^@s6000~S00000005Qo0stZa3jkE51^@s6002w?000000030-0stZa3jk~t z1^@s6003+N000000040E0stZa3joMc1poj5002Ay00000006b}0stZa3jpXH2LJ#7 z000yK000000018I0stWZ4FCwd2LJ#7001EX00000002Yt0stZa3jq8R2LJ#7000~S z00000008gv0stZa3jl~b2LJ#7001Ze000000039?0stZa3jn}q1poj5002w?00000 z007qX0stZa3jn z1poj5002Ay00000005r%0stZa3joZ`1^@s6004*p00000001KR0stZa3jlm31^@s6 z000~S00000004^k0stZa3jm-g1poj5000~S000000067_0stZa3jj>$1^@s6000;O z00000008><0ss*J00000000000000000000000>I0ss;K3jolv1ONa4003wK00000 z001)i0stZa3jiP$2LJ#7005`}00000007PT0stZa3jo}R1^@s6000yK00000000d7 z0stZa3jh!*2LJ#7002|~000000055q0stZa3jn;F1poj5002w?00000006G~0stZa z3jo|T1^@s6002k;00000000>K0stZa3jpXB2LJ#7003|R00000003G00stZa3jlNr z2LJ#7000yK00000005Kw0stZa3jl;M2LJ#7000~S00000001rg0stTY0000000000 z0000000000002Dv0stZa3jojn1^@s6000yK00000003G10stZa3jnkT1^@s6001Ze z00000004RX0stZa3jo+X2LJ#7003M700000001fd0stZa3jh=_1poj5005K#00000 z002Y%0stZa3jo+E1poj5001-q00000003Y80stZa3jk=b1poj5002M%00000007PX z0stZa3jl~S2LJ#7002|~00000000R70stZa3jl0R1poj5001BW00000002$?0stZa z3jho$1^@s6001Na000000070ss;K3jol&1ONa4004{!00000006}Q0stZa3jhor1^@s6001BW00000 z001=r0{|ib3jlap1poj5000~S00000004mi0{|ib3jkyw1^@s6003M700000006-N z0{|ib3jo~M1^@s6001Na00000007ni0{|ib3jlza1^@s6001-q00000003hF0{|cZ z00000000000000000000004af0{|ib3ji1_2LJ#7001xm00000005`~0{|ib3jowH z2LJ#7001xm00000000sK0{|ib3ji!R1^@s6002+`00000004FZ0{|ib3jo;N1^@s6 z000~S00000001%r0{|ib3jjC+1^@s6004LZ00000006H80{|ib3jh=X1^@s6001BW z00000001Ne0{|ib3jicU1poj5002k;00000004;u0{|ib3jnAY2LJ#7004jh00000 z008d<0{{{L00000000000000000000000{W0{|ib3jnm#1poj5002k;00000003D9 z0{|ib3jnMX2LJ#7001BW00000008*~0{|ib3jiou1^@s6006uM00000005c>0{|ib z3jjcQ1poj5007(o00000008F(0{|ib3jpLi1^@s6001xm00000000yR0{|ib3jk~w z2LJ#7001Ze00000003eK0{{{L00000000000000000000004gn0{|ib3jpZl1^@s6 z001li00000005N-0{|ib3jl!i1^@s6003|R00000004mq0{|ib3jl1^@s6003M700000006oP0{|ib3jmZ42LJ#7001li00000 z000vT0{|ib3jknw1^@s6006uM00000005~90{|ib3joOP1poj5001Ze00000001cq z0{|ib3jkE51^@s6002w?00000008I<0{|ib3jjd0{|ib3jl~T1poj5000yK00000002!60{|ib3jo;D1poj5000yK z00000005j00{{{L00000000000000000000006iS0{|ib3joML2LJ#7002M$00000 z001Hn0{|ib3jl1>1poj5001Na00000003kU0{|ib3jo|01^@s6005u?00000007(% z0{|ib3jo|*1poj5001xm000000003H0{|ib3jjni1poj5001-q00000004Us0{{{L z00000000000000000000005j20{|ib3jm-1poj5 z001Ze00000005d20{|ib3jmNz2LJ#7001li00000008k40{|ib3jkn^1poj5001xm z00000003|k0{|ib3jl=81^@s6001Na00000006@i0{|ib3jlbT1poj5000yK00000 z000gY0{|ib3jnOt1^@s6005i-00000004dz0{|ib3jn-J2LJ#7003|R00000000#g z0{|ib3jq8A1^@s6001Ze00000005R10{|ib3jmY|1^@s6001BW00000006}m0{|ib z3jp|v1poj5001xm00000008b40{|ib3ji=M2LJ#7003YB00000003nc0{{{L00000 z000000000000000004>>0{|ib3jlZl1^@s6005i-00000000*k0{|ib3jlZ?1^@s6 z000yK00000004^@0{|ib3jm-m1^@s6001xm00000002K20{|ib3jp{d2LJ#7001Ze z00000006QW0{|ib3jo}^1^@s6001}u000000000lb#rnrY-wUIXJcb8VPSG(Xf`x0 zY-w(Fcr9mcbuTwAGcGVME-o)FE-x-FFD@=GY-wUPG%sUvbZIVc03>(-V_|G;Uw36; zYhPw=055fOaxZLYVlQW7V=rN0a${&VG%ajtZgqGqXKr;bH!d?SFfT4HFD@=GE-o)F zE-!3pVm34{V{&wEE^h#1a&&Wab!KKRV*q4ja%E>}b97~LUvzC>V{C73Wpe-|WB^}Z zWN%+*Y;R&=Y+qz_Z*p^AVRd)_V{dJ6Y-Mz1WG*-`GB^NVUu17zXKZg`VQgPybZ>HV zUtx84UuJ1;Xrc|VQpn!WOZ$Ac>rHuW^!R|WnW}MtB zUtw}`VR>I=Zgg^a0AE^DbWAZhaA{>@Wp`mPB~v+XKr<0V|aK>F*sjeWq4y~VQyz-Utw-!UtwfqMNn30X#ihZ zPB~v+XKr<0V|aK>F*09YVRUb8X=7huWMoB9R%vMfUs_H%Utec#bzft6cuX=iUteW- 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 z0000000000000000000000000000000000000000000000000002=@R00#g700IC2 z000000006200000000620000003-ka00000000000000000aO4000000000000000 z04@Lk0QUd?Zvp@S0000004M?g0000004M?g000000EjdI0000000RI30000000;m8 z00000000000000005|{u01E&B00IC2000000I)Uy000000I)Uy000000PwT`00000 z00aO400RI300;m80000002lxO0000006+i$00RI300IC2000000HEst000000HEst z000000Nl9(0000000000000000096100000000000000007w7;0RR90Zvp@S00000 z0DPqb000000DPqb0000002B`Z0000000RI30000000IC20000000IC20000009610 z0RI2~Zvp@S000000Fbl;000000Fbl;000000Pp|+0000000aO400jU500;m800000 z00000000000Av6F00aO400IC2000000D!dv000000D!dv00000000aC0000000RI3 z0000000;m80000002lxO000000B!&P00aO4073u&000000D!>*000000D!>*00000 z0N{=Q0000000RI302TlM00;m80000002lxO000000C)fZ0096100sa6000000ANrA z000000ANrA0000002BZK00000000000000000aO40000000000000000CNBU00961 z00sa6000000Dw>g000000Dw>g000000AODL00000000000000001yBG0000001yBG z000000Db@f0096100sa6000000N}3#000000N}3#000000PLj#000000000000000 z00;m80000000000000000E7Sl0096100sa6000000L)bf000000L)bf0000001yBG z00000000000000000aO40000000000000000Ez$r0096100IC2000000N_;z00000 z0N_;z0000008eKC00000000000000000;m80000000000000000FnRz0096100IC2 z0000005H7=0000005H7=0000007NYS00000000000000000aO4000000000000000 z0H6Q>0096100IC2000000C?&L000000C?&L0000001U(c00000000000000000;m8 z0000000000000000IC200096100IC2000000EDgx000000EDgx0000005Tc?00000 z000000000000aO40000000000000000K5PI00;m800RU7000000AR@p000000AR@o z0000001yBG00000000000000000;m80000000000000000KxzO01f~E00RI300000 z0AR@p000000AR@o0000001yBG00000000000000000;m80000000;m8000000L}ma z01p5F00RI3000000C33(000000C33&0000000;m800000000000000000;m800000 z00;m8000000NMZm0096100RI3000000C>p>000000C>p=000000Qdp`0000000000 z0000000;m80000000000000000OtSz00sa600RI3000000C3C+000000C3C*00000 z0DuAj0000000aO40000000;m80000001yBG000000Pp|+0096100RI3000000PxNU z000000PxNT0000001z<%00000000000000000;m80000000;m8000000QCR>00961 z00RI3000000000A00000000090000003ZMW00000000000000000;m80000000000 z000000Q&#{00;m800RI30000003ZMg0000003ZMf00000000I6000000000000000 z00;m8000000000000000000310096105AXm00000000000000003ZMf0000001*HH z0000000000000000096100000009610000000{vA00#g7000000000003Zem00000 z05kvz000000N4Nk00000000000000000aO40000000000000000096100IC200000 z00000000000000001yEQ0000009b7S0000002}}S0I~-F00;m80000002lxO00000 z00{s900RI3000000000000000000000BCLs0000004Es(00000000000000000961 z00000000000000001*HH00RI3000000000000000000000FQ?a0000003QJW00000 c0000000000009610000000000000000FTZ+`~Uy| literal 0 KcmV+b0RR6000031 diff --git a/third_party/prebuild/aarch64/libslog.so b/third_party/prebuild/aarch64/libslog.so new file mode 100755 index 0000000000000000000000000000000000000000..700fc118d85469af3225484aacdcda0facef3467 GIT binary patch literal 150360 zcmV+W{{#SkMNCEl0RaF200000000030Ji`E00026UjP6A0000$000000001(L;?T+ z000000000$05|{#06+j602%-R000050000000000000000000000000000000001h zQ~>}00001hQ~>}0000000096100001000060001R_5lC@0001R_5uI^0001R_5uI^ z0001>5dZ)H0002EVgLXD000000096100002000060001x_5lC@0001x_5uI^0001x z_5uI^0000`0ssI20000`0ssI2000080000000004000040002U0RR910002U0RR91 z0002U0RR910000a000000000a0000000004000000000`<#c2O0001>C; zC;C;<{90001x2><{90000100000000040000K z000030000-PE`O0g;qI*Tfq+gk?mCWXA$65v5znS0001k0001J0000G0000A0000; z5<-9n0BC^7lZ-%KW(j~MgBZZ0q6ref(MSVO zhA;>e02pA)C=e3CvJlJYia-)8%uF|y000000000000000 z0002@0002^0002_0002{0002|00030000000000000000000010RR940RR960RR97 z0RR980RR990RR9B0RR910000B0RR9F0RRAaQGN+?kFn6O5a(H~&aO4m3@oIYCBbs|yxg5}l*w^efSkjKIv+K6^#te0^FYfTwn{{aPU z+SjrFyEJwPIbZ+mkP6mGyci8{=2V%+dmiDz!wKj27qPpISzZ$1wF3U1J1rw}wc+OK zjcUGrYnTD18E1&!hwUCgS~{X`m8=df4N?ANx|Y(lP0lJGdQn`c9kuH@^5gu&@}!6~ z2dNf}%5qSNsdnq8`pMZ{iavVMbg9O#x8eNWg)y`*JLI_x9y3=`O8t#PA&YFUks7kvDwzGDiYcIAdF9B2%%LpcP3cpI zW#enX&VNDG4{ zj=$L(A&vD3h{$njcvSf3yHvFQRtXgE8%w&5kuR|Xf#CgyL;8+ku)-e2nTo=`nvNPv z7Gw%Rg~4P39}q_Mi!ZUu{(Ta59J;ejT-hN*{QQ`dcY(t<{6wn+c>^N=Zh~ySIQgd4 z!YCg&-`5)6_m_Z;uW|J zQh6(&SQ~ZGSgEQ`I*ft9pbm8ZW?866feYkLqJqQ;nh{Mke8c&i!m1W)h7=+9Ryv{? zmMh>yrOK6cYI~IA4>pmrlPs=C@f99vAQSNC<{R000000000000000000000000t1^@sO00000000000000000000 z0002t3jhET000000000000000000000000L0ssIK000000000000000000000001v z1ONaM000000000000000000000000A3jhET000000000000000000000001Q3IG5S z000000000000000000000000U0ssIK00000000000000000000000000RR9J00000 z0000000000000000000*2><{R000000000000000000000002w0000I0000000000 z00000000000001>0000I000000000000000000000002d3IG5S000000000000000 z000000001~3;+NU000000000000000000000001+2LJ#P00000000000000000000 z0001B0000H00000000000000000000000112LJ#P000000000000000000000001s z3jhET000000000000000000000002g2LJ#P000000000000000000000002A0{{RL z000000000000000000000000=0ssIK000000000000000000000001X0{{RL00000 z0000000000000000002w1^@sO000000000000000000000002T0000I0000000000 z00000000000002*3jhET000000000000000000000002~1^@sO000000000000000 z000000001j3IG5S000000000000000000000002?3jhET00000000000000000000 z0000+0000Y000000000000000000000000C1pojN000000000000000000000002p z0000I00000000000000000000000173IG5S000000000000000000000000X3;+NU z00000000000000000000000012><{R000000000000000000000001e4FCWV00000 z000000000000000000223jhET000000000000000000000001>0ssIK0000000000 z00000000000002j1pojN000000000000000000000000$3;+NU000000000000000 z000000000|3jhET000000000000000000000001w3;+NU00000000000000000000 z0000o0RR9J000000000000000000000002)3IG5S000000000000000000000000* z4FCWV000000000000000000000000a4FCWV00000000000000000000000002><{R z000000000000000000000001?4FCWV00000000000000000000000142><{R00000 z0000000000000000001`2mk;Q00000000000000000000000200ssIK0000000000 z00000000000001^3;+NU000000000000000000000002y1ONaL000000000000000 z000000000-3;+NU000000000000000000000001r4FCWV00000000000000000000 z0002B0{{RL000000000000000000000002a2mk;Q000000000000000000000000u z3jhET000000000000000000000001;3jhET00000000000000000000000114FCWV z000000000000000000000000z2><{R000000000000000000000001N4FCWV00000 z0000000000000000000c3;+NU000000000000000000000001*2LJ#P0000000000 z00000000000002h2LJ#P000000000000000000000002|3jhET000000000000000 z000000002a0RR9J000000000000000000000002a2LJ#P00000000000000000000 z0001!2mk;Q000000000000000000000002u3;+NU000000000000000000000000I z3;+NU000000000000000000000002!3jhET000000000000000000000001u2mk;Q z000000000000000000000002p1^@sO000000000000000000000002>4FCWk00000 z000000000000000000023;+NU000000000000000000000002C2mk;Q0000000000 z00000000000000N0{{RL000000000000000000000001&3IG5S000000000000000 z000000002#3;+NU000000000000000000000000G0000W00000000000000000000 z0001b0ssIK000000000000000000000002M3;+NU000000000000000000000000J z4gdfW000000000000000000000000y1^@sO000000000000000000000001c3;+NU z000000000000000000000002I0000H00000000000000000000000143;+NU00000 z0000000000000000002c3;+NU000000000000000000000000i3;+NU0000000000 z0000000000000010000W000000000000000000000001j0{{RL000000000000000 z000000002#2mk;Q000000000000000000000000i0000W00000000000000000000 z0002U2LJ#P000000000000000000000001P3jhET01E)%+W-In000040RR910001E z2mk;Q01E&xxBvhE000000RR910002N0RR9J01E&JX#fBK0001_000000000*2LJ#P z01E)XrvLx|0002w000000000N1pojN01E(M&;S4c0001>000000001j0000I01E)1 z>;M1&0000;000000001I1pojN01E(clmGw#0002+000000002k1ONaM01E){eEn+a0002!0RR91 z000091ONaM01E&Rw*UYD00017000000002M0ssIK01E&(a{vGU0000;0RR910000= z1pojN01E(+k^lez0002+00000000080{{RL01E){dH?_b0001R000000002B0RR9J z01E)fXaE2J0000$000000001_1^@sO01E)9od5s;0000u00000000141pojN01E(s zlK=n!0002+000000000<1^@sO01E)9*8l(j0001p000000001I1ONaM01E(^U;qFB z0002E0RR910001S1ONaM01E&JvH$=80000u0RR910002e1^@sN02Kh>7y|$R00008 z000000002v0RR9J01E(MY5)KL0001l000000000V1^@sO01E(^)Bpeg0001}00000 z000100000I01E&pV*mgE0001l00000000091^@sO01E)1n*aa+000040RR910001a z1ONaM01E)9$^ZZW0002+0RR91000281^@sO01E)%od5s;0000`000000000z3IG5S z01E)9-v9sr0000u000000000t4FCWV01E(k>i_@%0000y00000000212LJ#P01E)1 ztN;K20001J0ssI20000o3IG5S01E(c-v9sr0000u000000002Y2><{R01E)<-2eap z0000u000000002a1ONaM01E(6ivR!s0001d00000000222mk;Q01E&ByZ`_I00017 z0RR91000270000I01E)P>i_@%0000u000000002N3jhET01E)<+yDRo0002|00000 z000070RR9J01E)H;Q#;t0001N00000000072><{R01E(^!T;M1&0000u000000000H0RR9J01E(6;Q#;t00017000000002+2mk;Q01E)P z!2kdN0002s000000001L2LJ#P01E(+;{X5v0001N000000000g1^@sO01E)X)c^nh z0000C0RR910001m1^@sO01E(Uod5s;0000$000000001t0{{RL01E)1fdBvi0002w z0ssI20002P1^@sO01E&xo&W#<0002=0RR910000Y2><{R01E(^!~g&Q0002E00000 z0001+2mk;Q01E(EHq)$0000u00000000251pojN01E&( znE(I)000000RR910001T0000I01E*4*Z=?k00017000000000a0RR9J01E(^*Z=?k z00017000000000M2mk;P02Kh}7y|$R00008000000000i1ONaM01E&JuK)l500000 z0{{R30002m2><{R01E&h(f|Me0001d000000000f4FCWV01E&(>i_@%0000y00000 z0000O3;+NU01E&h;s5{u0001N000000000K2><{R01E(M!vFvP0000u0RR910001@ z2><{R01E(+;s5{u00017000000002(1ONaM01E)f=Kufz00013000000000Q3IG5S z01E&J)Bpeg0001t000000002F1pojN01E&(ng9R*0001J0RR91000052LJ#P01E(E z*#H0l00017000000001Y2LJ#P01E(!ssI200001>0RR910002n2LJ#P01E(6#Q*>R z0000S0ssI20000b3jhET01E&h+W-In0002M000000000_1ONaM01E)9i2wiq0001_ z0RR910001S3;+NU01E&x<^TWy0001B000000002;0{{RL01E(6;{X5v0000y00000 z0000&1ONaM01E(6q5uE@000040RR910002%0RR9J01E)<{R01E(^$p8QV0001x00000000222><{Q02KiE zC<6ch0000G5C8xG0002h0RR9J01E)HX#fBK0002200000000290ssIK01E(k(*OVf z0001t000000001C3;+NU01E(s<{Q02KfTIRgLy000015C8xG0001G0{{RL01E)%e*gdg0002I0RR91 z0000g2LJ#P01E(UrT_o{000130RR910000F3IG5S01E(E-T(jq0001J000000001V z0RR9J01E(sX8-^I0000;000000000|2mk;Q01E)nw*UYD00017000000002q1pojM z02KfjSpxt70000G000000002<2><{R01E&Z(*OVf0001B000000002L3IG5S01E*4 z*#H0l0000e0RR91000273IG5S01E)9r~m)}0000$000000000w0ssIK01E&>v;Y7A z0002=000000001!1pojN01E&>mjD0&0001t000000000d3IG5S01E)X-T(jq0001N z000000002G2LJ#P01E&x*Z=?k0001F00000000014FCWV01E&}>Hq)$0001V00000 z0002J2><{Q02Ki67y|$R000085C8xG0000R0RR9J01E)HWdHyG0001h000000000r z3;+NU01E&BHq)$0001V000000001?1pojN01E)nmjD0&0001F z0RR910001J0ssIK01E&RZ~y=R0000a0{{R30001!1^@sN02Khx2m=5B0000G5C8xG z0000{3IG5S01E&Z-~a#s0000u000000002j3;+NU01E&}=>Px#00017000000001S z2><{Q02KfbNdo`?000085C8xG000101^@sO01E)9oB#j-0002M000000002_0ssIK z01E&}?EnA(0002A000000000b1pojN01E)9=>Px#0001F000000001f2><{R01E){ z;s5{u00017000000001?0{{RL01E(!ga7~l0000W0ssI20001{1ONaM01E&p$^ZZW z0000$000000000U2LJ#P01E&ZrT_o{0000?000000001i3;+NU01E(+<^TWy0001B z000000001l0RR9J01E)fX8-^I0000$000000002L2mk;Q01E(^zW@LL0002w00000 z0000R1ONaM01E(!hX4Qo0000W0ssI20001W1pojN01E(Ml>h($0002+000000001l z1pojN01E(6mH+?%0002+000000000r2mk;Q01E(k&j0`b0002w000000000<0RR9J z01E)XW&i*H0000$000000002<2LJ#P01E&>vj6}9000000RR910001%4FCWV01E&B z?f?J)0000u000000001>2LJ#P01E&ptN;K20001Z000000002!0ssIK01E)<>;M1& z00017000000000y0{{RL01E)PeE0{{RL01E&>e*gdg0001-000000000#2mk;Q01E(cw*UYD00017000000000M z2LJ#P01E)nr2qf`0000;000000000-3IG5S01E)%-v9sr0000u000000001)3;+NU z01E(U=Kufz0001700000000093;+NU01E(6-~a#s0001d000000002z2><{R01E&h z-T(jq0000u000000002W0{{RL01E)9h5!Hn0002s000000002*0000I01E)n-~a#s z0001d00000000022mk;Q01E)9%>V!Z0002c0RR910002a0000I01E&B(EtDd0001> z000000001y2><{R01E(^%m4rY0000C0RR910000@3;+NU01E&Z0000a0ssI20001@0RR9J01E&}XaE2J0001d000000001x0RR9J z01E&JXaE2J0000$000000000?4FCWV01E){>i_@%0001V000000002v0{{RL01E)P zwg3PC0000~00000000023IG5S01E&x-v9sr0000$000000001i2mk;Q01E&Bx&QzG z0002|0RR910000b2mk;Q01E(U$^ZZW0000$00000000181ONaM01E)X)c^nh0001d00000 z00000Utec!Z*E_6bYXIIUta)UNmNZ=WMy(?XK8bEWpY$aLu_wuWmI8eY-IpnNmNZ= za%E>}b97~LR82!{Z*FB&VPb4$0AF8Ycwt{=X>MU`X?kSr=V`~6kUvqR} zV{2byXlq|*bzyR3090>pY)y4^Wq4I?OmAar090>pY)55uMRIa)azk%qWdKleX>N2= zWo%|lZ)X5sUvqR}V{2byXlq|)VQFjtRBvx=M`d(SX=DIjUvP47XKrC_WdLnuZF6OG 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 zE^}`#HUMmCVr?#SZ!R_fY-wU=V`E=)E^}`#F#v37Vq-3IZ!R_faB^>Fa$#*>X>N9J zV_|e@Z*E_6Xm4_KUv6P-WdL7aa%E>}b97~LUtx4+Z*pq@Y-BBLX>N6REn#7DV`w%s zE^}`#F#v37VsmV7XD)MZ07pzoLPK9NE-^O%000000000200IC400IC500IC400IC4 z00IC200RI600RI300IC20000200RI500RI700IC500IC200IC400IC400IC400RI5 z00IC400IC500RI500IC50000200IC500IC400RI500RI500IC400IC200RI500IC4 z0000200RI600IC400RI500IC500IC400IC400RI600IC400IC400IC400IC500RI3 z00IC400IC400RI500IC400IC200RI500002009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00000000010096c4gdfU0000W0001&k(LGk00aO=4gdfE000010098B4FCWT0000W z0001&k(LGk00RI<4gdfE000010098&4FCWT000000001&k(LGk00IC;4gdfE0001R z_5uI^000031ONa40000WV*mgE0001h_5uI^000031ONa40002kVgLXD0000000RI3 z000031ONa40000000RI30000W00RI3000031ONa40000`2>}2A0000m00RI300003 z1ONa4000132>}2A0000$00RI3000031ONa40001B2>}2A0000`00RI3000031ONa4 z0001J2>}2A0001B00RI3000031ONa40001R2>}2A0001R00RI3000031ONa40001Z z2>}2A0001h00RI3000031ONa40001p2>}2A0001x00RI3000031ONa40001x2>}2A z0001>00RI3000031ONa40001(2>}2A0002600RI3000031ONa40001>2>}2A0002M z00RI3000031ONa40001}2>}2A0002c00RI3000031ONa4000262>}2A0002s00RI3 z000031ONa40002M2>}2A0002+00RI3000031ONa40002c2>}2A000000RsR400003 z1ONa40002s2>}2A0000G0RsR4000031ONa40002!2>}2A0000W0RsR4000031ONa4 z0002^2>}2A0000m0RsR4000031ONa4000083IPBB0000$0RsR4000031ONa40000G z3IPBB0000`0RsR4000031ONa40000W3IPBB0001B0RsR4000031ONa40000e3IPBB z0001R0RsR4000031ONa40000m3IPBB0001h0RsR4000031ONa40000u3IPBB0001x z0RsR4000031ONa40000$3IPBB0001>0RsR4000031ONa40000;3IPBB000260RsR4 z000031ONa4000133IPBB0002M0RsR4000031ONa40001B3IPBB0002c0RsR400003 z1ONa40001R3IPBB0002s0RsR4000031ONa40001Z3IPBB0002+0RsR4000031ONa4 z0001h3IPBB000000s{a5000031ONa40001p3IPBB0000G0s{a5000031ONa40001( z3IPBB0000W0s{a5000031ONa40001}3IPBB0000m0s{a5000031ONa4000263IPBB z0000$0s{a5000031ONa40002E3IPBB0000`0s{a5000031ONa40002M3IPBB0001B z0s{a5000031ONa40002U3IPBB0001R0s{a5000031ONa40002c3IPBB0001h0s{a5 z000031ONa40002k3IPBB0001x0s{a5000031ONa40002s3IPBB0001>0s{a500003 z1ONa40002!3IPBB000260s{a5000031ONa40002+3IPBB0002M0s{a5000031ONa4 z0002^3IPBB0002c0s{a5000031ONa4000003jqKC0002s0s{a5000031ONa400008 z3jqKC0002+0s{a5000031ONa40000G3jqKC000000|Nj6000031ONa40000O3jqKC z0000G0|Nj6000031ONa40000W3jqKC0000W0|Nj6000031ONa40000e3jqKC0000m z0|Nj6000031ONa40000u3jqKC0000$0|Nj6000031ONa40000$3jqKC0000`0|Nj6 z000031ONa40000;3jqKC0001B0|Nj6000031ONa40000`3jqKC0001R0|Nj600003 z1ONa4000133jqKC0001h0|Nj6000031ONa40001B3jqKC0001x0|Nj6000031ONa4 z0001J3jqKC0001>0|Nj6000031ONa40001R3jqKC000260|Nj6000031ONa40001h z3jqKC0002c0|Nj6000031ONa40000`2>}2A0002s0|Nj6000031ONa4000132>}2A z0002+0|Nj6000031ONa40001B2>}2A000001Oos7000031ONa40001J2>}2A0000G z1Oos7000031ONa40001R2>}2A0000W1Oos7000031ONa40001Z2>}2A0000m1Oos7 z000031ONa40001p2>}2A0000$1Oos7000031ONa40001x2>}2A0000`1Oos700003 z1ONa40001(2>}2A0001B1Oos7000031ONa40001>2>}2A0001R1Oos7000031ONa4 z0001}2>}2A0001h1Oos7000031ONa4000262>}2A0001x1Oos7000031ONa40002M z2>}2A0001>1Oos7000031ONa40002c2>}2A000261Oos7000031ONa40002s2>}2A z0002M1Oos7000031ONa40002!2>}2A0002c1Oos7000031ONa40002^2>}2A0002s z1Oos7000031ONa4000083IPBB0002+1Oos7000031ONa40000G3IPBB000001p@#8 z000031ONa40000W3IPBB0000G1p@#8000031ONa40000e3IPBB0000W1p@#800003 z1ONa40000m3IPBB0000m1p@#8000031ONa40000u3IPBB0000$1p@#8000031ONa4 z0000$3IPBB0000`1p@#8000031ONa40000;3IPBB0001B1p@#8000031ONa400013 z3IPBB0001R1p@#8000031ONa40001B3IPBB0001h1p@#8000031ONa40001R3IPBB z0001x1p@#8000031ONa40001Z3IPBB0001>1p@#8000031ONa40001h3IPBB00026 z1p@#8000031ONa40001p3IPBB0002M1p@#8000031ONa40001(3IPBB0002c1p@#8 z000031ONa40001}3IPBB0002s1p@#8000031ONa4000263IPBB0002+1p@#800003 z1ONa40002E3IPBB000001_J;9000031ONa40002M3IPBB0000G1_J;9000031ONa4 z0002U3IPBB0000W1_J;9000031ONa40002c3IPBB0000m1_J;9000031ONa40002k z3IPBB0000$1_J;9000031ONa40002s3IPBB0000`1_J;9000031ONa40002!3IPBB z0001B1_J;9000031ONa40002+3IPBB0001R1_J;9000031ONa40002^3IPBB0001h z1_J;9000031ONa4000003jqKC0001x1_J;9000031ONa4000083jqKC0001>1_J;9 z000031ONa40000G3jqKC000261_J;9000031ONa40000O3jqKC0002M1_J;900003 z1ONa40000W3jqKC0002c1_J;9000031ONa40000e3jqKC0002s1_J;9000031ONa4 z0000u3jqKC0002+1_J;9000031ONa40000$3jqKC000002Lk{A000031ONa40000; z3jqKC0000G2Lk{A000031ONa40000`3jqKC0000W2Lk{A000031ONa4000133jqKC z0000m2Lk{A000031ONa40001B3jqKC0000$2Lk{A000031ONa40001J3jqKC0000` z2Lk{A000031ONa40001R3jqKC0001B2Lk{A000031ONa40001h3jqKC0001h2Lk{A z000031ONa40001p3jqKC0001x2Lk{A000031ONa40001x3jqKC0001>2Lk{A00003 z1ONa40001(3jqKC000262Lk{A000031ONa40001>3jqKC0002M2Lk{A000031ONa4 z0001}3jqKC0002c2Lk{A000031ONa4000263jqKC0002s2Lk{A000031ONa40002E z3jqKC0002+2Lk{A000031ONa40002M3jqKC0001Z_5uI^000010RRAe0000000000 z0001p_5uI^000010RR950RR91000000001J{{jF2000011ONcu00000000000001R z{{jF2000011ONcr00000000000001Z{{jF2000011ONcg00000000000001h{{jF2 z000011ONaT00000000000001p{{jF2000011ONc_00000000000001x{{jF200001 z1ONag00000000000001({{jF2000011ONbm00000000000001>{{jF2000011ONcG z00000000000001}{{jF2000011ONcQ000000000000026{{jF2000011ONbj00000 z000000002E{{jF2000011ONa%00000000000002M{{jF2000011ONcL0000000000 z0002U{{jF2000011ONcf00000000000002c{{jF2000011ONb}00000000000002k z{{jF2000011ONb800000000000002s{{jF2000011ONbE00000000000002!{{jF2 z000011ONbI00000000000002+{{jF2000011ONbL00000000000002^{{jF200001 z1ONc?00000000000002^_yPa`000021ONd1000000000000000`2qj{000021ONa7 z000000000000008`2qj{000021ONa800000000000000G`2qj{000021ONa900000 z000000000O`2qj{000021ONaA00000000000000W`2qj{000021ONcB0000000000 z0000e`2qj{000021ONb@00000000000000m`2qj{000021ONcE00000000000000u z`2qj{000021ONc!00000000000000$`2qj{000021ONaB00000000000000;`2qj{ z000021ONb-00000000000000``2qj{000021ONc4000000000000013`2qj{00002 z1ONbP00000000000001B`2qj{000021ONaC00000000000001J`2qj{000021ONaD z00000000000001R`2qj{000021ONbW00000000000001Z`2qj{000021ONaE00000 z000000001h`2qj{000021ONcT00000000000001p`2qj{000021ONaF0000000000 z0001x`2qj{000021ONaG00000000000001(`2qj{000021ONaH00000000000001> z`2qj{000021ONc}00000000000001}`2qj{000021ONaB0RR910000000026`2qj{ z000021ONaI00000000000002E`2qj{000021ONbZ00000000000002M`2qj{00002 z1ONaJ00000000000002U`2qj{000021ONaK00000000000002c`2qj{000021ONaL z00000000000002k`2qj{000021ONaM00000000000002s`2qj{000021ONcH00000 z000000002!`2qj{000021ONbq00000000000002+`2qj{000021ONcU0000000000 z0002^`2qj{000021ONaE0RR910000000000`T_s|000021ONaN000000000000008 z`T_s|000021ONaO00000000000000G`T_s|000021ONaP00000000000000O`T_s| z000021ONcn00000000000000W`T_s|000021ONbc00000000000000e`T_s|00002 z1ONaA0RR91000000000m`T_s|000021ONb^00000000000000u`T_s|000021ONcP z00000000000000$`T_s|000021ONaQ00000000000000;`T_s|000021ONaR00000 z000000000``T_s|000021ONcx000000000000013`T_s|000021ONc@0000000000 z0001B`T_s|000021ONd400000000000001J`T_s|000021ONaS00000000000001R z`T_s|000021ONa50RR91000000001Z`T_s|000021ONcg00000000000001h`T_s| z000021ONaU00000000000001p`T_s|000021ONbi00000000000001x`T_s|00002 z1ONaV00000000000001(`T_s|000021ONcj00000000000001>`T_s|000021ONaW z00000000000001}`T_s|000021ONa70RR910000000026`T_s|000021ONaX00000 z000000002E`T_s|000021ONaY00000000000002M`T_s|000021ONaZ0000000000 z0002U`T_s|000021ONba00000000000002c`T_s|000021ONcN00000000000002k z`T_s|000021ONaa00000000000002s`T_s|000021ONab00000000000002!`T_s| z000021ONac00000000000002+`T_s|000021ONad00000000000002^`T_s|00002 z1ONae000000000000000`vL#}000021ONbs000000000000008`vL#}000021ONc| z00000000000000G`vL#}000021ONaf00000000000000O`vL#}000021ONag00000 z000000000W`vL#}000021ONah00000000000000e`vL#}000021ONcC0000000000 z0000m`vL#}000021ONb~00000000000000u`vL#}000021ONbm00000000000000$ z`vL#}000021ONai00000000000000;`vL#}000021ONaj00000000000000``vL#} z000021ONak000000000000013`vL#}000021ONal00000000000001B`vL#}00002 z1ONcS00000000000001J`vL#}000021ONam00000000000001R`vL#}000021ONan z00000000000001Z`vL#}000021ONao00000000000001h`vL#}000021ONc-00000 z000000001p`vL#}000021ONbt00000000000001x`vL#}000021ONb)0000000000 z0001(`vL#}000021ONap00000000000001>`vL#}000021ONaq00000000000001} z`vL#}000021ONbd000000000000026`vL#}000021ONar00000000000002E`vL#} z000021ONcR00000000000002M`vL#}000021ONc`00000000000002U`vL#}00002 z1ONc(00000000000002c`vL#}000021ONas00000000000002k`vL#}000021ONcY z00000000000002s`vL#}000021ONbx00000000000002!`vL#}000021ONat00000 z000000002+`vL#}000021ONcA00000000000002^`vL#}000021ONau0000000000 z00000`~m;~000021ONav000000000000008`~m;~000021ONb;00000000000000G z`~m;~000021ONc300000000000000O`~m;~000021ONaw00000000000000W`~m;~ z000021ONax00000000000000e`~m;~000021ONbY00000000000000m`~m;~00002 z1ONay00000000000000u`~m;~000021ONbo00000000000000$`~m;~000021ONcq z00000000000000;`~m;~000021ONaz00000000000000``~m;~000021ONb|00000 z0000000013`~m;~000021ONbu00000000000001B`~m;~000021ONa!0000000000 z0001J`~m;~000021ONa#00000000000001R`~m;~000021ONaD0RR91000000001Z z`~m;~000021ONc+00000000000001h`~m;~000021ONb>00000000000001p`~m;~ z000021ONb*00000000000001x`~m;~000021ONa$00000000000001(`~m;~00002 z1ONa&00000000000001>`~m;~000021ONb?00000000000001}`~m;~000021ONc# z000000000000026`~m;~000021ONa(00000000000002E`~m;~000021ONcw00000 z000000002M`~m;~000021ONa)00000000000002U`~m;~000021ONbU0000000000 z0002c`~m;~000021ONcv00000000000002k`~m;~000021ONd200000000000002s z`~m;~000021ONa*00000000000002!`~m;~000021ONa+00000000000002+`~m;~ z000021ONc{00000000000002^`~m;~000021ONbz000000000000000{Q>|000002 z1ONa-000000000000008{Q>|0000021ONcl00000000000000G{Q>|0000021ONa; z00000000000000O{Q>|0000021ONbR00000000000000W{Q>|0000021ONbv00000 z000000000e{Q>|0000021ONbV00000000000000m{Q>|0000021ONa<0000000000 z0000u{Q>|0000021ONa=00000000000000${Q>|0000021ONaF0RR91000000000; z{Q>|0000021ONa>00000000000000`{Q>|0000021ONcd000000000000013{Q>|0 z000021ONbk00000000000001B{Q>|0000021ONa?00000000000001J{Q>|000002 z1ONbg00000000000001R{Q>|0000021ONa@00000000000001Z{Q>|0000021ONbw z00000000000001h{Q>|0000021ONa^00000000000001p{Q>|0000021ONa_00000 z000000001x{Q>|0000021ONa`00000000000001({Q>|0000021ONcs0000000000 z0001>{Q>|0000021ONcJ00000000000001}{Q>|0000021ONa{000000000000026 z{Q>|0000021ONa|00000000000002E{Q>|0000021ONa}00000000000002M{Q>|0 z000021ONbh00000000000002U{Q>|0000021ONa~00000000000002c{Q>|000002 z1ONb000000000000002k{Q>|0000021ONaI0RR91000000002s{Q>|0000021ONb1 z00000000000002!{Q>|0000021ONaG0RR91000000002+{Q>|0000021ONa90RR91 z000000002^{Q>|0000021ONcz000000000000000{sI61000021ONc80000000000 z00008{sI61000021ONb300000000000000G{sI61000021ONb400000000000000O z{sI61000021ONc%00000000000000W{sI61000021ONb500000000000000e{sI61 z000021ONcy00000000000000m{sI61000021ONca00000000000000u{sI6100002 z1ONb600000000000000${sI61000021ONb{00000000000000;{sI61000021ONb7 z00000000000000`{sI61000021ONbl000000000000013{sI61000021ONb#00000 z000000001B{sI61000021ONc900000000000001J{sI61000021ONcF0000000000 z0001R{sI61000021ONbS00000000000001Z{sI61000021ONci00000000000001h z{sI61000021ONb900000000000001p{sI61000021ONaJ0RR91000000001x{sI61 z000021ONbA00000000000001({sI61000021ONb&00000000000001>{sI6100002 z1ONbB00000000000001}{sI61000021ONcc000000000000026{sI61000021ONc> z00000000000002E{sI61000021ONbO00000000000002M{sI61000021ONbC00000 z000000002U{sI61000021ONbD00000000000002c{sI61000021ONbF0000000000 z0002k{sI61000021ONbG00000000000002s{sI61000021ONbH00000000000002! z{sI61000021ONbI00000000000002+{sI61000021ONc&00000000000002^{sI61 z000021ONbJ000000000000000{{jF2000021ONc=000000000000008{{jF200002 z1ONb<00000000000000G{{jF2000021ONcM00000000000000O{{jF2000021ONbK z00000000000000W{{jF2000021ONaH0RR91000000000e{{jF2000021ONbn00000 z000000000m{{jF2000021ONbM00000000000000u{{jF2000021ONd30000000000 z0000${{jF2000021ONc500000000000000;{{jF2000021ONb=00000000000000` z{{jF2000021ONa40RR910000000013{{jF2000021ONb$00000000000002}d%vmu z0|1fg0|1o$d%>u{17Fqv00000000000002+d%vkr0RYeudPMmU!XuF&0w2~NAOqDO zAOqDOAOqD<0RYeuenj~Y;vO}bvLMM?R0w2~;0RYeu?nL6c0w2~;0RYeu`b7BO;wX_I0w2~;0RYeuB1QQS0x6Lo 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%0D#ir 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 z0RXl0Q$eZyd&j8217Fr3AOqDP0Duzq|Nj>N0Duzo|Nj@p+5eXxAOqF?d%mdy0RXW5 z0|1d@z(@IH06_Vq4*>ZD0D#h@4?y{206_VJ00YWn006c9d%~#5+W!}~+5eXV0RYfr z06_Wt+y58+d%vmu0|1fzd%>u{17Fqv00000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000001VZ*Od4Xklq?FKlmTFLP{fXD@SXZ)Y!PZ*z1nE-o)FE-!OzZ)ap_ zZggdGW?^GxFLP{fXD(v^0000000016MN(2vQe7Y=b2=qtIv{m!Y;R+0AaiVQXCQ5L zbY*xTW?^Y;Wn?TMa%FRMY;-*(WGoN38UvnUEX=ET~X>4U6W?^Y;Wn?TMaA{;;ZeeX@JtcE2AaH49 zJtbr;AaZ4Mb!>D!C1flhWpZ+EZ#^YsE(!o!S3y!vNlr&yASH7;C1g4vZ*XO9AaH49 zAZBT7Wguo@X>4U=EFf@cWM5`!Y-K$qb1WcmX=Gn+VQpnSC37qwaA{;cC1frN00000 z00016S3y!vNlr&yASH7;C1g4vcXDZTWgu{AWFTf~Y-J#3VQFk-WGo4UZC37qwaA{;;ZeeX@JtcE2 zAaH49Jtbr=3IG5A00016S3y!vNlr&yASH7;C1g4vY;R+0AZB4{Y%CyUa&m5OJtbrc z00016S3y!vNlr&yASH7;C1g4vTWM}^b#z@IVs&O_WpW^Cb0AJtOiV5c0000000016 zS3y!vNlr&yASH7;C1g4vb97;Jb#owTb0BGMc42I3WG*0cbYXOLb0BGRASGlj3IG5A z00016MN(2vQe7Y=b2=qtIv`tVZg6#UT_A2@ZDk;7b0BVYY-}zH00016S3y!vNlr&y zASH7;C1g4vZDnn9WprP2Aa8OYb98cJaCu*IAZB4{Y-MCDAZ2oLZf{>PJtbr;AZ2oL zZf{>QJtbr;AZ2oLZf{>RJtbr;AaH49Jtbr=3IG5A00016S3y!vNlr&yASH7;C1g4v zb7gcOZEs|CY-J#9Wp-t3AZB4{Y-MCDAZ>4Cb!=r{ZeeX@JtcE2AZ%rJWo$hqWGo4p|XJKqCAZ%rJWo$hqWGoD!C1flhaA{;cC1frN00016 zS3y!vNlr&yASH7;C1g4vZDnn9WprP2AZB4{Y-MCDAaZ4Mb!>D!C1flhWpZ+EZ#^Ys zEFf@cWIZKhE(!o;Zee0?;~AZB4{Y-MCDAaZ4Mb!>D!C1flhaA{;cC1frN0000^Z*FA(00016Nlr#j zT_7cMIwfQ}AaHVTV`X!5C~|LabRchcZe?;QAaiAIWFT;9WFU2JbZKlLZDn(FVP|C^ zadl;NWgug6Wnpw>WGoN38UvnUEa&Kd0b8{eRZf0*FW?^Y;Wn?TMa%FRM zY;-*(WGoD!C1flhWpZ+EZ#^YsEFf@cWIZKhE(!o!S3y!vNlr&yASH7; zC1g4vb7gL1AZ=xHb75y?AZB4{Y-MCDAZ2oLZf`v$WGoX=FVmWGo?;~EFf@cWIZKhEFf@cWM6J!ZDl@6CZaN@ka&m8SUv716Jtbr;Aa`MMZeMP7Z9OGqEFfuaW^Z3^b!|N* zWGo4U= zEFf}ab9HQVJtbr;AZ2oLZf`v$WGoY#?-LZDk;4 zVQFk-WGoB``8%EhR8AWGy8yGGsa> zFfwF1B``8%E+sHCY-BDaFf(jq0000000016S3y!vNlr&yASH7;C1g4vb8c{QX>N38 zUvnUIX>Da7W?^Y;Wn?TMa%FRMY;-*(WGoPgPU^0000n000000000-Oiw~VOkYe-M_)`uRz*wz0000000016 zNlr#jT_7cMIwfQ}AZKNCAaZGEXmlWDZgwC?Oiw~VOkYe-M_)`uRz*xGC1fceVQyp~ zWo~vLX>%ZOa%pdJAarjaV{dL|AZBT7WiAQ;0000000016S3y!vNlr&yASH7;C1g4v zV{C78Wgv5JV{2t}AZB4{Y-MCDAZ2oLZf`v$WGo%Y>RZL6@00016S3y!vNlr&yASH7;C1g4vTWM}^b#z@IZF6TJX>%Y>RZL6@00016 zS3y!vNlr&yASH7;C1g4vTWM}^b#z@IX>M?JbRcPSAZ~SRY#?uPAZ%rBXLM*FX>%ZH zZgyd8X=E%QY-Mg|bZ9*#WGoYDd2?lSAZB4{Y-MCDAaZ4Mb!>D!C1flhWpZ+EZ#^Ys zE(!o!S3y!vNlr&yASH7;C1g4vWq4t2X>Mg8VQyp~V`yP+XJsH^AaiMFZeeU7VPkY@ zZ*CxFVQFk-WGo4Cb!=rlC1frN0000000016S3y!v zNlr&yASH7;C1g4vTWM}^b#z@IVRC06X>%Y>RZL7S3IG6GS3y!vNlr&yASH7;C1g4v zTWM}^b#z@IZF6TJX>%Y>RZL7S3IG6GS3y!vNlr&yASH7;C1g4vZDn(FVP|C^Y-Mg| zbZ8)Hb0BPGb8{ecXkl(3Z*m}IadlyAAarjaFfJf$Wo~D5XgwulE(!o!C1hPZC1gG& zb0{TbEG2U(Iwf-;00016C1hPZC1gG&WGE$MEG2U(Iwf-;00016S3y!vNlr&yASH7; zC1g4vb8c{QX>N38UvnU4VQFk-WGo4Cb!-3yfck%BJtbr=3IG5A00000TUS9+PDxHjT_7cMIwfQ} zAZKNCAZ%rJWo#gBVQpm~W?^Y;Wn?Z20000000000TP1T{ASH7sC1flmb16C{b07c! z00000TP1T{ASGldC1flmb16C{b07c!00000TUS9+PDxHjT_7cMIwfQ}AZ>GJAZc?T zPE|}yE(!nuTP1TkC39UM0000000000TUS9+PDxHjT_7cMIwfQ}AaibTa%paKW?yq4 zW?^Y;Wn?TMa%FRMY;-*(WGoNFVRU6=UvnU4VQFk-WGoN0LVQg$JX>Mk30000000000 zFJ*LNFGy)YNndGhb97;BY%XbTW^VuhTUS9+PDxHjT_7cMIwfQ}AZc!CbRc7IZf0p` zAZ%%KbRcG7X>4U=EFf}ab9HQVJtbr;AaH49Jtbr;AZ2oLZf`v$WG)H-RdZ!>PGN0j z0000000000TUS9+PDxHjT_7cMIwfQ}AZKNCAZc!MbYX04Aa!$Pav)}5X>4U=EFf}a zb9HQVJtbr;AaH49Jtbr;AZ2oLZf`v$WG)H-TUS9+PDxHjT_7cMIwfQ}AZKNCAa!$P za&BR5Whf4U=EFf@cWIZKhEFfiaa&B)uC1frN0000000000TS-nv zPhB7-b2=qtIv{6dbRcPNb97;BY#?=WWpW^CZf0*fAa!$Pa!F)8C1flhXL4_Ka7ko6 zC1eT!00000TUS9+PDxHjT_7cMIwfQ}AVX+jZf9j6W@&6?JtcD>Z+C8Gav*eXAZc!M zbYX04Aa!$Pav)}5X>4U=EFf}ab9HQVJtbr;AZ2oLZf`v$WGoDb5E(!nuTSZb*Pf}eVC389@WI7;nWoKz~bY*fNW^Zz9AZB4{Y%Cyh zWpj0GbUh_xEFfiaa&B)uC1eT!TUS9+PDxHjT_7cMIwfQ}AW3d%bRcGFY-J#DVRUF9 zW^ZyJb7gF1AZ%}EAZB4{Y-MC1VQyp~V{dMBX>N68E-o%E3JL%KTSZb*Pf}eVC389@ zWI7;MZ*psMaA9L*JtcD>Zf|rTWq4_GbRc1FWFT^7bairWE(!_&00000TUS9+PDxHj zT_7cMIwfQ}AZ2)AZE0?0AYpD~AY*7@Zf9j6VIXs9XKrC^AYo&4X>V>IW?^Y;Wn?TM zWpZ+EZ#^YsEFf@cWIZKhE(!nuTSZb*Pf}eVC389@WI7;Ya%Ew3Wgv5JV{2t}AZB4{ zY-MCDAZ2oLZf`v$WGoN2NZ*F5{AZ2!Ca(N&nWFT~DZDn&V3IG5A z00000TUS9+PDxHjT_7cMIwfQ}Aa`KZ)a>}c4cfYbZKp6FK}sOFK}sOZeeX@DIjKHX>4U=E(!nu z00000TUS9+PDxHjT_7cMIwfQ}Aa`4U=E(!nu00000TUS9+PDxHjT_7cMIwfQ}Aa`M?JbX_23X>4U*Xkl(-Y-J#6b0BGMc42I3WGo4U*Xkl(-Y-K$q zWG)H-TSZb*Pf}eVC389@WI7;cWpp5BX>4U6b97;JWguo@X>4U=EFfiaa&B)uC1flh zaA{;cC1flhaB^vGbRchTV`U&^c4cyTASGlVbZKp6b1n)100000TSZb*Pf}eVC389@ zWI7;bX>4U6ZEs{{AZc?TX>N95Y-waHAZ2oLZf`v$WGoDb5E(!nu00000TUS9+PDxHjT_7cMIwfQ}AaiAOAZ%}EY-M(3 zY#?cFaCLMbWo}_&Y-L4uWo~pmC1fCJb0BGKY-ML*YzhDXTUS9+PDxHjT_7cMIwfQ} zAaiAOAZ%}EY-M(3Y#?cFaCLMbY-M(3Y&|7pAZc?TX>4p|XJKp#0000000000TSZb* zPf}eVC389@WI7;QX>M?JbX_28WqB=jVQh6}AYpQHVR;~Fb0BVYY-}zH0000000000 zTSZb*Pf}eVC389@WI7;QX>M?JbX_28WqB=jVQh6}AZ~SSVr6n5X>%ZHZgyd8X=E%Q zYh`&~c42IFWnXS}ZDM6|Jtbr=3IG5A00000TUS9+PDxHjT_7cMIwfQ}AaibTa%paK zW?yq4W?^Y;Wn>^>Ze$>1VQy}3bRcqNZEtpEAaH49AZBT7Wh@|YX=FVmWGoO+-UOPfblvP5=M^00000O+-UYPfkfxPf`E?00000O+-UN zQ&&&`O+-UPMMgnYOjG~>00000O+-UeLjV8(O+-UbPD20yO-xJx00000L`7CjO#lD@ zOGQ#nMN9wyOi4mbMMOzK0000000000LqkPFP*nf`K~qCTPDDgY0000000000QcqI= z00000NJB$V00000Qcpug00000R7FNrQ%O%w0000000000P*P7uNlZyjM*si-00000 zL{I<#00000K~PWt00000R8s%|00000R8vG%O;7*;K}kbURR910Oi%y-00000R76w& z00000MnwPs00000O+)|y00000O+o+w00000O+^3z00000NljG%00000Nlj1y00000 zM@0Yt00000O+-URRZ~F#LqSbNQb7O!K~qCTPDDdY0000000000R7FKkQvd(}NmEb& z00000Q%O?*00000NK;J!00000L{n1$00000P*P7rO-E7yLPAei00000K}l9cLsU;v z0000000000R6<1n00000L`6bXM*si-Nlr#j00000S3y!vNlr%qMN(2vQUCw|PE|}y z00000MOH;lQ~&?~R8m1hMF0Q*Pf$!xM*si-000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000TWM}^b#z@IV{dL|X=fmCVRUF9X>%ZMb!==d00000TWM}^b#z@I zV{dL|X=fl%VRUF9Y-Mg|bZ8)Hb0BGMc42I3WGo8LV`yP%ZZB+aXD@SXZ)Y!aY;R{TXm4|LFD@=GE-o)FE-!OvVRB_;FJoqB zUuJ1+WnXY%a&u)aV*mgETUS9+PDxHjT_7cMIwfQ}AX{l}aCLNDAY*TCW@%?2ZeeX@ zAZc?TZgp&IE(!nuTUS9+PDxHjT_7cMIwfQ}AX{l}aCLNDAY*TCW@%?2c42IFWguyD zAZ~SRY%U4_TUS9+PDxHjT_7cMIwfQ}AX{l}aCLNDAY*TCW@%?2ZeeX@AZ%rBXLM*F zX>%ZHZgyd8X=E%QY-Mg|bZ9*#bu1ulVR&C`Wo~D5XgwulE(!nu00000TUS9+PDxHj zT_7cMIwfQ}AX{l}aCLNDAY*TCW@%?2c42IFWgu*2ZfA68AZc?TX>N95Y-waHAZ%rB zXLM*iC3P$yZDDv{Y-Mg|bZ9*#WG)H-00000TUS9+PDxHjT_7cMIwfQ}AZ=l6Y;R*A zW?^Y;Wn?TMWpZ+EZ#^YsE(!nu00000TUS9+PDxHjT_7cMIwfQ}AaitbV{mz2b0B76 zX>4U=EFfiaa&B*5F+C+@EFfiaa&B*5GCd_^E(!nu00000TUS9+PDxHjT_7cMIwfQ} zAX{l}aCLNDAa8DEAZ%%FWguyDAZ~SRY#?TGZ*3rBZ*FF3XCP*2Y-KJA00000TUS9+ zPDxHjT_7cMIwfQ}AX{&BbZ~WaT_9s`Zf0p`AZ}r8WguyDAZ~SRY%U4_TUS9+PDxHj zT_7cMIwfQ}AX{&BbZ~WaT_9#@Y-J#DZ*ysMX>V>IaBpdDbY*fNX>%ZMb!==d3IG5A z00000TUS9+PDxHjT_7cMIwfQ}AY*TCW@%?2X>?_6AZTH8AZ~9Ub9rrIZ)_+%DJ}{C zTUS9+PDxHjT_7cMIwfQ}AY*TCW@%?2X>?_6AZTH8AZ~9UV{dL|X=fmAVQpnD3IG5A z00000TUS9+PDxHjT_7cMIwfQ}AaitbZewtHUvnU1Z*FF3XCQ82ZDk;4VQFk-WGoN95Y-waHAaG%HXkTn)ZfA68 zJtcK63IG5AE@NhA00000E@N+QW&i*HE@^INZvX%QE^KdS00000FLq&aFKlmTFK%#k zFJo_RW-oJWZ)Y!aY;R{SV{dL|0000000000TUS9+PDxHjT_7cMIwfQ}AX{l}aCLND zAZTxGWgui}a%E$5Z*qAcX>%ZMb!==d3IG5A00000TUS9+PDxHjT_7cMIwfQ}AX{l} zaCLNDAY^HBWn*-2a(N(ZWo~D5Xdr2GAZc!PVQgt+EFffQa%E$5Z*qBGY-Mg|bZ9*# zbu1ulVR&C`Wo~D5XgwulE(!nu00000TUS9+PDxHjT_7cMIwfQ}AZKNCAaZ44Y;a+8 zXdq@`X>4U=EFflSY-K$qb1Wcba&m5OJtbr=3IG5A00000TUS9+PDxHjT_7cMIwfQ} zAaZ44Y;a+8Xdr2GAZc!PVQgt+EFf}aVQg?=bZ9*#b1n)100000TUS9+PDxHjT_7cM zIwfQ}AZKNCAaZ44Y;a+8Xdq@`X>4U=Aa8OYW@&6?aA9<4AZc?TX>N95Y-waHAZBT7 zWj!TxE(!nuasU7T00000TUS9+PDxHjT_7cMIwfQ}Aa8JGZXjl9Y-J#3VQFk-WGo4UZC37wc00000TUS9+PDxHjT_7cMIwfQ}AaitbV{mz2b0A}HZf0p`Aa-GFb!8xQ zZy;iIW@cq_AZB4{Y-MCDAaZ4Mb!>D!C1flhWpZ+EZ#^YsE(!nuTUS9+PDxHjT_7cM zIwfQ}AZ~9UV{dL|X=fmIVQh6}AYo>7WpW^NXk{RCd2M2EY$!b`EFfcVZf0p`Uv6P- zWj!TxE(!nuTUS9+PDxHjT_7cMIwfQ}AY*TCW@%?2c42IFWguyDAZ2ZEba^ZwV{dL| zX=h(MYWq2TFVQFk-WGo4U=EFflSY-K$qb1WcoWpj0GbUh_x zEFfiaa&B)uC1frN0000000000TUS9+PDxHjT_7cMIwfQ}AZBxAWosZ~Z*FF3XCP*2 zY-J#3VQFk-WGo4UZC37qwa%FRMY;-*(WGo4U=EFf}ab9HQVJtbr; zAZ2oLZf`v$WG)H-00000TUS9+PDxHjT_7cMIwfQ}AaG%Fb7dfJZe<{BX>Mg8V{dL| zX=fm5bY*QIW?^Y;Wn?TMa%FRMY;-*(WGo4U=EFf}ab9HQVJtbr;AZ2oLZf`v$ zWG)H-C364(00000TUS9+PDxHjT_8hmZf0p`AaG%HXgwu!AZc!CbRc7IZf0p`AZ%%K zbRcG7X>4U=AYpD~AY*TCbZKsNWiAQ;TUS9+PDxHjT_96sbRc7IZf0p`AaG%HXdrZN zAaiJ8a%CWGWo>VAc_3zCX>4U=E&u=k00000TUS9+PDxHjT_7cMIwfQ}AaG%Fb7dfI zb!}p0a$j?Fa%pa7AarjaX>N2NW?^Y;Wn?TMZgp*9WpZD0baH8KXFVlzE(!nuE^lmP z00000FLP{fXJl+|X8-^I00000FLP{fXJl+|XD)ASWB>pFFLZ5iE^KdOYXATM00000 zFLq&aFKlmTFK%#kFLP{fXD@SXZ)apLb8K&CWNdF|0000000000c42ZaY;R{TZg6!k zb8K&CFLP{fXJjvPY;R{|Y;R{SZ){`$00000FLq&aFKlmTFK%#kFLP{fXD@SXZ)apL zbZu}hY;R+00000000000B``E(EhR8AWGy8yGGrhnFfwF1B``8%IwdeNWG*EzGi+o4 z00000XJvFCW@&6?AaiMYWguo@X>4U=AS@tda&m5OAUz-@WG)H-00000b98cUV{mz2 zb0BnSZDk;4VQFk-WGo8LV`yP%ZZB+aXD@SXZ)Y!aY;R{TXm4|L zFD@=GE-o)FE-!OvVRB_;FKlmTUt@1=ZEtR0b#!TLE@J=yTUS9+PDxHjT_7cMIwfQ} zAX{l}aCLNDAa!$Pav*7BAZc?TZgp&IE(!nu00000TUS9+PDxHjT_7cMIwfQ}AX{l} zaCLNDAZK!Kb#NeQWFTpCAZ~SRY%U4_00000TUS9+PDxHjT_7cMIwfQ}Aa!$Pav*MR zbRcGLb#7!X3IG5A00000TUS9+PDxHjT_7cMIwfQ}AZ>GJV{~jFW?^Y;Wn?TMZDn(F zVP|Duadl;NWnXDzJtbr;AaZ4Mb!>D!C1flhWpZ+EZ#^YsE(!nu00000TUS9+PDxHj zT_7cMIwfQ}AX{l}aCLNDAaG%HXdr2GAZ~SRY%U4_TUS9+PDxHjT_7cMIwfQ}AY*86 zcWxkXVRUF9W?^Y;Wn?TMW@&6?aA9<4JtcE2AaZ4Mb!>D!C1flhWpZ+EZ#^YsE(!nu zTUS9+PDxHjT_7cMIwfQ}AX{l}aCLNDAZTxGWgui}a%E$5Z*qAcaA9<4AZc?TZgp&I zE(!nuTUS9+PDxHjT_7cMIwfQ}AX{l}aCLNDAaG%HXdrB5ZfA68AZc?TX>N95Y-waH zAZ%rBXLM*iC3P$yZDDv{Y-Mg|bZ9*#WG)H-00000TUS9+PDxHjT_7cMIwfQ}Aaitb zV{mz2b0BDMZDk;2X>w&_bZ>HbAZB4{Y-MCDAaZ4Mb!>D!C1flhWpZ+EZ#^YsE(!nu zTS-nvPhB7-b2=qtIv{9oZDn6%X>w&_bZ>HbJtcE43IG5A00000TWM}^b#z@IaB^>B zWpi^NWNC6`V{~tFc_46MbZ8)Hb0BVYY-}z7FK}{iV=r@MY-TTIcx3B zWpi^NaA9<4AZB4{Y-MCF0000000000TSZb*Pf}eVLvLD!C1flhWpZ+EZ#^YsE(!nu zTSZb*Pf}eVP+@dvAZ%rBXLM*FZEtdAAarP9ZXk7VaAk5JY-w$2bSxlsaByXEUu>g$bu1ubZ*FF3XHa2uXgwu!E(!nu00000b8K&CE@N+QW&i*H00000TSZb*Pf}eV zb98cJVRT<}AZB4{Y-MCDAY*TCW@%?oVRUFcC37qwa%FRMY;-*(WGo4QWgv8DVQwIG zaByXEAZ%%EX>=?gb#QQHa$js|ZE18pC3P$yXm4$0L}_w8C37qwaA9<4JtcE43IG5A z00000TUS9+PDxHjT_7cMIwfQ}AaitbV_|e(b0B76X>4U=EFfraZDn6%X>w&_bZ>Hb zJtcE2AaG%HXgwu!EFf}ab9HQVJtbr;AZ2oLZf`v$WG)H-00000TS-nvPhB7-b2=qt zIv{6XcW-iQQ*dEpWl&*sXdq}|b0A@Ca%Ev;c_3nCWo{s8ZfSIBVQgu7WiAQ;00000 zY;R{*Z*psMaA9L*00000FLiTrFLP{fX8-^I00000TSZb*Pf}eVC389@WI7;cWpp5N zWnpY^VRUF9W?^Y;Wn?TMc42HiC37qwWpZ+EZ#^YsE(!nuTSZb*Pf}eVC389@WI7;J zXk{R9VRUF9W@&6}AYyqSB5ZGGS8sA_b8ul}Wg;MHb0BSRa%CWNXkl(3C1frN3IG5A z00000TSZb*Pf}eVC389@WI7;JZ*OcML1SZOb8{efZ*psMaA9L*AaG%HXdq@`X>4U= zEFfoJcW-iQQ*dEpWl&*sXgwu!E(!nuTS-nvPhB7-b2=qtIv{LsXIF1>Yjbd6V`U&c zASH7y3IG5A00000FLP{fXJh~Xb98cJVRT<}AZB4{Y-MCDAaG%HXgwu!EFf}ab9HQV zJtbr;AZ2oLZf`v$WG)H-FLq&aFKlmTFK%#kFLP{fX8-^I00000Y;R{lXJu}5Mrmwi zL}_vWRA^-&aA9<4AZBT7Y#?HJAR=sUXF+FWZgfUzY-L1gav~sUb0BSRa%CWNXkl(3 zC1frN00000XJvFCa%Ev`aA9<4AZB4{Y-MCDAa-GFJtcE2AZ2oLZf`v$WG)H-RA^-& zaA9<4AZBT7Y#?HJAR=sUXF+FWZgfUzY-L1gaw0t-C37HYb0BbKa&2jIb7^mGAY^53 zX=P+C3IG5ARA^-&aA9<4AR;AmA|PpVAaG@JZE16JX>V>IWMyt?Wn?Z200000FLP{f zX8-^ITUS9+PDxHjT_7cMIwfQ}AZKNCAZK55Z)0m^bVg}xWl&*sXdq@`X>4U=E(!nu zFD`I$Z({%eTUS9+PDxHjT_7cMIwfQ}AV+0%P-$dLX>)W?VRUF9W?^Y;Wn?Z23IG5A z00000TSZb*Pf}eVLvm$dbW>4U=EFfiaa&B)uC1eT!TSZb*Pf}eVRBvx= zQ)q2NbZj7IVQFk-WGo;?b;C_n%I5C;GNXg~k| zGzS0xs6YSzSO)+AC_w-Jhz9@wXh8q}tOo!95JCU{;0FKzz(N225C{MONJ9VrGzb6y zxI_Q{vf z09pV4d<_5q=v)8)01f~E2wwmHd=3Br=wAQ-s15)C2x0&K1P=fJuwwuJln(#^Fk}D! z#18-fcxnItln?*_@M-`5#1H@g;A;Q>3=seT&};wyR1p9Gz-<5joDl#3ux zpl<*FED`_!FmM0=SP}pLm~j99v=RUSm~sFA2onGR0CWHUz!Lxf2z3Ad@Dl(4$aMez z925Wm2zCGeKokG~Kz0BBWE21Zkahq6j1&L>h7#08k$bJ9+JQe@|Ab&-m>2*6po;(h%oqRwpo{@t{uo(aVaE|}~)ENK((2oEA_!$5IFpvNL92x)skdOcWNE!eDkdXiX zm>K{8V3Gg-;2Hn`V3Ysd8A7@7b7;2Zz| z_?iFz7##orz?%R6Kpg-8_?!R#a2)^uu$=$@tQ`OV(4PPQEFJ&=_@Mv)lpX*8h@t=g z$Q}Ry$f5uL>>dCB2%`W05FY>l_@n>-XdeIo2&Mo3v>yNf*rxyg6d(Wqz^DKJa3BBx zV5tB9pdbJM0IC1~&>#Q+fT{og{2%}T0IL80C?NmM2qypl@Vfv1EGGZ} zV7veSR3`ucxV!)VgeL$1AiV$ov?l-nc)b7r4 zfG7X}P`>~FuqXfk$iDyo*eC!1D8K*z04V?ffWQC$Fev~4(7*rxSSbJiK*0b1fGGd~ zsKEdKs3`yd2*LmV&?x`_aKZoo_$dGYsKNjL94Y_+Aj1FuL@EFPn8N@6Y$^Z%*uww+ zkSYKG7{mYnv?>4qP{aTK*eU=3$ix5t04o3h0L1_QBr5;_NW}mDOe+8YsKo#ObSnS= zV8#Fcpeq0Xn8pA9$SVK<000005C8xG000000eVsZ1b7|+8w?)+5C8xG7ytkOY&8G> zEC2ui000005C8xGEC2uih&2EIJOBUy00000Bme*aKmY&$v^4+!NB{r;06`8Qodli( zK@A;2lLAiO-O~&o000005C8xGXaE2J)HMJ91ONa400000C;$Ked;kCd$Ta`|ga7~l z06`8god%u-Lk%54lLV9lS_E+-qqIA)C?a0LJL8cgal2Pg9KsN*Fl$r1WeaL zmxKhEg9J(n*w;b}O4!#zn1ckDgaiNpBme*a3;_TDz&8K?fB*mh06`8god%u-Lk%54 zlLSx--rds-9{@oMBme*aGywnr7&rg_kN^Mx06`8wod})>LJb{3lLl4_-rds-9{@oM zAOHXWTmb+8fH(jDKmY&$06`8Qodli(Lk%5D3f|oe9{@oMEC2uifB^sioHzgfd;kCd z06`8Qodli(Lk%5D3f|oe9{@-TM+)BE3?BeN3jhEBAOHXWumJ!7>^J}aNB{r;06`8Q zodli(Lk%5F3f|oe9{@oMAOHXW)Bykh5IFz;KmY&$06`8Qodli(Lk%5D3f|oe9{@oM zAOHXW_yGU_EI9xFKmY&$06`8Qodli(Lk%5D3f|oe9{@oMEC2ui90C9UNI3uhd;kCd z06`8Qodli(Lk%5D3f|oe9{@-TM+)BE3?BeN3jhEBAOHXWOacG^m^lCcKmY&$06`8Q zodli(Lk%5D3f|oe9{@oMFaQ7mZ~_1Tv^f9&qyPW_06`8wod})>K@A;2l?0XpLX!rR z1z!r@-PP99)C?a0LJI%@EC2uiqyhi{C^`TCtN;K206`8wod})>K@A;2l>|bQ29yO^ z3f|q-)6@(f0744@AOHXW)B*qis5$@tga7~l06`8Qodli(LJb{R3f|oe9{@rNd;kCd z_yPa`3_Ab+Z~*`S06`8=oeG`_K@A;2mIXqS2uGC$N!3W+-PY3#9{@oN9Z-`9l?Ijt zoeG`_M3e_ZmjqAM)Irxll?Fx%)j|tF3X}&))zm=?Le)Z)2bBg&)zm@W-PY3#9{@oN z9Z-`9mIa*(o(Vyf29yUumjnO+kN^Mxcmn_c{5t>t>;V7(06`9r2|=Bb0iKZoK@A;2 zmy7{KlaK+GjsZoPiUCiXhyj|30Ya3I0YaFI0YjFJ0cqRXLDWIkLD);(-r3jH(+nQ~ zLJS>{36qckl#ccost2bkpWuN*4WzHL7RvHnu!5H zl#c;HmW=^Hn2P}bH~;_u3NV06`AG2tl2Q0iK5eK@A;2lZFA5g#kj9 zgaMX=0e=eJ-qqIA)C?a0K??u?qyPW_NCW@?0hXHqL6e>VL7JBVQ~&?~@B{z=WI+G_NC5x<06`8w zod})>L=7E5lLnLpPL>0e1W^js)k5Cg)6@(f06_~u*40Pe-P6`6)r~m)}NCf}@R6+m$gaiNp06`AG0YRMlo3Ij3YrT-mJf8+LemJgT> znGBi>n+ihI)z;YA+S@^u5R?%?nGBc>L7NJi3qh6-SO5S3^aTI_Fh&3W=m7u#06`A0 z0YRM-o)JL|9gqP*lMs{-M3xOql@3Ce3}@9r*Fu#JmkdhPLDxwN-QL#I)C?a0LJLTh z4wno{3e`c^K?_UOLDxc+4nda;Bme*aPzC@1yhi{3Z~y=R06`8god%u-Lk%54lLS=? z-rds-9{@oMm;e9(cm@Cf1V{h>kO2Sy06`95oeZ7}Lk%54lL|-o(n;i2Tqj;Lzo4Z211$xnFLnV*Vx(GLDWIkLX-)W2$lzz2ABnz1eyau z*w;bY*+$jWMAkvx-O~&o07VQPV3P`+44w-?l?apxL6-)W2SJ$xm<2(a13}l=+1f#v z1(yavngf{xH~;_u6bAqR_(%W$!~g&Q06`8wod})>K@A;2lLnLpMwJ9h3f|q-)6@(f z0745-3f|q-)6@(f06_}?AOHXWPzL}2gh>DYH~;_u06`8Qodli(LJb{B3f|oe9{@oM zKmY&$bO!(cm`MNsOaTA@06`8wod})>K@A;2lLnLpLX`whmIGGSP72=L)zj1r9{@rN zOqK&d3f4gjMb<@@0{{R3Bme*axCa0Lq)Gq(oB#j-06`8god%u-K@A;2lLS%<-rds- z9{@oMTmS$7;0FKz97_NHya50J06`9*1D!OUGeHd3f|q= z+11w5)C?a0K?^~fDw-=rmo8ok+uA|bK?_O>*FoFbK?_pb+CkSsn<|0h1b(8I>587nc^86`2&86P+BM8*0|s+EA7knG~86O$ydR z+Sx%1ND9_L+Sx%1O4ixhL7Eep6hW33cmMzZ#0UTY;7$MkAOZjY06`9*0i6_{6G06f zL6#3flM<8>M41el3r3p?OqdOq4nma>LYxU=)j`<{9C;$KeKnVZ< zgirtf-~a#s06`A00i70}6+sOhL6a1e6Ke|I-P6j=mJLvs3}Fh_LJL{fQQqCv*3;As9{@rO9gqQ&5R?y< z4wem<44o355kU&qK?_d`*Fg(U*Fu*JNB{r;$O!-d{89h^qyYc`06`8wod})>LJb{3 zlLk);-rds-9{@oMN0bFi3e-XiOA3_)P}S5y3rm#*P}M^U)ItkG)IpU5lm!3)KmY&$ z6bb+UpeX>o7f{qelovzPMwAy?)JqE9-PO|! z9{@oMQj`};)IpRNEC2uiSPB3D6jT5Id;kCd06`8wod})>K@A;2lLnLpLzM(q3f|q- z)6@(f06_}?%m4rYhzbAzWK;kDNCp4^06`AW3PGK!0iLM=K@A;2lc)idrvXHjrU90v z0YjIh0hpr!NtvPnPYT`M+1J?B*3;As9{@oMMw+1kY1%=Wp#htq0YTf^LzxLzK@A;2lLnLpLzM(p3f|q-)6@(f z06_}?L;wH)hzkG!Bw7Fe@Bjb+06`AG0-Y$HCqWGzL6as@l_ZoUM%C0u-rds-9{@rO z9l!#UCX^+WB%LUpCsozdLX{+xB>(^bL;wH)&(^bL;wH)7z_Xa zbXx!a@Bjb+06`AG0-Y$HCqWGzL6as@l_ZoUM%C0u-rds-9{@rO9l!#UCX^+WB%LUp zCsozdLX{+xB>(^bL;wH)U(^bL;wH)s0;uA#9ROW@Bjb+06`AG z0-Y$HCqWGzL6as@l_ZoUM%C0u-rds-9{@rO9l!#UCX^+WB%LUpCsozdLX{+xB>(^b zC;$Ke@C*O|Y+V2Ui~s-t06`8god%u-K@A;2lLV9lUJBmb)6@(f06_}?SO5S391Q>f z&|LrjWB~vG06`8=oeG`_LJb{3mjsvtLX!wXl?F?c2S%0!Pt-xyO5WYq*wxbv9{@rO z9Z-`9ln0dtmjsvtoeG`_OVmn~2SLK@A;2lLnLpLX`wz3f|q-)6@(f0744@C;$Kev z06`8=oeG`_K@A;2lL(XtNRK@A;2mIFeR1(gI&lLkf8QVQPP*3{Ju9{@rNRFeh(SO5S3To3>N z7-j$ecmeK@A;2lLnLpLX`xT18NH1 z-PP99)C?a0K??u?TmS$7+z|i($ZG%ppaB2?06`8=oeG`_K@A;2lL$hU21AzwNR$Um zmIYDNLe@#%-PhIA3?BeO3>{FD2$Tnv2A2e#3Z4l>)J&8ImIX@+)Irul3ro~N)M;K@A;2m7oKbp94ado&%Vj14NUe z1C*fyX_}h@nVbUxK-$?$-QL&O)z;J03?BeO3>}~vlcEEZp#znm1D2lym!1QdodcPi z1DcxyoumVvqXSgg+Dw_81DcxyLE70|nwtZeoC5#=FaQ7mToV8Q$Z-GvH~|0v06`8w zod})>K@A;2l?0XpLX!rR1yu^(-PP99)C?a0LJI%@GynhqkP`p^%yIw!0096106`8= zoeG`_K@A;2lL(XtLX`%V1xA+yU<%&d*VWe3)C?a0K??u?C;$Ke$P)knlyd+7^Z)<= z06`8god%u-LJb{3lLTf8-rds-9{@rN00000d;kCd^b-I8U~~WffB^si06`95oeZ7} zK@A;2lL|(a2t$+!M$}2(-PO|!9{@oN9bl6RlnIpxoeZ7}NS6kd2SJ$xm<49n)5$XKz0BB0096106`9*0YRM*o)19`9e@ErlMX_b3rv*^lnqDK)Jfgm*3%3h0748M zfB};Zlns>(mJ6K_o)1~o)IyaElnnp?L;wH)TonKS@OA(H%m4rY06`8wod})>Lk%54 zlLkVS1eOCylm%1NO5WYo*3%3h06`2LK$8ZP1(gJr1Dyz-2SLAL6{ep7(tm9XaE2JI2Hf^p6+)C5T-Vk?)Ir!v-rd>N(+nQ~K@1(> z0h1b(8I>587nc^86`2&B9G)9W)IrzQLD)o>7M2%5lo>&o6#xJLga7~lq!s`G*m(c{ zI066w06`Am3_+dD0iMeNK@A;3lga^Bmd62=$N@^1#sOiJ$pKZ>)IrzQNZsDk3?BeO z3?1MMlga^<$pMwf0hY%Bm&O5|%mJRu0Zmd62?#sNXr z)j`)nmB;~<$pJx^#sQYc0RR91EC2uiEEfO(hK@A;2lLnLp zLzM(r3f|q-)6@(f0744@L;wH)To(WUKzslHH~|0v06`AG0i7707eNgjL6a7g6;%q} z-P6K@A;2lLnLpRtnzT)6@(f06_~$l>|lALX`wd)k2j7Bme*a+!p`<*nI#0 z!~g&Q06`9b0i6(@4@3H~|0v06`8wod})> zK@A;2lLnLpLX`w#3f|q-)6@(f0744@H~;_uG#CH?fPVk~xBvhE06`8god%u-K@A;2 zlLSeW14z_I-rds-9{@oN9Wavwlmndxo&`wMNt6Qsd;kCda2Nmp{C@xc90C9U06`8= zoeG`_K@A;2ln0dtM3x0clL%6n1D6C?*w;bRN#5Po)YS|h06`2LP?HFh2bBhv1(yVv z1Dy(<2}=soLD<(q3rN#J*w;am2uIUFlL(gtm;*}FLD<(ulL$x((?JVI(?Xa7mjpqR z2mk;8WB>pF@E8C9oPhuTBmw{c06`8=oeG`_K@A;2lL(XtM3n|dmIY4MN#5Pn)6@(f z06`2LP?HFh2bBhv1)U0>2}PF#QP)e>L6!xV1WVV}L6!wd)>4)QNY+7?1(yU(*VaOp z1eOH=FaQ7mSQ!8ST!R1qkN^Mx06`8wod})>LJb{3lLnLpNtFah)kzB8-P6EQ3}>W3rGsqK?_I<)K@A;2lLkkX1VWSrQPfG^-PO|! z9{@rO9YB)?lm(Rpod})>MhetI3qsUHlm$xELX-snTmS$7cp3lzOojjd&;bAd06`AW z2tl2S0iKBgK@A;2lZXM7hXF^Gh5=0q-QLyH)C?a0LJL8cgaMX?0c{G`)06`8wod})>K@A;2lLnLpN0kIj3f|q- z)6@(f0744@EC2uiWE%hgxQGA$pa1{>06`8wod})>K@A;2lLnLpN0kIj3f|q-)6@(f z0744@C;$Kelp6p5D2V_6d;kCd06`8god%u-K@A;2lLV9lR|?+U)6@(f0744@C;$Ke zz#9Mne2D-5d;kCd06`8god%u-K@A;2lLV9lR|?+U)6@(f0744@Bme*a>>B_8(1`#4 zcmMzZ06`8god%u-L=7E5lLSx--rds-9{@rNBme*a6dV8mAc_C~U;qFB06`8god%u- zLJb{3lLS%<-rds-9{@oMBme*aJRAT3Sc(7ti~s-t06`8god%u-K@A;2lLT4{-rds- z9{@oMBme*aWE=nhz={9=i~s-t06`8god%u-K@A;2lLT4{-rds-9{@oMEC2uij2r*} zD2o68r~m)}06`8wod})>K@A;2lLnLpLX`wr3f|q-)6@(f0744@C;$Keyc_@kpo;(h zd;kCd06`8god%u-K@A;2lLV9lR|?+U)6@(f0744@FaQ7m=o|n5^osxg3;_TD06`8w zod})>L=7E5lLnLpLX`xT17ix_-PP99)C?a0K??u?L;wH)9321v(2M{7)Bpeg06`8w zod})>Lk%54lLkVS1eOCylm%4OO5WYo*3%3h0748MK$8ZP1(gJr1Dyz-2SL~z>NR@ zWB>pF06`8god%u-K@A;2lLS!;-rds-9{@rNBme*av>gBd0FD3uTmS$706`8god%u- zK@A;2lLSx--rds-9{@oMBme*a+#LV_IF0}RTmS$706`8god%u-K@A;2lLSx--rds- z9{@oMBme*a1RekYaE<@}TmS$706`8god%u-K@A;2lLSx--rds-9{@oMAOHXWEFJ&= zsEz;sJOBUy06`8Qodli(LJb{C3f|oe9{@oMGynhqP#ypP#Et*|C; zK@A;2lLnLpN0kIn3f|q-)6@(f0745^mIF@KNtOcuFaQ7mh#mj{w2uG(zyJUM06`8w zod})>K@A;2lLnLpLX`xT16T^)-PP99)C?a0K??u?Pyhe`ydD4mK#%|b1OWg506`9r z0i6<_5kn0fL6i@b4nmdl^pF4l`~Uy|06`9b0i6(@4?_(dL6i-Z3__L*Op^{& z(@Eal*3{Ju9{@rO9e@Fo4wMa*43-O>5S|Z0(?pXFMAJf(4gdfEAOHXWU>^Vgq>%sr zH~;_u06`8Qodli(LJb{B3f|oe9{@oMAOHXWgdYF^xRC$0T%#i>8XaE2J06`8Qodli(Lk%5E3f|oe9{@uOMhf2D3?BeN z3jhEBBme*a*dG7@1d;#$YybcN06`8god%u-Lk%54lLS%<-rds-9{@oMAOHXW03ZMW zOp*WpKmY&$06`8Qodli(LJb{B3f|oe9{@uOAOHXWBp?6)Xp#T_H~;_u06`8Qodli( zLJb{B3f|oe9{@oMAOHXWNFV?Je3AeEH~;_u06`8Qodli(LJb{B3f|oe9{@oMAOHXW zY#;ytkdgoYH~;_u06`8Qodli(LJb{B3f|oe9{@oMAOHXWkRSj6q>=ysH~;_u06`8Q zodli(LJb{B3f|oe9{@oMBme*av>*TgxRL+=d;kCd06`8god%u-Lk%54lLS=?-rds- z9{@rNBme*a+#mn|5R(7@d;kCd06`8god%u-Lk%54lLS@@-rds-9{@oMBme*a1R($b zXp;Z`TmS$706`8god%u-K@A;2lLSx--rds-9{@oMBme*aEFk~@ppyUpYybcN06`8g zod%u-Lk%54lLS!;-rds-9{@rNBme*aR3QKW=#u~cYybcN06`8god%u-Lk%54lLS!; z-rds-9{@rNBme*ad?5e;Fq8lPTmS$706`8god%u-K@A;2lLSx--rds-9{@oMBme*a zq#*zRXp{f{TmS$706`8god%u-K@A;2lLSx--rds-9{@oMAOHXW%pm{(pp*aqJOBUy z06`8Qodli(LJb{B3f|oe9{@rNBme*a@F4&Iyp#X`YybcN06`8god%u-Lk%54lLS!; z-rds-9{@rNEC2ui7$N`w1eE{(SO5S306`8Qodli(LJb{C3f|oe9{@oMMhf2D3?BeN z3jhEBEC2uiNFo3LER_HMWB>pF06`8Qodli(LJb{E3f|oe9{@oMM+)BE3?BeN3jhEB zEC2uicp?A*WR(B^SO5S306`8Qodli(LJb{C3f|oe9{@oMMhf2D3?BeN3jhEBBme*a zs3HIWjFkWXWB>pF06`8god%u-Lk%54lLSx--rds-9{@oMKmY&$&>{c;%#{ECtN;K2 z06`8wod})>K@A;2l?0XpN|XhY229k`NDAKF)z%Cj06_~z3f|q-)(js2K?^~Y1(OB< zEC2ui6e9otIFpF06`8god%u-Lk%54lLSx--rds-9{@oMBme*aY$N~x_?G|wTmS$706`8g zod%u-K@A;2lLSx--rds-9{@oMBme*alq3KEFqi-TWB>pF06`8god%u-Lk%54lLSx- z-rds-9{@oMAOHXWyd(esaF_r8H~;_u06`8Qodli(LJb{B3f|oe9{@oMBme*a;3NP5 zgqQ#SbN~PV06`8god%u-Lk%54lLS->-rds-9{@oMBme*a2qgdj)R+JNbN~PV06`8g zod%u-Lk%54lLS->-rds-9{@oMAOHXWFeLy0B$)sIJOBUy06`8Qodli(LJb{C3f|oe z9{@oMAOHXWR3!iaK$!pkJOBUy06`8Qodli(LJb{C3f|oe9{@oMAOHXWcqIS;T$um= zH~;_u06`8Qodli(LJb{B3f|oe9{@oMBme*aoFxDNaG3x9bN~PV06`8god%u-K@A;2 zlLS@@-rds-9{@oMAOHXW#3cX#z?lF4H~;_u06`8Qodli(LJb{B3f|oe9{@oMBme*a z=p_IE)R_PONB{r;06`8god%u-K@A;2lLSo)-rds-9{@oMBme*a5GDWs^qBwuTmS$7 z06`8god%u-K@A;2lLSx--rds-9{@oMC;$KeI3@r9ESdlRv;Y7A06`9LoerK2LJb{3 zlMIv#VhY~f)6@(f0744@Bme*aWF`OrxS9X|H~;_u06`8Qodli(LJb{B3f|oe9{@oM z000005C8xGj3xj8$eI8D3;+NC0000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000000000000000000000000000004mhe*gdg0000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000000000000000000000000000000000000003c%k00000 z00000000000N7#x00000000000000000961000000H_TB0000000961000000JIGN z0000000961000000K^Rd0000000961000000MiWs0000000961000000No7$00000 z00961000000P76^00000009610000003{9p0000001f~E0000006Pu<0000001N;C z000000H9I;0000001W^D0000007UKp0000002u%P000000C4sK0000002=@R00000 z01yBG0000002%-Q000000D$%a0000002}}S0000001yBG000000QLU=ZvX%Q0Pq0- z0000000jU5000000I(nc0000000sa60000005Ast00000015yA0000008tJA00000 z01E&B0000002lxO0000000RI3000000O0rn0000000IC20000005}r>0000002BZK z0000000#g70000002crN000000BAn|0000000#g7000000EjUF0000000;m800000 z0N@P(0000000{s90000002lxO0000002lxO0000000000000000Q>*{ZvX%Q00961 z000000RI2~ZvX%Q04Om4000000RR90ZvX%Q00RI3000000Pz3+ZvX%Q00J)n00000 z0Qvv_ZvX%Q0Dk}g00000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000000000000000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ00000 z0KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ z000000KifJ000000KifJ000000KifJ000000KifJ000000KifJ000000Fd?q00000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000CG_ zr?db70{{R300960|NsC0|Nj910003100960|Nj91002-40RR910000000000003AC z0RR910003100000003YK0RR910006200000003wS0RR910009300000003|a0RR91 z000C400000004Li0RR91000F500000004*y0RR91000I6000000058)0RR91000L7 z00000005W?0RR91000O800000005u~0RR91000R900000005{70RR91000UA00000 z006KF0RR91000XB00000006)V0RR91000aC00000007Vl0RR91000dD00000007_# z0RR91000gE00000008I-0RR91000jF00000008(20RR91000mG00000000OI0RR91 z000pH00000000mQ0RR91000sI00000001Bg0RR91000vJ00000001Zo0RR91000yK z00000001xw0RR91000#L00000001}&0RR91000&M00000002M=0RR91000*N00000 z002k|0RR91000;O00000003AD0RR91000>P00000003YL0RR91000^Q00000003|b z0RR91000{R00000004Lj0RR91000~S00000004jr0RR910012T00000004*z0RR91 z0015U00000005W@0RR910018V00000005{80RR91001BW00000006KG0RR91001EX z00000006iO0RR91001HY00000006)W0RR91001KZ000000077e0RR91001Na00000 z007Vm0RR91001Qb00000007tu0RR91001Tc00000007_$0RR91001Wd00000008I; z0RR91001Ze00000008g`0RR91001cf00000008(30RR91001fg000000000B0RR91 z001ih00000000OJ0RR91001li00000000mR0RR91001oj00000000;Z0RR91001rk z00000001Bh0RR91001ul00000001Zp0RR91001xm00000001}(0RR91001!n00000 z002M>0RR91001%o00000002k}0RR91001)p00000002-60RR91001-q00000003AE z0RR91001=r00000003YM0RR91001@s00000003wU0RR91001`t00000003|c0RR91 z001}u00000004js0RR910021v00000000000000000960|Nj60002-40RR91000F5 z00000003AC0RR91000F500000003YK0RR91000F500000003wS0RR91000F500000 z003|a0RR91000F500000004Li0RR91000F500000004*y0RR91000F5000000058) z0RR91000F500000005W?0RR91000F500000005u~0RR91000F500000005{70RR91 z000F500000006KF0RR91000F500000006)V0RR91000F500000007Vl0RR91000F5 z00000007_#0RR91000F500000008I-0RR91000F500000008(20RR91000F500000 z000OI0RR91000F500000000mQ0RR91000F500000001Bg0RR91000F500000001Zo z0RR91000F500000001xw0RR91000F500000001}&0RR91000F500000002M=0RR91 z000F500000002k|0RR91000F500000003AD0RR91000F500000003YL0RR91000F5 z00000003|b0RR91000F500000004Lj0RR91000F500000004jr0RR91000F500000 z004*z0RR91000F500000005W@0RR91000F500000005{80RR91000F500000006KG z0RR91000F500000006iO0RR91000F500000006)W0RR91000F5000000077e0RR91 z000F500000007Vm0RR91000F500000007tu0RR91000F500000007_$0RR91000F5 z00000008I;0RR91000F500000008g`0RR91000F500000008(30RR91000F500000 z0000B0RR91000F500000000OJ0RR91000F500000000mR0RR91000F500000000;Z z0RR91000F500000001Bh0RR91000F500000001Zp0RR91000F500000001}(0RR91 z000F500000002M>0RR91000F500000002k}0RR91000F500000002-60RR91000F5 z00000003AE0RR91000F500000003YM0RR91000F500000003wU0RR91000F500000 z003|c0RR91000F500000004js0RR91000F500000000000000000960|Nj60004*! z0RR9100000000000058+0RR910003100000005W^0RR910006200000005v10RR91 z0009300000005{90RR91000C400000006KH0RR91000mG00000006iP0RR91000F5 z00000006)X0RR91000I600000000000000000960|Nj60002irLpmTRM^05KAU7^E zE-(N9000O8000mG00001002ipBmpyFF#u3v00000003lS00000000O8000mG00001 z002ipBmpyFF#w=a000000068~00000000O8000mG00001002ipBmpyFF#tsF00000 z002zx00000000O8000mG00001002ipBmpyFF#tsF00000002bp00000000O8000mG z00001002ipBmpyFF#xPm00000006X700000000O8000mG00001002ipBmpyFF#t^N z000000030(000000000000000000000000000000000000000000000000930RYGW z00000000000000000000000930s!y<00000000000000000000000930{}1w00000 z000000000000000000931OTug00000000000000000000000931pops0000000000 z0000000000000931^_5A00000000000000000000000932LOmM000000000000000 z00000000932mok500000000000000000000000932>_r{00000000000000000000 z000933IM=T00000000000000000000000933jnZR0000000000000000000000093 z3;;y#00000000000000000000000934FFi~00000000000000000000000934gjDi z0RR91000000000000000000934*=jT0RR91000000000000000000935CCxY0ssI2 z000000000000000000935deVp0ssI2000000000000000000935&)3)0ssI200000 z00000000000009369C}&0ssI2000000000000000000936aWAK0{{R30000000000 z00000000936#x(j0{{R300000000000000000093761SM00000000000000000000 z000937XT<(0{{R3000000000000031000C4@&5n-000000000000000002J#00000 z3jk1J000000000000000002S&000623jk1J00000000yK00000002J#000002>_r{ z000000000000000002J#000003;;y#000000000000000002(_000C4@&5n-00000 z0000000000002J#000002>`58000000000000000002J#000003;;~-0000000000 z00000004~u000C4@&5n-000000000000000002J#000003jio%000000000000000 z005K#000623jnZV00000008^}00000005!@000623ji=?000000058x00000002J# z000003jmm4000000000000000006iE000005CC}g0ssI20000000000006rH00062 z3jolI00000002k^00000002J#000003jnZR000000000000000006iE000005detx z0ssI20000000000006iE000004FFi~000000000000000006iE000006aWYS0{{R3 z0000000000006}R000316aWYS0{{R3000C400000007Yd000316aWkW0{{R3000C4 z00000007wl000316aWwa0{{R3000C4000000086w000316aW+e0{{R3000C400000 z008m;000316aW|i0{{R3000C400000008{}000316aX9m0{{R3000C400000006iE z000006#y6r0{{R30000000000000aD000316#y6r0{{R3001xm00000000;P00031 z6#z&G0{{R3000C400000001Td000316#z^K0{{R3000C400000001!o000316#!5O z0{{R3000C400000002P&000316#!HS0{{R3000C400000002<|000316#!TW0{{R3 z000mG00000003SA000316#!@m0{{R3000C400000003?Q000316##4q0{{R3000C4 z00000004dg000316##Gu0{{R3000C400000005Bz000316##Sy0{{R3000C400000 z005u?000316##e$0{{R3000C400000006K7000316##q)0{{R3000C400000006iE z000006aXLq0{{R30000000000006%M000316aXLq0{{R3006K900000007Pb00031 z6adfz0{{R3006K900000007?s000316aat+0{{R30058x00000006iE000004FFj3 z000000000000000006iE000004**y$0RR910000000000008R&000C4@&5n-00000 z0000000000002J#000003jkKn0RR910000000000006iE000006#x(j0{{R3 z0000000000004pl000C4@&5n-000000000000000002J#000003jm;-0000000000 z00000006iE000004FJds0RR910000000000006iE000006#$qB0{{R30000000000 z005H$000316#$qB0{{R3001xm00000005r?000316#&Qx0{{R3000C400000006iE z000004FJdw0RR910000000000006iE000004*+010RR91000000000000653000C4 z@&5n-000000000000000002J#000003jjE^000000000000000006iE000004FE_Q z0RR910000000000006iE000006#(cM0{{R30000000000006iE000004FFIY0RR91 z0000000000006iE000004*<|X0RR910000000000006fF000C4@&5n-0000000000 z00000002J#000003jmnE000000000000000006iE000004FGr>0RR910000000000 z006iE000006#(!U0{{R30000000000006iE000004FGr_0RR910000000000006iE z000004*&>70RR910000000000007AX000C4@&5n-000000000000000002J#00000 z3jm000623jk2z00000003M700000 z006iE000004*+OO0RR910000000000000UD000C4@&5n-000000000000000002J# z000003jjFo000000000000000006iE000004*+OX0RR910000000000008R&000C4 z@&5n-000000000000000006iE000004*+~r0RR910000000000000~V000314*+~r z0RR91000000000000000000C4@&5n-000000000000000001fj000004gjDi0RR91 z0000000000002D$000316aWAK0{{R30000000000002q@000623;;y#0000000000 z00000008U|000622>_r{000000000000000002+}00031@&Aza0ssI20000000000 z003D7000316aWwi0{{R30000000000003tL000623jjFo00000000aC00000003nJ z000623jjFo00000000aC00000004Fa00031@&91|0ssI20000000000002J#00000 z3IM=T000000000000000004{w000sI3jiSA00000001}u00000005W+000sI00000 z000000000000000006B6000sI00000000000000000000006)P000sI0000000000 z0000000000007bh000sI000000000000000000000089!000sI3jiS700000006)M z00000008&{000sI3ji3B00000004LZ00000000pL000sI3jk2#00000002Ay00000 z000~W000sI3jip}00000002M$00000001on000sI00000000000000000000002G& z000sI3jm;j000000086y00000002`2000sI3jmPf00000003M700000003PC000sI z3jlDG00000008g+00000003(Q000sI3jhdd00000005)_00000004Ld000sI00000 z000000000000000004~y000sI00000000000000000000005u_000sI3jpwZ00000 z006`Q00000006NB000sI000000000000000000000071W000sI3jnB{00000001}u z00000007hk000sI3jkQ&00000003wJ00000007?v000sI3jnym00000007_s00000 z008d<000sI0000000000000000000000005000sI3jny;00000002Ay00000000sN z000sI00000000000000000000001Qg000sI00000000000000000000001rp000sI z3jpBX00000001}u00000001}z000sI3jhdc00000002M$00000002q_000sI00000 z000000000000000003?U000sI3jh$e00000003M700000004jm000sI0000000000 z0000000000005^2000pH6#x)P0{{R3000OO00000006WF000sI3jj#!000000049V z00000006@U000sI000000000000000000000080z000sI00000000000000000000 z008R+000sI0000000000000000000000904000sI3jlD(00000001Nc00000000#R z000sI3jnC!00000001}u000000018b000sI3ji3?00000003YB00000001rq000sI z3jly;00000002k;00000002G)000sI3jjFl00000002Ay00000002w|000sI3ji?R z00000002M$00000003DA000sI3jlcQ00000002Ay00000003tO000sI0000000000 z0000000000003|X000sI00000000000000000000004Ui000sI000000000000000 z00000005W<000sI3jjE^00000004ji00000006HB000pH6#&o(0{{R3000mW00000 z006)S000sI3jpwX00000003|R00000007Sh000sI3jj!H00000004Xd000000080! z000sI3jkny000000058y00000008d>000sI3jkPb00000008U(00000000aJ000sI z00000000000000000000001=y000sI00000000000000000000002k_000sI3jnC; z00000003kF00000002}6000sI3jj!N000000077V00000003(T000sI3jnCi00000 z007Vd00000008n2000sI00000000000000000000004gn000sI3jmnR00000000aD z000000058&000sI3jnZX00000004jh00000005Z>000pH00000000000000000000 z006fK000sI00000000000000000000007Ac000sI3jheR00000001}v00000007Yk z000sI00000000000000000000008d?000sI3jm000sI0000000000 z0000000000003DC000sI00000000000000000000003+V000sI000000000000000 z00000004vt000sI3jjEC00000002k<00000005H+000sI3jlc200000004{t00000 z005u}000sI00000000000000000000006NF000sI00000000000000000000006`Y z000sI00000000000000000000007qr000sI00000000000000000000008O;000sI z3ji4900000003kF00000008y~000sI00000000000000000000000*W000sI3jm<3 z00000003wL00000001Tl000sI3jpBg00000003kF00000001!w000sI3joli00000 z002k;000000021&000sI00000000000000000000002t~001HY000000000000000 z00000003qQ000sI00000000000000000000004an000sI3jn~U000000086w00000 z0052&000sI3jnBz00000005)`00000005i`000sI3jhG_00000001}u00000005^6 z000sI3jheO000000000300000006WJ000sI3jio%00000004vl00000006%U000sI z00000000000000000000007bn000sI3jhG*00000003A300000007+y000sI3jpY9 z00000003|S00000008O<000sI00000000000000000000000RJ000sI0000000000 z0000000000005B;000sI00000000000000000000000^a000sI3jk=Q00000003A4 z00000001ru000sI00000000000000000000002h{000sI00000000000000000000 z003wT000sI000000000000000000000043d000sI3jn}o00000002M$00000004vv z000sI3jlE600000001}u000000055)000sI3jmPg00000003+N00000005i{000sI z00000000000000000000006HF000sI00000000000000000000006=Y000sI3jolU z00000003kG00000007Vm000sI3joMy00000002M$00000007(y000sI3jo0C00000 z0049V00000008R>000sI00000000000000000000000vU000sI3jhez00000004{t z00000001Bh000sI3jpAq00000002+`00000001!y000sI3jpAM00000006uJ00000 z002S@000sI3jjcW00000005i-00000003MI000sI3jjcu00000004{t00000003$W z000sI3jm0R00000001BY00000004Un000pH6#xi10{{R30003H00000004^%000sI z3jpxz000000049V00000005N>000sI3jol!00000003M700000005>7000sI00000 z000000000000000006uT000sI3jp}p00000001Zf00000007Pl000sI3jnz500000 z001}u00000007ww000sI00000000000000000000008p~000sI3jk2X00000000~U z00000000XN000sI00000000000000000000001)#000sI00000000000000000000 z002e|000sI3ji>l00000008s>000000031C000sI3jkol00000001}v00000003hQ z000sI3jlEF00000003+N00000003+Z000pH6#y7n0{{R3000mG00000004gs000sI z000000000000000000000058-000sI00000000000000000000005&5000sI3jhdt z00000008I#000000065D000sI3jlz?00000001}v00000006xV000sI0000000000 z0000000000007Vo000sI3jnCf00000008g-000000089-000sI3jh#s00000001Nd z00000008$4000sI00000000000000000000000XO000sI3jmnd00000003M700000 z000>c000sI3jpZd00000001}u00000001Wq000sI000000000000000000000024- z000sI00000000000000000000002V`000sI3jnyb00000002|~00000002@A000sI z3jlb}000000086w00000003MK000sI3jkof00000001}w00000003zX000sI3jn~? z00000000aD00000004Fk000sI00000000000000000000004*$000pH6#(EE0{{R3 z000O800000005H>000sI3jpZc00000008^|000000068F000sI3jmOk00000008g+ z00000006rU000pH00000000000000000000007Pn000sI00000000000000000000 z007_(000sI3jom800000007hg00000008a{000sI3ji3V00000002w?00000008<8 z000sI00000000000000000000000sW000sI3jj#%00000006WA00000000C9000sI z3jnC700000002M$00000002Y?000sI00000000000000000000001Em000sI3jpwa z00000002w@00000001El000sI3jnB`00000006)M000000021-000sI3jnBw00000 z007_s00000002@B000sI00000000000000000000003tW000sI000000000000000 z00000004~+000sI3jlDp00000003M700000005v4000sI3jnZR00000008I!00000 z006EI000sI3jna;00000003+N00000006iS000sI00000000000000000000007et z000sI3jpxu000000049V00000007?(000sI3jk=H00000002M$00000008X{000sI z000000000000000000000000F000sI3jk2y00000004Xd00000000RO000sI3jkoy z00000005u>00000000*c000sI3jk1y00000004Xd00000001u!000sI3jiR}00000 z004Xd00000002A>000sI3jlz000000004vp00000002i1000sI000000000000000 z00000003JL000sI00000000000000000000004Lo000sI3jhGR00000008^}00000 z004v!000sI00000000000000000000005Q`000sI3ji?Y00000003YB00000005v5 z000sI3ji?K00000003kF00000006EJ000sI3jknh00000004vl00000006cR000sI z3jjEp00000003wK000000071h000sI3jmnO000000058x00000007Ys000pH6#)1s z0{{R3000mW000000080-000sI3jk>B00000001}u00000008k1000sI0000000000 z00000000000009J000sI3jk>600000003M700000000dT000sI3jnCs00000004*p z00000000>f000sI3jpBT00000000C500000000OG000sI00000000000000000000 z001@+000sI3jhGT00000003M800000002M`000sI00000000000000000000002@D z000sI00000000000000000000003nW000sI00000000000000000000004Io000sI z3ji4400000001}u00000004pz000sI3jm000sI3jm0O00000001BY00000005#9000sI3jkQz00000003M7 z00000006TQ000sI000000000000000000000071j000sI3jiSE00000003+N00000 z007Ss000sI3jko100000008g+00000007<*000sI00000000000000000000008q5 z000pH6#$S30{{R3000O800000000XT000sI3joMx00000002M$00000000*f000sI z00000000000000000000001fy000sI3jlzV00000008g+00000001}=000sI3jpxq z00000003M700000002u8000sI3jjd000000008s=00000003JO000sI0000000000 z0000000000004aw000sI3jp}o00000003M700000004~=000sI000000000000000 z00000005y9000sI3jmnZ00000005`}000000068K000sI3jk1-00000008g+00000 z006rZ000sI3jj#z00000003M7000000071k000sI3jpY-00000005i;00000007hy z000sI3jm0!00000005u?00000007_;000sI3jk1}00000000C500000008Y0000sI z3jm<(00000002k;000000090H001BW00000000000000000000000^j000sI3ji>= z00000007JY00000001Eq000sI00000000000000000000001--000sI3jjdX00000 z004Xd00000002G{000sI00000000000000000000002)D000sI3jk2z00000003M7 z00000003DN000sI00000000000000000000004Ir000sI3jo0000000003+N00000 z004p$000sI3jpZs00000003M700000005H{000sI3ji><0000000001000000062J z000sI00000000000000000000006@i000sI00000000000000000000007k!000pH z00000000000000000000008V0000sI000000000000000000000000K000sI00000 z000000000000000000vd000sI00000000000000000000001Zy001BW0000000000 z0000000000001`>000sI3jmnE000000086w00000002f5000sI000000000000000 z00000003MR000sI3jipr00000004LZ00000003tc000sI3jmnJ00000006iE00000 z004Ou000sI3jnZb000000068200000004&+000sI00000000000000000000005d4 z001BW00000000000000000000006WU000sI3jh%600000001}u00000006`k000sI z3jo0600000003A300000007Pu000sI3jm;-00000000C5000000086^000sI00000 z000000000000000008zB000sI3jomI00000004Xd00000000LS000sI3joOH00000 z003A300000000sd000sI3jnx%00000001}u00000001Es000sI3jkQ;00000003kF z00000001i$000sI3jhGo00000005u>000000024_000sI3jkQ700000004Lb00000 z0000lb#rnrY-wUIXJcb8VPSG(Xf`x0Y-w(Fcr9mcbuTwAGcGVME-o)FE-x-FFD@=G zY-wUPG%sUvbZIVc03>(-V_|G;Uw36;YhPw=055fOaxZLYVlQW7V=rN0a${&VG%ajt zZgqGqXKr;bH!d?SFfT4HFD@=GE-o)FE-!3pVm34{V{&wEE^h#HY;R{SV*o>PWnpw> zP-$dFX>4TxRB3HxL}_MbE@N+Qb98WWZ*VR#G5{oG09SHpbY(4RrX=DIrUu?^!a%paK zPIYYnXJ2DzZ+C7`a%paKPIYYnXJ2DzZ+C7_Y-CV!X>N2*b!`A=Ut@1>ZcuV*Zgfs{ zZ2)IqW^;65bWn0>Zgfs{Z2)IqZEs{{P;zN*bWU|`0B2uqZ)A0BWl3aCVQpmqXJ2h^ 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 zWoTb!a$#*{04`~6X>?y0000000093000vJ000O800000000;O00000004LZ00031000I6 z00000005v;00000005v;00000000yK000000000000000000C4000000000000000 z0046U00031000I600000006*J00000006*J00000008g|000000000000000000mG z00000000mG00000004df00031000I600000006LG00000006LG00000005MZ00000 z0000000000000O8000000000000000004vl00031000I600000002bp00000002bp z00000000mG000000000000000000C4000000000000000004>r000310006200000 z003C-00000003C-00000002lj000000000000000000O8000000000000000005Ez z000310006200000005vU0RR91005vU0RR91002A%000000000000000000C400000 z0000000000005u>000310006200000007`E0RR91007`E0RR91005vS0000000000 z00000000O800000000000000000620000gE00093000000040I0ssI20040I0RR91 z000mG000000000000000000O800000000O800000006cC000jF0009300000004mY z0ssI2004mY0RR91000mG000000000000000000O800000000O800000006=O000I6 z0009300000005Bo0ssI2005Bo0RR91002+|00000000C400000000O800000000mG z00000007GX000310009300000007|l0ssI2007|l0RR91001Bd000000000000000 z000O800000000O800000007Vc000310009300000000000{{R3000000ssI2000mO z000000000000000000O8000000000000000007ni000O80009300000000mO0{{R3 z000mO0ssI2000P004pj000O800000000;O00000000R90009300000000000000000000002-f z0ssI2002!D00000000000000000031000000000000000000pH000930000000000 z0000000000005ms0ssI2008;`00000000000000000031000000000000000008KN BE%yKb literal 0 KcmV+b0RR6000031 diff --git a/third_party/prebuild/x86_64/liberror_manager.so b/third_party/prebuild/x86_64/liberror_manager.so new file mode 100755 index 0000000000000000000000000000000000000000..cd9ad8bcbde41fabcc1ff2895b3428afcd04ecc7 GIT binary patch literal 852544 zcmV+W{{#SkMNCEl0RaO5000000000306qW#0001Bs00820000$0000000000`wRd8 z000000000$05|{#06+j802}}T000050000000000000000000000000000000000i z!UzBW0000i!UzBW0000003ZMW00001000060002s$p`=d0002s$tVB-0002s$tVB- z0000$HUIzs0002EHvj+t0000003ZMW00002000060002+%m@Gg0002+%qRc=0002+ z%qRc=0001B0ssI20001B0ssI2000080000000007000040002s$p`=d0002s$tVB- z0002s$tVB-00000000000000G0000000008000000000`<#c2O00026x(5IN00026 zx(5IN00026x(5IN0000iEdT%j0000iEdT%j00004000000000{<#c2Q0000000000 z00000000000000000000000000000000000000000000G000000000|<#c2O0002s z$p`=d0002s$tVB-0002s$tVB-0000WHUIzs0000WHUIzs0000100000000071ONbx z2LJ#70002k1^@sL1^@s_2LJ%Z1^@sn1pojh0002x1^@u!0{{SK2LJ$H2LJ%{0{{Tc z0{{S&1ONa40000_0{{Sh0{{Ra1pojT1pojL2LJ$j1^@u>0{{RV0001t1pojz1ONa4 z000011poj$0ssKh1polV1pol}1ONaq2LJ#s1pojL1polh1poka2LJ$#1pokR0ssKC z1^@s60000X0{{St1^@tr1ONbv0RRAs1^@u%1poln0RRBo1ONbI0{{TN1^@ta0{{S| z1^@uj1pokX1ONc31poj50002~1ONbq2LJ&31ONbw0ssI!1^@tC1^@t+1ONa40000; z1ONaY0RR9+0{{TP0RRAr2LJ$200000000000001w1^@s#2LJ#J0ssJ`1ONbz0{{RS z0001W1^@tl1^@su2LJ%c0{{R?1ONbl2LJ%$1^@tO1pojY1ONc90{{T31^@sR1ONa4 z000211polj0ssJE1^@uV0ssJm1ONar1^@sI0{{SQ0002b1ONbW1pok^1^@u(1poj5 z0001p0RRAf0ssIh0002D1ONc*0ssJ72LJ#}1ONa71poj5000000001X2LJ%v1polV z1ONb11^@uz1ONca0{{Rj2LJ$21pole1pojl0ssI=2LJ#70000y0RR9y1^@t{1ONaK z0RR91000281^@u31^@t$0{{To0000M2LJ$!1^@ue1ONcH1^@uh0{{T#1^@t<1^@uH z1pok91ONc+0{{RY0ssI22LJ%D1ONa40001V0ssI)1pok_1^@sR2LJ$N1^@ua0ssJi z1poj50001o2LJ$~1ONa4000101poj5000000001g0000V1ONcg1^@s60001Z1ONc2 z0{{S!0RR9H0{{Tv0RR9T1poj50002E1^@tc0ssI2000000001R1^@sO1^@s=1^@uU z1polN1^@u<0ssI2000000000p1^@tg0{{TU0{{Sp1pok}0ssI(0{{R30001<0{{R3 z0002I1ONa4000240ssIs0{{Sn2LJ%R000000001e1poj#1poj51pokS1polL0{{SR z1pok@0{{SA1polz1^@to2LJ#d1poj50000C2LJ#91^@tU1^@tr2LJ#70002|1^@sB z1pokS1^@t)1^@s|2LJ%P1pokN2LJ#h1^@sw2LJ$=1ONcq1poln1^@t?1ONa40001h z1^@sk0ssI82LJ#~2LJ$O1polp1pokF1^@tB1ONa4000000001j1ONax2LJ#f1pok{ z0ssJV2LJ#$1ONb&0RR910001J2LJ$m0{{SL1^@v51pokz1^@sZ0{{TM0RR9t2LJ%# z1poka1^@s6000000002b1^@t*1pojv0ssIC2LJ$q2LJ##1^@uo0000l2LJ$80RR93 z1ONbe0000I0RRA91^@sP0{{Ru1ONay0000000000000000002=1pok11^@t91polR z1^@um1ONa40000{2LJ$q1^@s6000161pokW2LJ#L0{{Rm0001b2LJ$I2LJ%)00000 z0001q0{{S81^@sf0RRBA1ONbq0{{R30001_1poj50000~0{{Rn2LJ#U0ssKW1^@s* z1^@sW2LJ#B0ssKI1pok31^@v01^@u#1pol10ssKS0RRA-1pojk1pokC0002!1^@s6 z0002+1^@tm1^@s=2LJ$N0{{R3000000000@1ONa52LJ$y0001`1poj$2LJ%s1pojx z1^@u>1^@tq0{{Tb0ssJE1ONa40000N1pokj2LJ%x1polJ0000<0001p1^@s600015 z0{{TV1pokr1^@s?2LJ%S1poj50001Z0001S2LJ$B0ssKY1^@t10RRBe1^@u-1ONcA z1^@uv1ONbS2LJ#70001`0RR982LJ$z2LJ%G1polt1ONaQ1^@s!0RR9p1pol+0{{Rs z2LJ#70002#1^@s;1ONce1^@uM0ssJ$1ONc61ONcA0ssIl1ONa(1pol*1poj_1^@s6 z0000C1ONa&2LJ#V2LJ%~1pol`1^@sX1^@t(1pokh2LJ#A2LJ#V1^@s~2LJ%u1pojO z1^@uN0000n1pol80RRB40ssJp0ssJk1pokx1^@sS0ssKS1^@sE0ssI2000000000= z1pol20RR9?1poj5000110ssK@1ONcm1pok>1^@t=0RRA40ssIb0{{S62LJ#_1pom3 z1^@t-0{{R30002C0000-0{{R3000221^@st2LJ#R1^@se1^@sc0{{T`0{{Sg0ssK5 z1ONbm0RR9d1poj50000L1^@u`1^@v21^@ui0{{RW1pol@0{{R3000000000d0ssL2 z1^@s60000_1^@uf0RRA&1ONaD2LJ%h0ssI20RR910000N0RR91000291^@sQ00000 z0001T1^@s6000000000|0ssK91ONa40000V2LJ$S0RRAk1poj`2LJ%|1pol;0RR9Y z0RRBw0ssJ)1^@sy0{{SN2LJ#7000000000F2LJ#W2LJ#70001!0001~1^@sb1^@t4 z0ssI20000M1poj<0ssK(1^@ue0{{S10RR91000280ssJ11ONcZ0ssJz1ONa40001N z2LJ%=1^@uZ1ONaY1^@tE1pojy1pojv1pojM2LJ%y1poj5000000001H0RRB{1^@s6 z0002}0ssJ#0{{R@1ONbD2LJ%A0{{R40ssI?0ssIG1ONc=0{{RO0RRAV1ONc;0RRAm z1poj91ONc>1poj5000171^@tH1^@t-1^@u&0{{R3000251pol~0000`2LJ#70001h z1pok61ONcT1poj50001r1poj<1ONb@0RRB11ONc+1^@tG1ONb82LJ%)1^@u|1^@uN z0{{SM0RRAF1pok81ONaB1^@sJ2LJ%<0ssIt1^@u11^@v61pok32LJ#(2LJ#70000& z2LJ#81ONb`1^@u=1ONcX0000k1^@u01ONa40002B1^@sJ1pojm2LJ#&1ONbM1ONc3 z0RRBB1ONce1polC1^@tI1pol^1pojY2LJ#p2LJ#70002j1ONa40000G1ONc+1pokI z0{{T|1ONbI1^@s60000I1pojp0001f2LJ%f1polJ0{{Tl1ONbQ1ONb31pol=1ONb} z0RRA~0RRBT1ONc;1^@s|0{{R30001M1^@uQ0RR91000000001g1ONcz0000#2LJ%t z00000000090{{ST1ONcz0{{Tw1^@s60001g0ssIc2LJ#70002b1pokf1ONcw1ONcV z0ssIy2LJ#;0002W0ssKL1^@s+1^@sA1pok?1^@sa0{{Tg1ONb~0ssI$1pok@1^@t8 z1ONa40001v1pokU0{{Rt1^@t41ONa40000$2LJ#G1^@un0RR910002o1^@sE0{{Tw z1polK1^@uN1^@t?0{{ST0ssKX1poj5000261polR1ONb>0{{RN2LJ%E0ssJp1pojD z1^@s60000e2LJ#M0{{Rj0RRAL0RR910001C2LJ#70002!1pokh1ONap1^@t&1pojl z1^@u=1polJ1ONbU1^@s?0ssI20002W1pok62LJ#=2LJ#70002j1^@tP1poj90{{TR z1^@uZ0{{S?1pojS1ONbR1ONaR1^@s60002?0ssI31^@s;0{{T~0ssJ{000000002} z1ONa40000=0RR910000E1pokM1ONa40002R1ONc*0RR910ssIR0{{T=1^@uf1ONcn z1poj5000162LJ$t1ONbe2LJ#e2LJ$g0{{SI1^@uC0RR9F2LJ$S2LJ#70001F2LJ#7 z0000B2LJ$r0002;0RRAE2LJ#}1^@s60000d2LJ%t1ONad1^@ua1ONaZ1pok&1^@s! z0{{Tu1ONc@0{{TI0002T0ssJf1^@t%1poj500000000000000F0000I2LJ%w1pojs z0000h0{{R?0RRA31^@s6000000001X1ONa41ONb{1^@s60002K0ssI41pojo1polj z0001G2LJ&61^@v00ssJ<1ONaj1^@s60000k1poj#1ONa40001F1ONa40000(0ssK2 z0{{Sq2LJ#=1^@s?1^@s60001j0RR9n0RRA<1poj50001>1^@sS1ONaG0RR952LJ#j z2LJ#I1^@sj0{{S$1ONcY0RRAY1^@s60000i0ssJF0RR910000Z2LJ##2LJ#Y1ONa> z2LJ#Y2LJ%n1^@uX1^@uv1^@tC1ONcT1ONc>1ONcY1poj&2LJ&30RRB=1ONag0RRB{ z1ONb31^@t%1^@tP1^@sW1^@tk1^@t02LJ%S1^@tA1pojU1^@s80001M2LJ$21^@un z1^@tf2LJ%z0ssIa2LJ%%1^@s60000P0ssKb1^@s60001=0ssKq0{{S(1polV0{{R3 z0002S0{{Re0ssIC1^@tq1polr0{{TI1ONcx0ssIt2LJ#l0002*0ssKn1ONa40001f z0ssJJ1^@u11ONae1poj50002R1pols0ssKD1ONa40001W2LJ#t1ONaz1pojl1pok( z1pok|1pokP1ONaa0RR9|0RR910001)0001Q2LJ#d2LJ#m1ONca00000000070ssIh z0ssI20000600000000000001J1ONbf1^@tK1ONc{1^@tf1^@u^1pol;1ONa!1^@tE z2LJ&01^@u91^@sF1poj50002X1ONbU1poj|1^@ul1ONad1pojD1pojM1pol+1pojZ z2LJ$>1pol21ONb$1^@t52LJ#70002S000022LJ#m2LJ#q2LJ%Q1poku2LJ#70002! z0{{R30001d1polv1^@tG0{{SB1ONb(1^@tJ1^@u+1ONbL0{{R3000000000Y0000< z1poj;0{{S02LJ#B1^@s@1ONcy1ONbB2LJ#7000000002<1^@s60000h1^@tc1pokY z1poj500000000061poj@0{{Sn1^@s-1^@uv0{{TJ1^@ta1^@uw0{{Tu1^@sz1^@tH z0{{R300000000122LJ$y2LJ$21ONbg0RR910002;1^@u60001>1poli0{{R60RR9Y z1ONb40{{Rz0001}1^@s(1pojt1^@u*1pojR0{{SS2LJ$b2LJ#j1^@tj2LJ%J0{{Rd z1ONan1^@tu1ONc)1^@te0{{SO1^@tV1^@t62LJ%R1pojZ1ONav0RR910001v1^@uI z0RRBL1ONaC2LJ%a1^@u;0RR910001g2LJ$|0{{S|0ssI(1ONa4000000000000000 z0002#0{{RK0RRAb0ssJ-1^@s60000000000000000000000000000000000000000 z00000000000000500000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000001000000000000000000000000000000000000000000000 z0000B0000000000000000000T0000000000000000000A00000000000000000000 z0000000000000000000*000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000a0000000000000000000- z00000000000000000000000000000000000000000000y00000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000001V00000000000000000008 z00000000000000000000000000000000000000000000{00000000000000000000 z0000000000000000000000000000000000300000000000000000000000000000| z0001<0000000000000000000000000000000001x0000000000000000002500000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000000000000001^000000000000000 z0001d0000}0001L00000000000000000000000000000000000000000000R00000 z000000000000000000000000r000240001G000000000000000000000000000000 z000000002O000000000000000000000000b00000000000002$000000000000000 z00000000000000000000000000000000000000000001v00000000000001o00000 z000000000q0000000000000000000000000000000000000000000000000000000 z000000000000000000000002b0001F00000000000000000000000000000000000 z00000000000000000000000080RR9100000000000002@00000000000000000000 z000260002}000000000z000000002-0000R0RRB|00000000000001P000000000t z0001|0001~0000000000000000000000000000000000000000000000000000000 z0000=00000000000000000000000000001T000090001$0000000000000000001? z00000000000000_00000000000000000000000000000000000000000000000000 z000000002a000000000000000000000001(00000000090RR9100000000000002& z0000s0RR91000000000m00000000000000000000000000002M000000000000000 z0000000000000000002t0000000000000000000E0000N0000K0RR910000000000 z0002J0000000000000000001k0RR9100000000000000#0RR910001*0000000000 z000000000w0RRAW0RR91000000000x0RR91000000001E00000000000000000000 z000000000n0RRAz0000000000000000002Z00000000000000000000000000000? z0RR910000000000000000001>0RRB30RR9100000000000000000000000000001> z0000I0000o0000000014000000002P0000000000000000001B0RR910000000000 z000000002P0RR910000000022000000001U0RR910002A0002E0RRAZ0RR910002! z0002f0001Z0RRAT000000001z0002c0RRB=0000!0001&0RRBA0RR910000000000 z0000000000000150RRBp0RR910002f0RR910002c0000000000000290000000000 z0002X0000000000000000001X0RRB10RRBh0001R00000000000000|0RR9l0RR91 z00016000130000000000000000000000000000000000000000000000000000000 z0002)000000002|000000000000000000000001H00000000000002u0RRA~00000 z0001=0RR9100000000000001B00000000000002*0RRBS0RR91000000000000000 z0002A0RR9M0ssJ<0RRB{0RR91000000000Y0ssI2000000001A000000002O0RR91 z00000000240RR910000000000000000001n0RR9q0000000000000000000000000 z0000000000000000000000012000000002k0002w0RR910001C00000000000002} z0RR91000000000000000000000000000000000020ssI2000000002#0000000000 z0000000000000000001o0RR91000000000g00000000210000@0RR9b0RR910000F z0RRA70ssJr000000001%000140RR910000!0RR91000000001q0RRAJ0RR9100000 z000280000000000000000000000000000000000-0RRAG0RR9)0000~0000000000 z0002^0001;0RR9*0000000000000000000000000000300RR9U0RRB=0RRBo0001Q z0000P0RR910002g0RR9i000000000U0000V000000000000000000000002b0RRAb z0RR91000000001E0ssI2000000001O0ssIg0RR910001%0RR910001C0RR9G0ssI2 z0001P0ssI2000000001{0RR91000000000;0ssI20001G0ssI2000050RR910002G z0RR910000000000000000000000000000000000@000000000W000000001;0ssJC z0RR950RRA20002n0RR910001i0000O0ssJZ0ssI20000;0001m0ssI20000000000 z0001T0RR91000000000W0ssKY0RR91000000001*0ssI200000000000000000000 z00000000000002I0ssI(0ssI20001~0ssI20000000000000210RRBZ000020RR91 z0001Y0002N0RRBl0RRB$0RR910001S0RR9^0ssI200000000000002h0ssI200000 z00000000000000O0RRBO0ssI20002G0000000000000000000H0000Y0RRBD0ssI2 z000000000000000000000001h0ssI20000i000000001)0ssI20002p0000000000 z000000001K0ssJl0ssI2000050{{TQ000000001c0ssIL0RRAi0RR910000000000 z0001e0RR9n0ssI20000w0ssKT0002^0RRBj0ssIk0RR910001M000000001+0ssI2 z000000000000000000000000X0000l0RR910000)0RR9100000000230001u0RRBa z0ssIL0ssI20001q00000000000001E0RR91000020{{S;0RR910002j0ssK_0RRAz z0ssKt0RR980001T0ssI2000000000~0ssI2000000002>0ssK$0RR910002S0ssI7 z0ssI2000000000_0ssJ40RR91000000000x0002*000000001W0RR9U0ssJH0ssI2 z00000000130RR910002;000190RRA90RR9100000000170{{R30000~0RR910001# z0RR91000000001i0ssI2000000002r0ssII0ssIq0{{Sh000000000!0ssI200000 z000000000000000000000002a0RR9>0{{R300000000000000`0ssK*0002Y0RR9D z0000r0{{RD0ssI90{{S*0ssI20000000000000000000t0{{Se0ssI20002E0ssK^ z0001t0000t0RRB}0RR9(00000000000001Q0{{Sf000000000f0RR910002h0000K z0ssI200000000180{{TO00000000180ssJo000000001}0ssI30{{R(0000U0ssI! z0ssI20001H0ssIm0{{R30000000000000000001R0RR91000000002V0RRAQ0RRA& z0ssKq00000000170ssIe0{{R3000000000^0{{T(0ssI20000+0001S0ssJ;0001+ z0RRC000000000000000>0{{SC000000002H0ssI20001O000000001V0{{R30001^ z0{{R30000B0RR910002J0{{R30001W0001w0RR910002I0RR9A0ssIl0ssK$0ssJa z0ssI20002_0RRBM0ssK%0ssJF0001j0000D000000002U0{{R3000000000t0ssKQ z0{{TE0RRAJ0001o0{{Tf0ssI2000000000s0000%0RR910001c0{{Rz0{{R300000 z0000000000000000000S0ssI20001(0RR910001f0000000000000000000000000 z0000p0ssKw0ssIC0RR910000b0RR91000000002j0RRBm0ssI2000000000000000 z0000000000000000002P0{{R300000000000000A1ONa%0{{R3000000000b0{{T+ z0{{R30001l0{{S70{{TO0{{SU0{{Rk0ssJL0001T0{{R30000K0{{R3000051ONa4 z000000000*0ssJ00{{TT0ssKC0{{Rm0RRAz0{{R30001D0ssJC0ssJ)0{{T!00000 z0001d0RR9W0{{R30002L0RR91000000000#000000002S0RRBj0{{SQ0{{R-0{{R3 z000000001x0{{SO0ssJd000071ONa40000l0ssIq0ssI20000?0ssIg1ONaU0ssI2 z0002N0{{Tz0ssKB0{{RE0ssJd0RR941ONbr0000000000000000000&0RR9-0{{R3 z0002Q0000v0RR910001v0ssKJ0RRBv00000000030ssIN0{{R30001@0001<0ssIG z0ssI20002B0{{Tw0RRB}0{{R`0{{Sa0{{RM0000_1ONbt0ssKj0{{R30001(0ssJW z0ssI!0{{TG0ssIs0RRAV000060RRBK0ssJD0ssI@0RR91000000002M0ssIO0RRB2 z0{{Rc0000Z1ONb{0ssI%1ONcM000000000y1ONcM0{{RA0RR910000D0RR9100000 z0000?000000001e1ONa40000h1ONd40{{Sg1ONa40001w0ssKm0{{S=000000001R z1ONaP0001^0RRB@0RR910000R0ssJE0{{T{0{{Ro1ONbk0RRB?0{{R30001{0{{R3 z0002D0RRBA0ssI20001T1ONaU0002e0{{SG1ONbP0{{S^0ssI2000000002V00000 z000000002_0{{R30001p0{{R30002+0000B1ONbR0ssK|00000000281ONbS1ONa4 z0000i0{{Re1ONa40002d000120{{T20{{R;1ONb$0RR9l0ssI2000000000n0{{T# z0ssKy000000002W1ONcB0RRB-0ssJj1ONbr1ONbA0RRAw0RR9}0{{R3000000000+ z1ONbv1ONch0ssI20001}1ONb~0000{1ONb`0RRB|0{{R30001x0ssJ%000251ONa4 z0002|0ssJi0{{Te0ssKQ0ssIU1ONct0RR9100000000000002m0ssK!0RR9100006 z0{{R!0{{RK1ONa4000000001W1ONa4000000001&0000h0RR91000000001t0RRAu z1ONa40002e0RR9q0{{S_0{{RR0{{TX000000001i1ONbR0RR91000000001&1ONc? z1ONa40000G00000000000001=0000{0{{Td1ONa?0RR910002^0ssI$0{{Sk00011 z0{{Tf1ONby1ONa4000000001l0RRBh0{{Sg0{{R70000P1pol&0RR9N000000002w z0{{RL0ssI20000D0ssKJ1ONb60ssI20000e0{{TA0{{RA1poj50001f1ONcq0RR9C z1poj50002j00000000000001$0{{R?0ssI2000000000{0ssI200000000000002~ z0RR9!0ssI20002g0ssI20000*0RR910000$1pokE0ssI20001t0{{S-1ONa400000 z000180000g1ONbw1ONc%1ONb$1ONbD0{{T70{{T40ssI|0{{Rf1ONa40000}1poj5 z0001#0{{SF0ssI2000280RR91000000002K0{{R30002N1ONa40000p1polk0ssI2 z0000l000000000K1poke0ssI200000000100ssI20{{Sx0000v0ssIH1ONcB0000| z1ONa40000s1pokW1pojr0{{R^000300001$0ssI<1pojk0{{RR1ONc10{{R30000D z1ONb{0RRC00{{RQ0{{RT0RRA<1ONa|0ssIk1pojz0ssJn0001U1poj50001L1ONcC z0{{R30000d1ONd41ONa40002=0000r0ssK|0ssI20002~0ssK20ssIT1poj)0ssIJ z0ssJB1ONa40000z0RR9Q1ONby0ssK+0ssI20002-0RRAk0{{SP0{{S@1ONcu1ONcF z0ssI20001s0RRB%0RR910000s1ONcZ1ONa40001(1pokA0ssJK0{{R30001t0ssJ2 z0001O0RRBx1ONcX0RRBb0{{S800000000000001M1polq0{{Rq0ssJ<1polM1polc z0ssI20002v1ONa40002!1ONbJ0{{R30000$1ONbQ0RR9k0{{R3000000002A1pojM z0{{R30000)1poj50002F1pol_0ssI20002O1ONa40000$0RRAp1poj50002f0{{R3 z0001Q0RRBK1ONbb1pojt0RR910000o1ONa`1pol%1ONat0RRB11poj50000000000 z0001Z1poj;1ONbl0{{T41ONa}0RRBl0ssI<0ssKF0000A0{{S;1ONbu0ssI200000 z0000O000100RR9u1ONba0{{R30002q0RRB;0{{TH1poj50001_0{{R30002s1poj^ z0{{SY1pojV1ONcC1pojQ1poj50000$0{{T<0RR910000B0{{R30002C1poj51^@u~ z1polI1pokn0{{To0RR9?1ONcn0{{S41polm1ONb~0{{Sf1poj5000081ONct0ssJ+ z0{{RV0RRAw1ONc90ssJy1poj50000b1^@t>0{{Ra0ssIY1^@so1ONaI1^@ty0002} z0{{R3000000001D1poj50001P1ONay1pokK1pokv1ONa4000000000@1pok-1pok= z1poj%1pojB1^@t}0{{SN0000d0RR9e1pol70{{R&0{{R30000K1ONa&1^@sg0{{T) z0001n0{{R300000000000001!0ssIm1ONa|0RR9d0ssJ^1ONc{1ONcG1ONa40001^ z1poj5000030{{RD1poj50002X0{{SJ0RR91000000001%1polR0{{Tu0000^00000 z0002N1pok91^@tx0{{T<1ONbD1^@u#0RRAs0ssI20001A1polG0001l0ssKp0{{Tt z0ssI)1^@s_1^@u|1ONam1^@s6000000000v0000{1polK0ssI2000221poj;0RR9Y z1^@un1polj1poj5000000001m0RR9_1polI0{{S@1polx000241pol11poj60RRA6 z1poku1poj50001?1pojl0{{TO1ONbO1pok^1ONa40002}1pokp0ssI)0ssKz0{{S$ z0ssJN1pok61^@uq1ONaz0{{RY0RR9X1ONbj1pok@0000e1pol=1poj50000;1^@s6 z0001q1pokC1ONbs1^@sI1^@uB0RR9m0{{Tj1pojw1poj$1pojY1^@uz0{{Rs1ONa4 z0000v1^@s?0RRBx1poj50000G1^@tt1^@ux0{{R30001G1pojO1pojs1ONb61pok8 z0{{R30002$0{{R$1ONau1ONcG1^@sB1^@t*0ssJT0ssJU1^@ty0{{RL1ONc51^@uZ z1pok}1^@s600000000000001=0{{R3000000000U1pojO1ONc`1pok(0{{U01ONc( z1ONcs0ssJc1^@se0{{R30002F0{{S01polB0{{Sv1pokE1poje0ssJ51^@s60002> z0000F1polK0RRBf1ONc10ssIS0{{U01poj>1poj50001Y1^@sh1pok*0RRAx1ONb% z0RRAv0{{Rd0ssIU1^@tl0RRA11ONaV0{{SN0{{SR0{{S90{{R3000000002s0{{T0 z1polc1pol?0ssK>0ssI20000>1^@u91pojI1^@s(1^@t61^@s60001G1ONc^1ONa4 z000300ssK^0{{R{1ONai1^@te1ONcr1^@th1ONbb0002s1^@v10{{SE1ONa71^@tH z1polq1^@tb1ONa<1pokO0ssK01poj50000H1^@tY0{{S+0{{Th1^@u;1ONa400000 z0002M1pok*1^@to1^@u?1pol_0RR9%0ssI-1^@u{0RR9F0RRB30ssIB1ONaA0ssJ} z000251^@ss1pokC0RRAc1polc1^@tu0ssJ<0ssK*1polU1^@u=0{{R30002;0ssI@ z0ssI(1pojg2LJ%B1ONcq1^@s60002G1ONa40000d1^@u}0ssIF0{{T71^@s60002d z0RR9T2LJ%)0{{R30000^1^@ul1^@u21ONc#0ssI81ONbp1^@s)1ONa40000I0{{TQ z1^@uw000000000d0001Y1pol41ONa^2LJ&31pol11^@t$0000J2LJ%E1poj50002x z1ONbt1ONa92LJ%c1^@uG0ssKZ0RRBz0000(1pokU1poj50000S0{{T|1pojS2LJ#7 z0002y1pold1^@s@1^@s60001E2LJ#X1pokd2LJ#70000%2LJ$i0{{S-1^@t01pom0 z1pojd1ONa40000m1^@u%0RR9D1pojx0ssJc1pokN0ssJL0{{T$0ssJM1^@s>2LJ#7 z0000000000000000000000000000000002?ZU6ux01E(+odo~@0000B0RR910001C zGXel201E(p90vdZ0002c000000000v9svL%01E(OR|Wt80000R000000002l9svL% z01E(`R|Wt80000w000000000Gp#T6P01E)>`~?620000;000000001;X955s01E&# zFb4nt0000;000000002kRsaAZ01E&9o0000y00000 z0002y761Su01E&BMg;%>0001q000000002W4gdfm01E(7Qw0D30002W000000002z z_5lDQ01E(t_67g|0000v000000000rTLJ(g01E(HEC&Dp0000n000000000Hu>b%f z01E)HoCN>?0000W000000002~I{*M801E(YQUw420000R000000002`CIA4Y01*HP z0000000008000000002=0000Y01E)KE(HJp0000f000000002oF#-T001E&j=mr1) z0000R000000002{!2kdf000000000000000000000001H9{~U&01E&>4h8@K0000R z000000001!n*jhK01E(k)dm0n0000Q000000000Ih5!H}01E&KT0000v000000002}0|Edd01E)73I_lH z0000E000000002+9|8a(01E(K5eEPO0000c000000000zj{pE701E&x?gan<0000j z0RR910000|jsO5601E)Div<7x0002U0RR910000x6afGt01E(`LIwZ;0000E00000 z0000jnS-0002c00000 z0000Xb^rh(01E&NOa}k}0000j000000000B5dZ)p01E(oJp}*&0000@000000000I zcK`q)01E)dzy$yR0000M000000002V(EtD<01E(CBnAKg0000I000000000LP5=NR z01E(sg9QKp0000v000000000DCjbB<01E(rOa%Y{0001Q000000000`H~;`501E&r zZ3O@T0000W000000002TRR91X02Bad%qRc=0000O000000001V836zy01E*2Ltuo01E&tKn4H+0000s000000001g#Q*>z01E)zzy$yR0000|0000000025r2qgT z01E)y0R{j70000_000000002Yn*jhK01E(;)dm0n0000>000000000oJplkB01E)r zD+T}n0000k000000001oNdW*N01E&TqXqx~0002h000000001)BLV;-01E&F5(fYP z0000!0000000024kpTcA01E(Y&ISMg0000`000000002l1pojd01E(QHU$6x0000U z000000000|qW}OR01E&e{sjO40000F000000000YjQ{{501E)biUj}w0000E00000 z0000AZUO)z01E&CH3t9y0000E0000000016NB{sL01E&zSp@(90000c000000001T zi2(p201E&-WCj2L0000z000000001+JOKbA01E(Kp9TN`0000>000000001$odEzM z01E)h*9HIp00023000000000^Y61Wv01E)9G6w(v0001S000000001GdjS9v00000 z0000000000000000001&egOa?01E){zXkvR0000B000000000>OacHR01E((CIMJ+0000?000000001J2?78j01E(6*#-ar0000R z0000000009i2(p201E)T#|8iZ0002B0000000026fC2y_01E)#I0pa#0001K0RR91 z0001Lh5-N~01E&T#RdQX0000Q0000000007fdBv^01E&{+ywvt0001c000000001( z$^if(01E&t;syW!0000Z000000000t*8l(#000000000000000000000001hGXMZ0 z01E(BYXtxR0001E0RR910000;wEzGT000000000000000000000001oIsgD701E&n zQUw420000B000000000M3jhEj01E&rHw6Fy0000s000000000(^Z)=N01E(mGzI_w z00012000000002OUjYCj01E)lss;c60000W000000002tBmn>-01E*2Vg>*J0000@ z000000002CO9B8Q01E(bCKm`B*0000z000000002^Hv#}601E(8AqM~e0000E000000002u zd;tI=01E&HyaoUO0000(00000000080{{Rb01E&rF$Dks0000d000000002Y0s#Ob z01E(SIR*d#0000I000000001wJpcd_000000000000000000000002FcmV(+01E(0 zwgvzI0002l000000002DS^)qe01E(osRjT50000T0000000001%>V!*01E(2BL)Bf z0000V000000001!V*&so01E)oEe8Mq0000<000000000l1ONac01E&XGX($u0000i z0000000009XaN8s01E(-tOfu80000n000000002W8UO$y01E(ORs{e60001(00000 z0000#!vFvx01E)%yafON0000;000000002%(*Xb?01E)A501E(!JO=;(0000Y000000002k2LJ#f01E&L zQUw420000R000000002Ok^ulB01E&N&jtVh0000`000000001ZPyhfT01E)3hy?%u z0000E0000000030>j3~F01E)F$_4-c0000A000000002!rvLyV01E&%m<0d;0000B z000000001N1_A&g01E&M3kLuI0000Q000000002dGXMY*00000000000000000000 z0001KcK`q)01E)zzy$yR0000|000000001$0ssIa01E(gFa-br0000b0000000005 zxc~qn01E&p4+a1L0002<0RR9100021UjP6i01E)fmIVL+0001C0RR910000M9RUC$ z01E(oQ3e120001~1poj50002%2LS*g01E(HJO%&&0000g000000002zTLAzf01E&P zss;c60000W000000000{*8u<_02BZ?$|wK;0000u000000002XDFOf@01E)j01E)l+64dr0002F000000002MqyPXS01E&F{{;X50001300000 z0002uy8r+p01E(g83q6V0000J000000001qVF3Ul01E*2HwFLz0000#000000002v zWB~vo01E)Ds|El70000R000000000iIRXG801E(`?*;$>0000T000000001mF#rG} z01E)FX9WNN0000S0{{R30001%1ONac01E&#Gz9i_^E01E)3E(QPq0001c000000001JQUU-X01E()DF*-m0000U z000000002EF#-T001E)d8V3LX0000B0000000015xB>to01E&jP6q%00000g00000 z0001ZM*sjK01E(KSOow80001S000000002zLI40F01E(kR|Nn70000V000000001E z6951q02Bb|$|wK;0000e000000002UFaZD}01E(8l?DI+0000S0ssI20002cj{yK8 z01E)%YX$%S0000c000000001!&Hw-+01E(+BL)Bf0000B000000001bSpfhd01E&} zsRjT50000Q000000001JxdH$X02crt04V?f00000000000001iqyYdT01E(0pauW{ z0000t000000002`iUI&401E*6I|l#&0000K000000000hp8^0P01E&zLk9o=0000! z0000000004Gynh+000000000000000000000002mFaiJ~01E)98V3LX0000I00000 z0001PO#lEQ01E)hfCT^m0000v000000002DZ2$lw01E&%K-o)01E(6;syW!0000n000000002r0|Edd01E&t3I_lH0000W0000000016 z3;+Nk01E&lI0XOz0000O000000001_6aWAs01E)@L01E&~yaoUO0000E000000002)b^!n)01E&( zv<3hG0000x000000000lxd8wo01E&JsRjT50000#000000000xLIMCH01E)FB?kZi z0000@0000000021CIA2;01E&>Oa%Y{0000B000000001Y!TgZ0002U z0000000027AOHX&01E)vO9cP`0000R000000001&WdZ;q01E)LE(ZVr0000K00000 z0002ewEzGj01E&I4F&)J0000c000000002xg#Z8|01E)t0000000017kpciB z01E*2KnDN-0001J000000002!G6Dc101E)(8wUUY0000E00000000279RUC$01E(9 zR|Wt80000F000000000%CjtN>01E&h6bAqR0000K000000000lCIA2;01E*0O9cP` z0000R000000000OHUR)401E)@BL)Bf0000B000000000H6951r01E&#Lj?c;0000z z000000001ig8={{01E&}!3F>T0000(000000001#CjbBv00000000000000000000 z000127Xbhw01E&ZLk0i<0000<000000001L4*>uo01E)@KL!8*0000#000000000A zT>tj{pE701E)TN(TS{0000j z000000000_f&l;`01E()zy<&S0000)000000000?+yMY001E&;=mr1)0000r00000 z00026lK=oB01E&B@C5(>0000T000000002G)Byk@01E)P1|01E(E76$+T z0000c000000000L1pojd01E)5H3a|w0000i0000000013P5=NR01E)Rg9QKp0001d z0ssI20001n*Z=?`01E)hC}2i01E&E zJq7>(0000T000000001+5di=q01E(gKn4H+0000?0000000029$pHW&01E)5;RXNz z0000&000000001b0{{Rb01E)vF$Dks0001u000000002;0000Y z000000001uk^ulB01E({dpn01E)>Z3O@T0000{000000000Ug8={{01E&X z!3F>T0000n000000002mi2wj101E)p=LG-&0000<000000000LD**r^01E)7cLo3e z0002>1ONa400030G5`P)000000000000000000000002#5di=q01E)XKn4H+0000Y z000000001GngReK01E)hLI(f<0000I000000000ufB*m@01E)Oegyyk0000E00000 z0001rDgpo^01E&Ny02Ba# z%qRc=0000O000000000I;Q;_501E*4>;?b;0000E000000000yFaiJ~01E)P7Y6_U z0000?000000002dTmS$f01E)4X9WNN0000B000000002!Gy(u301E*49R~ma0001a z0ssI20000vUIG9j01E)>EC&Dp0000U000000001Ka{&M%01E(cLk0i<0001W0RR91 z0000|*#Q6|01E&{<^})&0001F000000002DHvj-401E&jPz3-00000h000000000_ zE&u=$000000000000000000000002LNB{sL01E(qSp@(90000Q000000001FQUCxV z01E(GiUj}w0000?000000000F^8o-N01E&N^9BF_0000%000000002~F9HA}01E(r z7Y6_U0000v000000002OrvU&W01E&>p#}f|0000#000000001Ji2wj101E(i=LG-& z0000f000000000EdI10;01E&BxCQ_K0000v000000002qp#cCQ01E&d*#-ar0000Q z0000000002YXSfw01E*AGY0?w0000@000000002OU;zLU00000000000000000000 z0001UNC5yM01E)nq6Po}0000Q000000001)cmV(+01E&RMFs!>0000R000000001g zsR95Z01E&%Mh5@@000100000000016kN^N801E)}jRgPz0000f000000001^fB^s! z000000000000000000000001}Kmh(^-01E)TO9cP`0000R000000000mz5xIt01E(S-Ua{w z0000^000000002J_W%GQ01E(9HU;(V-0000k000000002d4FCWV00000000000000000000 z00022tpETb01E(En*{&>0000j000000000-e*gd?01E){+XVms0000?000000000^ z(*Xb?01E(n? z0000}0000000030i~;~601E)JJqG{)0002s0000000026WB>pX000000000000000 z000000002vh5-N~01E(s#RdQX0000~000000001u?EnBG01E&TGX?+v0002y00000 z0001eTmb+g01E)9HU0000c000000001gI{*M801E(O zZUq1U0001G000000002DG5`P)000000000000000000000000u+5rF}01E*A<^})& z0001*000000000>aRC4#01E)ovIYPE0000I000000001ej{*Q901E){J_i5*0000n z000000000?vH}1i01E)TN(TS{0000j000000001u+yDR~01E)FDh2=m0000_00000 z0000CvH$=g01E)(oCN>?0001D000000002_0s;Uc01E)F2?qcG00010000000002p zAprm)01E)*4h8@K0000R000000001Gy8r+p01E(m7X|z01E)PO9ub| z0000j000000001-D*^x_01E&@d0000Y0000000006d;tI=01E)fy9NLN z0000!000000002lcK`q)01E&v!36*S0001}6#xJL0000|0000Y000000000000000 z000000002W8Ug?!01E)y4+j7M0000?000000000ysR95Z01E&dMh5@@0000Q00000 z0001kw*UYl01E)D4h8@K0000E000000000aF#rG}01E(2X9WNN0000?0000000024 zPyhfT01E(Chy?%u0000?000000002yt^xod02Bb|%P0T<0000O000000000M7XSbf z000000000000000000000002Vo&o?O01E&lLk9o=0000E0000000007;sF3601E&H z?FIk<0000*000000002n#sL5#01E(e;06Ey0000Q000000000bv;qJj01W^jxCa0L z0001L000000001OcmMz*01E)t)&&3n0000?0ssI20001_iU9y301E)P$_4-c0001M z000000002NYXJZv01E&xt_A=A0000;000000000$0RaFa01E)RI0gU!0000W00000 z0001V?*RZJ01E&<@df|@0002n000000002legXg@01E*4DF*-m0000c000000000o zTmS$f01E)zlLY_(0001b000000002W0000Y01E($E(HJp0000f000000000Pr2qgT z01E(){{;X50001C000000002J-2nh101E){zXkvR0000B000000002cI{^S901E)s zo(2E_0001Q000000002n9{~U&01E&JTLu6C0000R000000002&g#iE}01E&B#RdQX z0000H00000000302>}2i01E&hJq7>(0000n000000000wa{>S&01E*ACI=K00012000000002G!~g&y01E)ny#)XO0000u000000001mAOZj) z01E(w5eEPO0000f000000001{oB;qL01E(e*9HIp0000V000000000`gZ0000W000000001}V*mgm01E)9Z3O@T0000E000000002% ztO5Wc01E(DNe2J`0000E000000001}p#lIR01E)HL00010000000000n9033# z01E)9Mg{-?00026000000000790C9$01E(y5C;GN0000n000000001E82|tx01E(6 zM+E=?0000V000000001fvjPAj01E&NOa}k}0000j00000000201E&jz6JmQ z0002m000000000o)Bpe?01E&N-30&u0000)000000002{0{{Rb01E){G6ett0000b z000000001eIspJ801E&Zo(2E_0000n000000002t=K0000V z000000002eQ2+oU01E(mi3I=v0000E000000001=&jA1;01E)XvjzYF0000V00000 z0000cE&%`{01E(?j0OMz0000E000000000;5&-}r01E)X1qJ{B0000Q000000000b z3;_Tl01E){{{;X50000)000000000heF6X?01E(0001M000000001)m;eAG01E)dkOcq$0000Q000000002>I{^S901E)5 zo(2E_0000W000000001C8UO$y01E(cM+E=?0000R000000000N8~^|!01E&-R|Nn7 z0000y000000002`;s5|501E)PECv7o0000r0000000008GXMY*000000000000000 z000000001Q+W-I}01E)1=LG-&0000c0000000021eE|R>01E)}y#@dP0000m00000 z00012FaiJ~01E&F7zY3V000180ssI20002(L;wIH01E){R|Nn70000h000000000S zhX4Q~01E*AN%01E)_;06Ey0001v00000 z0002YxBvhm01E)#palQ`0000R000000001_F#rG}01E)hY6SoQ0000Y000000001} zZ~_1#01E(lHU|Iz0000j000000001SQ~&@X01E(gjRgPz0000M000000000=Z2|xy z01E)nGzS0x0000n000000001zT>=0i01E)nEC&Dp0000Q000000002m0|5Xc01E)T zIR*d#0000E000000002El>q=E01E(!(FOnj0001*000000002klmP%D01E(A&;|ei z0001*000000000_paB3P01E)L*aiRq0000^000000001^RR91Y01E(QO9ub|0000j z000000001~*Z=?$000000000000000000000001?asdD$01E(|vjzYF0000Z00000 z0002>0RR9Z01E(3Pz3-00001>0RR910002`6#)Pt02BbQ%P0T<0000u000000002D z90C9$01E(S-Ua{w0000^000000001<=l}pB01E(mE(QPq0000A00000000257XSbf z000000000000000000000000cr2zmU01E(upauW{0000R000000002D1^@se01E&n zQUw420000B000000001qt^xoe01E(?Ne2J`0001D000000000fp#lIR01E&}KL-E+ z0000Q000000000e)&Kw^01E)ZCk6lj0000I000000002itpWfd01E(XN(TS{0000{ z000000001f7ytkw01E&VM+E=?0000V000000000oaRC4l00000000000000000000 z0001YW&!{r01E)fE(ZVr0000E000000000)B>(^-01E)1O9cP`0000R000000001; z(E$J=01E&Y?~; z01E&_V+H^K0001F000000001sCIJ8<01E)rWCj2L0000e000000002MSpWbc01E(Y zkp%z%0000N0RR910001C0000Y01E)>Ed>Ao0000T000000000ZH~;`501E*8Tm=9C z0000c0000000012IROA701E(4ody5^0000c000000001)SO5Sb01E)%kOcq$0000T z000000001PEdc-`01E&Bj0OMz0001K000000000?5di=q01E(OKn4H+0000I00000 z0001PLjV9G01E(^R|Nn70000R000000000EasdDm000000000000000000000000R zfC2y_01E)jI0pa#0000I000000002_2mk;g01E)tHU$6x0000R000000000Gf&c&_ z01E(&-30&u0001`0{{R30001lS^xkd01E)nk_7+&0000f000000000G2m$~i01E&= z3kLuI0000Q000000002~>Hz>E01E)@?*;$>0000Q000000002A0096Z01E(!I0gU! z0000n00000000270ssIa01E(`Fa-br0001A000000000%!~g&y01E(^y#)XO0000u z000000002mTL1te01E)TlLY_(0000W000000002+7yz`F01E)oHwOR!0000Q000000001s=K%mB z01E)d?*;$>0000F000000001a6aoMu01E&{4hH}L0001N000000000hwgCVl01E&X z+y(#u0000Q000000002xX8-^q01E&TZv_AV0000`000000000Kt^oid01E)x+6Djs z0000Q000000002I0|Edd01E(J3I_lH0000<000000002>EC2u^01E(!Uj+aF0000W z000000001WmjM7G01E){(*^(l0001*000000000q4gdfm01E(AIRyX!0000s0RR91 z0000@#{d8#01E(4AO-*c0001a0RR910001ZQvm=X01E(mGzI_w00012000000002z zA^-p)01E*2S_J?A0000R000000001u3jhEj01E)2Hw6Fy0000I000000001NqX7US z01E(0pauW{0000t000000000>Jpcd_000000000000000000000002`V*&so01E)1 zEe8Mq0000W000000002QfB^s^01E(rzy<&S0000E000000002*NC5yM01E)>q6Po} z0000d000000000dmH_}F01E&j(gpwk0001*0000000005KLP+E01E)rBL@Hg0000r z000000001Rpa1|O01E(&_XPj|0000(000000001ClmP%D01E)Vjs^e#0000E00000 z0002QvjPAi02Bbo%qRc=0000O000000002#CIA4Y01*HH00000000040000000019 zCjbB<01E(uTLl0B0001*000000002{!vO#y01E((-v$5x0000Q000000000ahyVa0 z01E)g<^=!%0000_000000001!6#xJt01E&pMFju=0000c000000002F9svL%01E(q zR|Wt80000R000000001>9svL%01E(04F&)J0000R000000001q!T|sx01E(F-v$5x z0000Q000000000q5dZ)o02BaV%P0T<0000e000000000+ivj>501E&PJO=;(00012 z000000002ZZ2|xi000000000000000000000001ds{jBZ01E&@2L=ED0000Q00000 z0002`%K-o)01E(u;syW!0000?000000001OG5`P~01E&dSOow80000q0000000023 zQvd)W01E(Yiv<7x0000$000000001!O922P01E&{qy_*00000_000000002lfdK#_ z01E&WT?POE0000E000000000#q5=RS01E&VMF#)?0000s000000001$p8)_O01E)P zp9TN`0000#000000002$GXel201E(5>;?b;0000E000000000^jsgH801E)7J_i5* z0000j0000000029O#lEQ01E&Ffdv2n0001d0ssI20001`hyeg101E)J#s&ZY00009 z0RR910002!V*mgm01E&dnFRm<0000A0RR910001nZ~*`!01E(ivIYPE0000;00000 z0002D+5rF}01E)n=LP@(0000s000000001>4gmln01E&R0|o#90000E0000000004 zasU7#01E&pbp-$b0000V000000002n4FLcm01E)7KL!8*0000h00000000121pojd z01E)nH3a|w0000m000000001gDggi@01E)Has~hZ0002>1ONa40002(R{#Ja01E)D zkOcq$0000Q000000002dOaK5P01E(8fCT^m0001G000000000x1pxpe01E(WItBm$ z0000@0000000030%K!i(01E(6*#!Uq0000R00000000036#xJt01E)@LPyC z01E(wE(QPq0000U000000001=NdN#M01E(Eegyyk0000T000000001(5&!@q01E)R zK?MK+0000z0000000016A^-p)01E)vS_J?A0000T000000000KPyzrV01E)14F>=K z00012000000001tbpQY&01E&Jz6AgP0000_0ssI20001|hynm201E&JEe8Mq0000T z000000000N@&N!M01E)i@&*6^0000%000000002g6aWAr02Bb2$|wK;0000e00000 z0000zfdK#_01E(dzy<&S0000E000000002kCISE=01E)I69)hQ0001Q000000000L zCIA2;01E)vO9cP`0000R000000001KC;$K=01E&dTm=9C0001c000000000hngIYJ z01E)7)CK?m0001G000000000ew*mkn01E)rO$Pt~0000Q000000001-y#W9s01E&- zss;c60000#000000000v-~j+401E(K>;?b;0001*000000001yQ2+oU01E(Ii3I=v z0000T000000001}Yykiw01E(~t_A=A0000k000000002L*8u<`01E)f$_h01E)tHUe)+01E)- z;|2f#0000d000000001VX955s01E&}F9!es0002&000000001aF#rG(0000000000 z00000000000000SF9HA}01E&M7Y6_U0000y000000000yt^fcc01E)dn*{&>0000B z000000000`yZ`_q01E&RO9ub|0000j000000001EX8-^q01E)xZUq1U0000R00000 z0001UtpETb01E&@n*{&>0000M000000000Xu>k-g01E&>+Xest0000c000000001* z0000Y01E&JE(HJp0001C000000002`?*RZJ01E&b@&*6^0000r000000001?sQ~~Y z01E)(*#-ar0000Q000000000!R{#Ja01E(UkOcq$0000f000000001E4*&on01E*A zIt2g#0000z000000000#00ICa01E(c2?qcG0000R000000001e1ONac01E)XGX($u z0001V000000002oZvg-z01E&jvIYPE0000c000000000P(E$J=01E&NgZ0000Q000000002!paK9Q01E(gKL-E+0000y000000002XVgUdm01E(K zs|El70000Q000000002;3jzQl01E)u3kLuI0000Q0000000000(EtD<01E*4BL)Bf z0000V000000002s#Q^{!01E)#-v$5x0001U000000000dIRO9?000000000000000 z000000002z{r~_X01E&%I0gU!0000Q000000000JQUCxV01E(!i3I=v0002e00000 z0000skN^N801E($jRgPz0000q000000000I3;+Nk01E)_Hw6Fy0000s000000001d zAOHX&01E&wNd*7^0001X000000001!v;qJT000000000000000000000000KQ2+oU z01E)Hhy?%u0000R000000000)5&!@q01E(pKm`B*0000y0RR910001VaRC4l00000 z0000000000000000001n7Xknx01E&%4+j7M000120000000027PXPcT01E&Zrv?B3 z0000I0000000000hXMd101E(cI|l#&0000T000000000^AOHZN02ly}0Vx0g00008 z000000001a*8l(_01E&{Cn++ z01E(X*#!Uq0000c0000000022VE_Ok01E)PYy|)S0000R000000001}UI73i01E(? zss;c60000Q000000002_r~m*W01E(!0|o#90000v000000001ebO8V&01E*7vjzYF z0000z000000000NlK}uC01E(>h6Vrt0000E000000000M0000I01N<3P6q%000000 z0000000030AOZj)01E&D-v$5x00012000000002mHUa=501E)VAO`>d0000;00000 z0001ys{sHa01E&p+6Djs0000E000000002s9RUC$01E&v4F&)J0000R000000000= zF#!M~01E(amj(a;0000S0ssI20000*9RL6#01E(INCf}@0000f000000000mGXel2 z01E&}90vdZ0000r0000000029H2?r201E)JPXzz~0000R000000000F4gdfm01E)# zI0XOz0001X000000001AHUI!301E)lPXzz~0000R000000001$$p8Q%01E(`A_f2e z0000g000000002ySOEYc01E)9H3k3x00012000000002WHUR)401E(YoCW{@0000g z000000000?RsjGa01E(Ss0IK40001U000000001y_yGVS01E(c`33+00001a0ssI2 z0000TY61Wv01E(fG6w(v0000r000000000Pi~;~601E)rJO=;(0000;000000000@ z*Z=?`01E)TCKmY(D01E($a0LJW0000R000000000`1Ofme01E)7 z*aiRq0000E000000002yIRF4601E(CZUq1U0000B0000000016uK@re01E)xqy_*0 z0000E0000000011=>Y&D01E(W#s&ZY0000-000000001ZcL4w*01E)%vjzYF0000R z000000001rEdc-`01E(`iv|Dy0001G000000001NH~;`501E(EZ3O@T0000`00000 z0002{yZ`_q01E)j83q6V0000#000000000=oB{wM01E)LItKs%0000F000000001p z1_1yf01E)`A*0001Z z000000000RDF6T>01E)jQUw420001m00000000249033#01E(EM+N`@0000Z3IG5A z0001$cLD$+01E(qHwOR!0000T000000000C_yGVS01E&%`33+00000v000000002I zLjV9G01E)LR|Nn70000x0000000028wEzGj01E)-o&^8^0000?000000001S#Q^{! z01E)a-v$5x0000Q000000000(+W`O)000000000000000000000000Ba{&M%01E(N zLk0i<0000E00000000184gdfm01E(*R0RM40002W0000000002xB>to01E&VP6q%0 z0000E000000000o76AYv01E(e2nGNE0000T000000001;RssMb01E&%4+j7M00012 z000000001=-T(k101E(4D+T}n0000E000000002yZvX%y01E(gbOita0000)00000 z0000dUjP6i01E)@Y6SoQ0000E000000002b9RL6#01E(|NCf}@0000M000000002b zJ^%nB01E&Xa0LJW00012000000002%e*gd?01E(`egyyk0000T000000002FK>`3G z01E(MB?kZi0000@000000001;5CH%p01E&H1O@;A0000E000000001X69E7s01E*8 z1_l5C0000+000000002il>h)D01E&X@&y0@0000j0RR910002^1pojd01E(uHU$6x z0000t000000000#hXDX001E&t#RdQX0000}0000000007c>(|;01E)AHwOR!0000Q z0000000017dIA6<01E&HI0pa#00010000000000g6aWCB01W_ix(5IN0000100000 z0001U)c^n@01E)bB?bTh0000I000000002(UH||h01E(@mIVL+0000n000000002@ z_y7PR01E)9H3k3x00012000000002s&H(@-01E)G zOa%Y{0000B000000000{0s#Ob01E)xI0gU!00016000000001fe*yp^01E&vDhB`n z0000Q000000001gJpcd_000000000000000000000000{X#xNu01E(8F$Vwu0002o z000000001>o&o?O01E&PJO=;(00012000000002oG64W001E&lBL)Bf0000B00000 z0001khX4Q~01E&R<^=!%0002F000000000lEC2u^01E)%Uj+aF0000Q000000000) z5CH%p01E)Z0|o#90000)000000001Y+yMY001E(e=mr1)0002c000000001kdH?_- z01E(-*#!Uq0000k000000002zlL7!D01E&vLI(f<0000E000000000&XaWEt01E){ zFb4nt0000E000000002mJpceA01E(`Zv_AV0001c000000002A>;V8G01E&@@CE}Y01E)_rv?B30000Q0000000007&j0`-01E)z*#!Uq0000R z0000000005x&Qzo01E*269xbP0000I000000000{E&%`{01E)5j0OMz0000Q0ssI2 z0001CTmk?h01E)P5C;GN00012000000002tJOBU^000000000000000000000001j z$^ZZ&01E)_A_f2e0000g000000000gw*UYl01E(`palQ`0000)000000001%k^%rC z01E)dK?eW;0001J000000000e=>Y&D01E(2#s&ZY0000U000000000?v;Y7i01E)a z3I+fG00011000000001<0{{Rb01E(SG6ett0000#000000000ui~s;401E(v=>-4) z0000_000000000@eE|R>01E(DyaoUO00025000000000&IsgD701E&LQUw420000R z000000000-F8}}{01E)PUt=4B0001-0ssI20000MDFFZ? z01E&{Yz6=T0000T0RR910002QmH+@E01E(s^929^0000j0RR91000044FLcm01E){ z{{;X50000)000000000MLI40F01E(WaRmSX0000a000000001hZvX%y01E(|o&^8^ z0000k000000001%Edl@{01E)f(^-01E)TO9cP`0000R00000 z0000n(*OV>01E)Z+ywvt0000y000000001AkpKW901E(K?*#w=0000b0000000013 z?f?KH01E*4GX?+v0000v000000000?8v+0#01E&p5C;GN00019000000000tK>`3G z01E&TB?kZi0000@0000000023ivj>501E(SJO=;(0000Y000000000-4*&on01E($ zIt2g#0001V000000002GnF0VJ01E)PLI(f<0000I000000002WS^@wf01E&p5C;GN z00019000000000hhyeg101E&R#s&ZY0000c000000002n0RR9Z01E(wF9iSq0001D z000000000U761Se000000000000000000000002;X#xNu01E&@G6w(v0000n00000 z0001GxBvhm01E(I4h8@K0000`000000001P9smF$01E)-NCf}@0000W000000002G z@&N!M01E)T&ISMg0000`000000001C2LS*g01E&IJO%&&0000~000000000bWB~vo z01E(;s|El70000Q000000000?9RdI%01E)P5C;GN00012000000002CWdQ&p01E)f zs|El70000Y000000000Ziva*401E&u%LV`d0001M000000002Dod5tL01E(g_5}a{ z00012000000001-4)0000Q000000001?8UO$y01E(&M+E=?0001P z000000002Y*#H0{01E(*DFy%l0000Q000000002g;{gC701E(~?gjt=0000(00000 z0002_Apigp000000000000000000000000}CjkH=01E&-WCj2L0000z000000001# z9s&R&01E&q5eEPO0000Q0000000030IROA701E)3ody5^0000Q000000000<76Jew z01E)t4hH}L0001A000000000@e*yp^01E&fDhB`n0000F00000000180ssIa01E(0 zFa-br0000g000000000X+W`O~01E)}xds3L0000s000000002_AOHXo0000000000 z00000000000001y+W-I}01E)}DFy%l0000F000000002oPyzrV01E(CDF*-m0000U z000000001yaRC4#01E)^vIYPE0001D000000001>B>(^-01E&*TLl0B0000v00000 z00002=m7vC01E&%#s&ZY0000M000000002#p#T6P01E)n_XPj|0000P1poj500019 zN&)~P01E&hC01E&(v<3hG0000x z000000001#4gdfm01E(FRRsV50000-000000001^0RjLb01E(`2?qcG0000K00000 z0002|d;kC<01E)z*#!Uq0000R0000000010E&u=`01E)(P6Yq}00017000000002c zeEEd>Ao0000T0000000013h5!H}01E(K1_uBD0001a z0ssI20001NMF9XJ01E)Lp#}f|0000T0000000007^Z@`O01E(3^9BF_0000%00000 z0000KG6Dc101E&H8wUUY0001S0000000008NdN#M01E(qSp@(90000Q0000000028 z^8o-N01E&N&jtVh0000`000000001I0000~000000001E6#xJt z01E&LMFju=0000T000000002(qyPXS01E(I{{;X50000n000000000%ECB!_01E)1 zfd&8o0002>1ONa400006A^-p)01E&_N(BG_0002&000000001-9{>O%01E&VNd*7^ z0000R000000002aB?15<01E&K69)hQ0001}000000002u4*&oX000000000000000 z000000000SaRC4l0000000000000000000000006Dgpo^01E&BHq*D01E&&@C5(>0000H000000002*Y5@Qu z01E)*tp)%90000Y0000000024tO5Wc01E&(Ne2J`0000H000000000?!2kdv01E(O z9R>gZ0000H000000000lvjPAj01E)PO9ub|0000j000000002C6#@Vv01E)b4hH}L z0000I000000001jxB&nn01E*6s0IK40000E000000002;aRC4l000000000000000 z000000001mvj6}h01E(Oodo~@0000k0000000006JpceA01E&)U9o0000y000000001o(f|M=01E(+BnAKg0002h000000002?mI44G01E(I zI0pa#0000T000000000(-2nh101E(!>IMJ+00025000000000#o&f+N01E(;*aiRq z0000K000000002>t^fcc01E)N2nGNE0001^000000001S&jA1;01E(6vjzYF0000h z000000000;asmJ%01E)VCIt@g02BZa%qRc=0000O000000000#+yMY001E&j=mr1)0000R000000001b z)&Kw^01E)rCk6lj0000h000000001=NB{sL01E&zSp@(90000c000000001p6951r z01E(dLj?c;0000y0RR910000~H~|1601E)tB?bTh0000)000000002nU;zLU00000 z0000000000000000000T+W-I}01E)*DFy%l0000E000000001cx&Z(p01E&D-39;v z0000Q000000001XN&x^O01E)0000000021IROA701E(gody5^0000k z00000000251ONac01E(8Gz91|01E(q76$+T0000Q0000000020 zn*snL01E)zLI(f<0000E000000002!ssR8Z01E&X+6Djs0000I000000000gA^-p) z01E)NS_J?A0000Y000000000iu>t@h01E(=O$Pt~0000#000000000>Spone01E(U zD+d4o0000f000000002cBmw{;01E(e;06Ey0000Q000000002AbN~P%01E)3wgmtH z0000n000000001&wg3Pk01E&v4F&)J0000R000000002cUH||h01E(1mIVL+0000? z000000001<4*&on01E*AIt2g#0000z0000000016WC8#p01E(Q6bAqR0001z00000 z0002mHUI!301E)>PXzz~0000R000000002Q#{d8#01E)fAqD^d0000Z000000000c z-T?q201E&J>;?b;0000Z000000000cqXGaT01E(cLk9o=0000Q000000002Sk^lfA z01E)X?*#w=0000Y000000000YQ2+oU01E&ri3I=v0000n000000001HeE0000B00000 z00014)d2t^01E)Pv<3hG0000R000000000zi2?v301E)8I|l#&0000E0000000007 ztpWfd01E(RNe2J`0000n000000002;A^`v*01E(=Tm}FD0001i000000000pJOKbA z01E&_p9TN`0000Q000000000?R{{Vc01E&TD+d4o0000U000000001s4FCWl01E)# zI0XOz0001X0000000001aR2}!01E(`palQ`0000)000000001&R{#Ja01E(;kOcq$ z0000Q000000001(jQ{{501E&>>IDD*0001d0ssI20001%P5}TS01E)prUn220000h z000000001dq5uFQ01E(={RIF30000)000000000BHvj-401E&HPz3-00000R00000 z0000CA^`v*01E(sTLu6C0000R000000001O76AYv01E(+2nGNE0000c000000002s zMgRaJ01E(KSOow80001S000000001-qXGaT01E(!MF#)?0000Y000000000)ZUF!y z01E&Mu?7GD0001Q000000000bi~#^501E)R%LV`d0000T000000002@H~|0>00000 z0000000000000000000kE&u=$000000000000000000000000?V*mgm01E(0Z3O@T z0000E000000000`0{{Rb01E(?F$Dks0000&0000000014PyhfT01E)3T?GID0000M z0RR910000YrvU&W01E&zp#}f|0000E000000002}+5rF}01E)%xds3L0000H00000 z0002p#sB~!01E&HAO-*c0000;000000002xzyJUu01E)J90mXY0000~000000001) zc>(|;01E)aHwOR!0000E0000000010X8-^q01E)Hhy?%u0000R000000001H<^TX9 z01E)DEd~Gp0000r000000001EEC2u^01E*6Uj+aF0000Y000000002hxd8wo01E)L z+y(#u0000^000000002YNdN#M01E(iegyyk0000Z000000002q3jhEj01E)tHw6Fy z0000N000000001x*#Q6|01E)*<^})&0000Q000000002Fv;qJj01W_;xCa0L0000O z000000001$LjV9G01E(^R|Nn70000R000000000z*#H0{01E(KDFy%l0000n00000 z0002t2m$~i01E(G3kLuI0000B000000000JM*#pL01E)}p#}f|0000I000000002? zRsjGa01E)xs0IK40000W000000000GaRLA$01E)7HU|Iz0000c0000000006+5rF} z01E&KLG$D z01E&TpauW{0000Q000000000BRsaAZ01E)dVg&#I000250RR9100030ZvX%y01E&z zp9KH_0000E000000000vJpcd_000000000000000000000000~NCE&N01E);CkFrk z0000Q000000002QQ~&@X01E(ijs*Y!0000e0RR910001_&;bA<01E)%vjzYF0000R z0000000015aR2}!01E)PbOita0001C000000002N-T?q201E&t>;?b;0000Z00000 z0000~uL1xf01E(MOa}k}0000z000000002L+W`O~01E&H=mr1)0000R000000000P zoB;qL01E(m)&>9o0002j000000001}76AYv01E(cLk0i<0001W0RR910001XDF6Tx z000000000000000000000001J!vFvx01E)%yafON0000;000000002Xg8%>`01E&* zfCT^m0000B000000002+1_1yf01E)rI|cv%0000p000000002>kpciB01E(KK?eW; z0001J000000002G+W-I}01E)d=LG-&0000B0000000010p#lIR01E(OKL-E+0000H z000000001UYytox01E(gGzS0x0000&000000000Y6#@Vv01E)J4hH}L0000I00000 z0001iMgagK01E&Fq6Po}0000I000000001)9RL6#01E(yNCf}@0000M0000000027 zQUCxV01E)7iUj}w0000U000000002E761Su01E)xMFju=0000c000000002X{{a9Z z01E&N)dm0n0000R000000000zHUR)401E&>oCW{@0000U000000001{w*mkn01E)_ zO$Pt~0000c000000000y0ssIK000000000000000000000000^`T+nU01E({{ssU5 z0000v000000000UIsyP901E(MAqM~e0000h000000000v_5lDQ01E&J^acO`0001a z0ssI20001o<^cdA01E(`?*;$>0000T000000000kIspJ801E)Tody5^0000&00000 z0002$wE_Sk01W^jx(5IN0000T000000000GPyhfT01E&(hy?%u0000U000000000U z69E7s01E)^1_l5C0000E000000000G0000I00;nZNdy1@00000000000000*IRF46 z01E(0ZUq1U0000B000000002SX#xNu01E&vG6w(v0000K000000000p(g6S>01E&@ zuo01E&f0|o#90000+000000001e5C8xY000000000000000000000002? zjQ{{501E(Yiv<7x0000$000000000K%>e)+01E)3;|2f#0000V000000002iP5=NR z01E&%h6Mls0000}000000000Sg8%>`01E(S;spQz0000v000000002cng9SI01E&{ z_5}a{0000k0000000007#Q*>y02BaF%qRc=0000O000000001+I067701E&&AqM~e z0000Q000000001ZCISE=01E)-;RXNz0000E000000002*kN^N801E(C@C5(>0000y z0000000027L;?UJ01E)F2?qcG000100000000006zySav01E)<-Ua{w0000Q00000 z0000t&Hw-+01E)X*#!Uq0000R000000002MdjbF=01E&xDF*-m0000c000000002g zZvp@!01E&OHU|Iz0001N000000001$MF0RI01E($as>bY0002A000000000WF8}}% z01E(0yaWIM0001$1poj50002wNB{sL01E(ESp@(90000c000000002;djJ3;01E*3 z*#!Uq0000c000000001$A^`v*01E(aTm}FD0000c000000002M-vIz301E&{&;|ei z0000E000000002<5CH%p01E)Z0|o#90000)0000000024IRXG801E)t?*;$>0000M z000000000;odEzM01E)N*9HIp0000K000000002JLIMCH01E*8B?kZi0001U00000 z0001qm;nGH01E($)CK?m0000R000000001WzX1Ru01E)l-Ua{w0000Q000000000{ zga7~{01E)R;spQz0000I000000001|Hvs@501E)tB?bTh0000)000000000HeE|R> z01E(qR|Wt80000R000000001tfdT*`01E&|ItKs%0000Q0000000022PXGWS01E)@ zhXnut0000?000000001@egFU>01E(z+XVms0000_000000002nCIA2u0000000000 z00000000000002tz5oCs01E)Z8U_FW0000!000000000_D*yl@01E&BUj+aF0000? z000000002lG5`P)000000000000000000000000J+yDR~01E&CDh2=m0002300000 z0000{vH<`h01E)1rv?B30000E000000002$CjbBv0000000000000000000000027 zumS)g01E&FO$Pt~0001w000000000M9{>O%01E&VNd*7^0000R000000000INB{sL z01E)beFXpj0000?000000000&odN(N01E)>LI(f<0000E00000000084*&on01E($ zIt2g#0001V000000001BLI40F01E(kR|Nn70000V000000000+MgjmL01E)1CkFrk z0000f000000002$>Hq*D01E(;@C5(>0000E000000001V=KugA01E)(Ed~Gp0000? z0000000026cme<-01E&{CHq*D01E&}@C5(>0000E000000000mssaEa01E(qM+X1^0001? z000000001bwE_Sk01W_;xd#9M0000V000000002O@c{rL01E(Y&ISMg0000`00000 z0001JiU0s201E(h=mh`(0000n000000002sC;$Kw01E(IsssQ40001I000000001T z0s;Uc01E&f)&>9o0000H000000002xu>t@g02BZy%qRc=0000G000000001W0000H z000000000000000000000000x0|5Xc01E(kIR*d#0000(000000000>MF0RI01E&d zSOow80000q000000001sc>w?-01E(2w*~+J0000n000000001f9RUC$01E&mR|Wt8 z0000k000000002IhyVa001E&@=LG-&0000Q0000000015g#Z8|01E)7;{^Z!0002& z000000001p1pojd01E)nH3a|w0000m000000002BKmq_F01E)bBnJQh0000@00000 z0000#fB^s^01E&(zy<&S0000B000000001RasU7#01E&pbp-$b0000V000000000K z1ONac01E&XGX($u0000i0000000023c>w?-01E(qw*~+J0001j000000002VCIA2; z01E(1Oa%Y{0000q000000002(mjD1F01E(;kOcq$0000Q000000001xumAue01E&< z3I+fG0000E000000001u;sF3601E(2?FIk<0000T000000002hJpuqC01E(SBL@Hg z0000t000000002n%mDx*01E(I;|2f#0000Q000000002T$N>N%01E(?;RXNz0000E z000000000j0s;Uc01E)#)dm0n0000c0000000012G6Dc101E(;8wUUY0000E00000 z0000sr2+sV01E&%Mh5@@00010000000000u*Z}|{01E)_0000@000000002A$N&H$01E&d zA_f2e0000h000000000fl>z`F01E&-LI(f<0000E000000001W4FLcm01E(GKL!8* z0000?0000000004GXel201E){8wUUY000130000000024*Z}|{01E&N<^})&0000v z0000000030Tmk?h01E)JEC&Dp0000U000000000v0RR9Z01E&DF9iSq0000x00000 z000162><{h01E)}HU$6x0000R000000002l3IPBj01E)*Jq7>(0001y000000002B zi2wj101E)d=LG-&0000B000000002xDF6T>01E&jT?GID0000b000000002`01E)1;spQz0000Q000000002n z&;S4;01E)@BL)Bf0000B000000000GOaK5P01E&vTLl0B0000B000000001?O8@{O z01E&{fCT^m0000B0000000006Apig(01E)7Nd*7^0001<000000000%lmGxC01E)1 z@C5(>0000w0RR910001;EdT%!000000000000000000000000$rU3vV01E(~pauW{ z0000R000000000NkO2T901E&HYz6=T0000c000000002ncme<-01E({HwOR!0000E z000000002M=>Y&D01E)t?*;$>0000M000000000rO#lEQ01E(fTLl0B0000E00000 z0001f=m7vC01E&%#s&ZY0000M000000001$v;hDj01E)(+Xest0000Q000000002* z2><{h01E&PHw6Fy0000R000000002|vjPAS000000000000000000000000j`2heT z01E)=`vw320000v000000001pBme*+01E(wO9cP`0000R0000000002VE_Ok01E&} zbp-$b0001V1^@s600000Yytox01E(1GzS0x0000Q000000000`TL1te01E*6k_7+& z0002N000000002m+5rF}01E)lxds3L0000I000000001|EdT%#000000000000000 z0000000000LID6G01E&Tp#}f|0000W0000000014p8^0P01E(cLk9o=0000Q00000 z00029r2zmU01E(upauW{0000R000000000-0s;Uc01E&F)&>9o0000Q000000001$ zE&u=`01E&(0000E0000000024JOBV9 z01E&TZv_AV0000`000000001`R{;Pb01E(mH3k3x0000k0000000010wEzGj01E)h zo&^8^0000R000000002uKL7wC01E)6a0LJW0001O000000000(I{^S901E(Uo(2E_ z0000y000000001x`~d(W01E*B0|x*A0000v000000000kqyhjU01E)BMF#)?00013 z0000000009Q~&@X01E)Div<7x0002U0RR910001UgaH5|01E)p!3F>T0000?00000 z0001~HUI!301E)>PXzz~0000R000000002Va{>S&01E&rHwOR!0000T000000000W z&;bA<01E&Btn z01W_ux(5IN0000l000000002%ivj>501E)BJO=;(0000g000000000X`~UzV01E)t zHUgZ0000I000000000M?g0QI01E)5@CE+|F01E)RpauW{00013000000000TUH||h01E)sl?4C*0000? z000000000_G64W001E&ZBL)Bf0000B000000001WA^`v*01E&B4+a1L0000d00000 z0001@5&-}r01E&PK?VQ-0000s00000000308~^|!01E&%NCf}@0000c000000002_ z+yMY001E&T>IMJ+0000g000000002Bga7~{01E)j;spQz0000I000000000$s{#Nb z01E&?NCyA_00013000000001CPXYiU01E&xDF*-m0000c000000002baR2}!01E&a zbp-$b0000E000000001pA^-p)01E&xO9cP`0000t000000000?lK}uC01E(I&jtVh z0000`000000001?AOQd(01E&lTLu6C0000r000000002Gv;Y7i01E&%3kCoH0001+ z0RR9100017djS9v000000000000000000000002fodN(N01E)NI|l#&0000B00000 z0000_IDD*0000v000000001PHUR)401E(KoCW{@0000E000000000#lK=oB01E)(?*#w= z0000T00000000030RjLb01E&p)dm0n0000`000000002qkpKW901E(w?*#w=0000Q z000000002tU;zLk01E);HwFLz0000E000000001kr~&{Y01E(3M+X1^0000n00000 z0001WO8@{O01E*2S_J?A0000R000000002wNdN#M01E(`egyyk0000T0000000028 z6afGt01E)9LIwZ;0000c000000001;KLP+E01E&LBnJQh0001V000000002s76Jew z01E)L+y(#u0000^000000001~vj6}h01E(+odo~@0000B0RR910002M0{{Rb01E)6 zG6ett0000>000000001thXMd101E(&EC&Dp0000c000000002C6951r01E)FLKm`B*0000z00000000001E*8WCj2L0001x000000001O(*OV> z01E*A+ywvt0000E000000001~Ap!s*01E)E5eEPO0000U000000002*r~v>X01E)f z*#-ar0000Q000000001*F9HA}01E(a7Y6_U0000H000000001gKmY(D01E*6Rs{e6 z0000E0000000019z5oCs01E(w8U_FW0000!0000000008PXYiU01E&x4F>=K0000h z000000002_cmMz*01E&j*#!Uq0000I000000001I+5rF(00000000000000000000 z0001IGywo201E&xBL)Bf0000R000000001Cvj6}h01E(Oodo~@0000k000000002E z(*OV>01E)Z+ywvt0000y000000001RegOa?01E)wzXkvR0000M000000000UNdf>O z01E&CC<{h01E)}HU$6x0000R000000002X0ssIa01E*6Fa-br z0000l000000001P4FCWV000000000000000000000001E&j0`-01E(|BL)Bf0000B z000000000$SOEYc01E&JsRjT50000#000000002y0000E00000 z0000|2mt^h01E(yJO%&&0000r000000001j)Byk@01E(;v<3hG0000c000000000p zX#fBs01E)Rn*{&>0000B000000000LQvd)W01E(lUHz>E01E(W z#s&ZY0000-000000002IT>th01E&m3kLuI0000Q000000000opaK9Q01E&IL0001}000000002inE(JH z01E&V!*01E(Y zBL)Bf0000Z000000000>SpWbc01E&lkp%z%0000Q000000001&f&c&_01E(s;ROHy z0002y000000002-B>?~;01E)(V+H^K00014000000001B%mDx*01E)l;syW!0001u z00000000280000I000000000000000000000002hkN^N801E&djs*Y!0000c00000 z0000|I|2YA01E)&AqM~e0000?0000000023fdBv^01E&y;ROHy0000_0000000026 ziva*401E(^%LV`d0000Y000000001PC;|W?01E*26bAqR0001T000000001W+5rF} z01E(^=LP@(0000b000000001mYXSfw01E(SGzS0x0000E000000002+<^TX901E&d zEd~Gp000120000000018_y7PR01E(eHUZ3O@T0000{0000000030Hvs@501E&bCI$ci0000E000000001K zNdN#M01E&%egyyk0000Y000000000?H30x301E(|BL)Bf0000B0000000030XaE2r z01E(aa0LJW0000R000000000{e*pj@01E*7zXkvR0000k0000000025C;|W?01E(U z6$bzS0000E000000001RfB^s^01E&^zy<&S0000k000000002+MF0RI01E)Tdj$Xh z0000s0RR9100006PXPcT01E*9rUn220000Q000000001YVgdjn01E(IEe8Mq0000R z0000000018UjP6i01E*6Y6SoQ0000E000000001eZvg-z01E*2u?7GD0000E00000 z0001Ud;$O>01E(lI0pa#0000Q000000001!@BsiK01E&k%?1Df0000E000000002V z2mt^h01E)TJO%&&0000g000000001RR004Z01E&fDhB`n0000F000000001IF#-T0 z01E&H=mr1)0000R000000000e)c^n@01E)JB?bTh0000I0000000027FaiJ~01E(O z8V3LX0000*000000001GsQ>^X01E)Rm<0d;0001D000000000l9{~U&01E)rR|Wt8 z000040{{R30001lkN^N801E)VjRgPz0000q000000002e8vy_!01E(^MFs!>0000G z0RR910002-j{yK801E&tYz6=T0000Q000000001)T>tb%f01E)noCN>?0000H000000002PX8-^q01E*2ZUq1U0000R000000002# zC;|W?01E(i;|2f#0000h000000000gVgUdm01E&Rs|El70000^000000000MO9B8Q z01E(S3kLuI00012000000002lK>z?E01E&-R|Nn70000y000000000Yr~&{Y01E&= zM+X1^0000E000000000Yod5tL01E&r_XPj|0000r000000002H+yMY001E&@=>`A* z00013000000002&O#uKR01E)WrUn220000I000000001G#sL5#01E(8;06Ey0000V z000000002#F#-T001E)o8V3LX0000r000000001r*#H0{01E)ps0IK40000c000000001&vH}1i01E&RO9ub|0000j000000001m zg8%>$000000000000000000000001)`v3qU01E(SHwFLz0000r000000000Ega7~{ z01E&{fCT^m0000B000000002&WB>pn01E(0ZUq1U0000B000000002qE&%`{01E)j zjs^e#0000n000000001UX#oHt01E&ptp)%90000E000000001+lmY-E01E(qHwOR! z0000T000000000NX8`~r01E&ktOfu80000c000000002`XaN8s01E)ntOfu800013 z000000002btO5Wc01E&~Ne2J`0000E000000000Qc>w?-01E&lw*~+J0000Q00000 z0002+wg3Pk01E(04F&)J0000R000000001;C;$Kw000000000000000000000001E zm;wMI01E)TI0pa#0000F000000000U0RR9Z01E)zE(HJp0000b000000001TU;+Rl z01E&mEe8Mq0000E000000002ZUIG9j01E&JEe8Mq0000T000000001=K z0000Q000000001_WdHyo01E(sngsv=0000I000000001mDF6Tx01E&PtONi60001v z1poj50001Y;{gC701E(C?gjt=0000;000000001QxdH$X02lxu04V?f0000000000 z0000otpWfd01E*4Ne2J`0001U000000002+R{{Vc01E&xD+d4o0000Q000000000N zXaWEt01E)TFb4nt0000p000000000VJ^%nB01E&TRs{e60000E000000000~8~^|! z01E*6M+E=?0000y000000001Hn*abJ01E)j_5}a{0000Q0000000022H~|1601E&D zody5^0000?000000000^K>z?E01E&TaRmSX000120000000022ivR#301E)h=mh`( z0002F0000000016{{a9Z01E($)CK?m0000R000000000@b^-t*01E(BHwOR!0000Q z00000000183jhEj01E(MHw6Fy0000l000000001ZKL7wC01E(ARs{e60000E00000 z0000|zyJUu01E(68wLOX0001Z000000002p4*~!p01E(=+Xest0000^0000000003 zumAue01E(foCN>?0000y000000002OGyni101E(mPXzz~0000t000000002oasU7# z01E(Wp9KH_0000m0RR91000233IPBj01E)KJq7>(0000n000000001@!2kdf00000 z0000000000000000002ieE|R>01E*8z6JmQ0000k000000002u0{{Rb01E){G6ett z0000b000000001EUjhIk01E(K5eEPO0000c000000002XW&!{r01E)tE(ZVr0000F z000000001}C;$Kw000000000000000000000000U1_1yf01E&%IR*d#0000m00000 z0001y!vFvx01E&py#)XO0000u000000002{3IG5i01E(YQUw420000R0000000022 z7Xbhw01E)-L01E(+YX$%S0000`000000001z zp8x9o0000E0000000026GXel201E(39R~ma z0001S000000002~4gdfW000000000000000000000002UfB*m@01E)qegyyk0000E z000000001(MFIdK01E(mCkFrk0000c0000000009=K%mB01E)P?*;$>0000E00000 z0002Nrvd;X01E&yM+X1^0000E000000001tzyJUu01E&<90mXY0000V000000002Z zF#!M~01E($nFas=0000S0ssI200006T>$_h01E&-ss;c60000#000000000WBmn>- z01E&ZVg>*J0001c000000001_rvLyV01E&rm<0d;0000B000000002F1pojd01E&B zHU$6x0001F000000002ki2?v301E)NI|l#&0000B000000000lCjbB<01E)_Oa%Y{ z0002=0RR910000jM*sjK01E()aRmSX0000E00000000066aWAr02Bbg$|wK;0000e z000000000+b^rh(01E(Ezy$yR0000I000000000nV*&so01E)XEe8Mq0000H00000 z0000v9smF$01E)gNCf}@0000S000000001EDFOf@01E)16$bzS0000v000000000N z>;M2F01E)aG6nzu0000_000000000_L;(OI01E(sp#}f|0000Q000000002(odEzM z01E(k*aiRq0000Q000000001t;Q;_501E(%!3F>T0000E000000001~-~j+401E&} z!3F>T0000(000000002jNdf>O01E(G3kLuI0000B000000001sJOBV901E(cZv_AV z0000g000000000_YXJZv01E&Ht_A=A0000g000000002GG6Dc101E)18wUUY0000& z000000001cd;tI=01E(OR|Wt80000R000000001Rc>n++01E&#*#!Uq0000R00000 z0002GjsO5601E)>>;(V-0000N0RR910002F0000Y01E(VE(HJp0000I000000000| zng9SI01E&d_5}a{0000g000000002m-T(k101E(ID+T}n0000@000000001;0|Edd z01E(23I_lH0000H000000000zJpuqC01E&rBL@Hg0000x000000001rsQ>^X01E)F z1qJ{B0000I000000000?0|Edd01E(8*9HIp0000V000000000p6#xJt01E&LMFju= z0000T000000001$q5%LR01E&%*#-ar0000Q000000002H!vFvx01E&py#)XO0000u z000000002&0RR9J000000000000000000000000pv;Y7i01E&b3kCoH0000R00000 z0000vf&u^{01E(NItKs%0000Q000000000>GXMY*000000000000000000000000f z_W%GQ01E&bHU1ONa400026asmJ%01E)gCI4h8@K0000R0000000007w*dem01E&>s0IK40000c000000000N*#Q6| z01E&NwgvzI0000!000000000}1OWgd01E)hIR*d#0000~000000002M4*&on01E&- zI|Tp$0000c000000002r+W-I}01E)p=LG-&0000<000000002bQvv`Y01E)DDF*-m z0000?000000002!i~s;401E)@=>-4)0000Q000000001+3IG5i01E&PHw6Fy0000R z000000000AivR#301E)P=mh`(0000I000000000^egXg@01E)TI0pa#0000F00000 z0000&H~;_=000000000000000000000000Og#Z8|01E)#;spQz0002U000000001w zC;$Kw000000000000000000000002Cp8^09000000000000000000000000#BLDy* z01E&xO9cP`0000t000000001yB>?~;01E)9V+H^K0000w0000000013r~v>X01E(m z*#-ar0000^000000000%tpNZc01E(a+6Djs0001N000000000dvH}1i01E)>N(TS{ z0000c000000002VG5`P)000000000000000000000002Lt^oid01E(?qy_*00000) z000000002`=m7vC01E(2#s&ZY0000U000000002=OacHR01E)8C-01E(=Vg>*J0001D000000002oQ~>}Y z01E&Js0IK40000Q000000000#CIJ8<01E(mWCj2L00014000000000**#Q6&00000 z0000000000000000001{)&Kw^01E&BCS&01E&ZHwOR!0000H000000002=uK@re01E(?qy_*00000) z000000001&2mk;g01E)tHU$6x0000R0000000005tpETb01E)#ngsv=0000!00000 z0000*7ytkw01E)to000000000000000000000000)7XSbv01E&BMg;%>0001q000000001i zg8~2|01E)@DhB`n0000c000000002P?g0QI01E)h@CEq01E)>s|El70000v000000002cWB>pn01E&+ZUq1U0000E z000000000ulL7!D01E&rHwOR!0000T000000000JBLDy*01E&vTLl0B0000B00000 z0000q=E01E)_&;|ei0001*000000000ws{jBZ01E*81_l5C0000+000000001y z!~g&y01E)ny#)XO0000u000000000F$^ZZ&01E)bA_f2e0000g000000000jECK)` z01E&n76$+T0000E000000002zG5`P)000000000000000000000002azW@Lt01E&T z8wLOX0000!000000002meF6X?01E*4DF*-m0000c000000000%$pHW&01E(o;RXNz z0000Q0000000027rU3vV01E(~pauW{0000R0000000001!2kdv01E&H9R>gZ0000y z0000000011qyPXS01E)n{sjO40000c000000000`RR91Y01E(~j|Bh#0001X00000 z0000u>Hq*D01E&e@C5(>0000Q0000000023-v9t201E)AD+T}n0000g000000000j zn*jhK01E&p)dm0n0000`000000002L3jhEj01E)cHw6Fy0000G000000001XyZ`_q z01E(!83q6V0000(000000000=VgLXl01E){Yy|)S0000v000000002*m;eAG01E)% zkOcq$0000T000000000!RRRDa01E&}DhB`n0001_000000002F8~^|!01E&%NCf}@ z0000c000000001mH39%401E(2?FIk<0000T000000000OCjbBv000000000000000 z000000001+J^=tC01E&DECv7o00012000000000}?EwHH01E&k%LV`d0000A00000 z0000^8vy_!01E&RMFs!>0000R000000002zr2+sV01E&GMF#)?0000E000000002M z>;M2F01E&fF9rYr0001`0{{R30000rLjeFH01E&>p#}f|0000#000000001H%>e)+ z01E)Z;|2f#0000Z000000000^761Se000000000000000000000001pWB>pn01E&n zngsv=00015000000001|M*#pL01E&Xq6Po}0002F000000001T%K!i(01E&ZBL)Bf z0000B000000001yI{^S901E)bo(2E_0000H000000001@^#K4P01E)m^9BF_0000v z000000001Zp8^0P01E($Lk9o=0000n000000000PAprm)01E(I4h8@K0000`00000 z0000uk^ulB01E)T&ISMg0000`000000002$RR91I000000000000000000000001o zV*vmn01E(ks|El70000Q000000002lMgjmL01E)L3I_lH00012000000002Ls{jBZ z01E(I2L=ED00015000000000F=l}pB01E&vE(QPq0000?000000000!#{mE$01E(& z;06Ey0000n000000000V6#)Pu01E)lLIwZ;0000k000000002R>Hq*D01E(C@C5(> z0000y000000002-836zy01E(k2?hWF0000}000000002#DFFZ?01E)DZ3X}U0002> z1ONa40000&F984|01E*Ajs^e#0000S0ssI20000P!vFvx01E(KyafON0001j00000 z0001R)Bpe?01E(6-30&u0000y0000000021YXATu01E&Pas>bY0001c000000002i zvjG4i01E(=+Xest0000^000000002Sb^rh(01E(Wzy$yR00017000000002Xe*pj@ z01E&qzy<&S0000F000000000AC;|W?01E(66bAqR0000K0000000022bpZe(01E(; zv<3hG0000c000000002$wEzGj01E(Wp9KH_0000m0RR910002jdI10;01E&px&{CM z0000*0RR910000a4*&oW000000000000000000000000(m;eAG01E)DkOcq$0000Q z000000001P8Ug?!01E(6-39;v0000M0RR910002mFaQ7|01E*2WCZ{K000100ssI2 z0001rJ^%nB01E&hRs{e60000q000000002MH30x301E*8n+5;?0000)0000000027 zCjtN>01EbAqR0000R000000002tJplkB01E)Pp9TN`0000#0000000016rvd;X z01E&hM+X1^0000H000000002mGXVf101E)Zn+5;?0000v000000002 z0000@000000001Q`vCwV01E(30S5p80000v000000002XDgXc?01E(wT?GID0000T z000000002{MF9XJ01E)pp#}f|0000W000000000e0{{Rb01E(8F$Dks0000(00000 z0000|4FUin01E&N3501E&rF9!es0000T000000000X82|tx z01E&#M+E=?0000R000000002EP5=NR01E($h6Mls0000~000000001oVFCam01E(3 zEe8Mq0000E000000001;-T?q201E&(zy<&S0000B000000001^`~UzV01E(|HwFLz z0000>000000002Sc>(|;01E)xCq01E&%IR*d#0000m000000002j&j0`-01E)9BL)Bf0000V000000002)y#N3r z01E(e8U_FW0000I00000000135dZ)p01E&cR0RM40000<000000001U>j3~F01E&H z@CE0000M00000 z0001sC;01E&J6b1kQ0000E000000001T1^@se01E)_Q3U`10000R000000000f zBme*+01E(UO9cP`0000R000000001jtN;Ka01E*22L=ED0000s000000000EiU0s2 z01E&d=mh`(000140000000005vjPAj01E)-O9ub|0000c000000000+;s5|501E(` zECv7o0000U000000000&3jhEj01E(!QUw420000)000000000;A_4#+01E)i5eEPO z0000Q000000001tFaQ7|01E)3WCZ{K0000}000000001$Gyni101E)PYy|)S0000R z000000000{k^lfA01E(~?*#w=0000Y000000002|a{&M%01E)XvjzYF0000V00000 z0002csQ>^X01E&V1O@;A0001)0RR910001@ya50r01E(6-39;v0000M0RR910001P z_W=MR01E)R_67g|0001d0ssI20001U3jhEj01E(*Hw6Fy0000I000000001;AOHXo z000000000000000000000000pmjD1F01E(UkOcq$0000f000000001V7XSbv01E($ zMg;%>0001q000000000Y4FCWl01E)FI0XOz0000H000000001JZUF!y01E(mu?7GD z0000g000000002GgaQB}01E(;D+d4o0000c000000000MB>(^-01E)1O9cP`0000R z000000002FD*yl@01E)9Uj+aF0000H000000001OdI10;01E&*xCQ_K0001!0RR91 z0001nxc~qn01E&d5e5JN0002m0ssI20001juK)ld01E&h3I+fG0000T000000002c zJOBU^000000000000000000000001JVE_Ok01E&rm<0d;0000B00000000160RR9Z z01E)zE(HJp0000b000000000SUI73i01E(oss;c60000Q000000000U3jqKk01E(i zJ_Y~)0000d000000000PP67ZT01E)xC0000p000000001X0|Edd01E&E3I_lH0000e z000000001|=>PyC01E&B@C5(>0000T000000000(SO5Sb01E)dkOcq$0000Q00000 z0000@0ssIa01E)-F9iSq0001F00000000192LJ#f01E)RHU$6x0000R000000002! zZ~y=z01E)#palQ`0000R000000002k-g01E(S+Xest0000k000000001rDFFZ?01E(QZ3X}U z0000w000000001*>Hz>E01E)J#s&ZY000090RR910002tvH}1i01E(QO9ub|0000j z000000002&4FCWV000000000000000000000001`Yybcv01E&=K z0000Z0000000012l>h)D01E&VkOcq$0000f000000002Kp8^0P01E)SLk9o=0000? z000000002vQUCxV01E)piUj}w0001*000000000OS^)qe01E(OsRjT50000Q00000 z0000NvjG4i01E)Frv?B30000#000000001RzyJUu01E)f8wLOX0001X000000000p zKL7wC01E&hRs{e60000q000000002QXaWEt01E)R8V3LX0000B0000000010wE_Sk z01W_Oxd#9M0000X000000000)9|8a(01E&^5eEPO0000Q000000002saRLA$01E)} zHU|Iz0000c000000002)F#rG}01E&JYXtxR0000@0000000030^Z@`O01E()^9BF_ z0000%000000002#F8}}{01E(iWCZ{K0000M000000001~)d2t^01E)rv<3hG0000R z000000000oZ~y=z01E&>p9KH_0000g000000000X{Qv+W01E&{_5}a{0000k00000 z0001Xy#N3r01E&N8U_FW0001G000000000J!~g&y01E(My#)XO0000u000000000A zjsXB701E(6%mx4e0001z000000002O-2eb001E&iD+T}n0000Q000000001X0RR9Z z01E&;F9iSq0000i000000000-Edl@{01E)P01E&Hy#@dP0002&000000002N0000Y01E(nE(HJp0000F000000000Ep#lIR z01E&jKL-E+0000c00000000039smF$01E)JNCf}@0000N000000000|DF6Tx01E&( zv;+VE0000I2mk;80001KGXVf101E&xBL)Bf0000R000000000rDgXc?01E&}T?GID z0000Q000000002!)Bpe?01E(SB?bTh0000>000000001C0|Edd01E(8*9HIp0000V z000000001(0000~000000001QwE+Mk01E*8+Xest0000Q000000001IvH$=g z01E(23I+fG0001G00000000307y$qx01E(G2?hWF0000U00000000288vp1|01E(^76$+T0001U000000002faRC4l0000000000 z00000000000002=(*OV>01E&N-30&u0000)000000000g8vy_k000000000000000 z000000002_A_4#+01E)+5eEPO0000U000000001gBLM&+01E&lT?POE0002=1ONa4 z0002RM*sjK01E)}d<6gi0002e000000000R5&-}r01E)(Kn4H+0000h000000000L zDFOf@01E(i6$bzS0000g000000000#E&u=$0000000000000000000000030C;|W? z01E(i;|2f#0000h000000002i@BsiK01E(6@&*6^0001c000000000yOaTBQ01E)< zqy_*00001)0RR910001xumJ!f01E*0+6Djs0000?0000000025P67ZT01E&x4F>=K z0000h0000000021D**r^01E)Bd1ONa40000+o&W$M01E(M_XPj|0000T z000000002FQUL%W01E)Frv?B30000#000000002<+yDR~01E*9Dh2=m0000I00000 z0002~FaiJ~01E)R8V3LX0000B000000002BECK)`01EL$+T0000Z0000000020 z2>}2i01E)-JO%&&0000T000000001!X8-^q01E)#ngsv=0000!0000000010-T(k1 z01E)p=>-4)0000Q000000002r3;+Nk01E(XI0XOz0000E000000001-e*gd?01E&- z+ywvt0000A000000000_CjbBv000000000000000000000001xiUI&401E)YI|l#& z0000v0000000005e*gd?01E)t+XVms0000Q000000002*#Q*>z01E(U9tHpa0001a z0RR910000oEdT%_01E&}U z0000B0000000005mjM7G01E(C(*^(l0001*000000001=qyhjU01E)HL00010 z000000001~8UX+z01E&h3I+fG0000T000000000PA^`v*01E)*4h8@K0000R00000 z00022kN^N801E)}jRgPz0000f000000000}S^@wf01E&DEC&Dp00014000000001= zwgLbW000000000000000000000001T7y$qx01E)N2nGNE0001^000000002kGywo2 z01E(+BL)Bf0000B0000000005QUL%W01E(2GzI_w0000k000000001IHUa=501E(= zAO`>d0000g000000000=+W`O~01E)fy9NLN0000!0000000000Utec!Z*E_6bYXII zUta)UX>MtB0AFTlZfO8tNmNZ=WMy(?XK8bEWpY$aLu_wuWmI8eY-IpnNmNZ=a%E>} zb97~LR82!{Z*FB&VPb4$0AF8Ycwt{=X>MU`X?kSV>rGDUU( zUs_aFQ*=3Hcw=R7bZKvH0AE^8Q*=3Hcw=R7bZKvHLor2m0AE^8OH*_?ba`-PUukY; zZ)I^sQcF``0CRM5V{LE%Us`T=ZBTXqUs_~rPMt4b!|mZQ(pjIT251RF*sjRVqbJ}Wo2J(Z)9a(VqtS-F)&|K zUu|J{X>E0FMNm^;0AE^8Q*<#kUs7UUbaG{7Uub1vWMy(gGDUU(Us_I6bTKtwQet0p za%E*-Xk}q!WpX%QOmPE&L-HD6L@Z*V?{P>Wo~D5Xhl#mQ*=3W zZ(nnCa%pa7X#jR}Zg6sGZggeMmpQ*&cQ zMO0r?y{bY*g3bZ>HBVqtS-Lo!8BZE65tT251RF*sjBX>?y{bY*g3 zbZ>HBVqtS-Lor2AZE65tT251RF*sjBX>?y{bY*g3bZ>HBVqtS-F)&|EUt)D_a9?$B zMRovRT251RF*sjBX>?y{bY*g3bZ>HBVqtS-F*09GUt)D_a9?C^cWy;?0AE^8Q*<#n zUqWegUukq@a$$6Da$jO$b7ePQO?_BVRUbDUt(c%Wm7R<0AE^8Q*<#i zUqWegUukq@a$$6Dazipjb^u>mPE&L-Ghae!bYE$7WpZJ3Z*oI1MRovRT251RF*9F6 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%0AE^8IBsljXl-F`ZZ>3PbYW?1 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%0AE^8IBsljXl-F`ZZ>3PbYW?1 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%0AE^8Q*=0AQet0p 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 zbZ>G=PB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fyMK@$+b98cV zc}Y_N6REqFLKEjBbRb8jv(0AFQfVRT^tUteN#b6<0G zVRCc;UuAA&0BmVuWpZ+Fa$jv>ZeeF-axQak07pYZUo$Q+07pzoLPK9NE;9f}Oi4mR zUotK<07pzoLPK9NE;24P07pzoLPJ2Oi4mRSXf^(E;IlD00962 z00962009620096200962009620096200962009620096200963009620096200964 z009620096200962009620096200962009620096200aO500962009620096200962 z00962009620096200962000010096200962009620096200962009620096200962 z00962009650096200962009620096200963009630096200962009620096200962 z0096200IC300962009620096200962009620096200962009620096200IC300962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200962009620096200IC30096200IC3009620096200962009620096200962 z009620096200962009620096200962009620096200962009620096200IC300962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200965009620096200962 z00962009620096200962009620096200RI40096200962009620096200IC300962 z009660096200962009620096200962009620096200962009620096200sa700962 z00962009620096200963009620096200962009620096800962009620096200962 z0096200962009620096200962009620096200962009620096200aO50096200962 z00963009620096200962009620096200962009620096200962009620096200962 z009620096200962009620096200962009620096200962009620096200IC300968 z0096200962009620096200962009620096200962009620096200;m90096200962 z00962009620096200962009620096200962009620096200962009630096200962 z00963009620096200962009630096200962009620096300962009620096200962 z00962009620096200962009620096A00962009620096200962009620096300962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200jU60096200962009620096200962009620096200962009630096200962 z00962009620096200962009620096200962009620096200962009620096500962 z00962009620096200962009620096200962009620096200962009680096200962 z00962009650096200962009620096200962009620096200jU6009620096200962 z00962009620096200962009620096200IC300962009620096200IC30096200962 z00#g8009630096200962009620096200#g8009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009650096200962009620096200962 z00962009620096200962009620096200962009620096200963009620096200962 z00962009620096200962009620096300962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200962009620096200IC30096200962009620096200962009620096300962 z00962009620096500962009620096200962009620096200962009620096200962 z00962009620096200IC3009620096200962009620096200962009620096200962 z0096200962009620096300IC3009620096200962009620096200IC30096200962 z009620096200962009620096200962009620096200IC300962009620096200962 z00962009620096200962009620096200962009620096200IC3009620096200962 z009620096200962009620096200962009620096200IC400962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096300962009620096200962009620096300962009620096200962 z00961009620096200962009620096200962009620096B00962009620096200962 z00962009620096200962009620096300962009620096200962009620096200962 z00962009620096200962009620096200962009620096200001009630096200IC3 z00962009620096200962009620096200962009620096200962009620096200962 z00963009620096200962009620096200962009620096200962009620096200962 z0096200962009620096200962009620096200IC80096200962009620096200962 z009620096200IC30096200962009620096800962009620096200IC30096200962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200962009620096200aO50096200962009620096200962009620096200962 z009620096200962009620096200962009620096200962009620096200IC300962 z00962009620096200IC3009620096200962009620096200IC3009620096200962 z00962009620096200962009620096200962009620096200962009650096200962 z00962009620096200962009620096200962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200968 z00962009620096200962009620096300962009620096200962009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200963009620096200IC300962009620096200IC300962009620096200962 z00962009620096200962009620096200962009620096200963009620096200962 z00962009620096200962009620096200962009620096200962009620096200962 z0096200962009620096200aO50096300962009620096200962009620096200962 z00962009620096200962009620000100IC6009620096200968009620096200962 z00962009630096200962009620096200962009680096200962009620096400962 z00962009620096200962009620096200962009650096200962009620096200962 z0096200962009620096C009620096200962009630096200962009620096200#g8 z00962009620096200962009620096200962009620096200963009620096200962 z009620096200IC30096200962009610096200962009620096201N;D0096300962 z00962009620096200962009620096200962009620096200962009620096200962 z00968009620096200962009620096200IC3009620096200962009620096200962 z0096200962009620096200IC30096200962009620096200962009620096200962 z009620096200962009620096200962009620096200IC300962009620096200962 z00001009620096200962009620096800962009620096200962009620000100962 z00962009620096300965009620096200963009620096200962009620096200962 z009620096200IC3009620096200IC300962009620096200962009620096200963 z0096200962009610096206Vz?01yBG03ZMW08l1*3jhEN0F=1`000000096208_aF z01yBG03ZMW0266x4FCWO0Gzo3000000096307<{D0I<0N000000096201~+Z01yBG03ZMW0CgH^2><{C0I<0N00000 z0096703x{p01yBG000000EK@k0ssIB0KB;Z01yBG0Au)<0ssIA0Lr-n01yBG0MoB) z1pojC0NJ?$01yBG0CD)20ssI80OYv>01yBG0A%==0ssI70Q0#501yBG0CXvm2mk;A z00O!K000000N}|e0000000;m80000005GWp000000O-jm0000000;m8000000Mso7 z000000Px8u0000000;m8000000Pv^;000000Qku$0000000;m8000000H{$100000 z007D;0000000;m8000000M1bd0000000_z`0000000;m8000000Nzmt0000001(P3 z0000000;m8000000OnB#0000002saN00000000000MP#^0000000sa6 z0A>aN000000000004T~R00000009610R93100000000000Equ60000000sa60R931 z000000000005HlZ00000009610ImQ400000000000NDO00000000sa60ImQ400000 z0000006@wp00000009610B->R000000000007%Lx000000096104f9k0000000000 z08q*(00000009610G0p%000000000009eW>000000096105S#u00000000000AR`} z00000009610D1%f00000000000BFi600000009610LKFW00000000000C>tM00000 z009610JQ@E00000000000D#IU00000009610PY3=00000000000Eo&c0000000961 z0PX<*00000000000FcTk000000096106GK!00000000000HDe!00000009610F?v) z000000000003ggL00000009610F?v)00000000000I13+000000096107M4>00000 z000000MN@Q000000096107M4>00000000000N~3g000000096107M4>0000000000 z0LaQH00000009610A&FH00000000000093e0000000sa60A&FH00000000000MN=P z00000009610NMZm00000000000OwN00000009610G0v(00000000000FcWl0000000961 z0Cxib000000000007%Rz00000009610Cxib00000000000AS2000000009610Cxib z00000000000C>zO00000009610Cxib00000000000FcZm00000009610Cxib00000 z000000I19;00000009610Cxib000000000001yBv00000009610Cxib0000000000 z0GP`t00000009610L=pc00000000000HDh#000000096105}E!00000000000JzI2 z0000000961051Xn00000000000Qk!&0000000961051Xn00000000000NBeY00000 z0096105|~v00000000000O-po00000009610M-Nm01yBG0000001(V50000000961 z0M-Nm01yBG00000065Gj00000009610M-Nm01yBG0000008q>*00000009610M-Nm z01yBG000000BFo800000009610M-Nm01yBG000000D#OW00000009610M-Nm01yBG z000000GP}u00000009610M-Nm01yBG000000I00000000000I2>b0000001yBG022TJ00000000000I>cj0000001*HH z022TJ00000000000LcC*0000000sa60Eqwq00000000000MPy@0000000sa60G000000000002u!$0000000sa60KEYK0000000000 z04V<`0000000sa60M!8i00000000000670B0000000sa60O|n%000000000006_mJ z0000001yBG05Ado000000000007(BR0000001*HH05Ado000000000008sxZ00000 z00sa605}2w000000000009gMh0000000sa609FD300000000000AT+p0000000sa6 z0Ad0F00000000000C4{(0000000sa60ImW600000000000C@i>0000000sa60JH)C z00000000000D%7}0000000sa60N?@u00000000000GR(M0000000sa60G0#*00000 z000000HFUU0000000sa60L=sd00000000000I2^c0000000sa6015>F0000000000 z0I>fk0000000sa60LTRZ00000000000J#4s0000000sa60Oth&00000000000Koq! z0000000sa600;&E00000000000LcF+0000000sa605Jvt00000000000NDR100000 z00sa60I&uC00000000000O0>90000000sa60Kx_U00000000000O+R0000000#g700RI30000000000 z0D#XZ0000000#g700aO400000000000Eo{h0000000#g700jU500000000000Fcip z0000000#g700sa600000000000GQ7x0000000#g700#g700000000000HDt(00000 z00#g700;m800000000000I1I>0000000#g700{s900000000000I<&}0000000#g7 z015yA00000000000JzU60000000#g701N;C00000000000Km^E0000000#g701f~E z00000000000LafM0000000#g701p5F00000000000MO4U0000000#g701yBG00000 z000000NBqc0000000#g701*HH00000000000N~Fk0000000#g702BZK0000000000 z0O-#s0000000#g702TlM00000000000PxQ!0000000#g702lxO00000000000Qk=+ z0000000#g702u%P0000000000007V^0000000#g702=@R000000000000_`100000 z00#g702}}S000000000001(h90000000#g70384T000000000002t6H0000000#g7 z03HAU000000000003gsP0000000#g703ZMW000000000004UHX0000000#g703iSX z000000000005H%f0000000#g703rYY0000000000065Sn0000000#g703!eZ00000 z0000006@?v0000000#g703-ka000000000007%d%0000000#g7044wc0000000000 z08r2<0000000#g704D$d000000000009eo{0000000#g704M+e00000000000ASE4 z0000000#g704V?f00000000000BF!C0000000#g704e|g00000000000C3PK00000 z00#g704o3h00000000000C>t00000000000LaiN z0000000#g705|{u00000000000MO7V0000000#g70672v00000000000NBtd00000 z00#g706G8w00000000000N~Il0000000#g706YKy00000000000O-&t0000000#g7 z06qW!00000000000PxT#0000000#g706zc#00000000000Qk@-0000000#g706+i$ z0000000000007Y_0000000#g706_o%000000000000_}20000000#g7073u&00000 z0000001(kA0000000#g707C!(000000000002t9I0000000#g707U=*0000000000 z03gvQ0000000#g707d`+000000000004UKY0000000#g707w7;000000000005H)g z0000000#g707(D<0000000000065Vo0000000#g707?J=000000000006@_w00000 z00#g7080P>000000000007%g&0000000#g7089V?000000000008r5=0000000#g7 z08Ib@000000000009er|0000000#g708Rh^00000000000ASH50000000#g708sz{ z00000000000BF%D0000000#g708#(|00000000000C3SL0000000#g708;<}00000 z000000C>?T0000000#g708{_~00000000000D#db0000000#g7096100000000000 z0Ep2j0000000#g709F7100000000000Fcor0000000#g709OD200000000000GQDz z0000000#g709gP400000000000HDz*0000000#g709pV500000000000I1O@00000 z00#g709yb600000000000I<<00000000#g709*h700000000000Jza80000000#g7 z09^n800000000000Km~G0000000#g70A2t900000000000LalO0000000#g70ABzA z00000000000MOAW0000000#g70AK(B00000000000NBwe0000000#g70Ac_D00000 z000000N~Lm0000000#g70Am0E00000000000O-*u0000000#g70Av6F0000000000 z0PxW$0000000#g70A&CG00000000000Qk`;0000000#g70A>IH0000000000007b` z0000000#g70A~OI000000000000`130000000#g70BHaK000000000001(nB00000 z00#g70BQgL000000000002tCJ0000000#g70BisN000000000003gyR0000000#g7 z0BryO000000000004UNZ0000000#g70B!&P000000000005H-h0000000#g70B-;Q z0000000000065Yp0000000#g70B`^R000000000006@|x0000000#g70C4~S00000 z0000007%j(0000000#g70CE5T000000000008r8>0000000#g70CNBU0000000000 z09eu}0000000#g70CWHV00000000000ASK60000000#g70CoTX00000000000BF)E z0000000#g70CxZY00000000000C3VM0000000#g70C)fZ00000000000C>_U00000 z00#g70C@la00000000000D#gc0000000#g70D1rb00000000000Ep5k0000000#g7 z0DAxc00000000000Fcrs0000000#g70DJ%d00000000000GQG!0000000#g70DS-e z00000000000HD$+0000000#g70Db@f00000000000I1R^0000000#g70Du4h00000 z000000I*000000000006^0y0000000#g70Gj{+000000000007%m)00000 z00#g70Gt2-000000000008rB?0000000#g70G$8;000000000009ex~0000000#g7 z0G|K=00000000000ASN70000000#g70H6Q>00000000000BF-F0000000#g70HFW? z00000000000C3YN0000000#g70HOc@00000000000C>|V0000000#g70Hgo_00000 z000000D#jd0000000#g70Hpu`00000000000Ep8l0000000#g70Hy!{0000000000 z0Fcut0000000#g70H*)|00000000000GQJ#0000000#g70H^=}00000000000HD(- z0000000#g70I2`~00000000000I1U_0000000#g70IC2000000000000I<_200000 z00#g70IL8100000000000JzgA0000000#g70IUE200000000000Kn5I0000000#g7 z0IvW500000000000LarQ0000000#g70I~o800000000000MOGY0000000#g70JH!A z00000000000NB$g0000000#g70JQ)B00000000000N~Ro0000000#g70JZ=C00000 z000000O->w0000000#g70Ji`D00000000000Pxc&0000000#g70Js1E0000000000 z0Ql1=0000000#g70J#7F0000000000007h|0000000#g70J;DG000000000000`75 z0000000#g70J{JH000000000001(tD0000000#g70K5PI000000000002tIL00000 z00#g70KNbK000000000003g&T0000000#g70KfnM000000000004UTb0000000#g7 z0KotN000000000005H@j0000000#g70KxzO0000000000065er0000000#g70K)(P z000000000006^3z0000000#g70K@0000000#g7 z0N(%r0000000000007k}0000000#g70N?-s000000000000`A60000000#g70O0@t z000000000001(wE0000000#g70O9}u000000000002tLM0000000#g70OJ4v00000 z0000003g*U0000000#g70OSAw000000000004UWc0000000#g70ObGx0000000000 z05H`k0000000#g70OtSz0000000000065hs0000000#g70O$Y!000000000006^6! z0000000#g70O00000000000HD<<0000000#g70QLX?00000000000I1a{ z0000000#g70QUd@00000000000I=040000000#g70Qdj^00000000000JzmC00000 z00#g70Qmp_00000000000KnBK0000000#g70Qvv`00000000000LaxS0000000#g7 z0Q~>}00000000000MOMa0000000#g70R8{~00000000000NB+i0000000#g70RI30 z00000000000N~Xq0000000#g70003100000000000O-{y0000000#g70099200000 z000000Pxi)0000000#g700IF300000000000Ql7?0000000#g700RL40000000000 z007n~0000000#g700jX6000000000000`D70000000#g700sd7000000000001(zF z0000000#g700#j8000000000002tON0000000#g700;p9000000000003g;V00000 z00#g700{vA000000000004UZd0000000#g701E*C000000000005H}l0000000#g7 z01N>D0000000000065kt0000000#g701W{E000000000006^9#0000000#g701g2F z000000000007%v-0000000#g701p8G000000000008rK_0000000#g701*KI00000 z0000009e*20000000#g7022WK00000000000ASWA0000000#g702BcL0000000000 z0BF`I0000000#g702KiM00000000000C3hQ0000000#g702ToN00000000000C?6Y z0000000#g702cuO00000000000D#sg0000000#g702u)Q00000000000EpHo00000 z00#g702%=R00000000000Fc%w0000000#g702=`S00000000000GQS&0000000#g7 z02~1T00000000000HD?=0000000#g70387U00000000000I1d|0000000#g703HDV z00000000000I=350000000#g703iVY00000000000JzpD0000000#g703rbZ00000 z000000KnEL0000000#g703!ha00000000000La!T0000000#g703-nb0000000000 z0MOPb0000000#g7044zd00000000000NBW0000000#g705kyr00000 z0000004Uce0000000#g705t&s000000000005I1m0000000#g705$;t0000000000 z065nu0000000#g705<^u000000000006^C$0000000#g70675w000000000007%y; z0000000#g706GBx000000000008rN`0000000#g706PHy000000000009e;300000 z00#g706YNz00000000000ASZB0000000#g706hT!00000000000BF}J0000000#g7 z06zf$00000000000C3kR0000000#g706+l%00000000000C?9Z0000000#g706_r& z00000000000D#vh0000000#g7073x(00000000000EpKp0000000#g707C%)00000 z000000Fc)x0000000#g707L-*00000000000GQV(0000000#g707d}-0000000000 z0HD_>0000000#g707n4;00000000000I1g}0000000#g707wA<00000000000I=66 z0000000#g707?M>00000000000JzsE0000000#g7080S?00000000000KnHM00000 z00#g7089Y@00000000000La%U0000000#g708Ie^00000000000MOSc0000000#g7 z08Rk_00000000000NB?k0000000#g708aq`00000000000N~ds0000000#g708s$| z00000000000O;2!0000000#g708#+}00000000000Pxo+0000000#g708;?~00000 z000000QlD^0000000#g7096410000000000007u10000000#g709FA20000000000 z00`J90000000#g709OG3000000000001((H0000000#g709XM4000000000002tUP z0000000#g709gS5000000000003g^X0000000#g709*k8000000000004Uff00000 z00#g709^q9000000000005I4n0000000#g70A2wA0000000000065qv0000000#g7 z0AB$B000000000006^F%0000000#g70AT?D000000000007%#<0000000#g70Ac|E z000000000008rQ{0000000#g70Am3F000000000009e>40000000#g70A>LI00000 z000000AScC0000000#g70A~RJ00000000000BG1K0000000#g70B8XK0000000000 z0C3nS0000000#g70BQjM00000000000C?Ca0000000#g70BZpN00000000000D#yi z0000000#g70BivO00000000000EpNq0000000#g70Br#P00000000000Fc-y00000 z00#g70B!*Q00000000000GQY)0000000#g70B`{S00000000000HD|?0000000#g7 z0C52T00000000000I1j~0000000#g70CE8U00000000000I=970000000#g70CNEV z00000000000JzvF0000000#g70CfQX00000000000KnKN0000000#g70CoWY00000 z000000La)V0000000#g70CxcZ00000000000MOVd0000000#g70C)ia0000000000 z0NB_l0000000#g70C@ob00000000000N~gt0000000#g70D1uc00000000000O;5# z0000000#g70DA!d00000000000Pxr-0000000#g70DJ)e00000000000QlG_00000 z00#g70DS=f0000000000007x20000000#g70Dl1h000000000000`MA0000000#g7 z0Du7i000000000001(+I0000000#g70D%Dj000000000002tXQ0000000#g70D=Jk z000000000003g{Y0000000#g70E7Vm000000000004Uig0000000#g70EGbn00000 z0000005I7o0000000#g70EYnp0000000000065tw0000000#g70Ehtq0000000000 z06^I&0000000#g70Eqzr000000000007%&=0000000#g70Ez(s000000000008rT| z0000000#g70E+l8000000000005IAp00000 z00#g70J8xA0000000000065wx0000000#g70JH%B000000000006^L(0000000#g7 z0JQ-C000000000007%*>0000000#g70JZ@D000000000008rW}0000000#g70Ji}E z000000000009e{60000000#g70Js4F00000000000ASiE0000000#g70J#AG00000 z000000BG7M0000000#g70J;GH00000000000C3tU0000000#g70J{MI0000000000 z0C?Ic0000000#g70K5SJ00000000000D#&k0000000#g70KNeL00000000000EpTs z0000000#g70KWkM00000000000Fc@!0000000#g70KfqN00000000000GQe+00000 z00#g70KowO00000000000HE3^0000000#g70Kx$P00000000000I1q10000000#g7 z0K)+Q00000000000I=F90000000#g70LB3T00000000000Jz#H0000000#g70LTFV z00000000000KnQP0000000#g70LcLW00000000000La=X0000000#g70LlRX00000 z000000MObf0000000#g70LuXY00000000000NC0n0000000#g70L%dZ0000000000 z0N~mv0000000#g70L=ja00000000000O;B%0000000#g70L}pb00000000000Pxx< z0000000#g70M7vc00000000000QlM{0000000#g70MG#d0000000000007%400000 z00#g70MY>f000000000000`SC0000000#g70Mh{g000000000001(?K0000000#g7 z0Mr2h000000000002tdS0000000#g70M`Kk000000000003h2a0000000#g70N4Ql z000000000004Uoi0000000#g70NMcn000000000005IDq0000000#g70NVio00000 z00000065zy0000000#g70Neop000000000006^O)0000000#g70Nnuq0000000000 z07%;?0000000#g70Nw!r000000000008rZ~0000000#g70N?=t000000000009e~7 z0000000#g70O0`u00000000000ASlF0000000#g70OA1v00000000000BGAN00000 z00#g70OJ7w00000000000C3wV0000000#g70OSDx00000000000C?Ld0000000#g7 z0OkPz00000000000D#*l0000000#g70OtV!00000000000EpWt0000000#g70O$b# z00000000000Fc`#0000000#g70O00000000000La@Y0000000#g70QCU?00000000000MOeg00000 z00#g70QLa@00000000000NC3o0000000#g70QUg^00000000000N~pw0000000#g7 z0Qdm_00000000000O;E&0000000#g70Qms`00000000000Px!=0000000#g70Qvy{ z00000000000QlP|0000000#g70Q>;}0000000000007)50000000#g70Q~^~00000 z0000000`VD0000000#g70R900000000000001(_L0000000#g70RI610000000000 z02tgT0000000#g700062000000000003h5b0000000#g7009C3000000000004Urj z0000000#g700II4000000000005IGr0000000#g700RO50000000000065$z00000 z00#g700aU6000000000006^R*0000000#g700sg8000000000007%>@0000000#g7 z00#m9000000000008rd00000000#g700;sA000000000009f280000000#g700{yB z00000000000ASoG0000000#g7015&C00000000000BGDO0000000#g701E;D00000 z000000C3zW0000000#g701N^E00000000000C?Oe0000000#g701W~F0000000000 z0D#;m0000000#g701g5G00000000000EpZu0000000#g701pBH00000000000Fc}$ z0000000#g701yHI00000000000GQk;0000000#g701*NJ00000000000HE9`00000 z00#g7022ZL00000000000I1w30000000#g702BfM00000000000I=LB0000000#g7 z02KlN00000000000Jz*J0000000#g702cxP00000000000KnWR0000000#g702l%Q z00000000000La`Z0000000#g702u-R00000000000MOhh0000000#g702%@S00000 z000000NC6p0000000#g702=}T00000000000N~sx0000000#g7038AV0000000000 z0O;H(0000000#g703HGW00000000000Px%>0000000#g703QMX00000000000QlS} z0000000#g703ZSY0000000000007-60000000#g703iYZ000000000000`YE00000 z00#g703rea000000000001(|M0000000#g703-qc000000000002tjU0000000#g7 z03`wd000000000003h8c0000000#g704D+f000000000004Uuk0000000#g704M?g z000000000005IJs0000000#g704V|h0000000000065(!0000000#g704f3i00000 z0000006^U+0000000#g704o9j000000000007%^^0000000#g704xFk0000000000 z08rg10000000#g704)Ll000000000009f590000000#g704@Rm00000000000ASrH z0000000#g705Jjp00000000000BGGP0000000#g705Spq00000000000C3$X00000 z00#g705bvr00000000000C?Rf0000000#g705t*t00000000000D#>n0000000#g7 z05<{v00000000000Epcv0000000#g70678x00000000000Fd1%0000000#g706GEy z00000000000GQn<0000000#g706PKz00000000000HEC{0000000#g706YQ!00000 z000000I1z40000000#g706hW#00000000000I=OC0000000#g706qc$0000000000 z0Jz;K0000000#g706zi%00000000000KnZS0000000#g706+o&00000000000La}a z0000000#g706_u(00000000000MOki0000000#g707C)*00000000000NC9q00000 z00#g707L=+00000000000N~vy0000000#g707U`-00000000000O;K)0000000#g7 z07e1;00000000000Px)?0000000#g707n7<00000000000QlV~0000000#g707wD= z0000000000007=70000000#g707(J>000000000000`bF0000000#g707?P?00000 z0000001)0N0000000#g7089b^000000000002tmV0000000#g708Rn`0000000000 z03hBd0000000#g708at{000000000004Uxl0000000#g708jz|000000000005IMt z0000000#g708s(}0000000000065+#0000000#g708|11000000000006^X-00000 z00#g709672000000000007%{_0000000#g709OJ4000000000008rj20000000#g7 z09gV6000000000009f8A0000000#g709pb700000000000ASuI0000000#g709yh8 z00000000000BGJQ0000000#g709^tA00000000000C3(Y0000000#g70AB(C00000 z000000C?Ug0000000#g70AT_E00000000000D#^o0000000#g70Am6G0000000000 z0Epfw0000000#g70AvCH00000000000Fd4&0000000#g70A>OJ00000000000GQq= z0000000#g70A~UK00000000000HEF|0000000#g70B8aL00000000000I1$500000 z00#g70BQmN00000000000I=RD0000000#g70BZsO00000000000Jz>L0000000#g7 z0BiyP00000000000KncT0000000#g70Br&Q00000000000Lb1b0000000#g70B!;R z00000000000MOnj0000000#g70B-^S00000000000NCCr0000000#g70CEBV00000 z000000N~yz0000000#g70CNHW00000000000O;N*0000000#g70CWNX0000000000 z0Px-@0000000#g70CfTY00000000000QlZ00000000#g70CoZZ0000000000007@8 z0000000#g70Cxfa000000000000`eG0000000#g70C@rc000000000001)3O00000 z00#g70DJ-f000000000002tpW0000000#g70Db}h000000000003hEe0000000#g7 z0Dl4i000000000004U!m0000000#g70D%Gk000000000005IPu0000000#g70D=Ml z0000000000065<$0000000#g70D}Sm000000000006^a;0000000#g70E7Yn00000 z0000007%~`0000000#g70EGeo000000000008rm30000000#g70EPkp0000000000 z09fBB0000000#g70Eq$s00000000000ASxJ0000000#g70E+?u00000000000BGMR z0000000#g70E_|v00000000000C3+Z0000000#g70F43w00000000000C?Xh00000 z00#g70FD9x00000000000D#{p0000000#g70FMFy00000000000Epix0000000#g7 z0FVLz00000000000Fd7(0000000#g70FeR!00000000000GQt>0000000#g70FnX# z00000000000HEI}0000000#g70Fwd$00000000000I1(60000000#g70F(j%00000 z000000I=UE0000000#g70F?p&00000000000Jz^M0000000#g70GI**0000000000 z0KnfU0000000#g70GR>+00000000000Lb4c0000000#g70Gk2;00000000000MOqk z0000000#g70Gt8<00000000000NCFs0000000#g70G$E=00000000000N~#!00000 z00#g70G00000000000O;Q+0000000#g70G|Q?00000000000Px=^0000000#g7 z0H6W@00000000000Qlc10000000#g70HFc^0000000000007`90000000#g70HOi_ z000000000000`hH0000000#g70HXo`000000000001)6P0000000#g70Hgu{00000 z0000002tsX0000000#g70Hp!|000000000003hHf0000000#g70Hy)}0000000000 z04U%n0000000#g70H^{0000000000005ISv0000000#g70I3210000000000065?% z0000000#g70IC82000000000006^d<0000000#g70ILE3000000000007&2{00000 z00#g70IUK4000000000008rp40000000#g70IdQ5000000000009fEC0000000#g7 z0Ivc700000000000AS!K0000000#g70I&i800000000000BGPS0000000#g70I>o9 z00000000000C300000000000081B0000000#g70Q3R?000000000000`nJ0000000#g70QLd^ z000000000001)CR0000000#g70QUj_000000000002tyZ0000000#g70Qmv{00000 z0000003hNh0000000#g70Q&*}000000000004U-p0000000#g70Q>>~0000000000 z05IYx0000000#g70Q~|00000000000065|(0000000#g70RI92000000000006^j> z0000000#g700093000000000007&8}0000000#g7009F4000000000008rv600000 z00#g700IL5000000000009fKE0000000#g700aX700000000000AS)M0000000#g7 z00sj900000000000BGVU0000000#g700;vB00000000000C3_c0000000#g700{#C z00000000000C?gk0000000#g701N{F00000000000D$5s0000000#g701X2G00000 z000000Epr!0000000#g701pEI00000000000FdG+0000000#g701yKJ0000000000 z0GQ$^0000000#g701*QK00000000000HES10000000#g701^WL00000000000I1?9 z0000000#g7022cM00000000000I=dH0000000#g702BiN00000000000J!2P00000 z00#g702KoO00000000000KnoX0000000#g702c!Q00000000000LbDf0000000#g7 z02l)R00000000000MOzn0000000#g702%`T00000000000NCOv0000000#g702>1U z00000000000N~;%0000000#g7038DW00000000000O;Z<0000000#g703HJX00000 z000000Px}{0000000#g703QPY00000000000Qll40000000#g703ZVZ0000000000 z0084C0000000#g703iba000000000000`qK0000000#g703rhb000000000001)FS z0000000#g703-td000000000002t#a0000000#g703`ze000000000003hQi00000 z00#g7044(f000000000004U=q0000000#g704M_h000000000005Iby0000000#g7 z04f6j00000000000660)0000000#g704oCk000000000006^m?0000000#g704xIl z000000000007&B~0000000#g704)Om000000000008ry70000000#g704@Un00000 z0000009fNF0000000#g705Agp00000000000AS-N0000000#g705Jmq0000000000 z0BGYV0000000#g705Ssr00000000000C3|d0000000#g705bys00000000000C?jl z0000000#g705t;u00000000000D$8t0000000#g705$^v00000000000Epu#00000 z00#g705}5x00000000000FdJ-0000000#g7067By00000000000GQ(_0000000#g7 z06GHz00000000000HEV20000000#g706hZ$00000000000I1_A0000000#g706qf% z00000000000I=gI0000000#g706zl&00000000000J!5Q0000000#g706_x)00000 z000000KnrY0000000#g7073%*00000000000LbGg0000000#g707C-+0000000000 z0MO$o0000000#g707L@-00000000000NCRw0000000#g707U};00000000000N~>& z0000000#g707e4<00000000000O;c=0000000#g707nA=00000000000Py1|00000 z00#g707(M?00000000000Qlo50000000#g707?S@00000000000087D0000000#g7 z080Y^000000000000`tL0000000#g7089e_000000000001)IT0000000#g708Ik` z000000000002t&b0000000#g708Rq{000000000003hTj0000000#g708j$}00000 z0000004U@r0000000#g708s+~000000000005Iez0000000#g708#@00000000000 z0663*0000000#g708;}1000000000006^p@0000000#g708|42000000000007&F0 z0000000#g7096A3000000000008r#80000000#g709FG4000000000009fQG00000 z00#g709XS600000000000AS=O0000000#g709gY700000000000BGbW0000000#g7 z09pe800000000000C40e0000000#g709yk900000000000C?mm0000000#g709*qA z00000000000D$Bu0000000#g709^wB00000000000Epx$0000000#g70A2$C00000 z000000FdM;0000000#g70AT|F00000000000GQ+`0000000#g70Ad3G0000000000 z0HEY30000000#g70Am9H00000000000I1|B0000000#g70AvFI00000000000I=jJ z0000000#g70A&LJ00000000000J!8R0000000#g70A>RK00000000000KnuZ00000 z00#g70B8dM00000000000LbJh0000000#g70BHjN00000000000MO(p0000000#g7 z0BQpO00000000000NCUx0000000#g70BZvP00000000000N~^(0000000#g70Bi#Q z00000000000O;f>0000000#g70Br*R00000000000Py4}0000000#g70B!>S00000 z000000Qlr60000000#g70B-{T0000000000008AE0000000#g70B{2U0000000000 z00`wM0000000#g70CEEW000000000001)LU0000000#g70CNKX000000000002t*c z0000000#g70CWQY000000000003hWk0000000#g70Coca000000000004U`s00000 z00#g70C@ud000000000005Ih!0000000#g70D1!e00000000000666+0000000#g7 z0DJ=g000000000006^s^0000000#g70DS`h000000000007&I10000000#g70Dc1i z000000000008r&90000000#g70Dl7j000000000009fTH0000000#g70DuDk00000 z000000AS@P0000000#g70D%Jl00000000000BGeX0000000#g70D}Vn0000000000 z0C43f0000000#g70E7bo00000000000C?pn0000000#g70EGhp00000000000D$Ev z0000000#g70EPnq00000000000Ep!%0000000#g70EYtr00000000000FdP<00000 z00#g70Ehzs00000000000GQ<{0000000#g70Eq(t00000000000HEb40000000#g7 z0Ez z000000000003hZl0000000#g70G0C;$Ke000L7006=R0000000000 z001E8C;$Ke000L7006@S0000000000001cGC;$Ke000L7006`T0000000000001!O zC;$Ke000L7006}U00000000000021WC;$Ke000L70071V0000000000002PeC;$Ke z000L70077X0000000000002nmC;$Ke000L7007DZ0000000000002C;$Ke000L7 z0071C;$Ke000L7008X+0000000000001E9C;$Ke000L7 z008a-0000000000001cHC;$Ke000L7008d;0000000000001!PC;$Ke000L7008g< z00000000000021XC;$Ke000L7008j=0000000000002PfC;$Ke000L7008m>00000 z00000002nnC;$Ke000L7008s@0000000000002~0000000000004;SC;$Ke000L7 z008_00000000000005BaC;$Ke000L7008|10000000000005ZiC;$Ke000L700902 z0000000000005xqC;$Ke000L7009330000000000005}yC;$Ke000L70003500000 z00000006M)C;$Ke000L7000660000000000006k?C;$Ke000L7000970000000000 z006+~C;$Ke000L7000C80000000000007A7C;$Ke000L7000F90000000000007YF zC;$Ke000L7000IA0000000000007wNC;$Ke000L7000LB0000000000007|VC;$Ke z000L7000OC0000000000008LdC;$Ke000L7000aG0000000000008jlC;$Ke000L7 z000dH0000000000008*tC;$Ke000L7000gI00000000000002#C;$Ke000L7000jJ z0000000000000Q-C;$Ke000L7000mK0000000000000o_C;$Ke000L7000pL00000 z00000000>2C;$Ke000L7000sM0000000000001EAC;$Ke000L7000vN0000000000 z001cIC;$Ke000L7000yO0000000000001!QC;$Ke000L7000#P00000000000021Y zC;$Ke000L7000&Q0000000000002PgC;$Ke000L7000*R0000000000002noC;$Ke z000L7000;S0000000000002T0000000000003C&C;$Ke000L7 z000^U0000000000003a=C;$Ke000L7000{V0000000000003y|C;$Ke000L7000~W z000000000000405C;$Ke000L70012X0000000000004ODC;$Ke000L70018Z00000 z00000004mLC;$Ke000L7001Ba0000000000004;TC;$Ke000L7001Eb0000000000 z005BbC;$Ke000L7001Kd0000000000005ZjC;$Ke000L7001Ne0000000000005xr zC;$Ke000L7001Qf0000000000005}zC;$Ke000L7001Tg0000000000006M*C;$Ke z000L7001Zi0000000000006k@C;$Ke000L7001cj0000000000006-0C;$Ke000L7 z001fk0000000000007A8C;$Ke000L7001il0000000000007YGC;$Ke000L7001lm z0000000000007wOC;$Ke000L7001on0000000000007|WC;$Ke000L7001ro00000 z00000008LeC;$Ke000L7001up0000000000008jmC;$Ke000L7001!r0000000000 z008*uC;$Ke000L7001%s00000000000002$C;$Ke000L7001-u0000000000000Q; zC;$Ke000L7001=v0000000000000o`C;$Ke000L7001@w0000000000000>3C;$Ke z000L7001`x0000000000001EBC;$Ke000L7001}y0000000000001cJC;$Ke000L7 z0021z0000000000001!RC;$Ke000L7002A$00000000000021ZC;$Ke000L7002D% z0000000000002PhC;$Ke000L7002G&0000000000002npC;$Ke000L7002J(00000 z00000002C;$Ke000L7002S+0000000000003y}C;$Ke000L7002V-000000000000406 zC;$Ke000L7002b<0000000000004OEC;$Ke000L7002e=0000000000004mMC;$Ke z000L7002k?0000000000004;UC;$Ke000L7002n@0000000000005BcC;$Ke000L7 z002q^0000000000005ZkC;$Ke000L7002t_0000000000005xsC;$Ke000L7002w` z0000000000005}!C;$Ke000L7002z{0000000000006M+C;$Ke000L7002(}00000 z00000006k^C;$Ke000L7002+~0000000000006-1C;$Ke000L7002@10000000000 z007A9C;$Ke000L7002}30000000000007YHC;$Ke000L7003140000000000007wP zC;$Ke000L7003450000000000007|XC;$Ke000L7003760000000000008LfC;$Ke z000L7003D80000000000008jnC;$Ke000L7003G90000000000008*vC;$Ke000L7 z003JA00000000000002%C;$Ke000L7003PC0000000000000Q4C;$Ke000L7003eH00000 z00000001ECC;$Ke000L7003kJ0000000000001cKC;$Ke000L7003nK0000000000 z001!SC;$Ke000L7003qL00000000000021aC;$Ke000L7003tM0000000000002Pi zC;$Ke000L7003zO0000000000002nqC;$Ke000L7003$P0000000000002v0000000000000o| zC;$Ke000L7004^w0000000000000>5C;$Ke000L7004{x0000000000001EDC;$Ke z000L70052z0000000000001cLC;$Ke000L70055!0000000000001!TC;$Ke000L7 z005E%00000000000021bC;$Ke000L7005H&0000000000002PjC;$Ke000L7005K( z0000000000002nrC;$Ke000L7005T+0000000000002000000000000408C;$Ke000L7005l?0000000000004OG zC;$Ke000L7005o@0000000000004mOC;$Ke000L7005r^0000000000004;WC;$Ke z000L7005u_0000000000005BeC;$Ke000L7005!{0000000000005ZmC;$Ke000L7 z005%|0000000000005xuC;$Ke000L7005-~0000000000005}$C;$Ke000L7005>0 z0000000000006M;C;$Ke000L7005^10000000000006k`C;$Ke000L7005{200000 z00000006-3C;$Ke000L7005~30000000000007ABC;$Ke000L7006240000000000 z007YJC;$Ke000L7006550000000000007wRC;$Ke000L7006860000000000007|Z zC;$Ke000L7006B70000000000008LhC;$Ke000L7006H90000000000008jpC;$Ke z000L7006KA0000000000008*xC;$Ke000L7006NB00000000000002(C;$Ke000L7 z006QC0000000000000Q>C;$Ke000L7006TD0000000000000o}C;$Ke000L7006WE z0000000000000>6C;$Ke000L7006ZF0000000000001EEC;$Ke000L7006cG00000 z00000001cMC;$Ke000L7006fH0000000000001!UC;$Ke000L7006iI0000000000 z0021cC;$Ke000L7006oK0000000000002PkC;$Ke000L7006rL0000000000002ns zC;$Ke000L7006uM00000000000027 zC;$Ke000L70078C;$Ke000L7000FA z0000000000001EGC;$Ke000L7000LC0000000000001cOC;$Ke000L7000OD00000 z00000001!WC;$Ke000L7000RE00000000000021eC;$Ke000L7000aH0000000000 z002PmC;$Ke000L7000dI0000000000002nuC;$Ke000L7000gJ0000000000002<$ zC;$Ke000L7000jK0000000000003C;C;$Ke000L7000pM0000000000003a`C;$Ke z000L7000sN0000000000003z3C;$Ke000L7000vO00000000000040BC;$Ke000L7 z000#Q0000000000004OJC;$Ke000L7000&R0000000000004mRC;$Ke000L7000*S z0000000000004;ZC;$Ke000L7000^V0000000000005BhC;$Ke000L7000~X00000 z00000005ZpC;$Ke000L70015Z0000000000005xxC;$Ke000L70018a0000000000 z005}(C;$Ke000L7001Ec0000000000006M>C;$Ke000L7001Ke0000000000006k} zC;$Ke000L7001Nf0000000000006-6C;$Ke000L7001Qg0000000000007AEC;$Ke z000L7001Th0000000000007YMC;$Ke000L7001Wi0000000000007wUC;$Ke000L7 z001Zj0000000000007|cC;$Ke000L7001ck0000000000008LkC;$Ke000L7001fl z0000000000008jsC;$Ke000L7001im0000000000008*!C;$Ke000L7001ln00000 z000000002+C;$Ke000L7001oo0000000000000Q^C;$Ke000L7001rp0000000000 z000p1C;$Ke000L7001xr0000000000000>9C;$Ke000L7001!s0000000000001EH zC;$Ke000L7001%t0000000000001cPC;$Ke000L7001)u0000000000001!XC;$Ke z000L7001-v00000000000021fC;$Ke000L7001=w0000000000002PnC;$Ke000L7 z001@x0000000000002nvC;$Ke000L7001`y0000000000002<%C;$Ke000L7001}z z0000000000003CAC;$Ke000L7003D90000000000001EIC;$Ke000L7003JB z0000000000001cQC;$Ke000L7003MC0000000000001!YC;$Ke000L7003PD00000 z000000021gC;$Ke000L7003SE0000000000002PoC;$Ke000L7003VF0000000000 z002nwC;$Ke000L7003YG0000000000002<&C;$Ke000L7003eI0000000000003C= zC;$Ke000L7003hJ0000000000003a|C;$Ke000L7003kK0000000000003z5C;$Ke z000L7003nL00000000000040DC;$Ke000L7003qM0000000000004OLC;$Ke000L7 z003tN0000000000004mTC;$Ke000L7003wO0000000000004;bC;$Ke000L7003zP z0000000000005BjC;$Ke000L7003$Q0000000000005ZrC;$Ke000L7003BC;$Ke000L7004gl0000000000001EJC;$Ke000L7004mn0000000000001cR zC;$Ke000L7004po0000000000001!ZC;$Ke000L7004vq00000000000021hC;$Ke z000L7004#s0000000000002PpC;$Ke000L7004&t0000000000002nxC;$Ke000L7 z004*u0000000000002<(C;$Ke000L7004;v0000000000003C>C;$Ke000L7004{y z0000000000003a}C;$Ke000L70055#0000000000003z6C;$Ke000L70058$00000 z000000040EC;$Ke000L7005B%0000000000004OMC;$Ke000L7005E&0000000000 z004mUC;$Ke000L7005H(0000000000004;cC;$Ke000L7005K)0000000000005Bk zC;$Ke000L7005Q+0000000000005ZsC;$Ke000L7005W;0000000000005x!C;$Ke z000L7005Z<0000000000005}+C;$Ke000L7005i?0000000000006M^C;$Ke000L7 z005l@0000000000006l1C;$Ke000L7005r_0000000000006-9C;$Ke000L7005u` z0000000000007AHC;$Ke000L7005x{0000000000007YPC;$Ke000L7005!|00000 z00000007wXC;$Ke000L7005%}0000000000007|fC;$Ke000L7005)~0000000000 z008LnC;$Ke000L7005>10000000000008jvC;$Ke000L7005^20000000000008*% zC;$Ke000L7005{300000000000002CC;$Ke000L7 z006E90000000000001EKC;$Ke000L7006HA0000000000001cSC;$Ke000L7006NC z0000000000001!aC;$Ke000L7006WF00000000000021iC;$Ke000L7006ZG00000 z00000002PqC;$Ke000L7006cH0000000000002nyC;$Ke000L7006fI0000000000 z002<)C;$Ke000L7006iJ0000000000003C?C;$Ke000L7006lK0000000000003a~ zC;$Ke000L7006oL0000000000003z7C;$Ke000L7006rM00000000000040FC;$Ke z000L7006xO0000000000004ONC;$Ke000L7006!P0000000000004mVC;$Ke000L7 z006%Q0000000000004;dC;$Ke000L7006)R0000000000005BlC;$Ke000L7006=T z0000000000005ZtC;$Ke000L7006@U0000000000005x#C;$Ke000L7006`V00000 z00000005}-C;$Ke000L7006}W0000000000006M_C;$Ke000L70074Y0000000000 z006l2C;$Ke000L7007Aa0000000000006-AC;$Ke000L7007Db0000000000007AI zC;$Ke000L7007Jd0000000000007YQC;$Ke000L7007Me0000000000007wYC;$Ke z000L7007Pf0000000000007|gC;$Ke000L7007Sg0000000000008LoC;$Ke000L7 z007Vh0000000000008jwC;$Ke000L7007Yi0000000000008*&C;$Ke000L7007hl z00000000000002=C;$Ke000L7007km0000000000000Q|C;$Ke000L7007nn00000 z00000000p5C;$Ke000L7007tp0000000000000>DC;$Ke000L7007wq0000000000 z001ELC;$Ke000L7007zr0000000000001cTC;$Ke000L7007$s0000000000001!b zC;$Ke000L7007+u00000000000021jC;$Ke000L7007 zC;$Ke000L7008|30000000000000Q}C;$Ke000L7009040000000000000p6C;$Ke z000L7009350000000000000>EC;$Ke000L7000060000000000001EMC;$Ke000L7 z000370000000000001cUC;$Ke000L7000680000000000001!cC;$Ke000L7000CA z00000000000021kC;$Ke000L7000FB0000000000002PsC;$Ke000L7000IC00000 z00000002n!C;$Ke000L7000LD0000000000002<+C;$Ke000L7000RF0000000000 z003C^C;$Ke000L7000UG0000000000003b1C;$Ke000L7000XH0000000000003z9 zC;$Ke000L7000aI00000000000040HC;$Ke000L7000dJ0000000000004OPC;$Ke z000L7000gK0000000000004mXC;$Ke000L7000jL0000000000004;fC;$Ke000L7 z000mM0000000000005BnC;$Ke000L7000vP0000000000005ZvC;$Ke000L7000yQ z0000000000005x%C;$Ke000L7000#R0000000000005}V0000000000 z006-CC;$Ke000L7000^W0000000000007AKC;$Ke000L7000{X0000000000007YS zC;$Ke000L7000~Y0000000000007waC;$Ke000L70012Z0000000000007|iC;$Ke z000L70015a0000000000008LqC;$Ke000L7001Bc0000000000008jyC;$Ke000L7 z001Ed0000000000008*)C;$Ke000L7001He00000000000002?C;$Ke000L7001Kf z0000000000000Q~C;$Ke000L7001Ng0000000000000p7C;$Ke000L7001Qh00000 z00000000>FC;$Ke000L7001Ti0000000000001ENC;$Ke000L7001Wj0000000000 z001cVC;$Ke000L7001Zk0000000000001!dC;$Ke000L7001cl00000000000021l zC;$Ke000L7001fm0000000000002PtC;$Ke000L7001in0000000000002n#C;$Ke z000L7001op0000000000002<-C;$Ke000L7001rq0000000000003C_C;$Ke000L7 z001ur0000000000003b2C;$Ke000L7001xs0000000000003zAC;$Ke000L7001)v z00000000000040IC;$Ke000L7001-w0000000000004OQC;$Ke000L7001`z00000 z00000004mYC;$Ke000L70024$0000000000004;gC;$Ke000L70027%0000000000 z005BoC;$Ke000L7002A&0000000000005ZwC;$Ke000L7002D(0000000000005x& zC;$Ke000L7002G)0000000000005}=C;$Ke000L7002J*0000000000006M|C;$Ke z000L7002M+0000000000006l5C;$Ke000L7002P-0000000000006-DC;$Ke000L7 z002S;0000000000007ALC;$Ke000L7002V<0000000000007YTC;$Ke000L7002Y= z0000000000007wbC;$Ke000L7002b>0000000000007|jC;$Ke000L7002e?00000 z00000008LrC;$Ke000L7002k^0000000000008jzC;$Ke000L7002t{0000000000 z008**C;$Ke000L7002w|00000000000002@C;$Ke000L7002z}0000000000000R0 zC;$Ke000L7002$~0000000000000p8C;$Ke000L7002)00000000000000>GC;$Ke z000L7002-10000000000001EOC;$Ke000L7002=20000000000001cWC;$Ke000L7 z002@30000000000001!eC;$Ke000L7002`400000000000021mC;$Ke000L700316 z0000000000002PuC;$Ke000L7003470000000000002n$C;$Ke000L7003DA00000 z00000002<;C;$Ke000L7003GB0000000000003C`C;$Ke000L7003MD0000000000 z003b3C;$Ke000L7003PE0000000000003zBC;$Ke000L7003VG00000000000040J zC;$Ke000L7003bI0000000000004ORC;$Ke000L7003hK0000000000004mZC;$Ke z000L7003kL0000000000004;hC;$Ke000L7003nM0000000000005BpC;$Ke000L7 z003tO0000000000005ZxC;$Ke000L7003zQ0000000000005x(C;$Ke000L7003$R z0000000000005}>C;$Ke000L7003(S0000000000006M}C;$Ke000L7003+T00000 z00000006l6C;$Ke000L7003HC;$Ke000L7004Xj00000 z00000001EPC;$Ke000L7004ak0000000000001cXC;$Ke000L7004dl0000000000 z001!fC;$Ke000L7004gm00000000000021nC;$Ke000L7004jn0000000000002Pv zC;$Ke000L7004mo0000000000002n%C;$Ke000L7004pp0000000000002<x00000000000040KC;$Ke000L7004{z z0000000000004OSC;$Ke000L7004~!0000000000004maC;$Ke000L70052#00000 z00000004;iC;$Ke000L70055$0000000000005BqC;$Ke000L70058%0000000000 z005ZyC;$Ke000L7005B&0000000000005x)C;$Ke000L7005E(0000000000005}? zC;$Ke000L7005H)0000000000006M~C;$Ke000L7005K*0000000000006l7C;$Ke z000L7005N+0000000000006-FC;$Ke000L7005Q-0000000000007ANC;$Ke000L7 z005T;0000000000007YVC;$Ke000L7005W<0000000000007wdC;$Ke000L7005c> z0000000000007|lC;$Ke000L7005f?0000000000008LtC;$Ke000L7005i@00000 z00000008j#C;$Ke000L7005o_0000000000008*-C;$Ke000L7005r`0000000000 z0002_C;$Ke000L7005u{0000000000000R2C;$Ke000L7005x|0000000000000pA zC;$Ke000L7005%~0000000000000>IC;$Ke000L7005*00000000000001EQC;$Ke z000L7005;10000000000001cYC;$Ke000L7005{40000000000001!gC;$Ke000L7 z005~500000000000021oC;$Ke000L7006260000000000002PwC;$Ke000L700657 z0000000000002n&C;$Ke000L7006880000000000002<=C;$Ke000L7006B900000 z00000003C|C;$Ke000L7006HB0000000000003b5C;$Ke000L7006TF0000000000 z003zDC;$Ke000L7006ZH00000000000040LC;$Ke000L7006cI0000000000004OT zC;$Ke000L7006fJ0000000000004mbC;$Ke000L7006iK0000000000004;jC;$Ke z000L7006lL0000000000005BrC;$Ke000L7006oM0000000000005ZzC;$Ke000L7 z006rN0000000000005x*C;$Ke000L7006xP0000000000005}@C;$Ke000L7006!Q z0000000000006N0C;$Ke000L7006%R0000000000006l8C;$Ke000L7006)S00000 z00000006-GC;$Ke000L7006-T0000000000007AOC;$Ke000L7006@V0000000000 z007YWC;$Ke000L7006}X0000000000007weC;$Ke000L70071Y0000000000007|m zC;$Ke000L70074Z0000000000008LuC;$Ke000L7007Ab0000000000008j$C;$Ke z000L7007Gd0000000000008*;C;$Ke000L7007Je00000000000002`C;$Ke000L7 z007Mf0000000000000R3C;$Ke000L7007Pg0000000000000pBC;$Ke000L7007Sh z0000000000000>JC;$Ke000L7007Yj0000000000001ERC;$Ke000L7007bk00000 z00000001cZC;$Ke000L7007el0000000000001!hC;$Ke000L7007hm0000000000 z0021pC;$Ke000L7007kn0000000000002PxC;$Ke000L7007no0000000000002n( zC;$Ke000L7007qp0000000000002<>C;$Ke000L7007tq0000000000003C}C;$Ke z000L7007wr0000000000003b6C;$Ke000L7007zs0000000000003zEC;$Ke000L7 z007$t00000000000040MC;$Ke000L7007(u0000000000004OUC;$Ke000L7007+v z0000000000004mcC;$Ke000L700700000 z00000008*K zC;$Ke000L7008v{0000000000001ESC;$Ke000L7008y|0000000000001caC;$Ke z000L7008#}0000000000001!iC;$Ke000L7008&~00000000000021qC;$Ke000L7 z008<10000000000002PyC;$Ke000L7008?20000000000002n)C;$Ke000L7008_3 z0000000000002W0000000000008*=C;$Ke z000L7000^X00000000000002|C;$Ke000L7000{Y0000000000000R5C;$Ke000L7 z0012a0000000000000pDC;$Ke000L70015b0000000000000>LC;$Ke000L7001Ee z0000000000001ETC;$Ke000L7001Hf0000000000001cbC;$Ke000L7001Kg00000 z00000001!jC;$Ke000L7001Nh00000000000021rC;$Ke000L7001Qi0000000000 z002PzC;$Ke000L7001Wk0000000000002n*C;$Ke000L7001cm0000000000002<@ zC;$Ke000L7001fn0000000000003D0C;$Ke000L7001io0000000000003b8C;$Ke z000L7001lp0000000000003zGC;$Ke000L7001oq00000000000040OC;$Ke000L7 z001!u0000000000004OWC;$Ke000L7001%v0000000000004meC;$Ke000L7001)w z0000000000004;mC;$Ke000L7001-x0000000000005BuC;$Ke000L7001=y00000 z00000005Z$C;$Ke000L7001`!0000000000005x;C;$Ke000L7001}#0000000000 z005}`C;$Ke000L70024%0000000000006N3C;$Ke000L70027&0000000000006lB zC;$Ke000L7002D)0000000000006-JC;$Ke000L7002G*0000000000007ARC;$Ke z000L7002J+0000000000007YZC;$Ke000L7002M-0000000000007whC;$Ke000L7 z002S<0000000000007|pC;$Ke000L7002b?0000000000008LxC;$Ke000L7002e@ z0000000000008j(C;$Ke000L7002h^0000000000008*>C;$Ke000L7002k_00000 z000000002}C;$Ke000L7002n`0000000000000R6C;$Ke000L7002t|0000000000 z000pEC;$Ke000L7002w}0000000000000>MC;$Ke000L7002z~0000000000001EU zC;$Ke000L7002-20000000000001ccC;$Ke000L7002=30000000000001!kC;$Ke z000L7002@400000000000021sC;$Ke000L7002`50000000000002P!C;$Ke000L7 z002}60000000000002n+C;$Ke000L7003170000000000002<^C;$Ke000L700348 z0000000000003D1C;$Ke000L7003790000000000003b9C;$Ke000L7003AA00000 z00000003zHC;$Ke000L7003GC00000000000040PC;$Ke000L7003JD0000000000 z004OXC;$Ke000L7003ME0000000000004mfC;$Ke000L7003PF0000000000004;n zC;$Ke000L7003SG0000000000005BvC;$Ke000L7003VH0000000000005Z%C;$Ke z000L7003YI0000000000005xNC;$Ke000L70043a0000000000001EVC;$Ke000L70046b z0000000000001cdC;$Ke000L70049c0000000000001!lC;$Ke000L7004Cd00000 z000000021tC;$Ke000L7004Fe0000000000002P#C;$Ke000L7004If0000000000 z002n-C;$Ke000L7004Lg0000000000002<_C;$Ke000L7004Oh0000000000003D2 zC;$Ke000L7004Ri0000000000003bAC;$Ke000L7004Uj0000000000003zIC;$Ke z000L7004Xk00000000000040QC;$Ke000L7004al0000000000004OYC;$Ke000L7 z004dm0000000000004mgC;$Ke000L7004gn0000000000004;oC;$Ke000L7004jo z0000000000005BwC;$Ke000L7004sr0000000000005Z&C;$Ke000L7004yt00000 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 z!2kdMCDLUi0BHUL008L#!2kdMCCX(a0BHXM008OmzyJULCBkJS0B8UN008OWzyJUL zCAwuK0B8XO008OGzyJULC9-8C0B8aP008O0zyJULC8}j40B8dQ008N*zyJULC8A{{ z0B8gR008NrzyJULC7NX<0B8jS008NbzyJULC6Z+%0B8mT008NLzyJULC5mMv0B8pU z008N5zyJULC4yxn0B8sV008M=zyJULC3c008OmzW@LKB|>E+0B8^d008OWzW@LKB|2p! z0B8{e008OGzW@LKB{F3s0B8~f008O0zW@LKB`Rek0B92g008N*zW@LKB_d@c0B95h z008NrzW@LKB^qTU0B98i008NbzW@LKB@$&M0B9Bj008NLzW@LKB?@IE0B9Ek008N5 zzW@LKB?4t60B9Hl008M=zW@LKCHiC}0B9Km008MwzW@LKCGun>0B9Nn008MgzW@LK zCF*1(0B9Qo008MQzW@LKCE{cx0B9Tp008MAzW@LKCE8>p0B9Wq008L_zW@LKCDLRh z0B9Zr008L#zW@LKCCX$Z0B9cs008Omz5oCJCBkGR0B9ft008OWz5oCJCAwrJ0B9iu z008OGz5oCJC9-5B0B9lv008O0z5oCJC8}g30B9ow008N*z5oCJC8A^`0B9rx008Nr zz5oCJC7NU;0B9uy008Nbz5oCJC6Z($0B9xz008NLz5oCJC5mJu0B9!!008N5z5oCJ zC4yum0B9%#008M=z5oCJC3<8e0B9)$008Mwz5oCJC30jW0B9-%008Mgz5oCJC2C|O z0B9=&008MQz5oCJC1PYG0B9@(008MAz5oCJC0b-80B9`)008L_z5oCJB~oN00B9}* z008L#z5oCJB}!x@0BA1+008Omy#N3IB|>B*0BA4-008OWy#N3IB|2mz0BA7;008OG zy#N3IB{F0r0BAA<008O0y#N3IB`Rbj0BAD=008N*y#N3IB_d=b0BAG>008Nry#N3I zB^qQT0BAJ?008Nby#N3IB@$#L0BAM@008NLy#N3IB?@FD0BAP^008N5y#N3IB?4q5 z0BAS_008M=y#N3ICHi9|0BAV`008Mwy#N3ICGuk=0BAY{008Mgy#N3ICF)}&0BAb| z008MQy#N3ICE{Zw0BAe}008MAy#N3ICE8;o0BAh~008L_y#N3ICDLOg0BAl0008L# zy#N3ICCXzY0BAo1008OmyZ`_HCBkDQ0BAr2008OWyZ`_HCAwoI0BAu3008OGyZ`_H zC9-2A0BAx4008O0yZ`_HC8}d20BA!5008N*yZ`_HC8A>_0BA%6008NryZ`_HC7NR- z0BA)7008NbyZ`_HC6Z$#0BA-8008NLyZ`_HC5mGt0BA=9008N5yZ`_HC4yrl0BA@A z008M=yZ`_HC3<5d0BA`B008MwyZ`_HC30gV0BA}C008MgyZ`_HC2C_N0BB1D008MQ zyZ`_HC1PVF0BB4E008MAyZ`_HC0b)70BB7F008L_yZ`_HB~oJ~0BBAG008L#yZ`_H zB}!u?0BBDH008Omy8r+GB|>8)0BBGI008OWy8r+GB|2jy0BBJJ008OGy8r+GB{E|q z0BBMK008O0y8r+GB`RYi0BBPL008N*y8r+GB_d-a0BBSM008Nry8r+GB^qNS0BBVN z008Nby8r+GB@$yK0BBYO008NLy8r+GB?@CC0BBbP008N5y8r+GB?4n40BBeQ008M= zy8r+GCHi6{0BBhR008Mwy8r+GCGuh<0BBkS008Mgy8r+GCF)`%0BBnT008MQy8r+G zCE{Wv0BBqU008MAy8r+GCE8*n0BBtV008L_y8r+GCDLLf0BBwW008L#y8r+GCCXwX z0BBzX008Omx&QzFCBkAP0BB$Y008OWx&QzFCAwlH0BB(Z008OGx&QzFC9+~90BB+a z008O0x&QzFC8}a10BB0BCOn z008Omxc~qEB|>5(0BCRo008OWxc~qEB|2gx0BCUp008OGxc~qEB{E_p0BCXq008O0 zxc~qEB`RVh0BCar008N*xc~qEB_d)Z0BCds008Nrxc~qEB^qKR0BCgt008Nbxc~qE zB@$vJ0BCju008NLxc~qEB?@9B0BCmv008N5xc~qEB?4k30BCpw008M=xc~qECHi3` z0BCsx008Mwxc~qECGue;0BCvy008Mgxc~qECF)@$0BCyz008MQxc~qECE{Tu0BC#! z008MAxc~qECE8&m0BCL_xc~qECDLIe0BC*$008L#xc~qECCXtW0BC;%008Om zxBvhDCBk7O0BC>&008OWxBvhDCAwiG0BC^(008OGxBvhDC9+{80BC{)008O0xBvhD zC8}X00BC~*008N*xBvhDC8A*@0BD2+008NrxBvhDC7NL*0BD5-008NbxBvhDC6Zwz z0BD8;008NLxBvhDC5mAr0BDB<008N5xBvhDC4ylj0BDE=008M=xBvhDC3;~b0BDH> z008MwxBvhDC30aT0BDK?008MgxBvhDC2C2&0BDc|008OWw*UYCB|2dw0BDf}008OGw*UYCB{E?o0BDi~008O0w*UYCB`RSg z0BDm0008N*w*UYCB_d%Y0BDp1008Nrw*UYCB^qHQ0BDs2008Nbw*UYCB@$sI0BDv3 z008NLw*UYCB?@6A0BDy4008N5w*UYCB?4h20BD#5008M=w*UYCCHi0_0BD&6008Mw zw*UYCCGub-0BD*7008Mgw*UYCCF)=#0BD;8008MQw*UYCCE{Qt0BD>9008MAw*UYC zCE8#l0BD^A008L_w*UYCCDLFd0BD{B008L#w*UYCCCXqV0BD~C008Omwg3PBCBk4N z0BE2D008OWwg3PBCAwfF0BE5E008OGwg3PBC9+^70BE8F008O0wg3PBC8}T~0BEBG z008N*wg3PBC8A&?0BEEH008Nrwg3PBC7NI)0BEHI008Nbwg3PBC6Zty0BEKJ008NL zwg3PBC5m7q0BENK008N5wg3PBC4yii0BEQL008M=wg3PBC3;{a0BETM008Mwwg3PB zC30XS0BEWN008Mgwg3PBC2C+K0BEZO008MQwg3PBC1PMC0BEcP008MAwg3PBC0bx4 z0BEfQ008L_wg3PBB~oA{0BEiR008L#wg3PBB}!l<0BElS008OmwEzGAB|=~%0BEoT z008OWwEzGAB|2av0BErU008OGwEzGAB{E60BFJl008O0v;Y79C8}Q}0BFMm008N*v;Y79 zC8A#>0BFPn008Nrv;Y79C7NF(0BFSo008Nbv;Y79C6Zqx0BFVp008NLv;Y79C5m4p z0BFYq008N5v;Y79C4yfh0BFbr008M=v;Y79C3;^Z0BFes008Mwv;Y79C30UR0BFht z008Mgv;Y79C2C(J0BFku008MQv;Y79C1PJB0BFnv008MAv;Y79C0bu30BFqw008L_ zv;Y79B~o7`0BFtx008L#v;Y79B}!i;0BFwy008Omvj6}8B|={$0BFzz008OWvj6}8 zB|2Xu0BF$!008OGvj6}8B{E+m0BF(#008O0vj6}8B`RMe0BF+$008N*vj6}8B_dxW z0BF<%008Nrvj6}8B^qBO0BF?&008Nbvj6}8B@$mG0BF_(008NLvj6}8B?@080BF|) z008N5vj6}8B?4b00BG0*008M=vj6}8CHh_@0BG3+008Mwvj6}8CGuV*0BG6-008Mg zvj6}8CF))z0BG9;008MQvj6}8CE{Kr0BGC<008MAvj6}8CE8vj0BGF=008L_vj6}8 zCDL9b0BGI>008L#vj6}8CCXkT0BGL?008OmvH$=7CBj}L0BGO@008OWvH$=7CAwZD z0BGR^008OGvH$=7C9+;50BGU_008O0vH$=7C8}N|0BGX`008N*vH$=7C8Ay=0BGa{ z008NrvH$=7C7NC&0BGd|008NbvH$=7C6Znw0BGg}008NLvH$=7C5m1o0BGj~008N5 zvH$=7C4ycg0BGn0008M=vH$=7C3;>Y0BGq1008MwvH$=7C30RQ0BGt2008MgvH$=7 zC2C$I0BGw3008MQvH$=7C1PGA0BGz4008MAvH$=7C0br20BG$5008L_vH$=7B~o4_ z0BG(6008L#vH$=7B}!f-0BG+7008Omu>b%6B|=^#0BG<8008OWu>b%6B|2Ut0BG?9 z008OGu>b%6B{E(l0BG_A008O0u>b%6B`RJd0BG|B008N*u>b%6B_duV0BH0C008Nr zu>b%6B^q8N0BH3D008Nbu>b%6B@$jF0BH6E008NLu>b%6B??|70BH9F008N5u>b%6 zB?4X~0BHCG008M=u>b%6CHh??0BHFH008Mwu>b%6CGuS)0BHII008Mgu>b%6CF)%y z0BHLJ008MQu>b%6CE{Hq0BHOK008MAu>b%6CE8si0BHRL008L_u>b%6CDL6a0BHUM z008L#u>b%6CCXhS0BHXN008OmumAu5CBj`K0B8UO008OWumAu5CAwWC0B8XP008OG zumAu5C9+*40B8aQ008O0umAu5C8}K{0B8dR008N*umAu5C8Av<0B8gS008NrumAu5 zC7N9%0B8jT008NbumAu5C6Zkv0B8mU008NLumAu5C5l}n0B8pV008N5umAu5C4yZf z0B8sW008M=umAu5C3;;X0B8vX008MwumAu5C30OP0B8yY008MgumAu5C2CzH0B8#Z z008MQumAu5C1PD90B8&a008MAumAu5C0bo10B8*b008L_umAu5B~o1^0B8;c008L# zumAu5B}!c+0B8>d008OmuK)l4B|=>!0B8^e008OWuK)l4B|2Rs0B8{f008OGuK)l4 zB{E$k0B8~g008O0uK)l4B`RGc0B92h008N*uK)l4B_drU0B95i008NruK)l4B^q5M z0B98j008NbuK)l4B@$gE0B9Bk008NLuK)l4B??_60B9El008N5uK)l4B?4U}0B9Hm z008M=uK)l4CHh<>0B9Kn008MwuK)l4CGuP(0B9No008MguK)l4CF)!x0B9Qp008MQ zuK)l4CE{Ep0B9Tq008MAuK)l4CE8ph0B9Wr008L_uK)l4CDL3Z0B9Zs008L#uK)l4 zCCXeR0B9ct008Omt^fc3CBj@J0B9fu008OWt^fc3CAwTB0B9iv008OGt^fc3C9+&3 z0B9lw008O0t^fc3C8}H`0B9ox008N*t^fc3C8As;0B9ry008Nrt^fc3C7N6$0B9uz z008Nbt^fc3C6Zhu0B9x!008NLt^fc3C5l`m0B9!#008N5t^fc3C4yWe0B9%$008M= zt^fc3C3;*W0B9)%008Mwt^fc3C30LO0B9-&008Mgt^fc3C2CwG0B9=(008MQt^fc3 zC1PA80B9@)008MAt^fc3C0bl00B9`*008L_t^fc3B~n}@0B9}+008L#t^fc3B}!Z* z0BA1-008OmtpET2B|=;z0BA4;008OWtpET2B|2Or0BA7<008OGtpET2B{Ezj0BAA= z008O0tpET2B`RDb0BAD>008N*tpET2B_doT0BAG?008NrtpET2B^q2L0BAJ@008Nb ztpET2B@$dD0BAM^008NLtpET2B???50BAP_008N5tpET2B?4R|0BAS`008M=tpET2 zCHh+=0BAV{008MwtpET2CGuM&0BAY|008MgtpET2CF)xw0BAb}008MQtpET2CE{Bo z0BAe~008MAtpET2CE8mg0BAi0008L_tpET2CDL0Y0BAl1008L#tpET2CCXbQ0BAo2 z008OmtN;K1CBj=I0BAr3008OWtN;K1CAwQA0BAu4008OGtN;K1C9+#20BAx5008O0 ztN;K1C8}E_0BA!6008N*tN;K1C8Ap-0BA%7008NrtN;K1C7N3#0BA)8008NbtN;K1 zC6Zet0BA-9008NLtN;K1C5l@l0BA=A008N5tN;K1C4yTd0BA@B008M=tN;K1C3;&V z0BA`C008MwtN;K1C30IN0BA}D008MgtN;K1C2CtF0BB1E008MQtN;K1C1P770BB4F z008MAtN;K1C0bh~0BB7G008L_tN;K1B~n`?0BBAH008L#tN;K1B}!W)0BBDI008Om zs{jB0B|=*y0BBGJ008OWs{jB0B|2Lq0BBJK008OGs{jB0B{Ewi0BBML008O0s{jB0 zB`RAa0BBPM008N*s{jB0B_dlS0BBSN008Nrs{jB0B^p~K0BBVO008Nbs{jB0B@$aC z0BBYP008NLs{jB0B??<40BBbQ008N5s{jB0B?4O{0BBeR008M=s{jB0CHh(<0BBhS z008Mws{jB0CGuJ%0BBkT008Mgs{jB0CF)uv0BBnU008MQs{jB0CE{8n0BBqV008MA zs{jB0CE8jf0BBtW008L_s{jB0CDK|X0BBwX008L#s{jB0CCXYP0BBzY008OmssI1~ zCBj-H0BB$Z008OWssI1~CAwN90BB(a008OGssI1~C9+y10BB+b008O0ssI1~C8}B^ z0BB0BCLn008L#ssI1~B}!T(0BCOo008OmsQ>@}B|=&x z0BCRp008OWsQ>@}B|2Ip0BCUq008OGsQ>@}B{Eth0BCXr008O0sQ>@}B`R7Z0BCas z008N*sQ>@}B_diR0BCdt008NrsQ>@}B^p{J0BCgu008NbsQ>@}B@$XB0BCjv008NL zsQ>@}B??+30BCmw008N5sQ>@}B?4L`0BCpx008M=sQ>@}CHh$;0BCsy008MwsQ>@} zCGuG$0BCvz008MgsQ>@}CF)ru0BCy!008MQsQ>@}CE{5m0BC##008MAsQ>@}CE8ge z0BC&$008L_sQ>@}CDK_W0BC*%008L#sQ>@}CCXVO0BC;&008Omr~m)|CBj)G0BC>( z008OWr~m)|CAwK80BC^)008OGr~m)|C9+v00BC{*008O0r~m)|C8}8@0BC~+008N* zr~m)|C8Aj*0BD2-008Nrr~m)|C7M|z0BD5;008Nbr~m)|C6ZYr0BD8<008NLr~m)| zC5l-j0BDB=008N5r~m)|C4yNb0BDE>008M=r~m)|C3;yT0BDH?008Mwr~m)|C30CL z0BDK@008Mgr~m)|C2CnD0BDN^008MQr~m)|C1P150BDQ_008MAr~m)|C0bb|0BDT` z008L_r~m)|B~n==0BDW{008L#r~m)|B}!Q&0BDZ|008OmrvLx{B|=#w0BDc}008OW zrvLx{B|2Fo0BDf~008OGrvLx{B{Eqg0BDj0008O0rvLx{B`R4Y0BDm1008N*rvLx{ zB_dfQ0BDp2008NrrvLx{B^p^I0BDs3008NbrvLx{B@$UA0BDv4008NLrvLx{B??(2 z0BDy5008N5rvLx{B?4I_0BD#6008M=rvLx{CHhz-0BD&7008MwrvLx{CGuD#0BD*8 z008MgrvLx{CF)ot0BD;9008MQrvLx{CE{2l0BD>A008MArvLx{CE8dd0BD^B008L_ zrvLx{CDK?V0BD{C008L#rvLx{CCXSN0BD~D008OmrT_o`CBj%F0BE2E008OWrT_o` zCAwH70BE5F008OGrT_o`C9+r~0BE8G008O0rT_o`C8}5?0BEBH008N*rT_o`C8Ag) z0BEEI008NrrT_o`C7M_y0BEHJ008NbrT_o`C6ZVq0BEKK008NLrT_o`C5l)i0BENL z008N5rT_o`C4yKa0BEQM008M=rT_o`C3;vS0BETN008MwrT_o`C309K0BEWO008Mg zrT_o`C2CkC0BEZP008MQrT_o`C1O}40BEcQ008MArT_o`C0bY{0BEfR008L_rT_o` zB~n-<0BEiS008L#rT_o`B}!N%0BElT008Omr2qf_B|=yv0BEoU008OWr2qf_B|2Cn z0BErV008OGr2qf_B{Enf0BEuW008O0r2qf_B`R1X0BExX008N*r2qf_B_dcP0BE!Y z008Nrr2qf_B^p>H0BE%Z008Nbr2qf_B@$R90BE)a008NLr2qf_B??$10BE-b008N5 zr2qf_B?4F^0BE=c008M=r2qf_CHhw+0BE@d008Mwr2qf_CGuA!0BE`e008Mgr2qf_ zCF)ls0BE}f008MQr2qf_CE`~k0BF1g008MAr2qf_CE8ac0BF4h008L_r2qf_CDK0BFMn008N*qyPW^C8Ad(0BFPo008Nr zqyPW^C7M?x0BFSp008NbqyPW^C6ZSp0BFVq008NLqyPW^C5l%h0BFYr008N5qyPW^ zC4yHZ0BFbs008M=qyPW^C3;sR0BFet008MwqyPW^C306J0BFhu008MgqyPW^C2ChB z0BFkv008MQqyPW^C1O`30BFnw008MAqyPW^C0bV`0BFqx008L_qyPW^B~n);0BFty z008L#qyPW^B}!K$0BFwz008OmqW}N@B|=vu0BFz!008OWqW}N@B|29m0BF$#008OG zqW}N@B{Eke0BF($008O0qW}N@B`Q}W0BF+%008N*qW}N@B_dZO0BF<&008NrqW}N@ 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�K07#8B`Ah)-NQuYjYEl0G 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 zV`yP=VPkY_9Zy;QCFfcGN00000 z00000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcGO0000000000X>N95Y-wa5b98cPZf80mV{dMB za&K%PV`yP=VPkY_9Zy;QCFfcGP z0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcGQ0000000000X>N95Y-wa5b98cPZf80m zV{dMBa&K%PV`yP=VPkY_9Zy;QC zFfcGR0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcGS0000000000X>N95Y-wa5b98cP zZf80mV{dMBa&K%PV`yP=VPkY_9 zZy;QCFfcGT0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5 zb98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY< zav)VJFfcGdASg^mDIjfib95kLWgum9V_|S*WFT~JAY64YFfc(NZ*m}9ZU6uPX>N95 zY-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5 zb98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY< zav)VJFfcGhAShE$DIjfib95kLWgum9V_|S*WFT~JAY64YFfc^`X>N95Y-wa5b98cP zZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJN0000000000X>N95Y-wa5b98cPZf80m zV{dMBa&K%PV`yP=VPkY_9Zy;QC zFfcJO0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJP0000000000X>N95Y-wa5b98cP zZf80mV{dMBa&K%PV`yP=VPkY_9 zZy;QCFfcJQ0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJR0000000000X>N95Y-wa5 zb98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJS0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY< zav)VJFfcJTAShE=PAMR5b#rteVr3v@b7Ns}Wn>_9Zy;QCFfcJT0000000000X>N95 zY-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJU0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP= zVPkY_9Zy;QCFfcJV0000000000 zX>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY< zav)VJFfcJeAShE+LMb3^b#rteVr3v@b7Ns}Wn>_9Zy;QCFfcJe0000000000X>N95 zY-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkY_9Zy;QCFfcJf0000000000X>N95Y-wa5b98cPZf80mV{dMBa&K%PV`yP= zVPkYN95Y-wa5 zb98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMBa&K%PV`yP=VPkYN95Y-wa5b98cPZf80mV{dMB za&K%PV`yP=VPkYN95Y-wa5b98cPZf80mX>4pQW^ZzBWn>^#R7Nd0AYyrRWdHyGX>N95Y-wa5Zgp*9 zWpX=fAW^`q8ASW#+0000000000X>N95Y-wa5Zgp*9WpX

=fAW^`q8ASW&-0000000000X>N95Y-wa5Zgp*9WpXCoCXuav)@BXK8dGVPN95Y-wa5 zZgp*9WpX=fAW^`q8AZ2)PZ*FC7bRctSXKnxh00000Wo~3} zbaEg)Js@;%Yh`X;Utw}`VR;UvFY+Wn*+GDFAY1W?yr3VPk79Vqs%zC@C#I zX>(t1Vrpe$bSNnRZf|rTYh`&~Yh`6{UvqR}V{0yDZE$pXC@BDMVrpe$bYEp`Wo>0{ zbN~PVbZBXEWM6P$a&&nwYIARHFKKRLY;|O1FK%paXl-F`ZZBkIbYW?1FKKjTa$$6D za&s?fbY*g1X>D+9E@*IY0Bv7yVrpe$bRZ!;AZ~SRY;bgP00000ZC`10E^lILWn*+- zX>?_BVRUbDAR#>BZC`10E@5(V zVR>I^bY*g3bZ>GXAw3{%UvFY+Wn*+LK5buiVQh6}E@5(VVR?_BVRUbDAY^Z4b0BVSbRcGFbRc7Oa&l#EbRc$NY;|P-X>?_B zVRUbDAa8YaAa7%X|Zf|rTbZ={AZeMeBa%pa7E@f?Sba^N#0AqD>a%FCG zAU!=GCv_(PFnBO9FfbrIJs@LmWMyz~X>N2NVQyp~V{c?-aBpdDbRaxEATW4FMn*;e z00000a$#;~WpgfbX?kTSDIh&PATl6tav*YHZf9k4E^}#mWhf~iJv|^aAa8OYa$#;~ zWpgfbX?kTSDIh&PAT|I1V_|M?Z*(AIZ*6d4a%CWCbY*g3bZ>HVAa7_9Zy;f8Y;R*>bY&oIWo>VA zc_9E$VRB(@Wprh7CvzZaZgyd8X=EV)Mqz1eWn>_9Zy;k~Y-}JyLq#A#P)Q*GMqz1e zWn>_9Zy;k~Y-}KMb#8QNZDk-qP)Q*GNp5sya&BR4AZ2oLZ*p@0Mqz1eWn>_9Zy;k~ zY-}KGX<}nvb7f;7K~PB{07hYHY-MC1bZ;PIVQg$5bY*2AK~PB{07Y(OAa7_9Zy;uAZe$=~Zh0VfVQgt+ zAaidZW@&6?Apk~UX>4U=AarjaW@&C@AYpEKAZB%LV{~b6ZXo~wMqz1eWn>_9Zy;%I zc5iECAYpEKAZB%LV{~b6ZXp0rVRB(@Wprh7CvzZmZgX{TaBp&SWn>`$Pjz%4Z)PBE zWo>VAc_9EtMM-XHbZKF1X?kTKMqz1eWn?Y@M@2?yZeeU`dSxI+VQFk-WG(LZ*m|;VQFk-WG(4U=E&x+y zb8~5LZXiKqWJhvgaA+V#VQFk-WG(;zQ)P2=X>V>IL1bh{a$#_2AVy(nY-MC1V{dMD zWpZ?BZf78Ha&L5RVs&O9M{;3sXi#!*bZ;&IQ)P2=X>V>IQe|y#c4bF$VQ^?5Mqz1e zWn?Y@Q)P2=X>V>IQgv=ea$#_2AVy(nY-MCF00000Q)P2=X>V>IQgv=ea$#_2AVy(n zY-MC1V{dMDWpZ?BZf78Ha&L5RVs&O9RAp{+Z*ov_Z**@i07pe2X>%Z9Y;t8`WO*QI zZfSIBVQgu7Wn?Y@00000M@1lMb0BVSbRc@5}Y-xIBWFT*HAZc?TW@&C= zY-xIBWG(;z00000O?7N^X>e?1AZc!CbZKF1X?kIFX>V?GAYpQ4AZ~ATAaiwaaBp&S zWn?Y@00000Mrm$gY-xIBAZc?TZf|rTVQg$~cV%QCVr6D;a%CWCZfSIBVQgu7VRUJ4 zZY}@-O?7N^X>e?1AZBT9VQgu7VRUJ4ZgU`Ea%CWHZ*(AYb#QQRa&%>6E&xVhX>4U= zAarjaX>MtBX<=+>dSxJUWpi_BZ*DFCQ)P2=X>V>IVQg|`VPttAa&>NQX>MmMZf|rT zb9HcVZ*p`XaA9&`Y;0w0AaZqXE&xYzVQ^?5NkkxSZ*(AKcxiKVE&xYzVQ^?5NkkxF zY;t8`WO*QEcxiKVE&xYzVQ^?5X>%ZQb#88HZf7n4Lt$V>IZDDR4U=AarjaX>MtBX<=+>dSxJIa$#_2E&u=kXL4b1 zXdq#1a%Ev;c_4CiZfM zAZ~ATAZ2)Ib962MM{;3sXdrE2Y;131AZB4{Y-MCF07r6RaA+V#Qbk1|W?^Y;Wn?Y@ z00000M{;3sXdp&XMMWTHVQFk-WGo4U= zE&x(>ZXjoJVQ^?5Zf|5|AZc?TZgp&IE&u=kM{;3sXdriJX=7+0X>N06a&#bMd2V5C zX=5O7a3E%3X>4U=E&xYzVQ^?5aB^jEa&Kd0b8{eOVQFk-WG(V>I zW?^Y;Wn?Y@Lt$)bVsc@0X>V>IW?^Y;Wn?Y@M{;3sXdrN5a&&2QX>V>Ib9G~5Wpi^Z zAYyfNAaiwMM{;3sXdrHNZ6IlLATTZfM{;3sXdrWSVn=deaA+W9Zf9w3Wgu>0ZDk;7 zb0BhMaAje1Wn?Y@PfbN2M`d(LZg6#UPjz%~b#z2!b7M(vW^W*7VQFk-WG(MgM07Y$Zba^0ibz&fAa$#_2AZc!9Z!Q2sVQg$5Q)P5RZ*F91bZKvHAZBTDb962M zP;zB(VRB_4W?^Y;Wn?Y@PfbT4Q)O~#VQgu7Wle8nWo$%cW*}x^X>4U=E&xwWM<7#S zc4bX(WMyn1W?^Y;Wn?Y@P;zBbb#5SLVQFk-WG(N95Y-waJ0000000000P;zB(VRB_4M{;3sXdr2BW@U17Xkl<=AZB4{Y-MBsQgv=e za$#_2AZc!Jb#x$OZ*6dObY&oCa$#_2AZc?TPE|}yE&u=kM{;3sXdqL0ZevAwWn*=8 zWle8nWo#g3VQFk-WG(4U=E&u=kP+@X&WgujEZeeX{ zV<2vCWMv>@Z*FF3XCP*2Y-J#3VQFk-WB>pFQ(<;xAZ>4CWo#gKX>@2HZFOvPX>e?1 zAaiwMAZK!6aA*KWa$#_2AZKNCAZK!6aA+WIZ)9a4W?^Y;Wn?Y@M{;3sXdq;7AZ~AT zAZc!CbS?mCZg6#UAZK!6aA+WDb0BVYY-|7kbZ>BPY;R|2V_|F{b8m8VX>MmAVQwIB zVRCe7bZKvHAZB4{Y-MBsVPj)ub8~5KXCPs2AZ2ZEba^0fVRCe7bZKvH00000b#8NY zaBy#ObY)~9W@TY?b#i4OX>K5JVRCe7bZKvH0AX`;X=iRAWo~C_Ze<{5VQFk-WB>pF zVPs?=aBN{?WoU0~WMy(7Wo~33Zf|5|AZB4{Y-MBsP+@X&Wgu^LbRceTWMv>`VQFk- zWG(;zPfbT4aA9(DWgujEZeeX{V<2vCWMv>@Z*FF3XCP*2Y-J#3VQFk-WG(;z00000 zPfbT4Q(<;xAXjB+XJ~YDAarjaO>bmnY#?S~X>4U=E&xSsaCCVfb98cPZf78FVQpnD z07Y$Zba^0lVRC6%ZHZgyd8X=E+{00000M{;3sXdr2GAZ~ATAYyfCY;+)EWoB=3 zWgt^wc4bX(WMynF07r6RaA+V?VRmIrZ)9a`AZB4{Y-MCF00000Mqz1eWn>^>Y;131 zVRUJ3XCQ55ZEtdUAZBlJAZ>4CWo#g3X>4U6Xk}q!WpXY6Mqz1eWn>_7Wo>VEWgusA zVQ^?5X>K5HZ)9a4b7f&;Xk~IP00000Mqz1eWn>^>WMm*`a$#_2AZczOZf|5|AaiA5 zV`yb^E&u=k00000Mqz1eWn>_8Wpp5Ca$#_2AZBT9X>({Ga%Ez5X>4R5X>K5HZ)9a4 zb7f(2V`yb^E&xVhX>4U=Aarjaa&>MXc42a9VPb4$AaG%Gb1nczVQFk-WFT~JAZc!C zbZKF1X?kTKWo~C_Ze=b2MQ&$lZe<{5X>MU`X?kTKW?^Y;Wn?Y@00000O=WFwa(N(h zd2nSQNJ32@X>%ZMWn*P?b769MAa`hGZXjiDXK8L_AZc?TX>K57Wp-&}WdHyGRA^-& zZf|5|Aa7_9Zy;%IX>@5}Y-xIBAWv{}OJ#Cy zWo$`qW^Yq;Z*pZW0000000000Mqz1eWn>_9Zy;%IX>@5}Y-xIBAV+dxaA;3(bZKpA zdS!Ah08empOJ#CyWo$`qW^W*FZ*(AKcxiKVE&xw(b4z7%Ze?sqZf0*&bZ>HHAZ~AT zAZ2)Ib962MMqz1eWn>_9Zy-ZqY-3MwQgv=_X>MmwVRB(@E&xVhX>4U=AarjaM`dnh za$$63RAF;#E&u=k00000Mqz1eWn>_9Zy--_bZKpAdSy>?X=iC}VQfcoVQ^?J07hYH zY-MC1bZ;O}aCB*HX?kTwb#rB8M{;3sXf6OnZf9w3WguyDAZ~ATAaZ4AX>)XCa%E&L z0000000000RA^;#WguyDAZ~9Uc42I3WFT{IAYo!}b#x$4aC1v#a&Bd8Np5CuQ*>`~ zWgu^IAV+dxaA;3(bZKpAdS!Ah0000000000Mqz1eWn>_9Zy;x7bRcJPVQ^?qaCB*H zX?kUHAYyqSZeeX@E&u=kMqz1eWn>_9Zy;x7bRcJPVQ^?qaCB*HX?kUHAYyqSaB^vH za%psVE&u=k00000Mqz1eWn>_9Zy;=MVPqg@WgusAVQ^?qaCB*HX?kUHE&ya@c4=c} zAZcVEX>%ZHZgyd8X=DHZb7gcOWMy_~V`U&_VQFk-WGoEbRcqNVPts# zZDDL|Z(|^BWo>VAc_3zCX>4U=0Bvt%Wo#g5VRImEZ*(AHWo2$4Y;R#?Wn=(tZ)9a` zAZ2)Cb#!GQW?^Y;Wn=(jV`U&?a%Ew3Wguu_Ze(m_AZB4{Y-MBsV`F6?b7gcOb98cL zVQnC0VQFk-WB>pFV_|G;AaZqXbZKp6AY*c6VRU66a&%2^WMyn1W?^Y;Wn=&V00000 zV_|G;AaZqXbZKp6AY*c6VRU66b98cLVQnC0VQFk-WB>pF00000V_|G;AaZqXbZKp6 zAYy55WFT{Na%Ev{AarjaZEs{{Y#?S~X>4U=0000000000V_|G;AaZqXbZKp6AY*c6 zVRU66Y++(-Wguo@X>4U=0000000000V_|G;AaZqXbZKp6AZ>4CWo#g9Z((F0V{dJ6 zY-Mz1AZB4{Y-MBsV_|G;AaZqXbZKp6AZKNCAar4KYanT4AZB4{Y-MBsV_|G;AaZqX zbZKp6AZulEZe?sBY+-e7V`v~|VQFk-WB>pF00000V_|G;AaZqXbZKp6AZulEZe?sB zY+-e7V`yb~AZB4{Y-MBs00000V_|G;AaZqXbZKp6AZulEZe?sBW_5FEZ*CxSbYXII zAZB4{Y-MBsV_|G;AaZqXbZKp6AZulEZe?sBW_5FEZ*CxEZe$>4VQFk-WB_AfY-}KM zb#8QNZDk;AVPb4$AaiAOAZB4{Y-MBs00000V_|G;AaZqXbZKp6AZ%e`Y-J#4Z**@U zW?^Y;Wn=&VV_|G;AaZqXbZKp6AZ%e`Y-J#GcWHEEXdq@`X>4U=0000000000V_|G; zAaZqXbZKp6AZ=xBAYp85Z(|^BVQyh(Wn>^`VQFk-WB>pFV_|G;AaZqXbZKp6AZ=xB zAZBu9Wgu-~ZeeF-WFTf?X>4U=0ApcnY#?%VZggpFWgup9Wn~~{VQFk-WB>pFV_|G; zAaZqXbZKp6Aai+cV<2;Ma%Ev{AZB4{Y-MBsV_|G;AaZqXbZKp6AZ>4CWo#g2cw=>R zWguo@X>4U=0ApcnY#?%VZggpFWgu;3Z6INDd2VAMW?^Y;Wn=&VV_|G;AaZqXbZKp6 zAYp85Z(|^6Z*z1YZDnn5a(N(TVQFk-WB>pFV_|G;AaZqXbZKp6AZBu9Wguv8b95kW zWo>VAc_3zCX>4U=00000V_|G;AaZqXbZKp6AYp85Z(|^2Wp-&}Wgu;3ZEtdUAZB4{ zY-MBsV_|G;AaZqXbZKp6AZBu9Wgui_c4=c}AZ=xBZ*qAcW?^Y;Wn=&VV_|G;AaZqX zbZKp6AZBcJb7&xAVPj}zAZB4{Y-MBsb#7v5Ze$>GbaQlaWnpa~W^!+BAaZnVZ)9a` zAZB4{Y-MBsWMy-7Z*qAcb98cLVQnC0VQFk-WB_Dkb98TVc_3_IVr6U~W?^Y;Wn=(k zWpi|Ia(N(aZ)9a`AZB4{Y-MBs00000V_|G;AY)@?AartJZgXa3av*eNZgX#PAY^58 zV{&P5bZ>GXW?^Y;Wn=&V00000V_|G;AY)@?AartJZgXa3av)}DY;GXW?^Y;Wn=&V00000V_|G;AY)@?Aa!tLVRU66Yh`k7Wo#f}a%XcOW?^Y;Wn=(k zWpi|Ia(N(VVQyq>Wguo@X>4U=0000000000V_|G;AaZqdX>Da7V{&C-bY&oAc4cmK zAZB4{Y-MBsV_|G;AaZqdX>Da7Wp-t5bRcqNV{dX~AZB4{Y-MBsV_|G;AaZqdX>Da7 zb98cLVQnCHVQF+AWp-t5bRcG7X>4U=00000V_|G;AZTM_Y#?Z3Z*3rAa&KW|V_|c2 zAZB4{Y-MBsV_|G;AZTM_Y#?Z3Z*3r9Y-}KBVRUF^av)}5X>4U=0000000000V_|G; zAZTM_Y#?Z3Z*3r9Y-}KMWn^_@Wguo@X>4U=0AyuzbZ>Hb004mhe;{&nAZ2!CZge1K zVQFk-WB>pF000000ApcnY#?Z3V{9O3V{dIBa%E(7V`U(7V_|f3WpW^9VQFk-WB>pF z07pe2MR;Xnb#!lXAZc?TZf|rTd1Z7UX>MtBX<=+>dSzrT07pe2K}k?hAZc?TZf|rT zWq4_GbS?k@0000007pe2M0svuZE0g5K}k?hAZc?TZf|rTb9HcVZ*p`XbZ;PWb!BpS zAarGIaBp&9a%pUNE&u=k07r6RaA+WHVQyh(WpW^CZfSIBVQgu7Wguo@X>4U=E&u=k z0000007r6RaA+WHVQyh(WpW^4WMm*`a$#_2AZB4{Y-MCF07r6RaA+WHVQyh(WpW^5 zb!lv5AZK!6aA+WAVQFk-WG(;z0000007r6RaA+WHVQyh(WpW^9X>MU`X?kTKW?^Y; zWn?Y@07r6RaA+WHVQyh(WpW^MVRmI8ZEs{{Y#?S~X>4U=E&u=k000000Du4h0KWhL z00000000000H6Q>0KWhL0Du4h0KWhL0Du4h0KWhL0Du4h0KWhL0Du4h0G|K=0Du4h z0KWhL0FVFx0KWhL0Du4h0KWhL0Du4h0KWhL00000000000Du4h0KWhL0Du4h0KWhL z0Du4h0KWhL00000000000Du4h0FM9w0Du4h0KWhL0Du4h0KWhL000000000001N;C z00;m800aO40000007-6XbN~PV000000000008(XeZ*p`+a&k>&b8}&5WdHyG00000 z000000000008e#vaCLM=a&k>&b8}&5WdHyG0000008n9ab7e|%Z*E3uY-Iod00000 z000000CRLMmcV`yP=J}e+^Y;S07VQy|ZI$~jSX=7h%b8l`uJ}e+} zbYwa@Y-MwEJacqpIyz!ub7^B=b98cPZf87WXkl_bAU-T0b97`nI$>;VZ)0I}Z*n|y zbYwa@aA9e3JY#Qeb95kcbYwa@VqtS>V_$Q0a%pa7JY#5Kay~2|ZftL8ZDDS1Iyz!u zb7^B=YIARHJU$>kAU+^IJ0L-FXLBGuAbWi~AWvdyWn*+yd2nSQJs@**WI8%+VQ@Pj zL2`0oc~p6DWgtBub97`nI(B7abZ>GyAX9X5X>Mm!d2nSQJs@**WI8%xVRLC?UvqSF zX>MmcV`yP=K06>nZ*Od6VQy4;aAhDpAYyNCY&#%Mb!}p0a!GDN2oAWn5{Vr6nwZgXj8Ze?Utd2nSQJs@mvZf78MZgXj8Ze?U3X>N2oAWn5{ zVr6nhY;R$7RC#b^AUz;tZ*^j9Wji22Y;131VRUbDRC#b^AUz;+bYwa@VQg$~V_|e} zayuYOQ%_D)WpZg@Y-xIBav(h*ZftL8ZDDS1IyzxwY+rL_a%o{~X?kUHT>t<800000 z0CRLbZ>GzZftL8ZDDS1Iyz!u zb7^B=YIARHJU$>kAU-=FL2_qvAUz;^eLEmeVrpe$bX0k8WgtBub97`nI&EQaJ0L-F za$$K?d2nSQJs@**WI8%_Wn*-2ayuYXbaH8KXHbZ>Gy zAWBnDPE%!aX<=+>dS!ATJs@suZ)j~{Zf-g{VPtGyb7gXAVQgu7WpZ5r0000000000 z000000CRLV_$Q0a%pa7JY#5Kay~mCLT_(uWnpeqd2nSQJs@IlZ)`gtPIYZ! zWpYVwbY*8{a#VS6WgtBuY;SI7AZc!NJ0MPVZDM6|Rc>=>XKrO=RC#b^AUz;#Z*FHG zb#8NMXKrO=AZc!NJ0MPVZDM6|Mr?0kbX0k8WgtBuWN&q1Y-KwjL2PVqV_|e}a#VS6 zWgtBub97`nI$>;VZ)0I}Z*n^zN>fixQ)O~#VQgu7WpW@rAZ~1LXl-F`ZaO+)WNcq^ zWpZg@Y-xIBa$Nub000000000000000000000CsO_WFT&AZ)j~{Zf-g{VqtS>V_#}> zZ*DwKVrpe$bX0k8Wh@{;a&lpLRC#b^EFe>Ka%pa7RC#b^EFeN}Z){~@Zd7@2Wh@|0 zb!}p0a!GD=>XKrO=RC#b^EFeyGZDM6|Mr?0kbX0k8 zWh@{;Y;131VRUbDRC#b^EFel#Pfk;1a%o{~X?kUHJ~}#Kb8}^KbYE$1c42a9VQzFN zDIjBSZgX@XTX$)6Xdq8wYGq?|RC#b^AUz;+bYwa@ZDDXbAVG3+VR=+}aAhDpAaitN zIy!b`V{~tFJ0MeZa%pa7RC#b^AUz;+bYwa@VqtS>V_$Q0a%pa7JY#5Kay~mCLT_(u zWnpeqd2nSQJs@IlZ)`gtPIYZ!WpYVwbY*8{a#VS6WgtBuY;SI7AZc!NJ0MPVZDM6| zRc>=>XKrO=RC#b^AUz;#Z*FHGb#8NMXKrO=AZc!NJ0MPVZDM6|Mr?0kbX0k8WgtBu zWN&q1Y-KwjL2PVqV_|e}a#VS6WgtBub97`nI$>;VZ)0I}Z*n^zN>fixQ)O~#VQgu7 zWpW@rAZ~1LXl-F`ZaO+)WNcq^WpZg@Y-xIBa$Nub00000000000CRLMmcV`yP=J}e+^Y;S07VQy|ZI$~jSX=7h%b8l`uJ}e+}bYwa@Y-MwEJacqpIyz!u zb7^B=b98cPZf87WXkl_bAU-T0b97`nI$>;VZ)0I}Z*n|ybYwa@aA9e3JY#Qeb95kc zbYwa@VqtS>V_$Q0a%pa7JY#5Kay~2|ZftL8ZDDS1Iyz!ub7^B=YIARHJU$>kAU+^I zJ0L-FXLBGuAbVqPZgX@Xb97`nI&EQaJacqpIyz!ub7^B=b98cPZf87WXkl_JAaitN zIyz%$VRBz|a$#w7b39{cVRAk!AaitNIyzx&Y;R*>bZ>GzV`yP=J|I3UAZ~1LXl-F` zZaO+*VRLC?Uutu2Zai~zWI8%+VQ?%Ub97`nI(B7abZ>GjAaitNIyz!ub7^B=b98cP zZf87WXkl_JAaitNIyz%$VRBz|a$#w7b39{cVRAk!AaitNIyzx&Y;R*>bZ>GzV`yP= zJ|I3UAYyNCY%CybZ*FHGX>N2ZAZ%}LXCQTMb7^O8Wn>^}ZgealWN&q1Y-KDUb97`n zI$>;VZ)0I}Z*nXkZftL8ZDDS1IyzxwY+rL_a%o{~X?kUHJ}e+}bYwa@Y-MwEJacqp zIyz!ub7^B=b98cPZf87WXkl_JAaitNIyz%$VRBz|a$#w7b39{cVRAk!AaitNIyzx& zY;R*>bZ>GzV`yP=J|I3IJ}e+}bYwa@VQg$~V_|e}ay)Z%WI8%MmcV`yP=EFg1qWI8%yXkl_+baG*7baOmoXkl_bEFg1qWI8%w zY;131VRUbDJY#5Kay}qFEFf-dZ)j~{Zf-g{VqtS>V_#}>Z*DwubYwa@ZDDXMAaitN zIy!b`V{~tFEFg1qWI8%xVRLC?UvqSFX>MmcV`yP=EFg1qWI8%yXkl_+baG*7baOmo zXkl_bEFg1qWI8%wY;131VRUbDJY#5Kay}qFEFfZUZ)_|eY;SI7AZc!NEFf%eZf78M zZgXj8Ze?U3X>N2ZAY^ZKVr*qBAaitNIyzx&Y;R*>bZ>GjAZ~1LXl-F`ZaO+)WNcq^ zWpZg@Y-xIBay}qFAU+^ICVe{~Phx6iV{}w`aAhDpAaitNIy!A(a62GDa&lpLRC#b^ zAUz;+bYwa@c4cF9Z*n^zQ*?4^Zf8_^aAhDpAaitNIyz!ub7^B=b98cPZf87WXkl_b zJ0L=DZ){~@Zd7@2WgtBuVsCG3J0MPVZDM6|Np5syXJv9!d2nSQJs@mvZf78AZge{! zPIYZ!WpY(+b7^O8Wn@%&aAhDpAZ%}LXCQTMb7^O8Wn>^}Zge{!PIYZ!WpYMrZ((#) zd2nSQJs@Onbz*E~J0L-9Y;R*>bZ>H0d2nSQJs@**WI8%wY;131VRUbDJ0MC^Pfk;1 za%o{~X?kUHAUz;%Y;S07VQy|ZI$>mNUvp)0X<=+>dS!B500000000000000000000 z0000000000000000CRLbZ>Gz zZftL8ZDDS1Iyz!ub7^B=YIARHJU$>kAU-=FL2_qvAUz;^V{dMAbRctdWI8%_Wn*-2 zay)KqZ)j~{Zf-g{VqtS>V_#}>Z*DwubYwa@ZDDXMAaitNIy!b`V{~tFEFg1qWI8%x zVRLC?UvqSFX>MmcV`yP=EFg1qWI8%yXkl_+baG*7baOmoXkl_bEFg1qWI8%wY;131 zVRUbDJY#5Kay}qFEFfZUZ)_|eY;SI7AZc!NEFf%eZf78MZgXj8Ze?U3X>N2ZAY^ZK zVr*qBAaitNIyzx&Y;R*>bZ>GjAZ~1LXl-F`ZaO+)WNcq^WpZg@Y-xIBay~2|b97`n zI$>;VZ)0I}Z*n|tY;S07VQy|ZI$~jSX=7h%b8l`ub97`nI&EQaEFg1qWI8%_Wn*-2 zax5TobYwa@VqtS>V_$Q0a%pa7JY#5Kax5TobYwa@V`yP=UvzR|X>@ZuV`yP=J}e+} zbYwa@VQg$~V_|e}ay(;bVRAkoJ}e+&Z*OcYAZ%}LXCP^AbSxljZ*FHGb#8NMXKrO= zAZc!NEFffWbz*E~EFg1qWI8%wY;131VRUbDEFf-dZ)j~{Zf-g{VPtGyb7gXAVQgu7 zWpX|sJ|I3OeLEmeVrpe$bX0k8WgtBub97`nI&EQaJ0L-Fa$$K?d2nSQJs@**WI8%_ zWn*-2ayuYXbaH8KXHbZ>GyAWBnDPE%!aX<=+>dS!AT zJs@suZ)j~{Zf-g{VPtGyb7gXAVQgu7WpZ5r00000000000000000000000000CRL< zbZKKCR4O2DY;S07VQy|ZI$~jSX=7h%b8l`uPhx6iV{}w`aAhnYL2`0oc~p6DWh@|5 zbaH8KXH;VZ)0I}Z*n|iXkl_bAU-C2J0MSDYGq?| zRC#b^AUz;+bYwa@ZDDXbAVG3+VR=+}aAhDpAaitNIy!b`V{~tFJ0MeZa%pa7RC#b^ zAUz;+bYwa@VqtS>V_$Q0a%pa7JY#5Kay~mCLT_(uWnpeqd2nSQJs@IlZ)`gtPIYZ! zWpYVwbY*8{a#VS6WgtBuY;SI7AZc!NJ0MPVZDM6|Rc>=>XKrO=RC#b^AUz;#Z*FHG zb#8NMXKrO=AZc!NJ0MPVZDM6|Mr?0kbX0k8WgtBuWN&q1Y-KwjL2PVqV_|e}a#VS6 zWgtBub97`nI$>;VZ)0I}Z*n^zN>fixQ)O~#VQgu7WpW@rAZ~1LXl-F`ZaO+)WNcq^ zWpZg@Y-xIBa$Nub0000008(XPWJ+^yZboTrWdHyG0CRLDO_UvO_}ZgeOq zAX|57bZ8(#VRLC?N^@^+RC#b^AUz;%Y;S07VQy|ZI$~jSX=7h%b8l`uK3xC+00000 z000000CsO_WFT&AZ)j~{Zf-g{WMy<=X>2+=Y-M<5ay&v|b7^Brb8l``d2nSuIy!Z3 zXJvFKDIi;SX>@2HLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j z000000000000000000000000000000000000B&q=Xl-F`ZaO+-WprU_Y&tq@Wq4(B zJVIe}X=6%rZ*Ek1aAiI^I&^PqWo}<|d2nSQZftL8ZDDS1Iyz)!bYW?1Iy!7+cx7@t zLSb`hV@h*xZd7@2Wj;DOb7Ns{Uut<80000000000000000000000000 z000000B&q=Xl-F`ZaO+-WprU_Y&tq@Wq4(BJVIe}X=6%rZ*Ek1aAiI^I&^PqWo}<| zd2nSQZftL8ZDDS1Iyz)!bYW?1Iy!7+cx7@tLSb`hV@h*xZd7@2Wj;DOb7Ns{UvqSF zX>MmIDIi;SX>@2HLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j z00000000000BLS?AZ~1LXl-F`ZaO+-WprU_Y&tq@Wq4(BJVIe}X=6%rZ*Ek1aAiI^ zI%j2cUt@1%WpHn4ZgeOqAX|57bZ8(#VRLC?N^@^+RC#b^AUz;%Y;S07VQy|ZI$~jS zX=7h%b8l`uK3xC+00000000000000000000000000Ag=%Y#?rIZ)j~{Zf-g{WMy<= zX>2+=Y-M<5ay&v|b7^Brb8l``d2nSuIy!D;cywQ4d30r8X>MO~VQyz-D06gVIyz}? zX>@5}Y-xIBa$js|b96juZgf5=AX|57bZ8(#VRLC?N^@^+RC#b^AUz;%Y;S07VQy|Z zI$~jSX=7h%b8l`uK3xC+00000000000000000000000000B&q=Xl-F`ZaO+-WprU_ zY&tq@Wq4(BJVIe}X=6%rZ*Ek1aAiI^I&^PqWo}<|d2nSQZftL8ZDDS1Iyz)!bYW?1 zIy!7+cx7@tLSb`hV@h*xZd7@2Wj;DOb7Ns{Uv716Vr6nDDIi;SX>@2HLSb`hV@h*x zZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j00000000000Ag=%Y#?rIZ)j~{ zZf-g{WMy<=X>2+=aA9(DWpX@1VRLC?N^@^+RC#b^J~}#cVR&C~VRCb2UukZ1WpZv| zY$#JfSSl$XTX$)6XdqKTSRg$hZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5;= zVQg$-VPk7waA9(DWpX@jY;S07VQy|ZI$~jSX=7h%b8l`uJ|I3jAVOhtX=6%rZ*Ek1 zaAhDpAZ~1LXl-F`ZaO+*VRLC?Uutu2Zah9+000000000000000000000000000000 z000000CRL?Iy!J+X>vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh!AZ~1LXl-F`ZaO+-WprU_ zY&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`hV@h*xZd7@2Wj;DOXkl(- zY-L||VQh6}C{|%?b!8?dEFfZUZ)_2+=c42IFWnXkVAVOhtX=6%rZ*Ek1aAhDpAZ~1LXl-F`ZaO+*VRLC?Uutu2Zah9+ z00000000000000000000000000CRL?Iy!J+X>vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh! zAZ~1LXl-F`ZaO+-WprU_Y&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`h zV@h*xZd7@2Wj;DOXkl(-Y-L||VQh6}C{|%?b!8?dEFfZUZ)_vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh!AZ~1LXl-F`ZaO+-WprU_ zY&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`hV@h*xZd7@2Wj;DOXkl(- zY-L||VQh6}C{|%?b!8?dEFfZUZ)_KbaG#G zJ0L<~b7^Brb8l``d2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3T>t<80000000000 z00000000000000000000000000CRL?Iy!J+X>vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh! zAZ~1LXl-F`ZaO+-WprU_Y&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`h zV@h*xZd7@2Wj;DOXkl(-Y-L||VQh6}C{|%?b!8?dEFfZUZ)_vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh!AZ~1LXl-F`ZaO+-WprU_ zY&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`hV@h*xZd7@2Wj;DOXkl(- zY-L||VQh6}C{|%?b!8?dEFfZUZ)_vSb zZ*OcYAVOhtX=6%rZ*Ek1aAhh!AZ~1LXl-F`ZaO+-WprU_Y&tq>b8l{6b76R2WN&R> zV_|G;Vqs%zUvOb^b7gWoLSb`hV@h*xZd7@2Wj;DOXkl(-Y-L||VQh6}C{|%?b!8?d zEFfZUZ)_MmcV`yP=J|;ULLSb`h zV@h*xZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j00000000000000000000 z000000CRL?Iy!J+X>vSbZ*OcYAVOhtX=6%rZ*Ek1aAhh!AZ~1LXl-F`ZaO+-WprU_ zY&tq>b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gWoLSb`hV@h*xZd7@2Wj;DOXkl(- zY-L||VQh6}C{|%?b!8?dEFfZUZ)_N2TJ0L<~b7^Brb8l``d2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3T>t<800000 z00000000000000000000000000Ag=%Y#?rIZ)j~{Zf-g{WMy<=X>2+=YIARHUvpu2 zUu17>Ut?ixY+_+!YhQ3-a&u*JJVIe}X=6%rZ*Ek1aAiI^I%RHTUtw}`VR2+=YIARHUvpu2Uu17>Ut?ixY+_+!YhQ3-a&u*JJVIe}X=6%r zZ*Ek1aAiI^I%RHTUvFY+Wn*+GDIi;SX>@2HLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1 zIyz!ub7^B=YIARHJU(3j0B&q=Xl-F`ZaO+-WprU_Y&tq=bY*g1X>D+9JVIe}X=6%r zZ*Ek1aAiI^I%#xea$jj}aBL`UY;S07VQy|ZI%H*ZVQFkSI%#xea$jj}aBMt6VRLC? zN^@^+RC#b^J~}#ZZ)t9HWpXJXTX$)6Xdpsib7^Brb8l``d2nSQJs@suZ)j~{Zf-g{ zVqtS>V_#}>Z*Dw3J0NasZ)j~{Zf-g{WMy<=X>2+=X>?_BUukV{Y&=3?b7^Brb8l`` zd2nSuIy!J~X>N37av(h*ZftL8ZDDS1Iyz!ub7^B=YIARHJU%L2000000000000000 z0000000000000000CsO_WFT&AZ)j~{Zf-g{WMy<=X>2+=X>?_BUukV{Y&=3?b7^Br zb8l``d2nSuIy!S@bYEg+XK8LIDIi;SX>@2HLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1 zIyz!ub7^B=YIARHJU(3j00000000000000000000000000CsO_WFT&AZ)j~{Zf-g{ zWMy<=X>2+=X>?_BUukV{Y&=3?b7^Brb8l``d2nSuIy!S@bYEp|WGE>hTX$)6Xdpsi zb7^Brb8l``d2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3T>t<8000000000000000 z00000000000Ag=%Y#?rIZ)j~{Zf-g{WMy<=X>2+=X>?_BUukV{Y&=3?b7^Brb8l`` zd2nSuIy!G~WpZJ3Z*o07C}VGKb95kXY;S07VQy|ZI%H*ZVQFkSI%#xea$jj}aBMt6 zVRLC?N^@^+RC#b^J|-z3V{dMAbRb)IX>@2HLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1 zIyz!ub7^B=YIARHJU(3j000000000000000000000000000000000000B&q=Xl-F` zZaO+-WprU_Y&tq=bY*g1X>D+9JVIe}X=6%rZ*Ek1aAiI^I&g1kZggdGAZ~1LXl-F` zZaO+-WprU_Y&tq=bY*g1X>D+9JVIe}X=6%rZ*Ek1aAiI^I&W}ga$$6DaxFe6DIjBS zZgX@XTX$)6Xdpsib7^Brb8l``d2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3J0Nas zZ)j~{Zf-g{WMy<=X>2+=X>?_BUukV{Y&=3?b7^Brb8l``d2nSuIy!J~X>N37av(h* zZftL8ZDDS1Iyz!ub7^B=YIARHJU%L2000000000000000000000B&q=Xl-F`ZaO+- zWprU_Y&tq=bY*g1X>D+9JVIe}X=6%rZ*Ek1aAiIwAZ~1LXl-F`ZaO+-WprU_Y&tq= zbY*g1X>D+9JVIe}X=6%rZ*Ek1aAiI^I&W}ga$$6Daw{t+DIi;SX>@2HLSb`hV@h*x zZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j0000000000000000Ag=%Y#?rI zZ)j~{Zf-g{WMy<=X>2+=YIARHUvpu2Uu17>Ut?ixY+_+!YhQ3-a&u*JJVIe}X=6%r zZ*Ek1aAiI^I&fifb7fy;a&m8SD06gVIy!S{dSzd9EFfcVZgX@Xb98cPZf7PeAY*TC zb95kXY;S07VQy|ZI%H*ZVQFkSI%RlcWpH$9Z*C?jAX|57bZ8(#VRLC?N^@^+RC#b^ zAUz;%Y;S07VQy|ZI$~jSX=7h%b8l`uK06?DbYwa@b7^{IUvwZnAZ%}LXCQTMb7^O8 zWn>^}Zge{!b97`nI&*Y#X>MmAJs@**WI8%xVRLC?UvqSFX>MmcV`yP=K3xC+00000 z00000000000000000000000000Ag=%Y#?rIZ)j~{Zf-g{WMy<=X>2+=aA9(DWpX@1 zVRLC?N^@^+RC#b^J~}#cVR&C~VRCb2UukZ1WpZv|Y$#JfSSl$XTX$)6XdqKTSRg$h zZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay)KqZ)j~{Zf-g{VqtS> zV_#}>Z*Dw3AU-=FLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j z00000077ANX=6%rZ*Ek1aAhhWZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2 zVRCb2ay&v|b7^Brb8l``d2nSuIyz`!Ze(m_Uv^<^b!8}4VQh6}CMGE$TX$)6XdqT$ zY;|QIJs@suZ)j~{Zf-g{WMy<=X>2+=c42IFWnXkVAVOhtX=6%rZ*Ek1aAhDpAZ~1L zXl-F`ZaO+*VRLC?Uutu2Zah9+0000000000000000000000000077ANX=6%rZ*Ek1 zaAhhWZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Brb8l`` zd2nSuIyz`!Ze(m_Uv^<^b!8}4VQh6}CMGE$TX$)6XdqT$Y;|QIJs@Onbz*E~COaTP zVRLC?N^@^+RC#b^AUz;%Y;S07VQy|ZI$~jSX=7h%b8l`uK3xC+00000077ANX=6%r zZ*Ek1aAhhWZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Br zb8l``d2nSuIyz`!Ze(m_Uv^<^b!8}4VQh6}CMGE$TX$)6XdqT$Y;|QIJs@**WI8%- zb!=>KbaG#GJ0L<~b7^Brb8l``d2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3T>t<8 z00000000000000000000000000000000000077ANX=6%rZ*Ek1aAhhWZftL8ZDDS1 zIyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Brb8l``d2nSuIyz`!Ze(m_ zUv^<^b!8}4VQh6}CMGE$TX$)6XdqT$Y;|QIJs@IlZ)_$zAVOhtX=6%rZ*Ek1aAhDp zAZ~1LXl-F`ZaO+*VRLC?Uutu2Zah9+0000000000077ANX=6%rZ*Ek1aAhhWZftL8 zZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Brb8l``d2nSuIyz`! zZe(m_Uv^<^b!8}4VQh6}CMGE$TX$)6XdqT$Y;|QIJs@mvZf78AZgeI)AVOhtX=6%r zZ*Ek1aAhDpAZ~1LXl-F`ZaO+*VRLC?Uutu2Zah9+00000077ANX=6%rZ*Ek1aAhhW zZftL8ZDDS1Iyz)!bYW?1Iy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Brb8l``d2nSu zIyz`!Ze(m_Uv^<^b!8}4VQh6}CMGE$TX$)6XdqT$Y;|QIJs@**WI8%xVRLC?UvqSF zX>MmcV`yP=J|;ULLSb`hV@h*xZd7@2WgtBuZftL8ZDDS1Iyz!ub7^B=YIARHJU(3j z0000000000000000000000000077ANX=6%rZ*Ek1aAhhWZftL8ZDDS1Iyz)!bYW?1 zIy!1|Z*E_6VR&C;Z*5<2VRCb2ay&v|b7^Brb8l``d2nSuIyz`!Ze(m_Uv^<^b!8}4 zVQh6}CMGE$TX$)6XdqT$Y;|QIJs@mvZf78MZgXj8Ze?U3X>N2TJ0L<~b7^Brb8l`` zd2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3T>t<80000000000000000000000000 z000000Ag=%Y#?rIZ)j~{Zf-g{WMy<=X>2+=YIARHUvpu2Uu17>UvOb^b7gWoLSb`h zV@h*xZd7@2Wj;DOaA9(DWnX1-a&K}db97`nI&*1yWnXkGAY*TCb95kcbaH8KXC^El zV{dMAbRceQZ)j~{Zf-g{WMy<=X>2+=Wq4y{aCB*JZYC)pTX$)6Xdpsib7^Brb8l`` zd2nSQJs@suZ)j~{Zf-g{VqtS>V_#}>Z*Dw3J0Np(WI8%?X?kT}bRaz-Y;SI7Aa!nY zX=iR_WFTp7bUPq(bYwa@b98cPZf77pAaitNIyz!ub7^B=b98cPZf87WXkl_bT>t<8 z06|nkQe|*&a&$#}9 z|0nwW|Ka!j|AP1Z|Frl0|5^C`|DX8%{}cHA|FQM`|0VVP|AO)T|0nwW|0nwW|0nwW z|0nwW|K<4o|AG(x|7s5Y|Jn}z{}K=W|Dq25|4I-3{|6fW|G^jj|6&*Z|CAU0|2Y`` z|9=?%|MM6A|B)5`{{)h|5lm)|8JT8|A?9X|Dl=w z|GJs}|I?ZN|LmFm{{@=<{~ntD|2LZc|4^F#|7n{3|ALzS|C^fr|FoL^|IM2I|K^(h z|Nol){}`M8|1q2X|4N(w|6`l}|9qSN|CO8m|E`<<|HqsD|KOYc|M{E#{}P=3{}P=3 z{}z@0{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{~(qA{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3{}P=3 z{}P=3{}P=3{}P=3|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x z|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x z|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x z|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x z|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x|45$x z|45$x|45$x|45$x|45$x|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT z|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT z|16yT|16yT|16yT|16yT|16yT|16yT|16yT|16yT|Aw6Y|KObd|KObd|KObd|KObd z|KObd|KObd|KObd|KObd|KObd|KObd|KObd|KObd|1O>W|KObd|KObd|9qYP|H_^I z|H_^I|H_^I{|TP{|AUeK|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx z|NNBx|NNBx|NNBx|F4n$|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx z|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx z|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx z|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx|Cy2g|NNBx|NNBx|NNBx z|NNBx|NNBx|HYC1|NNBx|NNBx|NNBx|J#xN|NNBx|NNBx|NNBx|NNBx|NNBx|NNBx z|NNBx|M8Lj|NNBx|NNBx|NNBx{|A!(|NNBx{~eP4|1*;Q{{R30000000000000000 z0000008?}_Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07VQy|VWMy<=X>2ku zX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9F*09FZ)0m;aBpmB zV|hg~MMVGr0000008?}^IbTz7Uu|J)WnXh>VRB_;Uvyz-00000000000000000000 z000000000008Th=Y;S07VQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMF0Q* z000000000000000000000000008Th=Y;S07VQy|VWMy<=X>2kwX>M?JbYEd)VQ_S1 za$j(AZ**^CZ)`;X000000000000000000000000008Th=Y;S07VQy|VWMy<=X>2hu zZ**v7a$jX~a&K})08Th=Y;S07VQy|VWMy<=X>2hvZ*_EEZ)RU|VQyz-MF0Q*00000 z000000000008Th=Y;S07VQy|VWMy<=X>2htba`-PUuAM~Z*oNd000000000000000 z0000008Th=Y;S07VQy|VWMy<=X>2hzX>N95Y-wa)X>?_BVRUbDMF0Q*0000000000 z0000000000000000000008Th=Y;S07VQy|VWMy<=X>2huaA9(DWnX1-a&K})08Th= zY;S07VQy|VWMy<=X>2)Vcw=R7bZKvHMF0Q*08?}^HeXY4Ut@1|Zggd2Ut(c%Wl2m< zIbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ200000000000000008?}^F<(t}bY*y7 zVqtS-NlZ>TUtec#bzft6crh|xOmAarUvO`1X=8asGDSrI00A2VJ1i{#0Hg%~0N{@N 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%0D64?|JdCC0GE9K|M=Yi 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 z0K-`Q|49G<002P_5QYLn4F&>43232 z3i3s3R0000%4iJU{Lk$L43R0000%4iJU{Lk$L430000%4iJU{Lk$K;j01xN0znK12mk;8001Na002}K z007-){r_VD000EvrT_pz4iJU{Lk$K{r?UC0000% z4iJU{Lk$K=3q5uFv4iJU{Lk$K+g98GA3R0000%4iJU{Lk$L43R0000%4iJU{Lk$L43R0000%4iJU{ zLk$L43{r@Qd0000%4iJU{Lk$LG3R0000%4iJU{Lk$L4 z3002sX{r|xL0000%4iJU{Lk$K3ybK2j000~S008VM008WP{r?~U0000%4iJU{ zLk$L730000%4iJU{Lk$K;j01xN0znK12mk;8000~S000Co0020K{r^({ z0000%4iJU{Lk$K3P7DVK000~S001N|003)-{r@}w0000%4iJU{Lk$K+g9CC52M8Ph z002ZT004-F{r?~U0000%4iJU{Lk$L73R0000%4iJU{Lk$L43h)i4iJU{Lk$K3M+^rD00000000~S0049^007#D z{r?UC0000%4iJU{Lk$K=3h)i4iJU{Lk$K+g98I50SpHS001Na005jQ007#E z{r^M&000Dll>h)i4iJU{Lk$Lh3h)i4iJU{Lk$K3h)i z4iJU{Lk$K;j01xN149A~2M8Ph007J}005|_{r?gG0000%4iJU{Lk$K^3h)i4iJU{Lk$KR0000%4iJU{Lk$L43R0000%4iJU{Lk$L43R0000%4iJU{Lk$L43005HB{r@fi0000%4iJU{Lk$LL z3R0000%4iJU{Lk$L43600000000~S005jn005oV{r?XD0000%4iJU{Lk$K>3{r_PA0000%4iJU{Lk$K+g98Fr3R0000%4iJU{Lk$L43R0000%4iJU{Lk$L43{r?dF0000%4iJU{Lk$K@3 z007SF{r^({0000%4iJU{Lk$K3P7DVK000~S007KM0008({r^+|0000%4iJU{Lk$K3 zPYeeL000~S008Vs001`Y{r@}w0000%4iJU{Lk$K+g9CC52M8Ph000b1002_!{r?~U z0000%4iJU{Lk$L73#{r@Te0000%4iJU{Lk$LH38{r?L90000%4iJU{Lk$K-3umm2mk;8 z000~S001mb0036+{r^h<0000%4iJU{Lk$K3MhpiC000~S002x*004sT{r?gG0000% z4iJU{Lk$K^3{r@Te0000%4iJU{Lk$LH33n-G4iJU{Lk$K+g98Gi30000% z4iJU{Lk$K+g98FX3;{r@=t z0000%4iJU{Lk$LW3R0000%4iJU{Lk$L430000% z4iJU{Lk$K+g98FX3R0000%4iJU{Lk$L43R0000% z4iJU{Lk$L43ZvX&64iJU{Lk$K+g9CL82M7QF001Na007)n001of{r@%q000Cd zZvX&64iJU{Lk$LT30027t{r?gG0000%4iJU{Lk$K^33{r?&O0000%4iJU{Lk$L1 z33{{I^Q z0000%4iJU{Lk$L23XaE2~4iJU{Lk$K;j01xN0~7)b2M8np z003-T000~v{{Q3y000EuXaE2~4iJU{Lk$K;j01xN1K0x$2M8Ph007it007t^{{K(_ z0000%4iJU{Lk$K3OAH4H000~S008u2000Of{{JQb0000%4iJU{Lk$LD3P0000%4iJU{ zLk$L13X8-^}4iJU{Lk$K=jRTAXg9QWU z1PliV00000000~S008u4006x?{{IdD0000%4iJU{Lk$K=3R0000%4iJU{Lk$K+g98H)0t^QT00000000~S000bT007QF{{IdD0000%4iJU{ zLk$K=35{{I{T0000%4iJU{ zLk$K+g98H+0t^QT00000001Na005k3006c`{{I{T0000%4iJU{Lk$K+g98H+0t^QT z00000001Na006{h0062+{{I{T0000%4iJU{Lk$K+g98H+0t^QT00000001Na008V} z005py{{I{T0000%4iJU{Lk$K+g98H+0t^QT00000001Na000zc005Fo{{I{T0000% z4iJU{Lk$K+g98H+0t^QT00000000~S002B^004$e{{I^Q0000%4iJU{Lk$L23p`4iJU{Lk$LW3p`4iJU{Lk$Lh3;{{L(M0000%4iJU{Lk$K;j01xN z0$>aW2mk;8000~S001;-008Pt{{Kt>0000%4iJU{Lk$K3M+^rD000~S002~I000(E z{{JQb0000%4iJU{Lk$LD3P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13G{{J@s0000%4iJU{Lk$LU3P0000%4iJU{Lk$L1 z3P0000%4iJU{Lk$L13P0000%4iJU{Lk$L134iJU{Lk$K?jsuMZj0J-R0>umm z2mk;8000~S007)<001aY{{Kq=0000%4iJU{Lk$K3MhpiC000~S008`K002}^{{IpH z0000%4iJU{Lk$K^3{{IpH0000%4iJU{Lk$K^3P0000%4iJU{Lk$L13t<<4iJU{Lk$K+g9CL82M7QF001Na002y9008<>{{J=r000ErT>t<<4iJU{Lk$LT z3P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000% z4iJU{Lk$L13P0000%4iJU{Lk$L13{{I>P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P z0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13S^xk+ z4iJU{Lk$L230053s{{Joj0000%4iJU{Lk$LL3000P8{{J5U0000%4iJU{Lk$L63P0000% z4iJU{Lk$L1330000%4iJU{Lk$K3 zM+^rD001Na007)|0016c{{MUe000E5PXGWx4iJU{Lk$K;j01xN18@Qi2M8Ph002aN z0044d{{LkF0000%4iJU{Lk$K3UP0000%4iJU{Lk$L13006>a{{No<0000%4iJU{Lk$K+g98GU z32M8Ph z0010+006FI{{IR90000%4iJU{Lk$K+3P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L1 z3P0000%4iJU{Lk$L13P z0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{ zLk$L13aW2mk;8000~S002~n005$E{{I>P0000%4iJU{Lk$L130000%4iJU{Lk$K3M+^rD000~S005MS0078q{{JQb0000% z4iJU{Lk$LD3P0000% z4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000% z4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{ zLk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13P0000% z4iJU{Lk$L13P0000%4iJU{Lk$L13P0000%4iJU{Lk$L13 z0000%4iJU{Lk$K3M+^rD001li001O~004$={{M{t000C#K>z?j4iJU{Lk$K?jsuMZ zj0J-R0(}ez2mk;8000~S005MX0087}{{I>P0000%4iJU{Lk$L13000DcKmY(i4iJU{Lk$K;j01xN z0+kF02ml-a003N#003`q{{I{R0000%4iJU{Lk$L333 z003-n{{J}u0000%4iJU{Lk$LW3{{LhE0000%4iJU{Lk$K3 zUknEb001Na006v)007Ew{{K1v000EbJ^%ng4iJU{Lk$LX3P0000%4iJU{Lk$L130000%4iJU{Lk$K+g98FW z33P0000%4iJU{Lk$L13002&P{{Pzm0000%4iJU{Lk$K+g98H533jQ;-~ z00000K@Jdx0z(Z3SqujV0000S0000yod5u00000K@Jdx0z(Z3PYeeL0000a z0000~mjD3ljsE|V00004yD$I%K@Jdx0z(Z3MS}wZhzth^0000a0001dmjD1(j{g60 z00004s4xHkK@Jdx0z(Z3MS}wZXbcAk0000S0002wo&W%#j{g4+00000K@Jdx0z(Z3 zNel-F0000S00004p8x=kj{g5D00000K@Jdx0z(Z3Wef)h0000S0000ap8x=uj{g5S z00000K@Jdx0z(Z3bPNXw0000S0000)p8x=|j{g5l00000K@Jdx0z(Z30!Iu72mk;a z0001Fp8x>fj{g4+00000K@Jdx0z(Z3Nel-F0000S0001lp8x>Nj{g5600000K@Jdx z0z(Z3UJM5a0000S0001_p8x>Rj{g5900000K@Jdx0z(Z3VGIWd0000S0002Qp8x>X zj{g4|00000K@Jdx0z(Z3RSX9R0000i0001_m;eCKj{g6100004kS_oLK@Jdx0z(Z3 zNsR-H1cL^bng0I|00000 zK@Jdx0z(Z3N(=`G0000S0000qsQ>^Lng0J800000K@Jdx0z(Z3RSX9R0000a0000~ zsQ>^Fng0Kz00000K@Jdx0z(Z3MS}wZnhXaB000000000S0001dsQ>_sng0JK00000 zK@Jdx0z(Z3VGIWd0000S0001-sQ>_yng0JC00000K@Jdx0z(Z3SqujV0000S0002I zsQ>_wng0J800000K@Jdx0z(Z3RSX9R0000S0002osQ>_qng0JC00000K@Jdx0z(Z3 zSqujV0000S0002|sQ>_ong0JN00000K@Jdx0z(Z3WDExg0000S0000SssI3zng0JK z00000K@Jdx0z(Z3VGIWd0000S0000yssI3(ng0Jt00000K@Jdx0z(Z30z?c42mk;a z00017ssI4Ong0J-00000K@Jdx0z(Z30#pnK2mk;a0001dssI4{ng0JV00000K@Jdx z0z(Z3Yzzko0000S0001-ssI2Cn*RSL00000K@Jdx0z(Z3VGIWd0000S0002IssI2I zn*RSD00000K@Jdx0z(Z3SqujV0000S0002ossI2Gn*RS900000K@Jdx0z(Z3RSX9R z0000S0002|ssI2An*RSD00000K@Jdx0z(Z3SqujV0000S0000Ss{jB9n*RSC00000 zK@Jdx0z(Z3SPTaU0000S0000ys{jB6n*RR|00000K@Jdx0z(Z3Nel-F0000S00017 zs{jD=ng0J800000K@Jdx0z(Z3RSX9R0000S0001ds{jD)ng0I{00000K@Jdx0z(Z3 zNel-F0000S0001-s{jDpng0J900000K@Jdx0z(Z3RtyIS0000S0002Is{jDkng0JM z00000K@Jdx0z(Z3V+;of0000S0002os{jDtng0JE00000K@Jdx0z(Z3TMP#X0000S z0002|s{jDtng0I~00000K@Jdx0z(Z3ObiDI0000S0000StN;Mfng0Jt00000K@Jdx z0z(Z3MS}x>3p8o$G00000K@Jdx0z(Z3SPTaU0000S0002YumAv;p8o$100000 zK@Jdx0z(Z3Nel-F0000S0002&umAvsp8o$D00000K@Jdx0z(Z3RSX9R0000S0000C zu>b&np8o$100000K@Jdx0z(Z3Nel-F0000S0000iu>b&Wp8o$G00000K@Jdx0z(Z3 zSPTaU0000S0000?u>b&Tp8o$100000K@Jdx0z(Z3Nel-F0000S0001Nu>b&Bp8o$D z00000K@Jdx0z(Z3RSX9R0000S0001tu>b&5p8o$100000K@Jdx0z(Z3Nel-F0000S z00022u>b%;p8o$D00000K@Jdx0z(Z3RSX9R0000S0002Yu>b%&p8o$D00000K@Jdx z0z(Z3RSX9R0000a0002&u>b%zp8o$;00000K@Jdx0z(Z3MS}wZOAH4H000000000S z0000KvH$>Np8o$G00000K@Jdx0z(Z3SPTaU0000S0000qvH$>Kp8o$D00000K@Jdx z0z(Z3RSX9R0000S0000~vH$>Ep8o$S00000K@Jdx0z(Z3WDExg0000S0001VvH$>N zp8o$200000K@Jdx0z(Z3N(=`G0000S0001#vH$>7p8o$500000K@Jdx0z(Z3O$-MJ z0000a0001Vs{jB-p8o%70RR95R~-NVK@Jdx0z(Z3MS}waUjYmU2mk;a0002ovH$>w zpZ@qpZ@00000K@Jdx0z(Z3MS}wZO$-MJ z000000000S0001tv;YA1pZ@aW2mk;i0000?wEzHu zp#J~h00000K@Jdx0z(Z3MS}wZ)(i&-000000000S0001VwEzG*q5l6A00000K@Jdx z0z(Z3PYeeL0000S0001#wEzGvq5l6Z00000K@Jdx0z(Z3XbcAk0000S0002AwEzG+ zq5l6J00000K@Jdx0z(Z3SPTaU0000S0002gwEzG(q5l6d00000K@Jdx0z(Z3Yzzko z0000S0002=wEzH0q5l6S00000K@Jdx0z(Z3VGIWd0000S0000Kwg3Q7q5l6G00000 zK@Jdx0z(Z3RSX9R0000S0000qwg3Q1q5l6700000K@Jdx0z(Z3ObiDI0000S0000~ zwg3P;q5l6o00000K@Jdx0z(Z3MS}x!300000K@Jdx0z(Z30;3EE2mk;a0000i zxc~s5qyGO@00000K@Jdx0z(Z30#FPG2mk;a0000?xc~swqyGO600000K@Jdx0z(Z3 zNel-F0000S0001Nxc~sfqyGOk00000K@Jdx0z(Z3MS}xu3aW2mk;a z0002gy8r-2rT+gp00000K@Jdx0z(Z3bPNXw0000S0002=y8r-SrT+gB00000K@Jdx z0z(Z3ObiDI0000S0000KyZ``ErT+g800000K@Jdx0z(Z3Nel-F0000S0000qyZ`_{ zrT+g800000K@Jdx0z(Z3Nel-F0000S0000~yZ`_#rT+gh00000K@Jdx0z(Z3Yzzko z0000a0000qwEzG z00000K@Jdx0z(Z30!$1C2mk;a0002&yZ`{~rT+gd00000K@Jdx0z(Z3XbcAk0000S z0000Cy#N6ErT+gW00000K@Jdx0z(Z3VGIWd0000S0000iy#N3JrvCpe00000K@Jdx z0z(Z3XbcAk0000S0000?y#N3XrvCpX00000K@Jdx0z(Z3VGIWd0000S0001Ny#N3d zrvCpe00000K@Jdx0z(Z3XbcAk0000S0001ty#N3rrvCpX00000K@Jdx0z(Z3VGIWd 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 z1!e$x1pom5n;8KQUIk?VfB^-C0RWQ$1poj60000000030{{aC1nB1OVm)1poj60000000030ni5 z0OZ20OkY*0003100000 z00030nZ20OkY*000310000000030nZ20OkY*000310000000030nZ20OkY*000310000000030nB1OVm)1poj6 z0000000030nZ20OkY*000310000000030{{ah= z0R^4`0I~rE009600SGn)JpfV#00030n;8KQD+O}_i2(|e0RW)^1poj60000000030 z{{aX?1xf&31pom5{{ayn1poj#1#tjX1zZ4z0R;d6|Nj9DD+K@mN(E5>W(5EM|Nj99 zM+Hs*Vg&#I00030n;Xp80|D9sIRF5g1R=Zx0Llaf000310000000030 z{{aC1nZ20OkY*000310000000030n;8KSjsXRg z0RgZ91+@VH!vO^V0096100030{{aX{1y2BD1pom5{{aX`1x^5B1pom5n;iiaD+K@m zYnB180s+MW3eN%n-2w#w0096100030n;8KQRRwbai2(|e0RW)^1poj60000000030 z{{ah=0R^4`0I~rE00030n;8KQUIk?VfB^-C0RWQ$1poj60000000030{{aji1poj# z1wjB-1pom5{{aX`1x^5B1pom5{{g2HJOuy%d7fAt zq#Om1+Sw40IVSe>!Sex#32RRqX7V%A_bPD0RXfj1%;#m z0E{CA!K48Iq$35eqyYf@BL(cF0RWUF1>2+n0PG|Mm!$y!ge3)rr2zokB?ZEz0RZ$R z1+k?80L&%@?WF+#L3r0E{XHnWq5&q$&l7rvU)`Dh0%+0RWUM1+%9C0PHIT@23F(ge(Q#rvU)m zECrgV0RZ$Y1&OEu0L(1~#i#)QdLv0IV+so2dZ+#4iPk zsR00-Fa^e`0RXfx1+}RG0E{sO@u>j-q%j5HsR01|F$J8e0RWUT1&gWy0PHda$EpDU zgfj)UssRApGX?Uh0RZ$f1>vdz0L(N6ovQ%=>#5M)us{sIV$*chYq&Nk*tN{T0I0f{q0RWUa1>>v% z0PHyhpREA^ggOO|tpNbsIt9wD0RZ$m1-Y#O0L(iD^{oK_*0E|Bcp|1e|q(23auK@u3KLyOM z0RWUh1-q{S0PH{o_pbo}gh2)7uK@tuK?S0)0RZ$t1(C1;0L(%K&9DIgqp<-1#6$&>u>k;_MFq~W0RXf`1--EW0E|Wj`LO{2q(%kk zu>k=5Mg^p@0RWUo1(UJ?0PIHv&$0mkgh&OxvH<|xNCo<`0RZ$!1?jQ@0L)1RrLzG5 zxd8zDTLrAT0RWU-1)I770PI`^*SY}!gk1&3 zx&Z*(T?K->0RZ$}1@XE80L)$mt-ApLas`UR0RZ%J1^L1O0L*g*wZj1bOcLj{a0RWVE1^dJS0PJ`Lx5WVfgn0#~#Q^}^c?IId0RZ%Q1<}O;0L*#? zjm7~0K3T+<*ZEy2t?l z^nd{csmK8U%z*&~<;Vd5uNWoP+@d=E(s7w1fc#)yV+>jD-OOk;(x8q=f+mfXV>?{DlDpyvhLpl!gHXtI7cY z?1lja=gI*9gognI*2)0@+=l@LlFI=A^oIcjfy)5^%!mO6y~_arC6ED zq>KRt*vtU{{EPtwl+6JEl#KxegUtZ|?2Q2hzs&&vgpL6PuFU}e+>QYS>dgTF^o{`q z+06j}%#Q&DmCgYG&^iH#E}67+Rgz0 zoRR?rmd^nIw2}b@h0g&1jFSNc!OsBzq>}*!u+ISi{F4C%?9TxJl#~Gl+s^?2?34io zm(T$Kgp~mWhR^{3+?4?Z!q5Q#^pybxvCshk%$5NK?a%=LAo0002+s00820001}Q3n730002aQ3n730002qQ3n730002yQ3n73 z0002-Q3n730000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00001000000002{xB>tG000010000000006xdH$H00001000000000IxdH$H00001 z000000000YxdH$H00001000000000nxdH$H00001000000000xxdH$H0000100000 z0000J0000MWCQ>J0000cWCQ>J0000sWCQ>J0000+WCQ>J00011WCQ>J z0001HWCQ>J0001XWCQ>J0001nWCQ>J0001%WCQ>J0001{WCQ>J0002CWCQ>J0002S zWCQ>J0002iWCQ>J0002yWCQ>J0002?WCQ>J00006Wdr~K0000MWdr~K0000cWdr~K z0000sWdr~K0000+Wdr~K00011Wdr~K0001HWdr~K0001XWdr~K0001nWdr~K0001% zWdr~K0001{Wdr~K0002CWdr~K0002SWdr~K0002iWdr~K0002yWdr~K0002?Wdr~K z00006W&{8L0000MW&{8L0000cW&{8L0000sW&{8L0000+W&{8L00011W&{8L0001H zW&{8L0001XW&{8L0001nW&{8L0001%W&{8L0001{W&{8L0002CW&{8L0002SW&{8L z0002iW&{8L0002yW&{8L0002?W&{8L00006X9NHM0000MX9NHM0000cX9NHM0000s zX9NHM0000+X9NHM00011X9NHM0001HX9NHM0001XX9NHM0001nX9NHM0001%X9NHM z0001{X9NHM0002CX9NHM0002SX9NHM0002iX9NHM0002yX9NHM0002?X9NHM00006 zXaoQN0000MXaoQN0000cXaoQN0000sXaoQN0000+XaoQN00011XaoQN0001HXaoQN z0001XXaoQN0001nXaoQN0001%XaoQN0001{XaoQN0002CXaoQN0002SXaoQN0002i zXaoQN0002yXaoQN0002?XaoQN00006X#@ZO0000MX#@ZO0000cX#@ZO0000sX#@ZO z0000+X#@ZO00011X#@ZO0001HX#@ZO0001XX#@ZO0001nX#@ZO0001%X#@ZO0001{ zX#@ZO0002CX#@ZO0002SX#@ZO0002iX#@ZO0002yX#@ZO0002?X#@ZO00006Y6JiP z0000MY6JiP0000cY6JiP0000sY6JiP0000+Y6JiP00011Y6JiP0001HY6JiP0001X zY6JiP0001nY6JiP0001%Y6JiP0001{Y6JiP0002CY6JiP0002SY6JiP0002iY6JiP z0002yY6JiP0002?Y6JiP00006YXkrQ0000MYXkrQ0000cYXkrQ0000sYXkrQ0000+ zYXkrQ00011YXkrQ0001HYXkrQ0001XYXkrQ0001nYXkrQ0001%YXkrQ0001{YXkrQ z0002CYXkrQ0002SYXkrQ0002iYXkrQ0002yYXkrQ0002?YXkrQ00006Yy5n0000Mf&>5n0000cf&>5n0000sf&>5n0000+f&>5n00011f&>5n0001Hf&>5n z0001Xf&>5n0001nf&>5n0001%f&>5n0001{f&>5n0002Cf&>5n0002Sf&>5n0002i zf&>5n0002yf&>5n0002?f&>5n00006g9HEo0000Mg9HEo0000cg9HEo0000sg9HEo z0000+g9HEo00011g9HEo0001Hg9HEo0001Xg9HEo0001ng9HEo0001%g9HEo0001{ zg9HEo0002Cg9HEo0002Sg9HEo0002ig9HEo0002yg9HEo0002?g9HEo00006gaiNp z0000MgaiNp0000cgaiNp0000sgaiNp0000+gaiNp00011gaiNp0001HgaiNp0001X zgaiNp0001ngaiNp0001%gaiNp0001{gaiNp0002CgaiNp0002SgaiNp0002igaiNp z0002ygaiNp0002?gaiNp00006g#-Wq0000Mg#-Wq0000cg#-Wq0000sg#-Wq0000+ zg#-Wq00011g#-Wq0001Hg#-Wq0001Xg#-Wq0001ng#-Wq0001%g#-Wq0001{g#-Wq z0002Cg#-Wq0002Sg#-Wq0002ig#-Wq0002yg#-Wq0002?g#-Wq00006h6Dfr0000M zh6Dfr0000ch6Dfr0000sh6Dfr0000+h6Dfr00011h6Dfr0001Hh6Dfr0001Xh6Dfr z0001nh6Dfr0001%h6Dfr0001{h6Dfr0002Ch6Dfr0002Sh6Dfr0002ih6Dfr0002y zh6Dfr0002?h6Dfr00006hXeos0000MhXeos0000chXeos0000shXeos0000+hXeos z00011hXeos0001HhXeos0001XhXeos0001nhXeos0001%hXeos0001{hXeos0002C zhXeos0002ShXeos0002ihXeos0002yhXeos0002?hXeos00006hy(xt0000Mhy(xt z0000chy(xt0000shy(xt0000+hy(xt00011hy(xt0001Hhy(xt0001Xhy(xt0001n zhy(xt0001%hy(xt0001{hy(xt0002Chy(xt0002Shy(xt0002ihy(xt0002yhy(xt z0002?hy(xt00006i39)u0000Mi39)u0000ci39)u0000si39)u0000+i39)u00011 zi39)u0001Hi39)u0001Xi39)u0001ni39)u0001%i39)u0001{i39)u0002Ci39)u z0002Si39)u0002ii39)u0002yi39)u0002?i39)u00006iUa@v0000MiUa@v0000c ziUa@v0000siUa@v0000+iUa@v00011iUa@v0001HiUa@v0001XiUa@v0001niUa@v z0001%iUa@v0001{iUa@v0002CiUa@v0002SiUa@v0002iiUa@v0002yiUa@v0002? ziUa@v00006iv$1w0000Miv$1w0000civ$1w0000siv$1w0000+iv$1w00011iv$1w z0001Hiv$1w0001Xiv$1w0001niv$1w0001%iv$1w0001{iv$1w0002Civ$1w0002S ziv$1w0002iiv$1w0002yiv$1w0002?iv$1w00006j06Ax0000Mj06Ax0000cj06Ax z0000sj06Ax0000+j06Ax00011j06Ax0001Hj06Ax0001Xj06Ax0001nj06Ax0001% zj06Ax0001{j06Ax0002Cj06Ax0002Sj06Ax0002ij06Ax0002yj06Ax0002?j06Ax z00006jRXJy0000MjRXJy0000cjRXJy0000sjRXJy0000+jRXJy00011jRXJy0001H zjRXJy0001XjRXJy0001njRXJy0001%jRXJy0001{jRXJy0002CjRXJy0002SjRXJy z0002ijRXJy0002yjRXJy0002?jRXJy00006jsySz0000MjsySz0000cjsySz0000s zjsySz0000+jsySz00011jsySz0001HjsySz0001XjsySz0001njsySz0001%jsySz z0001{jsySz0002CjsySz0002SjsySz0002ijsySz0002yjsySz0002?jsySz00006 zj|2b!0000Mj|2b!0000cj|2b!0000sj|2b!0000+j|2b!00011j|2b!0001Hj|2b! z0001Xj|2b!0001nj|2b!0001%j|2b!0001{j|2b!0002Cj|2b!0002Sj|2b!0002i zj|2b!0002yj|2b!0002?j|2b!00006kOTk#0000MkOTk#0000ckOTk#0000skOTk# z0000+kOTk#00011kOTk#0001HkOTk#0001XkOTk#0001nkOTk#0001%kOTk#0001{ zkOTk#0002CkOTk#0002SkOTk#0002ikOTk#0002ykOTk#0002?kOTk#00006kput$ z0000Mkput$0000ckput$0000skput$0000+kput$00011kput$0001Hkput$0001X zkput$0001nkput$0001%kput$0001{kput$0002Ckput$0002Skput$0002ikput$ z0002ykput$0002?kput$00006k^}$%0000Mk^}$%0000ck^}$%0000sk^}$%0000+ zk^}$%00011k^}$%0001Hk^}$%0001Xk^}$%0001nk^}$%0001%k^}$%0001{k^}$% z0002Ck^}$%0002Sk^}$%0002ik^}$%0002yk^}$%0002?k^}$%00006lLP<&0000M zlLP<&0000clLP<&0000slLP<&0000+lLP<&00011lLP<&0001HlLP<&0001XlLP<& z0001nlLP<&0001%lLP<&0001{lLP<&0002ClLP<&0002SlLP<&0002ilLP<&0002y zlLP<&0002?lLP<&00006lmq|(0000Mlmq|(0000clmq|(0000slmq|(0000+lmq|( z00011lmq|(0001Hlmq|(0001Xlmq|(0001nlmq|(0001%lmq|(0001{lmq|(0002C zlmq|(0002Slmq|(0002ilmq|(0002ylmq|(0002?lmq|(00006l>`6)0000Ml>`6) z0000cl>`6)0000sl>`6)0000+l>`6)00011l>`6)0001Hl>`6)0001Xl>`6)0001n zl>`6)0001%l>`6)0001{l>`6)0002Cl>`6)0002Sl>`6)0002il>`6)0002yl>`6) z0002?l>`6)00006mIMF*0000MmIMF*0000cmIMF*0000smIMF*0000+mIMF*00011 zmIMF*0001HmIMF*0001XmIMF*0001nmIMF*0001%mIMF*0001{mIMF*0002CmIMF* z0002SmIMF*0002imIMF*0002ymIMF*0002?mIMF*00006mjnO+0000MmjnO+0000c zmjnO+0000smjnO+0000+mjnO+00011mjnO+0001HmjnO+0001XmjnO+0001nmjnO+ z0001%mjnO+0001{mjnO+0002CmjnO+0002SmjnO+0002imjnO+0002ymjnO+0002? zmjnO+00006m;?X-0000Mm;?X-0000cm;?X-0000sm;?X-0000+m;?X-00011m;?X- z0001Hm;?X-0001Xm;?X-0001nm;?X-0001%m;?X-0001{m;?X-0002Cm;?X-0002S zm;?X-0002im;?X-0002ym;?X-0002?m;?X-00006nFIg;0000MnFIg;0000cnFIg; z0000snFIg;0000+nFIg;00011nFIg;0001HnFIg;0001XnFIg;0001nnFIg;0001% znFIg;0001{nFIg;0002CnFIg;0002SnFIg;0002inFIg;0002ynFIg;0002?nFIg; z00006ngjp<0000Mngjp<0000cngjp<0000sngjp<0000+ngjp<00011ngjp<0001H zngjp<0001Xngjp<0001nngjp<0001%ngjp<0001{ngjp<0002Cngjp<0002Sngjp< z0002ingjp<0002yngjp<0002?ngjp<00006n*;y=0000Mn*;y=0000cn*;y=0000s zn*;y=0000+n*;y=00011n*;y=0001Hn*;y=0001Xn*;y=0001nn*;y=0001%n*;y= z0001{n*;y=0002Cn*;y=0002Sn*;y=0002in*;y=0002yn*;y=0002?n*;y=00006 zoCE*>0000MoCE*>0000coCE*>0000soCE*>0000+oCE*>00011oCE*>0001HoCE*> z0001XoCE*>0001noCE*>0001%oCE*>0001{oCE*>0002CoCE*>0002SoCE*>0002i zoCE*>0002yoCE*>0002?oCE*>00006odf^?0000Modf^?0000codf^?0000sodf^? z0000+odf^?00011odf^?0001Hodf^?0001Xodf^?0001nodf^?0001%odf^?0001{ zodf^?0002Codf^?0002Sodf^?0002iodf^?0002yodf^?0002?odf^?00006o&*2@ z0000Mo&*2@0000co&*2@0000so&*2@0000+o&*2@00011o&*2@0001Ho&*2@0001X zo&*2@0001no&*2@0001%o&*2@0001{o&*2@0002Co&*2@0002So&*2@0002io&*2@ z0002yo&*2@0002?o&*2@00006p9BB^0000Mp9BB^0000cp9BB^0000sp9BB^0000+ zp9BB^00011p9BB^0001Hp9BB^0001Xp9BB^0001np9BB^0001%p9BB^0001{p9BB^ z0002Cp9BB^0002Sp9BB^0002ip9BB^0002yp9BB^0002?p9BB^00006pacK_0000M zpacK_0000cpacK_0000spacK_0000+pacK_00011pacK_0001HpacK_0001XpacK_ z0001npacK_0001%pacK_0001{pacK_0002CpacK_0002SpacK_0002ipacK_0002y zpacK_0002?pacK_00006p#%T`0000Mp#%T`0000cp#%T`0000sp#%T`0000+p#%T` z00011p#%T`0001Hp#%T`0001Xp#%T`0001np#%T`0001%p#%T`0001{p#%T`0002C zp#%T`0002Sp#%T`0002ip#%T`0002yp#%T`0002?p#%T`00006q67c{0000Mq67c{ z0000cq67c{0000sq67c{0000+q67c{00011q67c{0001Hq67c{0001Xq67c{0001n zq67c{0001%q67c{0001{q67c{0002Cq67c{0002Sq67c{0002iq67c{0002yq67c{ z0002?q67c{00006qXYl|0000MqXYl|0000cqXYl|0000sqXYl|0000+qXYl|00011 zqXYl|0001HqXYl|0001XqXYl|0001nqXYl|0001%qXYl|0001{qXYl|0002CqXYl| z0002SqXYl|0002iqXYl|0002yqXYl|0002?qXYl|00006qyzu}0000Mqyzu}0000c zqyzu}0000sqyzu}0000+qyzu}00011qyzu}0001Hqyzu}0001Xqyzu}0001nqyzu} z0001%qyzu}0001{qyzu}0002Cqyzu}0002Sqyzu}0002iqyzu}0002yqyzu}0002? zqyzu}00006r33%~0000Mr33%~0000cr33%~0000sr33%~0000+r33%~00011r33%~ z0001Hr33%~0001Xr33%~0001nr33%~0001%r33%~0001{r33%~0002Cr33%~0002S zr33%~0002ir33%~0002yr33%~0002?r33%~00006rUU>00000MrUU>00000crUU>0 z0000srUU>00000+rUU>000011rUU>00001HrUU>00001XrUU>00001nrUU>00001% zrUU>00001{rUU>00002CrUU>00002SrUU>00002irUU>00002yrUU>00002?rUU>0 z00006rvv~10000Mrvv~10000crvv~10000srvv~10000+rvv~100011rvv~10001H zrvv~10001Xrvv~10001nrvv~10001%rvv~10001{rvv~10002Crvv~10002Srvv~1 z0002irvv~10002yrvv~10002?rvv~100006s00820000Ms0082000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000D%90001cf0000000000000000000000000 z0000000000M?*t8ASg#pRVg4hE;BAL00000000000000000000000000000000000 z00000000000{{U4$N>NV000000000000000000000{{X5ATR&`000000000000000 z000000{{a6K;-}c000000000000000000000{{d7PM-q+00000000000000000000 z0{{g8Xs!bQ000000000000000000000{{j9Xs-hR000000000000000000000{{mA zu)6~Q000000000000000000000{{pBa7hFJ000000000000000000000{{sCkVymp z000000000000000000000{{vDAgBZY000000000000000000000{{yEV5kHD00000 z0000000000000000{{#FOil*?000000000000000000000{{&GU`_`B0000000000 z00000000000{{*Hu(}5T000000000000000000000{{;I;O7Sb000000000000000 z000000{{>Je5VKi000000000000000000000{{^K;K?We00000000000000000000 z0{{{L;K?We000000000000000000000{{~M@X06u000000000000000000000{|2N z_{k^$000000000000000000000{|5O@XROx000000000000000000000{|8PP|qj; z000000000000000000000{|BQ001cf000000000000000000000{|ERAOI-<00000 z0000000000000000{|HS000000000000000000000RR911OV~>000000000000000 z000003;+NC0sspDV5kHD0000000000000004gdfE0sspDpr`}@000000000000000 zApigX0sspD@Tdd;000000000000000Hvj+t0RR{PAOI-<000000RR9100000MgRZ+ z0RR&K@X06u000000000000000Z2$lO0sspDFsTFp000000000000000c>n+a0RR#J z;K?We000000000000000x>*1K1OV~>00000000000000000000m;e9(0RRmEU`_`B z000000RR9100000vj6}90RR*LAj&8J000002mk;800000OV00000{Qv*}0sspDS*Zj7000008UO$Q00000B>?~c0sspDbEyOX000007ytkO z00000M*#o;0sspDi>U+v00000DgXcg00000bpZeX0sspDwW$OE000009{>OV00000 zodEy<0sspD)Tsmj00000LjV8(00000%>e)a0sspD7pepR00000L;wH)00000_W=L^ z0RRmEXif(J000000RR91000003<3ZE0RRmEX-)?K000000RR910000083F(R0RR{P zKmaKK000000RR9100000C;|Wg0RRmEY)%IN000001ONa400000PXYh{0RR*LD9R`R z000002mk;800000bpikY0RR*LFv=(Z000002mk;800000nF0U+0RRmE>`n&&00000 z1ONa400000zybgO0RRmE@J#TL000000RR91000006axSN0RRmE{7we|000001ONa400000 zBm)2d0RR{PLI5cM000000RR9100000KLY>&0RRmE08a-1000001ONa400000Spxt7 z0RR{PLjWlN000000RR9100000eFFdh0RRmE1WyM5000001ONa400000l>-0(0RR{P zL;xuO000000RR9100000w*vqG0RRmE2u}w9000001ONa400000%mV-b0RR{PMF1%P z000000RR9100000>jMA)0RRmE3{M9D000001ONa400000{sRC20RR{PMgS=Q00000 z0RR910000090ULW0RRmE5KjjH000001ONa400000H3R?v0RR{PM*t}R000000RR91 z00000SOfq70RRmE6i){L000001ONa400000Z3F-S0RR{PNB}7S000000RR9100000 zj06Ax0RRmE7*7WP000001ONa400000p9BB^0RR{PNdPGT000000RR9100000y#xRN z0RRmE98U)T000001ONa400000*8~6n0RR{PN&qPU000000RR9100000`vd?00RRmE zAWsJX000001ONa40000090dRX0RR{PO8_YV000000RR9100000M+E=?0RRmEBu@tb z000001ONa400000XaxWO0RR{POaLhW000000RR9100000lLY_(0RRmEC{G6f00000 z1ONa400000wgmtH0RR{PO#mqX000000RR9100000;{^Z!0RRmEEKdgj000001ONa4 z000001qJ{B0RR{PP5>zY000000RR9100000F$Mqt0RRmEFi!^n000001ONa400000 zM+N`@0RR{PPXH+Z000000RR9100000X9fTO0RRmEG*1Tr000001ONa400000e+B>m z0RR{PPyi_a000000RR9100000p#}f|0RRmEI8O%v000001ONa400000z6JmQ0RR{P zQ2;3b000000RR9100000@000001ONa400000N(cY|0RR{PRsbmg000000RR9100000dk6pk z0RRmEP)`Q{000001ONa400000p9lZ|0RR{PR{$vh000000RR9100000%?JPh0RRmE zR8I#0000001ONa400000?g#(?0RR{PSO6&i000000RR910000083_OY0RRmESWgE4 z000001ONa400000K?wi=0RR{PSpX>j000000RR9100000a|r+d0RRmETu%o800000 z1ONa400000n+X5_0RR{PS^y~k000000RR9100000%?SVi0RRmEU{41C000001ONa4 z00000@d*F`0RR{PTL38l000000RR91000009|`~f0RRmEWKRbG000001ONa400000 zHwpj%0RR{PTmUHm000000RR9100000SqcCE0RRmEXiovQn000000RR9100000p$Y&10RRmEY)=OO000001ONa400000y$S#T0RR{P zUH~Zo000000RR9100000;|c%(0RRmEa8CyS000001ONa4000000Sf>C0RR{PUjQip z000000RR9100000DGLAq0RRmEbWaBW000001ONa400000OA7!10RR{PU;rrq00000 z0RR9100000cMAXj0RRmEcuxla000001ONa400000nF{~_0RR{PVE`!r000000RR91 z00000#R~uc0RRmEd`|}e000001ONa400000>k9w?0RR{PVgM-s000000RR9100000 z8w>yd0RRmEfKLYi000001ONa400000J`4Z=0RR{PV*n`t000000RR9100000YYYGY z0RRmEgii+m000001ONa400000iVOe%0RR{PWB@4u000000RR9100000vkU+L0RRmE zh))Lq000001ONa400000*$e;x0RR{PWdJDv000000RR91000002@L=M0RRmEj86vu z000001ONa400000C=CDr0RR{PW&kMw000000RR9100000Q4Ih90RRmEkWU8y00000 z1ONa400000bPWIi0RR{PX8xd0RR{PXaFey000000RR9100000@eKd~0RRmEm`?`)000001ONa400000 z7!Cjc0RR{PX#gnz000000RR9100000Ne%!20RRmEoKFV;000001ONa400000Z4Lkc z0RR{PY5*w!000000RR9100000n+^Z~0RRmEpic(?000001ONa400000ybb^W0RR{P zYXB(#000000RR9100000=MDe>0RRmEq)!I`000001ONa4000001`hxL0RR{PYyc?$ z000000RR9100000FAo3!0RRmEs80s~000001ONa400000R1W|E0RR{PZ2&0%00000 z0RR9100000gAV`z0RRmEtWO63000001ONa400000qz?c90RR{PZU89&000000RR91 z00000&kq0q0RRmEuulg7000001ONa400000{to~E0RR{PZvZI(000000RR9100000 zHxK{-0RRmEv`+^B000001ONa400000XAl4Y0RR{PZ~!R)000000RR9100000p%4H7 z0RRmExK9TF000001ONa400000&kz6r0RR{PaR4a*000000RR91000002N3`O0RRmE zyiW%J000001ONa400000I1vB<0RR{PasVj+000000RR9100000a}fXl0RRmEz)uGN z000001ONa400000p%DN80RR{Pa{ws-000000RR9100000*%1H$0RRmE#7_qR00000 z1ONa4000002@(JR0RR{PbO0#;000000RR9100000LlOW00RRmE$WI3V000001ONa4 z00000auNUl0RR{PbpR;<000000RR9100000s}cYJ0RRmE%ufdZ000001ONa400000 z&=LRu0RR{Pb^s{=000000RR9100000{}KQI0RRmE&`$>d000001ONa400000FB1R& z0RR{PcK|5>000000RR9100000X%hed0RRmE)K3Qh000001ONa400000juQX?0RR{P zcmOE?000000RR9100000y%PWc0RRmE*iQ!l000001ONa400000;u8P>0RR{Pc>pN@ z000000RR91000005flIb0RRmE+)oDp000001ONa400000GZX*-0RR{PdH^W^00000 z0RR9100000UlafU0RRmE;7`w;(000001ONa400000a}@vp0RR{PegG)|000000RR9100000pA`TA0RRmE z@J|N-000001ONa400000!xaDk0RR{Pe*h@}000000RR9100000@f8370RRmE^iKx> z000001ONa4000005EcLc0RR{PfB-1~000000RR9100000ITio_0RRmE_)iA_00000 z1ONa400000S{48R0RR{PfdDB0000000RR9100000g%$t+0RRmE{7(k}000001ONa4 z00000tQG(O0RR{Pf&eK1000000RR9100000-4*}<0RRmE08j@2000001ONa400000 z0v7-P0RR{Pg8(T2000000RR9100000F&6*;0RRmE1W*S6000001ONa400000OBVnD z0RR{Pga9c3000000RR9100000Zx;Xn0RRmE2v7$A000001ONa400000lotR10RR{P zg#al4000000RR9100000!xsPm0RRmE3{VFE000001ONa400000<`)0}0RR{Ph5#u5 z000000RR91000006Bqyh0RRmE5KspI000001ONa400000Ll^)60RR{PhX5%600000 z0RR9100000eHZ`$0RRmE6i^2M000001ONa400000r5FGJ0RR{PhyW=7000000RR91 z00000*BAf*0RRmE7*GcQ000001ONa400000`WOHJ0RR{Pi2x}8000000RR9100000 zCm8?$0RRmE98d=U000001ONa400000Lm2=70RR{PiU279000000RR9100000X&C?j z0RRmEAW#PY000001ONa400000hZz6>0RR{PivTGA000000RR9100000uNeRU0RRmE zBv1zc000001ONa400000(-{B&0RR{Pi~uPB000000RR91000000U7`R0RRmEC{PCg z000001ONa400000BpLt!0RR{PjQ}YC000000RR9100000Q5paM0RRmEEKmmk00000 z1ONa400000a2fyr0RR{PjsPhD000000RR9100000nHm590RRmEFi-~o000001ONa4 z00000!5RPn0RR{Pj{qqE000000RR9100000^BMpE0RRmEG*AZs000001ONa400000 z85;lq0RR{PkN_zF000000RR9100000NgDtF0RRmEI8X-w000001ONa400000dm8`% z0RR{PkpL+G000000RR9100000w;KQe0RRmEJWvM!000001ONa400000>Kgz60RR{P zk^m_H000000RR9100000Cma9(0RRmEKu`w&000001ONa400000P8jLK000000RR91 z00000I~@Q30RRmEOi%{^000001ONa400000WgP$j0RR{PmH;UL000000RR9100000 znH>NC0RRmEP*4W|000001ONa400000#2o+t0RR{PmjEdM000000RR9100000`5gcN z0RRmER8R*1000001ONa40000093B7w0RR{Pm;fmN000000RR9100000NgeQ000000RR9100000cOL)%0RRmEWKahH000001ONa4 z00000lpg>90RR{PoB$~R000000RR9100000yB`1m0RRmEXix_L000001ONa400000 z-yZ+~0RR{Pod78S000000RR91000004Ilsj0RRmEY)}UP000001ONa400000G#~%~ z0RR{Po&YHT000000RR9100000Wgq|m0RRmEa8L&T000001ONa400000njioG0RR{P zp8zQU000000RR9100000*&qM_0RRmEbWjHX000001ONa4000003n2gi0RR{Ppa3ZV z000000RR9100000M^0RR{Pu>dIm000000RR9100000TPFYj z0RRmEyif-K000001ONa400000d?x?^0RR{PvH&Rn000000RR9100000rzZda0RRmE zz)%MO000001ONa400000)+Yb}0RR{Pvj8ao000000RR91000004=4Zt0RRmE#83wS z000001ONa400000KqvqJ0RR{Pv;Zjp000000RR9100000dnf<^0RRmE$WR9W00000 z1ONa400000r6>RZ0RR{PwE!sq000000RR9100000*(d-20RRmE%uoja000001ONa4 z00000{3rkb0RR{Pwg4#r000000RR9100000DJcK|0RRmE&`<{e000001ONa400000 zODO;V0RR{Pw*V;s000000RR9100000cPRh>0RRmE)KCWi000001ONa400000m?;1N z0RR{PxBw{t000000RR9100000!zlm&0RRmE*iZ)m000001ONa400000Va0RR{PyZ|Wx000000RR91 z00000FDn250RRmE=uig$000001ONa400000V=Djv0RR{Py#Ofy000000RR9100000 zp(_9Y0RRmE>`(^)000001ONa400000)GGi00RR{Pz5poz000000RR91000005i9@z z0RRmE@K6T;000001ONa400000LM#9P0RR{PzW^x!000000RR9100000eJlU~0RRmE z^iT%?000001ONa400000uPgun0RR{PzyK)#000000RR9100000>ns2O0RRmE_)rG` z000001ONa400000BrN~{0RR{P!2l@$000000RR9100000XDt8#0RRmE{7?q~00000 z1ONa400000o-F_X0RR{P!T>1%000000RR9100000-z@+D0RRmE08s}3000001ONa4 z000005-tD$0RR{P!vHA&000000RR9100000Pc8re0RRmE1W^Y7000001ONa400000 zgf0L80RR{P!~iJ(000000RR9100000!!7^-0RRmE2vG+B000001ONa400000{4M|h z0RR{P#Q-S)000000RR9100000KQ90P0RRmE3{eLF000001ONa400000b}s+`0RR{P z#sDb*000000RR9100000w=Vzy0RRmE5K#vJ000001ONa400000<}UyM0RR{P#{ek+ z000000RR9100000A20v_0RRmE6j28N000001ONa400000PcQ%g0RR{P$N(t-00000 z0RR9100000i7)^F0RRmE7*PiR000001ONa400000yD$I%0RR{P$p9$;000000RR91 z00000_b>ne0RRmE98m`V000001ONa400000E-?TA0RR{P$^a<<000000RR9100000 zZ!rJ>0RRmEAW;VZ000001ONa400000r7-{i0RR{P%K#|=000000RR9100000AA%0RR{P%m66>000000RR9100000LoxsW0RRmE zC{YIh000001ONa400000bTR+{0RR{P%>XF?000000RR9100000uQC7t0RRmEEKvsl z000001ONa400000;W7XK0RR{P&HyO@000000RR91000009Wwv`0RRmEFi{5p00000 z1ONa400000Ofvug0RR{P&j2X^000000RR9100000g);yE0RRmEG*Jft000001ONa4 z00000xibI&0RR{P&;Tg_000000RR9100000_cH(h0RRmEI8g@x000001ONa400000 zDl`B90RR{P(Eup`000000RR9100000XEXo+0RRmEJW&S#000001ONa400000oiqRd z0RR{P(f}y{000000RR9100000-829I0RRmEKv4$(000001ONa4000005;Xt-0RR{P z(*P*|000000RR9100000Q8fSn0RRmEL{SF-000001ONa400000f;9jD0RR{P)Bq^} z000000RR9100000y)^&;0RRmENKpp>000001ONa400000@HGGc0RR{P)c`2~00000 z0RR9100000Ej9oE0RRmEOi>2_000001ONa400000VKx8&0RR{P)&MC0000000RR91 z00000pEdvh0RRmEP*Dc}000001ONa400000(l!790RR{P*8nL1000000RR9100000 z4>te+0RRmER8a>2000001ONa400000LN@>a0RR{P*Z?U2000000RR9100000e>VUC z0RRmESWyQ6000001ONa400000tv3Jw0RR{P*#Id3000000RR91000000RR{P+5jm4000000RR9100000OE>@k0RRmEU{MDE z000001ONa400000e>eaD0RR{P+W;v5000000RR9100000y*K~>0RRmEWKjnI00000 z1ONa400000?Kl7c0RR{P+yE&6000000RR9100000CpiEB0RRmEXi*0M000001ONa4 z00000Svddz0RR{P-2f>7000000RR9100000l{o+a0RRmEY*7aQ000001ONa400000 z$2kB10RR{P-T)~8000000RR910000013CZz0RRmEa8U;U000001ONa400000IywLV z0RR{P-vB89000000RR9100000dpZCB0RRmEbWsNY000001ONa400000r#b)t0RR{P z-~cHA000000RR9100000-8ujO0RRmEcu@xc000001ONa4000003OfJ*0RR{P;Q%QB z000000RR9100000K|25d0RRmEd{GAg000001ONa400000ZaV+~0RR{P;s7ZC00000 z0RR9100000r8@us0RRmEfKdkk000001ONa400000*gF6K0RR{P;{YiD000000RR91 z000006+8d{0RRmEgi!|o000001ONa400000Mmzuj0RR{PRDJ000000RR9100000M?L@m0RRmEoKXh=000001ONa4 z00000e?9;J0RR{P>HsMK000000RR9100000!9D;00RRmEpiu_^000001ONa400000 z_C5dr0RR{P>i{VL000000RR9100000H9r6V0RRmEq)`U|000001ONa400000Y(D@1 z0RR{P>;NeM000000RR9100000tv>(&0RR*L_{k^$000002mk;800000(LVqH0RR*L z0Lmx;000002mk;800000@jn0n0RR*L2+Ak`000002mk;8000004nP0^0RR*L5XvY3 z000002mk;800000FF*hQ0RR*L7|JLB000002mk;800000Oh5nt0RRmE08$4400000 z2mk;800000Xg~k}0RR{P00Aig00000Pyhe`00000lt2Ig0RR{PPys0b000002mk;8 z00000!ax830RRmEAc6+~000001poj500000>_7kj0RRmEFoFjF000005dZ)H00000 zPC)0RRmEAcY4200000GXekr00000G(!LY0RRmEpqmE( z00000!~g&Q00000=tBSi0RRmEpr;1_000001_1y700000ltcgk0RRmEz^DfR00000 zy8r+H00000KScll0RRmEV6F!M00000{Qv*}00000;za-e0RRmEfPx1A00000nF0U+ z00000d`18O0RRmEV21|)000004gvrG00000_C^2z0RRmEV2cL;00000Lo(300000>jMA)000008%O{E0RRmEz?26700000N&)}?00000lSlvn z0RRmEAeRRK00000b^rhX000007)byC0RRmEz@i5L00000e*gdg00000u1Np@0RRmE zK%xf#00000egFUf00000LP`Jt0RRmEAeaXL000001pxp600000)=B^X0RRmEK$!;s z00000mjD0&00000RZ9Q>0RRmEaDfK^000002mk;800000T1x-`0RRmEfPn`900000 z5C8xG00000UrPW00RRmEkbwsP000005C8xG00000WJ>@50RRmEpn(Sf000005C8xG z00000X-fbA0RRmEuz?2v000007ytkO00000Zc6|F0RRmE(18a4000007ytkO00000 zb4vgK0RRmE@PP*a000007ytkO00000cuN2P0RRmE0GkH@00000mjD0&00000_e%f( z0RRmEfSd;a00000%m4rY00000uS@^{0RRmE0H+5400000lK=n!00000CrtnV0RRmE z0Hy~300000@Bjb+00000piKY(0RRmEV4Vj500000x&QzG00000O-=v+0RRmE0G|f{ z00000xBvhE00000`c41<0RRmEAf5*R00000!2kdN00000r%wO?0RRmEz@G;I00000 zyZ`_I00000R8Rl_0RRmEfS?Be00000%K!iX000000#N_}0RRmEV4(*900000#Q*>R z00000uTcO10RRmEfT;%n00000tN;K200000Q&Io`0RRmEK&l4-00000ng9R*00000 z>{0*#0RRmEpsNP}00000m;e9(00000g;M|k0RRmE;Hn1z00000p#T5?000009#jAT z0RRmEK&%G<00000oB#j-00000w^RTC0RRmE;H(D#00000s{jB100000QB?o{0RRmE zpsfc000000r2qf`00000>Qw*$0RRmEpqB>#00000V*mgE00000VpaeE0RRmE;F$*i z00000Y5)KL00000<5mCw0RRmE5P}B)000005C8xG00000=~e&$0RRmEV44R200000 ziU0rr00000g;xLo0RRmEK%)l$00000=l}o!0000009XJ30RRmEK%@r%00000YXATM z00000fLH(k0RRmEz@!HN00000X#fBK00000{#XD20RRmEK&1x&00000qW}N^00000 zdszSg0sspDGQ|V{00000qG$jB00000t62a50sspD)GY-7000006#xJL000000RR91 z1OV~>00000000000000000000%UJ*b0RRsGc&7*e000000000000000000001OV~> z00000000000000000000*;xPp000gEu(}5T000000000000000>{$Q+0RR^O5CACv z000002mk;8000006j}fP0RR^O001cf000000000000000AzA0RR^OAOI-<0000000000 z00000Qd$520RR>NP|qj;000000000000000Xj%XO0RR^O2mmPn000002mk;800000 zl3D-&A^-~jkevkp000003jqKC0000099sYYA^-~jeH;e>00000&;S4c00000Yg+&S zA^-~jVpj$L000008vpKA^-~j z>ih)&00000NB{r;00000X|6i00000i2wiq00000 z&0YWiA^-~jQBwr~00000$^ZZW000000bc+BA^-~jf%XOf00000IRF3v00000h+hBz zA^-~jTPz0v00000F#rGn00000DPRBqA^-~ju$%<|00000AOHXW00000reFX7A^-~j zY*GaP000008vp(|c000004rBlTA^-~j z94!U_00000R{#J200000l4Jk?A^-~jSPTaM00000*8l(j00000Vr2jTA^-~jnZX7C z00000IRF3v00000>tz4{A^-~jrV0lD000004gdfE00000K4t&_A^-~jUJ(ZX00000 zCIA2c00000(`EnwA^-~jFzy8a00000Edc-k00000HfI0;A^-~jtcwKz00000$N>NV z00000o@W36A^-~jnnDHu000004gdfE000006=(neA^-~jz9t6%000003jhEB00000 zeP{pxA^-~jz8wbu00000IRF3v0000018D#NA^-~jT;~M<000008UO$Q00000RA~SJ zA^-~jFx&k00000(6A^-~jDs2S-00000AOHXW00000Z(0BVApjHrXv`=8 z000007ytkO00000vu*$YA^-~j_Cy8%000008UO$Q00000FmC_=A^-~jP)7v-00000 z9{>OV00000k8c0~A^-~jatH00000761SM00000 zd~g5&A^-~jYLo>400000B>(^b00000n{WUCA^-~jEI00000L2>{9A^-~j)GG!600000E&u=k00000@NxhEA^-~j5~BtH z00000)c^nh00000-*W%}A^-~j1QG`T00000J^%m!00000Q*;0TA^-~jY|aJ%00000 zPyhe`00000sB{1TA^-~jWHto=000009smFU00000$8-PyA^-~j9sUIX000004*&oF z000004RrtjA^-~j#EJy~000004gdfE00000LUjNDA^-~j0W}8z000004gdfE00000 z(scj;A^-~jGFb%x00000CIA2c00000@^t_JA^-~jJY)s{00000Jpcdz00000S9SmZ zA^-~jUY`a400000O8@`>00000?sfnGA^-~j%GU+}00000tpET300000Mt1-JA^-~j zs4@ot00000aR2}S00000ly?9C5&!@I00000000000000000000sdoSXA^-~j@V^EC z000003jhEB000005_kXrA^-~jjVK2I000008UO$Q00000yLbQqA^-~jJn9Aj00000 zOaK4?00000*LVN`A^-~jP}v3m000008vpwmA^-~jDmMiH z00000HUIzs000009(@1+A^-~jdNc+A00000R{#J200000%Y6UOV00000t%3jmA^-~j(Jco600000 zNdN!<000006oUW&A^-~j7Bd9^00000EC2ui00000FM|L8A^-~jk*o#)00000F#rGn z00000z=Hq)A^-~jVpatJ00000m;e9(000008H4};A^-~j;JgI@00000NB{r;00000 zLWBSSA^-~jspSR$000004gdfE00000*@OT9A^-~jdNl?B00000E&u=k00000bcFx_ zA^-~jhA0LA00000HUIzs00000+=T!DA^-~j_dx{!00000JOKaz000003x)syA^-~j zh&%@X00000A^-pY00000D24z4A^-~j3Q`3C000008vprA^-~jHkbtf000003jhEB00000@rM8aA^-~j3kwGT000008UO$Q z00000z=!|<5&!@I000000000000000000000EqwqA^-~j+`t6@00000QUCw|00000 zaESl_A^-~jbT9<~00000B>(^b00000jEMjMA^-~jC=Uhz00000^8o+=000004T=B& zA^-~j$d&~F00000VF3UD00000uZjQwA^-~jd{G7f00000sRaN4000007mEM@A^-~j zTRa8;00000DgXcg00000ev1GAA^-~j4ypzK00000AOHXW000006pR1>ApjHrILash z00000H~;_u00000f{XwFA^-~j%;W|D00000GXMYp00000y^H_=A^-~jL^TEg00000 zH2?qr00000aE$-}A^-~jpeF|a00000DF6Tf000001C9UyA^-~j&e{b400000xc~qF z00000iH-mOA^-~j1pfs900000SO5S300000wvGS*A^-~jbQuN!000006951J00000 zB#!_9A^-~j_BRFq00000KL7v#00000#g700A^-~jtg8k9000008vpk00000Fp>ZOA^-~jqAmsi00000 zdjJ3c000008YOA^-~j#u^6z000003jhEB z00000{gVIyA^-~jB2EVY00000DgXcg00000R+In$A^-~jURVVH00000aR2}S00000 zqm%#uA^-~jcvl4g000009{>OV00000DwO~LApjHr=*lPn00000C;$Ke00000Pn7@w zA^-~jQk4b(0000090C9U00000(UkxIA^-~j;A;i|00000CIA2c00000@|6GpA^-~j zkRt{F000003jhEB00000W|jZ|A^-~jNT~(@000008UO$Q000001eX8+5C9hdAOI-< z0000000000000003zq-@A^-~jN}vV+00000Hvj+t00000u$KS;A^-~j`a1^z00000 z6aWAK00000{FeX#A^-~jGD8Od00000J^%m!00000DwqHO5&!@I000000000000000 z00000W|#l~A^-~js2T?V000005&!@I00000ikJWZA^-~j%76s`00000IRF3v00000 z&zJxJA^-~jK63>C00000ivR!s00000S(yL;5&!@I00000000000000000000dzkky@00000F#rGn z00000^_&0zA^-~jm{|n?000009RUCU00000CY=BPA^-~jP~rvv00000F#rGn00000 zfSmvUA^-~jED8qz00000AOHXW00000o}B;yA^-~jBsc{C000007ytkO00000z?}d9 zA^-~j>_i0s000009RL6T00000@SOkvA^-~ju&@RI00000TL1t600000NS*)yA^-~j zNxTLC000004gdfE00000WS#&3A^-~jIJ5=;00000I{*Lx00000?w$YuA^-~j2&o1D z00000KL7v#00000l%D_qA^-~jt|bQm00000O#lD@000007N7tCA^-~jKuiSy00000 z3jhEB00000G@t+gA^-~jpdAJP00000$N&HU00000u%G|{A^-~j*h>Wf000008vp000007oq?FA^-~j_CN;!00000XaE2J00000u%Z9}A^-~j z;u{A5000004gdfE00000%%T7QA^-~jQ&$E6000004*&oF00000`=S5>~yM00000 z3jhEB00000s-pk^A^-~jG(!ad00000Jpcdz00000)1v?YA^-~jNWlgG00000LjV8( z00000Jfr{s5&!@I00000000000000000000m81XwA^-~j7()gC00000NdN!<00000 z>ZAYwA^-~j>^}wo00000KL7v#00000S)~8~A^-~jR+I$*000006951J00000aHRkM zA^-~jEdB)m000004gdfE00000!leKJA^-~jmPrQy00000VgLXD00000AEp2RA^-~j zZMy~l00000HUIzs00000h^7DlA^-~jD$E7|00000B>(^b000009j5>QA^-~j88Zg} z00000300000 z4gdfE00000zNi2IA^-~jyh;ZE00000EdT%j00000000009RL6T00000 z2C4u6A^-~jxa9@_000004*&oF00000RjL30A^-~j63GSt00000oB;p;00000yQ%;H zA^-~jWC;fV000003jhEB00000LaP7(A^-~j7AXb*00000NB{r;00000iK_qrA^-~j zXe0&z00000CjbBd00000+p7QoA^-~jy$c5b000008UO$Q00000hpYeqA^-~jr8Nft z00000XaE2J00000A*}!aA^-~jSQZBW00000CIA2c00000b*%sZA^-~jq%{Qq00000 zEC2ui00000maPB)A^-~jx`PD(00000d;$Of00000_N@Q_A^-~j$|wc^00000A^-pY z000008Lj{TA^-~jDlr8B00000CjbBd00000Ij#TzA^-~j_E-e~000008UO$Q00000 zX|4bOA^-~jmYfCv00000YybcN00000`K|x}A^-~jdM5_}00000CIA2c00000r>_72 zA^-~jbSwq{00000CIA2c00000Pp|+0A^-~jHr)mQ000008UO$Q0000060raPA^-~j zgpvgS00000OaK4?00000Y_R|UA^-~j13d-+000009RL6T00000z_9=TA^-~jbU+3G z00000OaK4?000004zd6MA^-~jq~Qht00000LI3~&00000fU*DpA^-~j*f9kF00000 zjQ{`u00000q_O}2A^-~jc<%-P00000A^-pY00000IkNx&A^-~jn|uZU000004gdfE z00000ZnFRYA^-~j1|bIk00000F#rGn000000JH!AA^-~jHj@Sb0000090C9U00000 zg0uhtA^-~j5KILC00000F8}}l00000q_hA4A^-~j)U*Zw000008vpTLx800000Q2+n{00000YPA3WA^-~j7QqGp00000F#rGn00000&9wjkA^-~j(&q&L z00000NdN!<000000k!}DA^-~jrgsJa00000^#lL_00000m$m=^5&!@I0000000000 z0000000000t+oIFA^-~jz(58700000A^-pY00000-?jh%A^-~j%0dSK000005&!@I z00000iMId%A^-~jw|)fx000004gdfE00000*S7!wA^-~j4CMv@000003jhEB00000 zTetuKA^-~jSXl)C00000CIA2c00000f4BeuA^-~j22ce6000008vp(|c00000t-AmKA^-~j>MREU000009smFU z00000LA(F}A^-~ja6<+F00000bpZeX00000)Vu%yA^-~jM&pF00000 z^1J{5A^-~jB2WbY00000D*ylh000002fY9Q5&!@I000000000000000000008odAj zA^-~jepv+o000008UO$Q00000KfM3|A^-~jT8ae#00000OaK4?00000jJ*H=A^-~j z4D$v600000K>z>%00000FTMZ(A^-~je-{S;00000IRF3v00000ZN2~iA^-~jK%oWz z00000KL7v#000001HS+OA^-~jcIO2E00000DF6Tf00000P`>~GA^-~j0JsJK00000 zIRF3v00000ufG5QA^-~j9N7i{000008UO$Q00000X21XdA^-~j{xb&v00000O#lD@ z00000>A(O05&!@I0000000000000000000055WKcA^-~j(4qza000008UO$Q00000 zi@^W@A^-~j5Jd(6000008vp00000P5=M^00000$;1EvA^-~jQ#J+w00000 z9smFU00000X~h5lA^-~jpyveu00000CIA2c00000dc^<$A^-~j(hLRw00000H2?qr z00000sl@;QA^-~jif{!0000008vpcU000008vpTA^-~j&QApZ000008vp00000<^TWy00000G0^}3A^-~js5S-w00000E&u=k00000 zy3qgtA^-~j>?#KU00000CIA2c00000RMG$dA^-~jB2WbY00000D*ylh00000Y0>}y zA^-~jnyCf=00000a{vGU00000`qBUZA^-~jLI(x_000008UO$Q00000J<|XHA^-~j z9Ge9I00000CIA2c00000R?`3gA^-~jVr~Th00000WdHyG00000)zbg~5&!@I00000 z000000000000000^V0wTA^-~j{^kY%00000ng9R*00000BGdo?A^-~j(Xs{r00000 z5&!@I00000OVj`WA^-~j@ID6s00000F#rGn00000y3_ywA^-~jyh;ZE00000EdT%j z00000-_!sAA^-~jt||rq00000PXGV_00000Mb!WRA^-~j;+zEl00000VgLXD00000 zpw$2XA^-~jt_cSK00000RR91000000^VI+VA^-~jA^-~j$h!sr00000J^%m!00000joknMA^-~jF2Mx=00000 zs1*PJ00000A>IH0A^-pY00000000000000000000J>CESA^-~j+Ybi-00000OaK4? z00000zuo`^00000AOHXW00000Yvcd`A^-~jKJf+s00000+W-In00000 z@#FviA^-~j_$dbf00000CIA2c00000W#s?>A^-~j+>-?W00000dH?_b00000zvTb` zA^-~jiY^5J00000DF6Tf00000>E!?bA^-~jj{gM!00000VE_OC00000f93!HA^-~j z@V^EC000003jhEB00000=;i?j5R00000DgXcg00000$>{(9A^-~jpbZBA00000R{#J200000k?H^d zA^-~j(7go!00000H~;_u00000y6OM`A^-~jgb@b-00000DF6Tf00000H0uBWA^-~j za@Pg`000009{>OV00000h3fzSA^-~j0`3I>00000E&u=k00000`Rf1xA^-~jUc3bW z00000f&c&j00000AM5}CA^-~juJi=}00000E&u=k00000k?a5fA^-~jh*AXr00000 zL;wH)00000tn2^)A^-~jI$H$*00000IRF3v00000^XvcsA^-~jo^1vI000004gdfE z00000DD40MA^-~jh+qW(00000FaQ7m00000bL{{CA^-~jLLCMG00000AOHXW00000 zuI&H-A^-~jsBHxR000004gdfE00000?(F~oA^-~jS4jr|000004gdfE000003hn>^ zA^-~jutWy{00000RR91000000q3!?xA^-~js73|=00000umAu6000009`67EA^-~j zh7bn;00000F#rGn00000&hG#KA^-~jP)7v-000009{>OV00000E${#UA^-~j3`_?A z00000EdT%j00000Qt$u(A^-~jBEALy00000+5i9m00000r0@U$A^-~j4BZ6)00000 zL;wH)00000;_v_fA^-~j@G=De00000B>(^b00000`|tn&A^-~j7@h_I00000F#rGn z00000I`IGi5&!@I00000000000000000000g7E+VA^-~j-qi*G00000CIA2c00000 zobdnvA^-~jMh*u600000YybcN00000Me+au5&!@I00000000000000000000YVrU8 zA^-~j#gqjA00000QUCw|00000k@5flA^-~j1QG`T00000J^%m!000001@iy^A^-~j zLYM^r00000WdHyG00000Z1VsBA^-~jKDY${00000AOrva00000`ttw)A^-~jC?*B~ z00000nE?O*00000T=W0{A^-~jywU~$00000ng9R*00000%k%&MA^-~jWCI2O00000 z5&!@I00000GW7reA^-~jTnz^R000009{>OV00000$MpaJA^-~jdWi)9000004gdfE z000002=)K~A^-~jz_SJb000009{>OV00000iS_^hA^-~jmW&1f000004gdfE00000 zwDtf1A^-~jzy$^X000008UO$Q000004)*{6A^-~j@c#t>00000L;wH)00000fA;_Y zA^-~jlQ;(e00000DF6Tf00000F8BZdA^-~jEJX$Y00000YXATM00000lK21sA^-~j z#*hU7000008UO$Q00000==cBtA^-~jq@D%<00000AOHXW00000CiwsWA^-~ja7P6I z000008vp;A^-~jxGV+$00000 zH2?qr00000QThM?5&!@I00000000000000000000r1}5=A^-~jpyveu00000CIA2c z00000wfX=6A^-~j^1TKC00000FaQ7m00000;Q9anA^-~j1Q-VZ00000T>=0A00000 zI{N?sA^-~j@K*%@00000D*ylh00000nEL<#A^-~j{^bP#000005&!@I00000|N8&{ zApjHr5X&e400000C;$Ke00000BK!aVA^-~jI)DWL000003jhEB00000W&8jDA^-~j z!#W2500000tpET300000AN>FTA^-~jT{r~*000004gdfE00000Q~dw{A^-~jYNrMO z00000HUIzs000000sa60A^-~js^$g&00000IsgCw00000A^rdWA^-~j4Alkz00000 z8vpVXA^-~jh|vZB z00000ng9R*00000;sOBxA^-~jRL}+h00000ng9R*00000Qv(42A^-~jwAcm!00000 zP5=M^000004FmxIA^-~jWJ?DC00000EdT%j00000F$4hs5&!@I000000000000000 z00000Tm%6CA^-~joU;Z100000BLDyZ00000#smQXA^-~jO;7~@00000paB2?00000 z4Fv%JApjHru*)a_00000H~;_u00000MFjx>A^-~jX5Iz>00000P5=M^00000+64gs zA^-~jdM*Y4000003IG5A00000Zw3JX5&!@I00000000000000000000u?7JEA^-~j zf}jQf000008vpOV z00000{Rja75&!@I00000000000000000000BMAWjA^-~j$Swx}000004gdfE00000 zcL@OiA^-~jpi2b+000008vppF00000t`7kKA^-~j z)MN$#00000C;$Ke000006c7ObA^-~jY>@>3000007XbhO00000eh>iwA^-~j>MaET z000009RL6T00000k`Ms^A^-~j{9FY900000CIA2c00000u@C_OA^-~jPMrn-00000 zCIA2c000001rY%NA^-~j;E)9X000009RL6T00000TM+>OA^-~j0E`9z00000X#fBK z00000cM$;qA^-~jVn7A}000005&!@I00000#t{JkA^-~jm{$b=000008vppF00000%oqUxA^-~j47LUU00000J^%m!00000`WOKKA^-~j zHkbtf000003jhEB00000J{bW3A^-~jDyIej00000KL7v#00000@EHLBA^-~jOf&`n z00000E&u=k00000q#6MLA^-~jl9~ko000005&!@I00000A{zk!A^-~jX)gr;00000 z5C8xG00000N*e(HA^-~jK1&Ax00000CIA2c00000a2o*tA^-~j-i8GL00000JOBUy z00000z8e7mA^-~j05%2y000008UO$Q00000RU82TA^-~ju&M?C000009RL6T00000 z;v4}0A^-~jV7&zZ00000H~;_u000005FG&kA^-~j^x*~o00000H~;_u00000gB<|? zA^-~j(KiPG000008UO$Q00000%N+p#A^-~j#_t9I000004*&oF00000LLLDCA^-~j zMh*u600000YybcN00000>mC6BA^-~j7Tg8^000008UO$Q00000#~%RzA^-~j5^n_n z00000Pyhe`00000=^p_AA^-~j+S&#H000008UO$Q00000lpp~BA^-~jT?z*P00000 zNdN!<00000w;%xkA^-~jh+hQ&00000AOHXW00000^dJEMA^-~j@Y4nW00000ng9R* z00000V<7w?b00000 z10n$cA^-~jdNc+A00000R{#J200000up$8fA^-~j_F4r1000008vpY@e!00000CjbBd00000C?x>^A^-~jBGLu`00000 zng9R*00000mn8uJA^-~j)FTG~00000H2?qr00000FD3y1A^-~jjQ0fq00000LjV8( z00000&n5u?A^-~jzK#X}000004gdfE00000MkfIPApjHr$jm4J000007ytkO00000 zekTC{rT`HD00000000001ONa400000k0${DA^-~jf?EXu00000ng9R*00000#U}v( zA^-~jjo$_U000008UO$Q00000eJB9{A^-~j$>s$B00000PXGV_00000`zQebA^-~j zC`APT00000CIA2c00000D=7g0A^-~jepdzn000008vpWA^-~jN(}}8 z000008vpFZ#000008UO$Q000008Y%$*ApjHrV9O`~00000 zC;$Ke00000J}LnKA^-~j4m<|{00000R{#J200000XDR^z5&!@I000000000000000 z00000u_^%oA^-~jLI(x_000008UO$Q00000^eO=WA^-~jg5m}M00000OaK4?00000 zS}OqnA^-~j99RVa00000Gynhq00000q$>dcA^-~jY>Nc|00000KmY&$0000004xCj zA^-~jMx+J+00000PXGV_00000sVo5iA^-~j6}2A00000ZZH7=A^-~j9GL|G000003IPBB z00000^)LYdA^-~jcCrQl00000NB{r;00000buj?|A^-~j(B}pK00000HUIzs00000 zm@xqWA^-~j5CaAP000004gdfE000002r>ZxA^-~jD0Kw@000009{>OV00000bTR<| zA^-~jrauM%00000D*ylh00000xiSF&A^-~j&@}}B00000FaQ7m00000>M{WUA^-~j zuyO_f00000^#lL_00000fHMIAA^-~jtdIo&000008UO$Q00000)-wSBA^-~jQh)^j z00000WdHyG00000Iy3bV*A^-~j>_i0s000009RL6T00000KQ#dWA^-~jz}W==000008vp7IdA^-~jjoJkO00000E&u=k00000&@}-75&!@I00000000000000000000 z=QRNUA^-~jqB8{m000009smFU0000005$;tA^-~jP_qUA00000D*ylh00000E;a!G zA^-~jUK|Dh00000Qvd(}00000Of~@kA^-~jgf0dE000009smFU00000z%~H@A^-~j zSbhZn000009RL6T00000?KS}bA^-~jxz>% z00000*EsWf000008vpeA^-~js5S-w z00000E&u=k00000#6bZ7A^-~j%AN%P000008vp-pB00000 zK>z>%00000mqGymA^-~j);0zJ00000R{#J2000008AAa8A^-~j7H|as00000R{#J2 z00000eM12NA^-~j(!d4)00000LjV8(00000(^b00000 z4nzR}A^-~j0^bGz00000R{#J200000xI_T}A^-~j$Rh>-00000BLDyZ00000Iz<5h zA^-~jGExNq00000IRF3v00000oJ9cuA^-~jq_GA700000QUCw|000008b$#CA^-~j zk}C%Q00000CIA2c00000ZbktBA^-~j=Hmtc00000CjbBd00000!$tuBA^-~jNG}Hf z00000>;M1&00000>_!0q5&!@I000000000000000000002uA?`A^-~j3l|3f00000 zJOBUy00000Q%3;+A^-~j#+wBI000003jhEB00000o<{)yA^-~j5K9LD00000EdT%j z00000#76-DA^-~j+HM5^000008vpOV00000u1^5~A^-~j-roiQ00000 za{vGU00000Gf)8l5&!@I00000000000000000000a8LmNA^-~jHaG?V000008UO$Q z000002~hz6A^-~jh=~ON00000(f|Me00000T2TQ2A^-~jij4&T00000Gynhq00000 ze^CJdA^-~j?l%Ph00000HUIzs00000nNa}%A^-~jFG&Re00000b^rhX00000x={fD z5dZ)H00000000000000000000>`?&#A^-~ju!sc!000008vpi9000004gdfE00000_f-J^5&!@I000000000000000000007*+uQ zp#T^FU;!xr00000FaQ7m00000L{&4^A^-~jZkGlC0000090C9U00000bz1=d zA^-~jTu21~00000DF6Tf00000$y)&cA^-~jNE`(|c00000Y+nHYA^-~jb20}200000H2?qr00000 zonHX}A^-~j)I0|O00000NB{r;00000;$Hy(A^-~jyeI|$000004gdfE000008(;wd zA^-~jRj>vC00000TL1t600000bYKAhA^-~jyeS3%00000C;$Ke00000r(gj9A^-~j zif{!0000008vp000004*&oF00000uVeuLA^-~j=sE@f00000>;M1&000007i9qe zA^-~j{zwM^00000IRF3v00000zGVRbA^-~jENlh<000008UO$Q00000A^-~j znK}mm000008UO$Q00000gJuB$Api{k0J;YN00000AOHXW00000r)B{FA^-~j78C{m z00000Zvg-R00000AZGypApjHraLOnE00000C;$Ke00000O=kfBA^-~j5LpEP00000 zA^-pY00000erEvyA^-~jn&}1r00000cmMzZ00000n`Z$4A^-~j%u)pa00000g#Z8m z00000(q{nxA^-~jSVsl`00000BMJZj00000I%oj^A^-~jem4gI000009RL6T00000 z$Y=ooA^-~jHu(ks00000IRF3v00000O=$rDA^-~jv{wZH00000I{*Lx00000s%ZfL zA^-~j=AH!r00000OaK4?00000%4q=rA^-~j!`}t~000008UO$Q00000Icfm_5&!@I z00000000000000000000O=K000004gdfE00000I%@#{A^-~jatH}mx7000004gdfE00000 zu51ASA^-~joJa)#00000761SM00000;%or`A^-~j7H|as00000R{#J200000Mr{EA zA^-~jntlZU000009RL6T00000lWhS2A^-~jU?m3t00000O#lD@000006>b3lA^-~j z1_TBG000004gdfE00000Yi-*00000RR910 z00000PjLYNp#Tj4bh-xs000000RR9100000jd1}0A^-~j#3cp*000005&!@I00000 z;Bf%}A^-~jmzD(p00000F#rGn000008gc;uA^-~js5J%v00000R{#J200000u5tkY zA^-~jujB>*000008~^|S000005pw|mA^-~j8Vd#h000008vpyRA^-~j5atB{00000xc~qF00000 znsxyIA^-~j;9ms*000008UO$Q00000&UOI+A^-~j!UF~X00000L;wH)00000CwBn= zA^-~ja_9yC00000&;S4c00000Yj*(vA^-~jk=X?R00000E&u=k0000033vejA^-~j zEKgt000008Ug?S00000=6eAEA^-~jxDW>b00000R{#J200000 zgnR)25&!@I00000000000000000000qkI7XA^-~j?ji;N00000DgXcg000009(@4- zA^-~jnxF*$00000L;wH)00000cYOf>A^-~j#z6-F00000XaE2J000008GZo(A^-~j zOvVNP000009smFU00000M}7eSA^-~j!wLof00000RsaA100000wSEBrA^-~jW-00000L;wH)00000(t-g1A^-~jYHA^-~joSp>$00000E&u=k00000f`b77A^-~j$mIqA00000 zCIA2c00000`-1@hA^-~jP&ftv000008UO$Q00000m4pERA^-~jDgp)o00000<^TWy z00000HH85HA^-~j(&YsJ000009RL6T00000cZC4}A^-~jLNf&b00000U;qFB00000 zk%a*OA^-~j@K*%@00000D*ylh00000?}Y&XA^-~jN<{|%000005dZ)H000008-@V@ zA^-~jOkV{600000JOBUy00000Xodj*A^-~jij4&T00000Gynhq00000jfMdLA^-~j zsh(^b00000iHZRLA^-~j_%j9o00000IRF3v00000IEw)Q zA^-~jC=dq#00000UH||900000ql*CmA^-~j5+w%!00000O#lD@00000C5!<8A^-~j zW;_P~00000A^-pY00000MvMUfA^-~jiaG@V00000bN~PV00000VvGR*A^-~jxIza2 z000005&!@I000004UGW+A^-~jC=dq#00000UH||900000c#Q!7A^-~j5XJ@o00000 zCIA2c00000@{IuiA^-~jgf9gE00000VgLXD000000*(Oy5&!@I000000000000000 z00000KaK$aA^-~jLNW&c00000F#rGn00000YK{Q_A^-~jTn+{R00000Pyhe`00000 z(T)KCA^-~j=12tq00000AOHXW00000|Be9wA^-~jyv_yy00000Pyhe`00000RF44w zA^-~j2RsG<00000Q~&?~00000-j4wQA^-~jlB)&)000008UO$Q00000oR9$kA^-~j zxDW>b00000R{#J200000I*|bYA^-~j$g2hb00000A^-pY00000sgVHyA^-~jEz1S~ z00000YXATM00000Hj)7VA^-~jboK=R00000R{#J200000#gYL4A^-~j(&+^N00000 z8UO$Q0000050e1^A^-~jj7J3k00000ZU6uP00000IFkVYA^-~jk0}NK000008UO$Q z00000xRU_@A^-~jp6&(!00000LjV8(00000Sd;+(5&!@I00000000000000000000 za+Co8A^-~jJY)s{00000Jpcdz00000*OUPOA^-~jDG>(%000008UO$Q00000hm`>U zA^-~jqMZf+000008UO$Q00000wv_<@A^-~j)(!^%00000UjP6A00000O_l)wA^-~j z9x4X_000004*&oF00000ewG0MA^-~jN-zZg00000DgXcg00000nw9|oA^-~j^0@{8 z00000HUIzs00000yp{m~5&!@I00000000000000000000)|LSPA^-~j@+k%Y00000 z4*&oF00000|CRv&A^-~jRw)Mn000009smFU00000yq5t0A^-~j?Xm^{00000VgLXD z00000{+9s&A^-~jI$H$*00000IRF3v00000MVJ8qA^-~jHpT`300000761SM00000 z!I%L6A^-~j(DwxZ0000083h0U00000RG9$)A^-~jASed_00000CIA2c00000;h6yd zA^-~jR3Zle00000)c^nh00000(V77OA^-~jvo{3*000005&!@I00000>Y4!nA^-~j zd_4sK00000O#lD@000006Pp15A^-~j5e^3c000008UO$Q00000?VAArA^-~jsF(!+ z000005&!@I00000KAZsnA^-~jSV9K?00000U;qFB000003Y`G}A^-~j13v`-00000 zJOKaz00000J)HpnA^-~jIJ5=;00000I{*Lx00000$DIKHA^-~jSycr900000M*si- z00000{ha{-A^-~jnh6I0000006aWAK00000NS*-zA^-~j+}Q;H000008vpMaET z000009RL6T00000@1FqxA^-~jUgZS<00000a{vGU00000004mhe=nc`01^NI00000 z00000000000000007jqz03rYj0Af1@0000002u-R000000EeIf03rYj0N2X~00000 z06YKy000000284B03rYj0BhL>0000001f~E0000007{_&03rYj0KSa{0000005kvq z000000CJ%L03rYj0H&J;0000002=@R0000002iVG03rYj0Mz~l000000C@rc00000 z0JEY203rYj0OIZj0000005bpp00000041XV03rYj0Ag03rYj0QUX`0000001f~E000000BxiJ03rYj08rTl z0000002=@R000000OF(p03rYj0O|$@000000C@rc000000Dh$b03rYj0JNb700000 z0384T0000001c)A03rYj08R4-0000006_o%000000I;S303rYj00tWe000000C4~S z000000Q05+03rYj0Df5o0000002%-Q0000002rqM03rYj01VFt0000008jt`00000 z0BxrM03rYj03`1Q0000008{_~000000Qjc?03rYj018C~000000384T0000004S&d z03rYj09^kC0000005Jdn00000092>}03rYj0HA>e000000QCd_000000PCm$03rYj z07Oa!000000PFw&0000001v4F03rYj02E0D0000002=@R000000F|i$03rYj00|QZ z000000H^=}0000006(e$01^NI0000000000000000000008^>~01^NI0000000000 z00000000000CuVY03rYj0089%0000001E&B000000Q#x{03rYj0G=ZU0000005t#r z000000FtW#03rYj03tsJ00000044wc000000IjP503rYj03xUc000000384T00000 z0A;KJ03rYj05|Xj0000001*HH000000FkT#03rYj0OYL(0000003rYY000000P(B= z03rYj060kp0000001*HH0000001~YM03rYj0Ad{m0000001*HH0000008Xs|03rYj z0JuvB0000004)Fj000000C=qd03rYj0K^Ul0000001^NI0000001K`G03rYj0Q#r~ z0000001f~E000000JyFJ01^NI000000000000000000000O76y03rYj0Aig500000 z04@Lk0000000plB03rYj06Aa<0000001f~E00000064D!03rYj03ntI0000004e|g z000000FSQ$03rYj0HR$50000002ToN000000IshA03rYj0D`6l0000001^NI00000 z07kF@03rYj0QPPL0000002=@R000000BEoQ03rYj06x|R0000006YKy000000FAH# z03rYj0FWdG000000M!5h0000005`D#03rYj09-f+000000384T000000PC><03rYj z0Ep@a000000IvW50000004lNp03rYj0Fu}S0000002BZK000000Kc*U03rYj0JaDQ z000000HXi^0000008Fz103rYj08q0A0000004o3h000000D7|l03rYj0KO&%00000 z01E&B000000OGR&03rYj01o5^000000HFW?000000A{oS03iSr01(V50000002lxO z000000F$%<03rYj03zrH0000002=@R000000HCx103rYj0MsW20000004o3h00000 z0L-)j03rYj05Vwx00000044wc000000PM5@03rYj0C7VF0000006YNz0000002;Lc z03rYj0M;c20000007L))000000CKef01^NI000000000000000000000EM*y03rYj z0OTnK0000001f~E000000N1qv03rYj00P|x0000002%-Q000000GPG`03rYj0O+Fz z00000080P>00000035dg03rYj0Cb%O0000004@Lk000000C2Yf03rYj08%ss00000 z04V?f000000ExE&03rYj0JK*H0000006PEx000000Oq#=03rYj0L-oi0000003QGV z000000C>0o03rYj0Dcw+0000002%-Q000000L!=m03rYj0Ng?c0000001f~E00000 z0BgAc03rYj02bN?0000001^NI0000002I0b03rYj0Jd5M0000003rYY0000007be1 z03rYj0F+G!0000006zc#000000MWVu03rYj0B9=*0000004V?f000000AafU03rYj z0CM040000002%-Q000000K~fi03rYj0HU@90000005Jdn0000004}@%03rYj04@y% z0000002=@R000000EfH*03rYj085qy00000089V?000000HnMD03rYj0RB1!00000 z06hQz000000LHul03rYj0Av&g000000FnRz000000P4H}03rYj0P0T#0000002=@R z0000002{pl03rYj0LUQ*0000003!eZ000000FS)^03rYj00`^`0000003!eZ00000 z00zDR03rYj0B}PG0000002%-Q00000042Tw03rYj0Ko4B0000003rYY000000G_@9 z03rYj04j+E0000005Jdn0000001dwZ03rYj0B70-00000044wc0000007Ab303rYj z00z7U0000007C!(000000CB$o01^NI000000000000000000000GGc303rYj0Q^D* z0000002=@R000000Ik0P03rYj0Ea*a000000B-;Q0000008GFE03rYj0O(Z(00000 z04e|g000000ENH-03rYj0J@t60000001E&B000000MNhz03rYj0JyXU0000002=@R z0000003g8u03rYj0H-?#0000001f~E000000K35f03rYj0A)!B0000005Jdn00000 z0Or8~03rYj0F+z?000000D%Ai000000CU0t03rYj07Rb#0000002%-Q000000NcU= z03rYj01_()0000003HAU000000Dr>)03rYj0NywS000000CoTX000000HnhK03rYj z0Ggl$0000007L))000000R6)O03rYj0Fsae0000002%-Q0000008_*P03rYj06^*m z000000DJ-f000000I|dY03rYj0Me!g0000004o3h0000003pQz03rYj0F?a&00000 z07L))000000L#Sz03rYj00vM60000002=@R000000Q|)P03rYj0DxNt0000002=@R z00000013tc03rYj0FVd<00000044wc0000007S+C03rYj0A5%H000000C4~S00000 z0FlN403rYj0Ek5g0000003rYY0000003*i%03rYj01L4O000000B-;Q0000007u6G z03rYj0J_Tt000000384T000000Jz5i01^NI000000000000000000000QJWK01^NI z00000000000000000000029ao03rYj07`8I0000001f~E0000007}RK03rYj0G2TY z00000073u&000000CdO!03rYj0HR$50000002ToN000000F%f803rYj05YKl00000 z01f~E0000005iz}03rYj0N}X>0000001*HH0000009VNY03rYj00tli0000007w7; z000000LRGz03rYj0J0ng0000008{_~000000OQF403rYj0K+#20000001f~E00000 z01(On03rYj0I-M!0000002=@R0000003ON#03rYj0IV$r0000005t#r000000I13V z03rYj0Qz4A0000003rYY000000N~0203rYj0JPi&0000008Rh^000000EWu}03rYj z0Cs)_0000003!eZ000000G`VM03rYj0M<7J0000002crN000000JzHm03rYj0OaNd z0000002%-Q0000004~e{03iSk0Fbx`0000002lxO0000007}dO03rYj0GL+=00000 z02=@R000000CCI#03rYj0A48u0000005Jdn000000KUut03rYj09p$N0000001E&B z0000007cCK03rYj0P>**0000001^NI000000NKp}03rYj0NSVq0000003ZMW00000 z0Eo^303rYj0H!tv00000044wc000000PxNM03rYj06w<{0000001f~E0000003y!; z03rYj0Msi60000004@Lk000000MX9@03rYj0FJ;00000007L))00000065SA03rYj z0Ce^R0000009OD2000000LRb)03rYj0JwAo000000AT@01^NI000000000000000000000Fc!I03rYj0Mx|> z0000006YKy0000003Ox>03rYj0GPc60000005|{u0000007ljU03rYj00wLZ00000 z044wc000000BhC(03rYj0B&#v0000002=@R000000H4+Y03rYj0C_J30000001E&B z000000K3)!03rYj0ATk8000000384T0000006W(K03rYj04gsB000000384T00000 z0D0E|03rYj0LpU(000000I2`~0000004~@803rYj01}`E0000002%-Q000000O8mH z03rYj0LEek000000IvZ6000000591A03rYj05YEi0000001f~E000000Akqz01^NI z000000000000000000000D;*703rYj0OuzM0000002%-Q000000882d03rYj0CtWA z0000004M03rYj0H%rs0000003HAU00000 z0Gi000000672v000000BYj_03rYj0AL{p z0000004o3h000000OsQX03rYj00{I3000000C@rc000000F>kb03rYj0GjUx00000 z0384T0000002bu|03rYj0KAtF0000005kvq000000P*Jm03rYj0Py7n z0000001f~E0000005j+T03rYj0AM!-00000051Rl0000007>Wp03rYj06P8!00000 z0G0p%000000JZ1=03rYj0FvYd0000007C!(0000002S#003rYj03HJd0000007d`+ z000000B`9501^NI000000000000000000000FUVb03rYj0Bnl|0000006+i$00000 z0PE=i03rYj0HWgt0000003QGV0000006ppf03rYj05*mN0000008;<}000000A1<< z03rYj0A}I^000000672v000000LJP803rYj07mu&0000004@Lk0000009@+<03iSr z08q>*0000002lxO000000D5A0000002%-Q00000021s003rYj0OsKa z0000001f~E000000CMaB03rYj09Nn?0000006YKy000000GI3m03rYj0ImrK00000 z09610000000P5@k03rYj0O;NZ0000002%-Q000000G#as03rYj0KnM=0000002=@R z000000Ql_z03rYj05B;B00000044wc000000ITi+03rYj01Y+=000000BisN00000 z0DtcR03rYj0E%)2000000JH!A000000NU>X01^NT07|?B000000F?y*0000000Hm; z03rYj09aWC00000044wc00000044AN03rYj0QcDi00000044wc000000IKi-03rYj z0B&3c00000044wc0000000;2_03rYj07lRT0000001f~E000000D$oU03rYj0Kx+X z0000007L))000000NL>Y03rYj0M_pY0000002TlM0000007>!z03rYj0Jhf#00000 z02BZK000000Cw^L03rYj0Q@Bf000000CNBU000000QvF(03rYj0E*NG0000002=@R z000000BQ3903rYj0M6b90000002%-Q000000Q&O*03rYj0J`D@0000001^NI00000 z0ABO~03rYj0M;c20000007L))000000Jii203rYj0De~n0000002=@R000000M_&Y z03rYj07p6p0000002%-Q000000E6`b03rYj0PKea00000089V?000000O$1q03rYj z0EgQJ0000008an_0000007~`&01^NI0000000000000000000009f_`03rYj0Kysu z0000006qW!000000MzyY03rYj003VF00000089V?000000P*$#01^NI0000000000 z000000000001Wp503rYj00Aln000000IdK3000000EYJg03rYj0HCJ^0000001f~E z0000008ID+01^NI000000000000000000000Im1|03rYj00d13000000FM9w00000 z04VtZ03rYj02E0D0000002=@R000000IvA~03rYj0K|O-00000089V?000000QdO; z03rYj0O~>q0000001f~E000000Eqel03rYj0E#*V000000CWHV000000Hpc>03rYj z0C-mg0000003QGV0000004w_e03rYj0H7xa0000004V?f000000KWSH03rYj0Fv+p z0000001f~E00000008^}03rYj0OBnM00000089V?000000Gs>)03rYj07fVW00000 z04V?f000000LJ_Q03rYj0Pd;=0000002BZK0000007Cr%03rYj0Ggo&0000002%-Q z000000MY#c03rYj0Q{Q<0000007L))0000004e?f03rYj0L6X<0000001f~E00000 z0BimM03rYj0KT#Y00000022TJ000000D=Ai03rYj0MkAP000000384T0000002KcL z03rYj0RFWG0000001f~E000000FwU!03rYj000{X0000001^NI0000000RI503rYj z03;&@0000001E&B000000FVFz03iSr0N~6h0000001yBG000000K)(R03rYj07&o! z0000001f~E000000Qmp{03rYj0DeaY000000HFW?000000K5SL03iSk0Fb!{00000 z03QGV000000N()u03rYj0Bp_%0000008jt`0000005k#u03rYj0CngE0000005Jdn z000000F?p)01^NT09>jB000000A~OI000000JZ`G03rYj03Ox`0000001*HH00000 z0OA4y03iSr04U5T0000001yBG0000001*QM01*HH00000000000000000000051aq z03rYj0C+hD0000007C!(000000L}vf03rYj0328a0000005kvq0000002l-U03rYj z08Ft000000JI1K03rYj09@k+ z0000002%-Q000000PP3@03rYj0G8nf0000001f~E000000A~pT03rYj0N&LG00000 z044wc000000D%bt03rYj0FoOA0000001f~E000000JaGN03rYj05(Pk0000009610 z000000A~sU03rYj0Pf`m0000003HAU000000Nn}#03rYj0ANf90000006hQz00000 z08R@603rYj0Pt)D000000672v000000GJB`03rYj0NnHi0000004)Ik000000Qn07 z03rYj0MeTU0000008Ib@000000A~yW03rYj030F)0000004o3h000000ND%z03rYj z06anm0000001f~E000000Bj8c03rYj09ro=00000089V?000000MZQt03rYj0Pq_J z0000009XJ3000000R9aE03rYj01V~^000000672v000000A~&Y03rYj0J1Cx00000 z03HAU000000QwFB03rYj00J)s0000006PEx0000002~hj03rYj0P;2k0000002=@R z000000A>#Y03rYj0OUOe000000FeLy000000ILrI03rYj0LJG90000001E&B00000 z0MHKt03rYj03uxl0000003`qb0000003Z+o01^NI0000000000000000000006-7| z01^NI000000000000000000000DBMu03rYj0C=tj00000044wc000000M`%#03rYj z0A>va000000NMZm000000Qe9B03rYj036*00000002%-Q000000Gkm403rYj01Ea6 z0000001^NI0000004x#$03rYj0LEek000000IvZ6000000D2Mv03rYj0B}1800000 z0384T0000000t8R03rYj05qfq0000001^NI000000G|^A03rYj0BY?9000000PFw& z0000000P0000002=@R000000Ky&u03rYj z0HtsR000000BryO0000004pB?03rYj0BD{D0000006YKy000000C^t*03rYj0RICA z000000672v000000RJBX03rYj0IEd?0000009XJ3000000B|4z03rYj0IZ7z00000 z0LTFV000000N5Y`03rYj0Mfw*00000089V?0000005c&103rYj0P0T#0000002=@R z000000AwKo03rYj04g^J000000384T00000023kt03rYj0089%0000001E&B00000 z0GA>H03rYj00Jxq0000009OD20000006!xF03iSk0D!s&00000051Rl000000CFP& z03rYj0IEC(0000004e|g000000H7lR03rYj0M<4J0000009OD20000003sv;03rYj z0FE670000001^NI000000FfjD03rYj0Hp8+00000044wc0000006rxG03rYj0J@+C z0000009XJ3000000OKVB03rYj0M(TR00000089V?0000006!)I03rYj02m_%00000 z01E&B000000L&%=03rYj000jL0000004D$d000000PH3L03rYj01iP00000005$*s z000000B9!y03rYj05(Vk00000044wc000000Inwj03rYj021m30000004e|g00000 z0Nf`603rYj0Lt000000J13p03rYj09?-o0000008jt`0000000$}p03rYj03=%m z0000005t#r000000Dme103rYj05%H-000000Gj~-000000N*MC01^NI0000000000 z00000000000QD*Y03rYj0Jb{^0000001E&B0000009`8r03rYj0CX(|0000002%-Q z000000OTtI03rYj03N~y000000DJ-f000000E8?803rYj02t>50000004V?f00000 z0G=!Y03iSr007J=0000001yBG000000J000000672v000000PigV03rYj z0A8F10000001f~E00000081_c03rYj0OIcj000000384T000000K6^&03rYj04UW4 z0000008jt`0000003t5}03rYj0EF)a0000002%-Q000000F^HS03rYj0OvOb00000 z01f~E0000006j1Q03rYj08K{+0000005Jdn000000Ie_r03rYj0QOo10000002=@R z000000NF4C03rYj0GfUU000000384T00000046a403rYj0H{I+00000044wc00000 z0FyBS03rYj016}r000000CWHV0000004Fj603rYj0JPi&0000008Rh^000000L?N2 z03rYj0Fa#p0000001E*C0000009P{t03rYj0Hrbo00000080P>000000C_V403rYj z0E{dL00000044wc0000000cAw03rYj0Ioy@0000006hQz0000004y{D03rYj0PwU1 z000000Pg?*000000IM_t03rYj0N7dv00000051Rl000000LC-|03rYj0Ay4J00000 z04o3h000000NgYJ03rYj0M^?D0000002%-Q0000003J0003rYj06;(m0000006hQz z00000082Fj03rYj01!+C00000051Rl000000Btn_03rYj0F0000001p5F000000Fg-o03rYj03{0t0000002%-Q00000 z0A@-803rYj00%?|000000H^=}0000000Bz^03rYj06vig0000004@Lk000000DVgW z03rYj09I}V0000001E&B000000NG0d03rYj0Bj=$0000003!eZ000000CY?O03rYj z03?wG0000002%-Q000000O?Eu03rYj0D$2I000000OkMy000000B%hJ03rYj0ODf? z0000009gP4000000K82C03rYj0M6nD000000F3|u0000005?to01^NI0000000000 z00000000000835+03rYj0341500000044wc000000A)@B03rYj0O27A00000089V? z000000QF7+03rYj05RbO0000008an_0000009a1~03rYj0GP`L0000003rYY00000 z0L@PV03rYj0QM9I000000CE5T0000001i+B03rYj0GQ_n0000003`qb0000004q=e z03rYj0A@4?0000001f~E000000H#m^03rYj030m_0000009OD20000004h-e03rYj z0CF}40000005t#r000000K`!O03rYj0Q#T>000000H_rJ000000AW%B03rYj0NQQ^ z0000002=@R000000FhDx03rYj0L+L5000000A2t9000000Ju^D03rYj0F4g^00000 z02%-Q000000CQ6U03rYj03HJd0000007d`+000000L@bZ03rYj0P1Z80000008sz{ z000000OnHy03rYj02(F+0000001f~E0000006SCy03rYj05*OF0000003rYY00000 z0C7|T03rYj0GuNR0000001E&B000000OeEy03rYj0B&#v0000002=@R0000002x&R z03rYj0QpZ0000009OD2000000JmKN z03rYj06bR(0000006YKy000000Q6k~03rYj06#|u0000001f~E00000099TB03rYj z04nzd0000005t#r000000P0=>03rYj07B^o0000009XJ30000001ICN03rYj0KcXN z0000001^NI000000JUEN03rYj08-!v0000003QGV0000004rbu03rYj0MQx;00000 z05t#r0000009IfE03rYj0Mg|J000000384T000000GMC`03rYj06?e)00000044wc z0000001aUR03rYj01!(D0000004)Fj0000005f3%01^NI00000000000000000000 z08L>603rYj0A@D^0000005t#r000000M%gv03rYj07ifX0000001E&B0000002pEd z03rYj07`BJ0000001E&B000000CZvk03rYj0L+dC0000005Jdn000000N7#z03rYj z04S{n0000001f~E00000061d;03rYj0Dd03rYj z078xh0000005kvq000000KI1d03rYj0CXt_0000002%-Q000000E}n?03rYj0PwU1 z000000Pg?*0000001IgX03iSk0Km8h0000004V?f00000061v^03rYj08H8i00000 z02=@R0000007hv703rYj0KVr20000001*HH000000BdOi03rYj0CYbG0000006YKy z000000Fh||03rYj00P+t0000002%-Q000000A^|e03rYj03av_00000044wc00000 z0P|`B03rYj0Jtj$0000007(D<000000BdUk03rYj0EPhv000000C@rc0000000(RW z03rYj0J=5>0000002=@R000000D)`*03rYj0F65b0000002%-Q0000001<5h03rYj z06QcG0000002%-Q000000CsHx03rYj0QU_C0000002%-Q0000007`BG03rYj0DzhW z0000001^NI000000Lg9w01^NT01m7K000000FDI!0000002^-t03rYj09Nh>00000 z07w7;000000C;Z#01yBe03ZM<0000000000000000EBM>03rYj0QgA<000000CNBU z0000004Q(*03rYj05B^D0000002%-Q000000N!u{03rYj0K6~<0000005bpp00000 z010sd03rYj01{RO0000001f~E000000CaHz03rYj0QyG-0000006YKy000000NHT@ z03rYj0L=CU0000002%-Q000000Bdpr03rYj00Nx`00000089V?000000Jd@h03rYj z01|Np0000009OD20000006}vC03rYj0LthE000000J#7F000000L^m(03rYj0E*NG z0000002=@R0000006la903rYj097{!0000002%-Q000000Pu7I03rYj0AM!-00000 z051Rl0000000wme03rYj08~~50000001f~E0000006cX903rYj08kqS000000C)fZ z0000009thd03rYj0F>JX0000008Rh^0000002y`y03rYj0CSuL0000006YKy00000 z0H$^V03rYj0D4aa0000005<>t0000000?&i03rYj0BWBF0000005Aan000000JV1l z03rYj0JA*?0000005Jdn000000O5B601^NI000000000000000000000Qz?V03rYj z0Q|lN0000004@Lk0000002g=y03rYj0Pr#e0000003`qb0000005Et003rYj0A3LX z00000044wc000000L6F$03rYj0M;%C0000001p5F000000QGnR01^NI0000000000 z000000000006KXB03rYj05&-W0000005AXm000000Hk>W03rYj04Ti$0000005|{u z000000M2;=03rYj0BlkP0000002=@R000000O@%G03rYj0Omvn0000001p5F00000 z0Izxi03rYj0RE5#00000044wc0000001JBp03rYj0Gx3J000000CE5T000000Kj_! z03rYj0ML>J0000004V?f000000E~PB01^NI000000000000000000000I_@m03rYj z0MJ+k0000003`qb000000OfoF03rYj0Av&g000000FnRz000000115p03rYj05UWN z0000002%-Q000000FQkF03rYj07RVy000000384T0000002h7&03rYj0Hieq00000 z04x9i00000062aE03rYj0J>iV0000003`qb000000C0W+03rYj0HnJH0000003!eZ z000000HA&X03rYj0FY}20000008jt`000000QY_Z03rYj0Dkuc0000001f~E00000 z0C#@^03iSr0Eo*d0000004M+e000000GNLQ03rYj0H&J;0000002=@R0000006l;L z01^NT0N}v{0000008#@0000000Dpi203rYj0BVc|000000384T000000KR|%03rYj z06vff0000004V?f0000003?9|03rYj0L!K000000672v000000JVYw03rYj06GW;00000 z05|{u000000Of)L03rYj0BVc|000000384T0000003?F~03rYj0I~`O0000001*HH z000000HK2d03rYj0Q}ho0000002%-Q0000009Awn03rYj0OKYH0000002%-Q00000 z0GEUU03rYj0LB^z0000001E&B000000K0?&03rYj05Vbq000000672v0000003C$_ z03rYj0K%*W0000001f~E000000DXl503rYj0Mxbx0000001p5F000000GNdW03rYj z058@C0000001f~E000000M3O103rYj08JeS000000C4~S0000000@Qx01^NI00000 z00000000000000003U_|03rYj0MmX20000001f~E000000A7Xy03rYj0D30}00000 z044wc0000001Sr$03rYj0J!f40000001f~E000000FH+O03rYj05L}g0000001f~E z000000Plwa03rYj06rWB0000003QGV0000001t=)03rYj0E(Fg0000002~4U00000 z0Fj6S03rYj06eM&0000006zc#00000040e603rYj02pEh000000DAxc000000E&qM z03rYj04kUT0000001E&B000000M3a503rYj001@x000000Av6F000000Pcwb03rYj z0Jb{^0000001E&B0000009J|u03rYj0Pai$000000Q3O>000000CtK303rYj0FH45 z0000001f~E000000Ktj^03iSr0Km#90000004M+e000000Og7T03rYj09e2U00000 z01^NI000000A-5;03rYj0KhE=0000001*HH000000LP0003rYj0Le%N0000002}}S z000000Q`#r03rYj0H75I000000672v000000A!2;03rYj0K+l{0000008an_00000 z01b@-03rYj0Dz$e0000002%-Q000000Go{h03rYj0C?C20000002%-Q000000PT$e z03rYj0E@u}0000001f~E000000BDW^03rYj07$_G0000007C!(000000MU*D03rYj z09p$N0000001E&B0000009cO#03rYj0B~;w0000004e|g000000DF%D03rYj00yoG z0000004e|g000000PT+g03rYj0H7NO00000073u&0000002`1303rYj0Ag1L00000 z02=@R000000D_PL03rYj05sVJ0000002=@R000000QZmr03rYj0P5@o0000002cuO z000000D6%E03rYj0BJ4-0000001^NI000000D_SM03rYj037xO0000004e|g00000 z005E#03rYj09-2u0000008Ib@0000006vle03rYj089!80000001*HH0000009}#- z03rYj04gH~0000006PEx000000QHgr03rYj0ImfF0000001^NI0000006UWc03rYj z08-Zm0000003QGV0000008oVu000000J{JH000000MeNP03rYj0P8mg00000 z02%-Q0000002G=603rYj0Q5@*0000002=@R0000004|yW03rYj0K`lO0000006zc# z000000I8Y+03rYj0PC&>000000BQjM0000002`YE03rYj06-1~0000002=@R00000 z0Favk03rYj06?e)00000044wc0000000o=^03rYj01UPU0000006qW!0000005hBd z03rYj0LnQA0000008{_~000000I{3`03rYj06aSd00000044wc000000MncT03rYj z0Mh3L0000007(D<0000000*4{03rYj0IVqo00000089V?000000H~b;03rYj0PN`n z0000002%-Q000000OFkj03rYj01h_=0000002=@R0000004$yY03rYj0J!J{00000 z01^NI000000DPVT03rYj0K7N{0000001p5F0000000*A}01^NI000000000000000 z0000002QAC03rYj0N&yS000000LTCU0000009T&^01^NI00000000000000000000 z0CJxK01^NI000000000000000000000EeFf03rYj05D4h0000005<>t000000Op?p z03rYj0H|XI0000006G8w0000007jq!03rYj0D9R50000008Rh^000000NtPh03rYj z0B+g_000000BisN000000I;C~03rYj0P0Ey00000044wc000000M(%a01^NI00000 z0000000000000000P&#$03rYj0G6Z%0000007L))000000F9yo03rYj08GXP00000 z03HAU000000K1|B03rYj0H-Ji0000003HAU0000008yg?03rYj0GwL}000000MY;e z000000Dhwa03rYj0E9~g0000002=@R000000L7yM03rYj0E{dL00000044wc00000 z08pd?03rYj0F+_|000000Ac_D000000IZ|}03rYj00^iC0000002%-Q000000A!^C z03rYj0D5Ew0000009gP4000000I;P301^NI000000000000000000000LrBT03rYj z001Zk0000004o3h000000QRK<03rYj0P-mY0000001p5F0000003W6T03rYj02nt1 z0000001*HH00000070e#03rYj0G6Z%0000007L))000000Nthn03rYj0M<4I00000 z02=@R0000006(V!03rYj0N$Df0000006qW!000000B@%P03rYj0O(Z(0000004e|g z000000H~(|03rYj0JvTS0000007w7;000000LP~S03rYj0I1&v0000002=@R00000 z04=Bj03rYj01$o!0000003`qb000000BNWK03rYj0IDel0000001^NI000000IaA2 z01^NI000000000000000000000L`cZ03rYj0H9R`0000007n1-0000000XH403rYj z09-8x0000002=@R0000008^;~03rYj0L%#n0000008{_~000000IsP503rYj0LpU( z000000I2`~000000As2G03rYj05UWN0000002%-Q000000O_g%03rYj0PHjd00000 z0672v000000G6u)03rYj05bgr000000Ac_D00000028bN03rYY000000000000000 z0000005z-v03rYj002e>000000Eqwq000000A;KK03rYj0PHFU00000044wc00000 z0ROB403rYj0Lt(N000000CNBU000000I;nB03rYj0CMvM0000001f~E0000005+}y z03rYj0RAQi0000007C!(000000Hdw~03rYj0L+L5000000A2t9000000Lrcc03rYj z0MS1N0000002%-Q0000007|a{03rYj04OyD000000DAxc000000A#NM03rYj0P3p- z000000672v000000PL><03rYj06T640000001f~E0000000^)G03rYj04g^J00000 z0384T000000JpFL03rYj04`ev0000001E&B000000OPO%03rYj0PfHR000000Ga>* z0000008+6603rYj0Q?390000007d`+000000F20000001yBG000000NJ(z03rYj0Eig|0000007C!(000000A9BO z03rYj0Pt)D000000672v000000I0VD03rYj0N{`X000000384T000000RFcE03rYj z07xna000000Hgo_000000K>Qf03rYj05(Vk00000044wc00000013GQ03rYj08H%$ z000000384T000000E)Q+01^NI000000000000000000000HnDB03rYj00Jxq00000 z09OD20000008F|903rYj03*u=00000015yA0000001vwY03rYj01!n60000002=@R z00000057`&03rYj00l({0000001f~E000000JXaU03rYj03I&}000000Hp%}00000 z0D`;%03rYj06?Jz0000006zc#0000002sXj03rYj0K(%20000003!eZ000000BXGg z01^NI000000000000000000000JFUU03rYj04ACR0000009pV5000000NcF+03rYj z02ZPK000000J#7F000000H?kJ03rYj02m_%0000001E&B0000005rb>03rYj0K}dK z0000001*HH000000CT?r03rYj0MGLV000000672v0000001ChY03rYj0E$Bg00000 z05Jdn0000007$?B03rYj09+0R0000008jt`000000I$FT03rYj0KCoy0000008jt` z0000000hAT01^NI00000000000000000000035*r03rYj0C=kg0000002%-Q00000 z0J^~f03rYj0JI7R0000009OD2000000DZy&03rYj09*$K0000009pV5000000J*{f z03rYj04^>D00000089V?0000007%0E03rYj0F2-U0000005Jdn000000LsGx03rYj z0M0@N0000004@Lk0000005`+}03rYj09Nn?0000006YKy0000009?cZ03rYj0C))o z0000008;<}000000J+2h03rYj0IY2W000000QCd_0000008hmN03rYj0RD~!00000 z02~4U000000MW$)03rYj0A9QW000000D=Gj000000QbcL03rYj08rfp0000006YKy z0000005iq{03rYj01k2m000000DAxc0000003XK!03rYj0F>JX0000008Rh^00000 z0N%#}03rYj0BXPm0000009*h70000004m4=03rYj04cx*0000001p5F000000G`MK z03rYj08kVM0000002BZK0000000PMZ03rYj0Ftx@00000044wc0000006NJ603rYj z0BWBF0000005Aan000000O!d903rYj04TZ!0000007U@+000000Bp(v01*HH00000 z0000000000000000FTN703rYj0IZM&0000002%-Q000000OiU803rYj08rfq00000 z02ToN00000071(F03rYj0QO`B0000009672000000E^2403rYj03cQc0000005kvq z000000MN?<03rYj0Q{Q<0000007L))0000004U4?03rYj05lW_0000002=@R00000 z0D;T`03rYj0Jxt90000006zc#0000006WbB03rYj03b&P0000001*HH000000HMtS z03rYj0K%IF000000672v0000004~k~03rYj03S#P0000003rYY000000DH~?01^NI z000000000000000000000GiGM03rYj0MeTU0000008Ib@0000000_?l03rYj08If0 z000000672v000000FBQA03rYj0EAry000000384T000000MpL`03rYj0Melb00000 z03ZMW0000009nui03rYj08%jp0000007C!(000000D;f~03rYj01ONV00000089V? z00000020vx03ZMW0000000000000000000004~u203rYj0341500000044wc00000 z07%gS03rYj04gsB000000384T000000EW>503rYj05nGh0000002=@R000000Lak- z03rYj0E&hM0000008{_~000000OrvG03rYj08K3i0000001f~E000000AkVt03rYj z064$~0000001E&B000000EW^603rYj0Gu}l00000080P>0000000h$l03rYj0NN-A z0000009610000000GiVR01^NI000000000000000000000J75p03rYj0Mu*+00000 z02=@R000000N>LB03rYj05;kN0000001f~E000000D;s301^NI000000000000000 z000000GreT03rYj0LX3y0000001^NI0000000h+n03rYj05&-W0000005AXm00000 z0B+R+03rYj0H`Ad0000003QGV000000PxiU03rYj0CE}z0000001^NI000000ASVv z03rYj02@>V0000007(D<000000G8GQ03rYj00!^|0000006YKy0000003z1{03rYj z0Cocg0000001^NI000000EpKD03rYj06aJa0000003iSX000000H4q03rYj0QLt40000005$*s000000597D03rYj037HA0000009gP4000000Akw$ z03rYj0Om^v00000044wc000000F2uL03rYj0GccY0000003HAU0000006^RV03rYj z0Ekir0000007L))0000009)Jw03rYj0Lu{v0000002%-Q0000001Vv%03rYj0HS0C z0000008;<}0000009xGw03rYj0Jv-g0000002=@R000000EgWI03rYj0G{s!00000 z03rYY000000Q}to03rYj0Kl^b0000003QGV000000Day903rYj02BlU000000GR;* z000000OH;P03rYj08rfq0000002ToN0000006yOW03rYj0J`=D000000DJ-f00000 z0NmdK03rYj0FO5X0000001^NI000000QTPk01^NI0000000000000000000002bf^ z03rYj0BDc}0000004V?f000000B_&|03rYj0E$Kh000000Eqwq000000IJ{u03rYj z0IoO%0000001*HH000000MOt903rYj0D7?o0000004e|g0000005;(Q03rYj0Fo;Q z00000044wc000000E*!P03rYj0H8|+0000002=@R000000Jz}-03rYj0H|LD00000 z01*HH000000QTVm03rYj06Mq^000000Fwa#000000AS(*03rYj02~np000000NMfo z000000N>&Q03rYj03Zqm000000384T000000AS++01^NI00000000000000000000 z0Dj{F03rYj04kUT0000001E&B000000K($}03rYj0NgGG0000003`qb000000NvvP z03rYj0DP(j0000002%-Q000000BPg`03rYj0CqkG0000004D$d000000M_IJ03rYj z0NN-A0000009610000000Bq#~03rYj01q_>000000G0p%0000001V~=03rYj0EU|d z0000005bpp0000008Zut03rYj00RmK0000004M+e000000Cna903rYj008g>00000 z0384T0000000!p*03rYj0LG970000002%-Q0000009@w+03rYj0Ol_R000000Av6F z000000Bq+103rYj0J=5>0000002=@R000000Oscc03rYj0N$Vl0000002=@R00000 z0RQI#03rYj00Kq_0000002%-Q0000007&Qp03rYj01{gT0000002=@R000000CeaA z03rYj07UZz0000004@Lk000000QKks03rYj07B;l0000002%-Q0000008r@y03rYj z0A||;0000004@Lk000000O;ug03rYj0Ay_j0000006G8w0000007vQq03rYj0J6pg z0000000{vA000000ITW(03rYj0Ax!C0000004)Fj000000MF_I01^NI0000000000 z00000000000PyMp03rYj06udC000000E++s000000D9{J03rYj01qn$0000001^NI z000000OIQc03rYj00goI0000003HAU0000002Ay203rYj0C_kC0000005kvq00000 z03z%H03rYj0LCZ>0000002BZK000000I}=>03rYj02D_B0000003QGV00000021v2 z03rYj0Jwk!0000001^NI000000ATF`03rYj01pud0000002%-Q0000001EB`03rYj z0NND?00000089V?000000GRFq03rYj0DKJx0000003!eZ0000004?tV03rYj02Gh~ z0000004V?f000000Icr<03rYj0J}p600000089V?0000003h%J03rYj0Md#D00000 z0Ga>*0000008;P*03rYj0Ai^I0000002%-Q000000P*kw03rYj0IsJ70000006zc# z000000I=}_03rYj0LU8#000000CoTX000000L<|M03rYj03cQc0000005kvq00000 z01@&603rYj0J<6n0000001E&B000000DAHQ03iSk0ARTX0000003iSX000000H5*# z03rYj07DT60000002%-Q00000088@%03rYj0P;2m00000044wc000000JHM~03rYj z00?UZ0000008Ib@0000005bFf03rYj0FLtp0000006_o%000000M+yY03rYj0Cr>r z0000002TlM0000004DVU03rYj0MxVw0000002=@R000000G;&$03rYj06?Dw00000 z04e|g000000KWAC03rYj07mu&0000004@Lk00000095t@03rYj01O%i000000A&CG z000000L=CR03rYj0ARfZ0000005|{u000000Q&X<03rYj08q>Z000000FnRz00000 z0DkuZ03rYj03j;|0000002%-Q000000Ot1s03rYj06i}S0000004x9i0000000;O2 z03rYj0J!A_0000001p5F0000009N<{01*HH000000000000000000000Ce~Q01^NT z0K}>U0000007(G=000000FL+q03rYj09+CW000000IdK30000004ezb03rYj0EmnR z0000001f~E000000BHFF03rYj0B|M;0000008Ib@000000P6Vy03rYj0Op z0000009gS50000004e000000384W03rYj08-Zm0000003QGV0000005Sjr03rYj0K%IF00000 z0672v000000KWhO03ZMW000000000000000000000NDTo03rYj07fVW0000004V?f z0000000aR803rYj0Cz110000004M+e000000B!*T03rYj08u>#0000008{_~00000 z0MY>i03rYj0Q}nq0000002%-Q000000FD9!03rYj089!7000000A&CG0000001E>H z03rYj09pwK0000003HAU000000DuDn03rYj0QyG-0000006YKy000000ObP%03rYj z0GJjB000000CNBU00000080b|01^NI000000000000000000000Cxlf03rYj01Vv) z0000007L))000000JQ`I01^NI000000000000000000000L=sg03rYj0Ob(}00000 z03HAU000000Br>W03rYj03=-o000000Q3X^0000001gHN03rYj0P=hV000000MY;e z0000009ytF03rYj0OCLf0000004o3h000000Eh+y03rYj0Cp7z0000004e|g00000 z0M-Tr01^NI000000000000000000000P_X|03rYj0CwXB0000004o3h0000000{>J z03rYj08sJ<000000DAxc000000QCn003rYj0O+I!000000GR;*000000G$W}03rYj z0QA}h00000089V?0000004@mw03rYj05A;)0000004o3h000000EYt000000Phb201^NI000000000000000 z0000001yxZ03rYj0JPo)0000002%-Q000000KgCf03rYj0GMY50000001E&B00000 z00j{P03rYj00v0~0000001f~E000000Dln!03rYj0Os}u00000044wc0000001grZ z03rYj09!=|0000004)Fj000000A&&b03rYj02Gh~0000004V?f000000OS$_03rYj z02Isy0000002TlM0000005=l@03rYj0LGgI0000001E&B000000D=<(03rYj09Mlm z000000Ga>*000000P+(903rYj0I);{0000009610000000ErX>03rYj03Zqm00000 z0384T00000016cY03rYj0OSq^0000002=@R00000067%{03rYj0P>9m0000004V?f z000000Advb03rYj00Jxr0000009gP4000000NE7-01^NI00000000000000000000 z0R9yN03rYj0JaDQ000000HXi^000000E-p_03rYj0FWaF0000001E&B000000RI*P z03rYj08BIn0000004@Lk000000J9eZ03rYj0F)pH0000004e|g00000045j%03rYj z0LZ%r0000006qW!00000003ihbaQldW@av90AyuyWoKz~bY*g1bZuW_Y;SI5a{ymo zWN%+*Y;R&=Y+qz_Z*p^AVRd)_V{dJ6Y-Mz1WG*&2G%x^PUu17zXKZg`VQgPybZ>HV zUtx84UuJ1;Xrc|VQpn!WOZ$Ac>rHuW^!R|WnW}MtB zUtw}`VR>I=Zgg^a0AE^DbWAZhaA{>@Wp`mPB~v+XKr<0V|aK>F*sjeWq4y~VQyz-Utw-!UtwfqMNn30X#ihZ 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%0AE^8IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&g 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

D+9NmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6b zb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z& zQ*<Qa!E^5b5k{6MMXtgPE$2sHe+&SVRU6lQ$t@$MMXtW zR9{4JPgF2pMOAE2Q$t@xUqv=wOV_#}>Z*ECbbTe&Xa8qQ(;b1 zGG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0 zQ(;L{IA29YF)?33Y;131Uv6(?WkWGVQd31=0AE^8Q*<+JVQ@)mQ*%>vG;C#ab4hAN zQ(;L{bTn{bX>v(RYEyGXMMXq1MRovRT251RHFR}wY-LGGP*ZbSPB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7 zWpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqoYRbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(V zT250nUp8ZMWnpw>NmDmpN>WQxH(y0XMNm{ zZfS9KWnXY~a!FG{UsNz(MMQ1@Us_I6VM$YSMME-0QcF``0AE^8Q*<#hUsh#fbZ>HB zVqtS-Nn=xCNn=GtF*9FHUu0!rY;131VRU6hP-ATXUs_I6VM$InZftL8ZDDS1He_XV zVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1az#Z%GDUU(Us_I6bTKe>ZfS9KWnXY~a!FHj zT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{vG;m>Qa!E^5b51cbMRIa)a!p}wVP|D> zIYn}EZ*oa)W^YABQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^kb462ONmDdmMMW_( zUrk?Ra&K^7Zf|5|MNm_8F*9FMVqbJ}Wo2J(Z)9ajQ#4;i0AE^8Q*<#jUsG^jWnyn% zXk~10WpYVOX)r}oVM$InZftL8ZDDS1He_XVVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1 zaz#ZNmDmpN<~FQP*h(;a8Fb)Uqw}HQ#fBmUqwYjGD%WXIA2mr zQ$}A*VlhQUMNd;fUr$spUjScPR8v!QF*aXQa9?9@b#8QJWM5)ob7e_PPB~v+XKr<0 zV|aKmGG9z@V{2bG~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXq0MRovR zT251RF*09PWn*-2a$jO$b7e_RIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VLo!8n0AE^8 zQ*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YAB zQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^kb462ONmDdmMMX4bX>MdiQd2Qs0AE^D zbZ%uyQ*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzFke%1Vr*?> zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc%HD5Mka%Ew3Wl2*vUrI$q zMNm{ZfS9KWnXY~a!FG;UsNz(MMQ1@Us_I6 zVM$YTF*9FMVqbJ}Wo2J(Z)9ajQ*<&%0AE^8Q*<#ia&>NWX>Da+WpZ+F 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%0AE^8Q*<#oUqWegUt@1>b97&6 zbY*g3bZ>G)GDT8LQ*<#iUqWegUukq@a$$6DasXdiPB?CCZ)j~{Zf-VYWprU_Y%(}% zb8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gW#PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_(Xkl(-Y-L||VQh6} zNm61(MN@P%aA9e3Nn%h_HeW?gR9|8MUs_H$ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MKLgHb8l{6c42IF zWkWGVYye+cPE&L^Us7UUbaG{7NorGcG;m>Qa!E^SQ*%XAbTKerQ)O&rV{|cdbV*Y( zUqw@NG;C#ab4hANQ(;L{GG9eSIA2X)WpZJ2Wkpa^bTKnuQet0pa%E*-Zf|5|NmDXk zMF3w~Q*<4psP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYCJUqyCQUsE?G~b7E|5WK&^I zQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<2kwX>M?JbYEd)VQ_S1a$j(AZ**^CZ)`&` zMRovRT2518NmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ(sea zVr*?>Q(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#4;iMMXm~MRovRT251RF*adr zY;R*>bZ>HBbaG*7baP2lVM$YSMMW_%WMyG&Y;R*>bY(?SQ!rmpQ*&(qc5`lUa%paK zW?y{bY*g3bZ>HSa7A_iUs_I6bTn{bX>v(R zQ*%x+GDUK7Z*omxZeeF-aydnEa&K};Zf0*qMMN@1b^u>mPD@jCHg;uWbZ>G=V^d*C zV?{+ZVr6G(ZbfzgUs_I6bTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GG8$?VPtGyb7gXA zVQgu7WpYJDMMXt9Urk?jVQg@8az%CkUs_H}Q*<#mUs7UUbaG{7Uukq@a$$6Da!FHk zG;m>Qa!E^SQ*%W{WMxHm0AE^8IBsljXl-F`ZZ>3PbYW?1F)(y_aAjX*a&m8SLo!8a zP)lO~Us_H}Q*<#mUs7UUbaG{7Uukq@a$$6Da!FHkG;m>Qa!E^SQ*%W{aCAj>0AE^8 zQ*<#gUsQE)Y-L|*ZE$Q!Ol>elN>EdDGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2 zZb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwE zNmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N>WQxLtjNjMNm{< zL~u`3FkeMgY*R#EMPEflLorEGQ$$}%QcF`!UqyCBMNd;mUsFt90AE^8IBsljXl-F` zZZ>3PbYW?1GB|2;Z*E_6VR&C;Z*5;=VQg$-VPk7waA9(DWpYVQQ(rMKVqtS>V_#}> zZ*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLjO zVRCb2UuAM~Z*oO#QcF{FQcF%#Fkd-kcw=R7bZKvHMF3w~PE&L-FkeVzVPs!oVRL0k zOl>hmT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmDalNmDgnQ(;L{HD5(VN<~FQP*h(; za8Fb)Uqw}HP*XTxMPE!}FhxZ}F-1~KQ$}9^Us_H$ZftL8ZDDS1F*IRhY+rL_a%o{~ zX?kUHNo00KH*{}bYIARHNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnQ!rmeMN(u%MMP9%ZDVXqUs_I6UokRYM@&ybK}=s?PG2!MbZ=j3b8l`%MP_hc zV{A8OZ*q5Ga%4$VFkeMxa4=s*MPqh$UqwYyR9{b1IbQ%@T2xj}IBsljXl-F`ZZ>3P zbYW?1GBRmyaCLNFVPs)&bY*g1aB^>SZ)0z4MF3w~Q*<|GZ*q5Ga%4$PIBsljXl-F` zZZ>3PbYW?1HgI8bb7gW#PE#;nF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLF*9&sa&u*0Wp-t5bYFBuMNd>;QchEJ zF*b5#ZEtpEUvgz;WpZV1V`WKGL0?5Qba`-PMF3w~Q*<#fUqf$hb98cbV{}PQIBslj zXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^ zWpZg@Y-xIBaz#Z&N>WQxHD5(Vc2HDbL~u`3Fkb*)T23-&Wic~TbYXOLb4FofbZ>Hb zLo!8n0AE^8Q*<_VWn*-2a!FHjQ(;L{b45itaCLKNUt(cnYeiB^Q*!`cT251RIA2m? zUvzS1Wl2+WQ*<`cD zQ#fBmQ*<M?AVPj=UPB?CCZ)j~{Zf-VYWprU_ zY%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{GG9eZPB~v+XKr<0V|aKmGG9z@V{2b< zZ)|B}c||fsMKxbZZE$QjUrk?OY;131MRovRT251RF*RRbb#7^KUvPACUukV{Y)Mmd zT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4JPgF2pMOAE2Q*%XM zMME-4QcF`tUqwYzMPE--IbQ%@T251RHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}> zZ*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMW_( zWo>Y5VPj=qVqs%zNlH^RUqwYlc0_PbR9^sJT247%UuSN0Ut@T9F*jddZf|mJVQgP% zbY*g3bZ>G=P*ZbLbT)QnV{~tFNmFxEVM$YSMMXtJF-1~KQ!!rvUs_I6bTKwzY;131 zVRUbDUvzR|X>@Z*Q(;L?IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2 za#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MMW_%WMyG&Y;R*>bY(?SQ#M~v zQ#D_00AE^8Q*<&jUsG^jV{dhCbY)~;aCCBCX>M?AVPj=UPB?CCZ)j~{Zf-VYWprU_ zY%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{GG9eZPB~v+XKr<0V|aKmGG9z@V{2b< zZ)|B}c||fsMKxbZZE$QuF-21|UjScUV|Za-XLVt6WM6V+Y-M3{Wk5hfSXeV_#}>Z*ECbbTe&Xa8qQ(;b1 zUokXcWNcq^WpZg@Y-xIBaz#ZoWpZJ2Wl2s`Up8cAbYW?1Icaoda$jj}aBN9aG+#wU zOldGhMMYF!Q#oG%Us_I6bTKqvMs;pubZKvHUt(c%WkWGVb^u>mPE&L-Fmq^Oa%E&+ zaCCA>PB?CCZ)j~{Zf-VYWprU_Y%(%wZg6#UUtwfnaCBvIUvP47bZ=vCY(+&xGDUU( zUs_H$ZftL8ZDDS1He_XVVQFkJFm!ovWnX1-a&K}&F-2)mOJe|ET251RF*adrY;R*> zbZ>HBbaG*7baP2lVM${}MK@$+b98cVc}ZhMMRrnCFketqUjScPQ*=3DWMpz>b8~NI zNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MMXtWR9{k4HeUc=T247%UuSN0Ut@T9F*9yucVA&_Y;R*> zbZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ#4;OG+|_HUvp)0X<=+>dS!A&MMXtL zMLA<{ZgX^Ubz^i%Q$b%!QcF{GGBI#zWn*P`X>(;?V{dMAbaHiLbYFB+bTxE!aBO8s zN>WoZUqwYzNMA`xMMXtLMRrhBUqooOBUvPACNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mE zOH*@2MMY3lUqomPB?CCZ)j~{Zf-F&VPtGyb7gXA zVQgu7WpYVVb9O~HbZ=j3b8l`*PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^NFkeMQQd4t9MMP9%ZDVXqUs_I6UokRYM@&ybK}=s?PG2!MbZ=j3b8l`% zMP_hcV{A8OZ*q5Ga%4$VFkeMxa4=s*MPqh$UqwYyR9{b1IbQ%@T251RF)(#*X>oOB zUvPACNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqo2kw zX>M?JbYEd)VQ_S1a$j(AZ**^CZ)`;PgF2p0AE^EQ%*Q;Y;S07VQy|VWMy<=X>2hzX>N95Y-wa)X>?_BVRUbDMF3w~ zPE&L-F<(@5aBO8?X>D+9Nla}pMM_XpbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(V zT250nUp8ZMWnpw>NmDmpN<~FQP*h(;a8Fb)Uqw}HQ#fBmUqwYjGD%WXIA2OqOH)Q) zMRr9+Pg6l(Q$=3@Us_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNmFz-c4cF9Z*oaa zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!!stb7E|5WK&^IQ!-yMG+|_HUvp)0 zX<=+>dS!A&MMYC#NmDjoMMXt1Fl1$6Y;131VRU6hP*XTxZ2(_dPE&L^Us7UUbaG{7 zNmFxEbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF-aydnEa&K};Zf0*qMN@P!Fke$;Y-M9~ zF>`cDQ#4;iQ*<@Z*Q(;L{bTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9Z zMRIa)a!GDxZ$(8#MMXJdZ*FsRa&=>LNmDgnN>WpEQd2ZvMMXt+Qd2iyP*h(;a8Fb) zUjScPPE%n?PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MME-0QcF`cUjScPPE&L^Us7UUbaG{7NmFxE zbTn{bX>v(RQ*%>uMN@P!Fke$;Y-M9~F>`cDQ!-ygQ*<Zf|5|MRovRT24z-bT)QnV{~tFNn=xCNn=GtF*09GUt?%xV{2b*Wo|`n zP)lO~Us_I6b750OPg8S1Ku1hTLPJG=R9{puUqwYz zLSF!1T247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=PB?CCZ)j~{Zf-VYWprU_Y%(xu zZg6#UUvqSFWnpb!VPs)&bY*fyMMN=0b^u>mPB?CCZ)j~{Zf-VYWprU_Y%wx#b#z~E zW?yn)Zf9jgF-3L&Us_I6bTKktR%K&!Z*pH^VRL0kQ*%>cNmFx0MKLm8R%K&!Z*pI0 zZE$QvF-3L&Us_I6bTKqvUvp?-a%E&+V{dhCbV*E3IbUCAZgpQ{cz7`~UrcXfYhQ40 zY-wY8MKVQ2Lo!8n0AE^8Q*<#lVQg$~V_|e}a$j_EVQF-8NmF4-Q*<#iUs7UUbaG{7 zUv6(?Wl2+XG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!`&NG+|_HUvp)0X<=+>dS!A&MMXtLMMXDcWpi|LZ+S^mIbTIZ zc2ZM9UrG~b7E|5 zWK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMN(69MMXqZV{Kz>H*{}bYIARHW^i9)Y&T|a za(7{JWJy#oUqxncFkeMQV|I35MMY9nUr$pxUjScPPE&L-HD6zKZfS8}aCCBCX>D+9 zNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zFkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEK`~!TV?{+pP*h(;a8Fb)Uqw}H zP*Zb7Uqvx6Urk?RWo%`1WpYJ!0AE^8IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mT zQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMW_%YIARHUv^<^b!9^_ zMN&&sa{ymjPB?CCZ)j~{Zf-VYWprU_Y&m6kV`Xr3X>V>sGDUU(Us_I6VM$InZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0 zX<=+>dS!A&MMXtKGDUU(Us_I6bTKnuLTPkgX>?_BVRUbDaBxLw0AE^8Q*<#lVQg$~ zV_|e}a$j_EVQF-8NmF4-Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b5nCgMMXt7 zWMy-7a&LJ_Q!`&hMRrnCHD6FvUjScPPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oaf zbTTtvQ*d8nZ*^{TWn^D)baG#5Zg6a2V`WKBIBsljXl-F`ZZ>3PbYW?1GB9awaCLNF zb98cLVQpVwWMOc0WpYJRVM$XoUqwt#Q(rMMUrcXfYhQ40Y-wY8MKVQ2MMN@1b^u>m zPE&L-FkeVzVPs!oVRL0kOl>elP*Zd>ZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARH zNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k{6MMXtSVlYKTH(yO(Xk}q!MN&&sMPC44T244_Y;S07 zVQy|VWMy<=X>2huaA9(DWnX1-a&K}(FhzC%Us_H%Utec#bzft6cri0>Wp`g;Y;131 zVRUbDNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B= zYIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#~rF*IRhY+rL_a%o{~X?kUHMMXtL zMMXq0MRovRT247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=P);~*Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A& zMMXt9V{dMAbaHiLbV*Y;UrJLqUqwYlc2HDbL~u`3Fkb*)T251QIdFAzXkTJsV{1iY zKtM-KNkT(dSYI(R8vkkZftL8ZDDS1He_XVVQFkJF>iEeWpZC-a&m8SMF3w~ zPE&L>VRCX|c}ZhTZ8=3nG-P3PVMTTTUs_I6bTKhsRCRD{WnXD+aBN9TZ7@YjQcF{F zMMXn0MNd;QUjScPQ*<+DWpqhQZ7@YjP*Zd^c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgn zMMYXpQ#D^UV{&C-bY)3XH(yFcMMY3lUqovbTKn@b#QED zUuA4%ZDnqBNmx{0MN@P&bailSWl2gza8pBHMMXt4ba`-PMN(5rUjScPQ*<+DWpqhQ zZ81ekP*ZbSPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEK`~!TV?{+pP*h(;a8Fb) zUqw}HQ!rmeUqwYyPE&L-Gjw%uY-L|%Y-Md_ZgfdlR9{6?bTxE!aBO8sNWp`g;Y;131VRUbDNmFx0H)LgVbaHQb zNmFx0MRrhBUjScPPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oaaIBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIB zaz#Z&MLA<{ZgX^Ubz^i%Q#M~pQcF`dUqwYlc2HDbL~u`3Fkb*)T2pi}IA2m?UvzS1 zWnXD-V{&C}Wo~p(Q*<#nUs7UUbaG{7Uv6(?WnW@pb7eq4M@&gVLs(c}GcGg$Us_I6 zbTKtwUv+M2abIwBa$jj}aBN9abT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VT250n zUp8ZMWnpw>NmDmpN<~FQP*h(;a8Fb)Uqw}HP*XQwMPEfWUrk?dbaF*@0AE^8OH*_> zUs7UUbaG{7NmFxEbTn{bX>v(RQ*%>uMN@P!Fke$;Y-M9~F>`cDQ!-ygQ*<bailSWl2g;Q*%W{LorE8Q*%X3VlhQU zMMQ8V>{VqtS-L^4Ho0AE^8GG}EmGgEY7bait^VPkY} za(OsOZgX^DZewLdb^u>mR8~$gFkfF|cz9uAX?8I&H(y_4Y+-YAUvznJWnXD-W^YA6 zKtotqK|)DiF)lLzUs_I6VM$YSMMN=0b^u>mPB?CCZ)j~{Zf-VYWprU_Y%wr&d2nT4 zWpZ+FayDafWnpw>MQKt?Q*!`cT2pi}IbUCNXmW3NUuelN>EdDHg;uWbZ>G=PB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XpUqwY)PE$2sHe+&SVRU6lQ#W5qQcF`eUqwYlP*h(;a8Fb)Uqw}HQ#fBm zUqwYjGD%WXIA2OqOH)W+MRr9+Pg6r*Q%7F_Us_H}Q*<#fUsGjlWn*+Pb96~lbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLMPqD5QcF`fUjScPPE&L-FkeVzVPs!oVRL0k zOl>hmT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4JPgF2pMOAE2 zQ*%XMOkyxaMME-0QcF`tUjScPM^;)+GG}EmGgEY7bait^VPkY}a(OsOZgX^DZewLd zc11X8ZgX^DZewKtUs_I6bU0s9VqbJ}Wo1cfQ*<`cDQ!-ygQ*<vG;C#ab4gQkMN?r(Q*<$Q!-ykQ*%>uMRr9+Q!-ykQ*<#mUs7UUbaG{7Uukq@a$$6D za!FG(Uqxa?PgGw3Us_XiF*t2uYh_<;Z+2y0X>?_BVRUbDNl;EWZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUH zMMXtLQ*<#iZEtpEUukq@a$$6Da!FKQMN>Fm0AE^DbT?*ia(7{JWJyv`Q*<_VWn*-2 za!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzFke%1Vr*?>Q(;b1F<&t>VPtGy zb7gXAVQgu7WpYJDMN?r(Q#D^jMMY0kUs6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ$b%v zG<11zWkmpAUt@S-UuJS;WnX1@V`Xr3X>V>oKtotqK|)DiF)lLzUs_sDGG}EmGgEY7 zbait^VPkY}a(OsOZgX^DZewLdc11X8ZgX^DZewKtUs_I6bTKwzY;131VRUbDUvzR| zX>@Z*Q(;L{bTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbFke%2Hg;uWbZ>G~ zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<Qa!E^5b5nCgMMXm~MRovRT251RF)(#*X>oOBUvPACNmFxLPB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGy zb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqoNmF4-Q*<&jUsG^j zV{dhCbY)~;aCCBCX>M?AVPj=UPB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb! zVPs)&bY*fyQ(;L{GhanaPB~v+XKr<0V|aKmGG9z@V{2bD+9Nla}p zMM_XpbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D0UsH2pY;9yy zVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VT250nUp8ZMWnpw>NmDmpN<~FQ zP*h(;a8Fb)Uqw}HQ#fBmUqwYjF-cNWIA2OqOH)Q)MRr9+Pg6l(Q$=3@Us_XiGcsRa zZDDI=Uu|!8WnXD#Uv6(@cw=R7bYE$7WpZJ3Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}> zZ*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN@P! zGi`5nWnXD@WpZJ3Z*oacQ#M~kMN}|fP*h(4Us_H%Utec#bzft6cri9#Utw%%XKrO= zUu|V=Vs&OoQ*<Q(;b1 zFkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMME-0b^u>mPB?CCZ)j~{Zf-VYWprU_ zY%w`%b8l{6b76R2WN&R>aA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLmHVQyq>WnXq-Y;|QxQd4t9 zMNm^VUr$tD0AE^8IBsljXl-F`ZZ>3PbYW?1F*9jyaCLNFVPs)&bY*g5c2jgQFmq^O za%E&+aCCA>PE#;nGBRmyaCLNFVPs)&bY*g1aB^>SZ)0z4MMXt+0AE^DbTKktUu|i0 zWpZC)VRL0kQ*<#oUqWegUt@1>b97&6bY*g3bZ>G+R9{muUjScPPE&L^Us7UUbaG{7 zNmFxEbTn{bX>v(RQ*%>uMN@P!Fke$;Y-M9~F>`cDQ!-ygQ*<vG;m>Qa!E^5b5nCgQ*<#f zUsGjlWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMXm~MRovRT244_Y;S07VQy|V zWMy<=X>2h$YIARHUvpu2Uu17>UvOb^b7gW#PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_*Zgp*9WpZC>Zggd5 zWpYJq0AE^8Q*<#fb#7^Kb!A_0baF{kbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(V zT250nUp8ZMWnpw>NmDmpN>WQxH(y0XMNm{Qa!E^S zQ*%W{MMXGaY;131VRU6hQd2cwZ2(_dPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oaf zbTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbF<(=3Hg;uWbZ>G~b7E|5WK&^I zQ!-yMG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<LNmE2$N>WQxL|;WkMRrhBUqoN06a&$>bQe;I%MRra(Utec#bzft6 zcriC$Uv6)5ZDDL*X>?_BVRUbDNl;TXUsE<;MMXq#PgGw3Us_XiF*09YZfSI7a$jO$ zb7e_WbTK(!LTPkgV{dMAbYE$7WpZJ3Z*oOcUsEw(0AE^DbTcwvUu|J)WnXP?c4c2_ zW?yb^Wq4y{aCBd3bY*g3bZ>G=V^ef7Gi`5nWnXD@WpZJ3Z*oacV?{+&FketqUjScP zPB~v+XKr<0V|aKmHeX+1Y-wk1Wn^D%Wo=@0W=T_YG;m>Qa!E^SQ*%W{H(yO(VPs@- zMRovRT251RF)?3XV{dSIUu|!8Wl2n8FhxvaFhx^zGB$EyZe(w5UtwcoWpi_1X>?_B zVRUbDUvyz-ML1tyV{dSIUu{WHOH*@DQ*%W{R4`vuUsE?@Z*V?|S8Nn=GtVp2;}Vo6kAR4`vuF<(VfI9~u?T2518NlrL!Y;S07 zVQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMMXq0MRovRT2pj4W^ZzLVRB?i zQczQLGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?> zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_ zUqwYlMNd>;QchEJF*b5#ZEtpEUvgz;WpZV1V`WKGMqfoVba`-PMF3w~PB~v+XKr<0 zV|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PBAh? za&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8#MMN@1b^u>mQ*<|GZ*q5Ga%4$TP*Zdv(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE#{qF*IRhY+rL_a%o{~X?kUHMMXtLMMY0kUs6s}bTKw^ zWo>VEWnXe-W@U0^ZewLhQ$$}yG<11zWkmpAT244_Y;S07VQy|VWMy<=X>2h!X>N37 za&BR4Uukq@a$$6Da!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO$DF*IRhY+rL_a%o{~X?kUHMMXtLLo!8n0AE^8Q(;L{bTTtvQ*d8nZ*^{TWn^D) zbaG#5Zg6a2V`WKBIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJR zVM$XmUqwt#IbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2MMN=0b^u>mPD@jCHg;uW zbZ>G=VpCyBVnszYVr6G(ZbfzgUs_XiIc;HUWnXY%X>v(YOH*@GF<(VfbTn{bX>v(U zQ*<#mUteTpV_|t;VQyq!b98cPa7k2OMK)hwba`-PMNU&QUrAIjUqv=wUvznJWkp3# zQ#4;sQ#W4#Us_H$ZftL8ZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m-V{2b< zVRCb2a!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRh zY+rL_a%o{~X?kUHMMXtLH)3yZY-M3?MPdM7T247%UuSN0Ut@T9F*9yucVA&_Y;R*> zbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zF<&t>VPtGyb7gXAVQgu7WpYJDMMXm~MN&&sH(vl>T24z-bT)QnV{~tFNlrL!Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XoUqwYRGG9$!V`yb#YhP?-ZbfZSOJe|ET251RF*adrY;R*>bZ>HBbaG*7 zbaP2lVM$YTF*9FMVqbJ}Wo2J(Z)9ajQ*<elQcF{FOkyxaMME(~Q!!rvUs_I6bTKhsRCRD{WnXD+aBN9TZ81ek zT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmDalNmDgnQ(;L{HD5(VN>WQxIA29YMNm{< zL~u`3FkeMgY*14;UqxR3PbYW?1 zF)?sqa&u*0WpZ+Fazy}NT244_Y;S07VQy|VWMy<=X>2k$YIARHUvpu2Uu17>Ut?ix zY+_+!YhQ3-a&u*JNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE%hoG+|_HUvp)0X<=+>dS!A&MMXt3Yh`&wQd4sPUs_aFPB?CCZ)j~{Zf-VYWprU_ zY%(xuZg6#UUvqSFWnpb!VPs)&bY*fy0AE^8OH*_)H(yd>UvzS1WnXD@WpZJ3Z*oaf zbTn{bX>v(RYEyGXMQ&w9QcF`aUjScPPD@jCHg;uWbZ>G=VpCyBVnszXb7^{IMRovR zT2pjzY)NBNbTKhwXkl_+baG*7baP2#MN?r(V?{+%Vo6kAR4`vuF<(VeOH(#qP)k!Y zUjScPPB?CCZ)j~{Zf-VYWprU_Y&C3Ucx7@)PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_&b7Ns{UvqSFX>Mml zb^u>mPE&L-FkeVzVPs!oVRL0kOl>hmT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5 zQb93aOJhYvMNm{@Z*Q(;L?IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2 za#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MMXJdZ*FsRa&=>LNmDgnN>XG+ zMMZW}Q#M~vR9{4JPgF2p0AE^8IBsljXl-F`ZZ>3PbYW?1HEd;gWpYVQQ(rMKVqtS> zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z& zMMN@1b^u>mPE&L-GGA6@V{~tFUt(c%Wl3XGVM${}MMN=0b^u>mPE&L-G;nWeZggdG zUvzR|X>@Z*P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXt1FmP{aZggdGUvzIpQd2cw0CRM5bZ=xp zKu1hTLPK9NE;24P0AE^DbTn;mc4bLYOH*MT2pjzY)NBNbTKhwXkl_+baG*7baP2#MN?r(V?{+%Vo6kAR4`vuF<(VcOH(sn zQcF`dUjScPPE&L-G+$G2Uu9x%Uub1)aAk5yOldGhQ(;L?IBsljXl-F`ZZ>3PbYW?1 zGB9awaCLNFb98cLVQpVwWMOc0WpYJDOky!bMK)hkUuR`>MN(5VUjScPPE&L-HeXY4 zUt@1|Zggd2Ut(c%Wl2melN>EdDHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}> zZ*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwY) zPE$2sHe+&SVRU6lQ#W5qQcF`eUqwYlP*h(;a8Fb)Uqw}HQ#fBmUqwYjF-cNWIA2Oq zOH)W+MRr9+Pg6r*Q%7F_Us_H}IbUCAZgpQ{cz7{3UteKtX=iR_WM6G%ZDMt1NmFz* zaA9e3NlR06Q*%W{H(yO(VPs@-MRovRT251RHg;uWbZ>G=V^d*CV?{+oGDUU(Us_Xi zH)d~gcVTj5Nm5gDMNd>;QchEJF*b5#ZEtpEUvgz;WpZV1V`WKGF<(VAba`-PMF3w~ zPB?CCZ)j~{Zf-VYWprU_Y%(x#a%pX8bZK^FUukq@a$$6Da$j^eb7gd2Wo~3eb^u>m zPE&L-GGAYFXkl_?WM6P}a!F1&ZftL8ZDDS1He_XVVQFkKGHGsbb#z~0WMOc0WpZC| za&L5RV{dFlOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXn0MNd;TUjScPPE&L; zGhb3-UvzS1WnW`&ZgX^BX>?_BVRUbDNmFz*aA9e3NlR)|b45i%GDT8LQ*<#mUs7UU zbaG{7Uukq@a$$6Da!FG%Uqt|4T247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGy zb7gXAVQgu7WpYJDMMXJdZ*FsRa&=>LNmDjoNQa!E^5b5nCgMMY0kUs6s}bTKw^ zWo>VEWnXe-W@U0^ZewLhQ#W5lG<11zWkmpAT251RG;m>Qa!FHkF*jdQVqbJ}Wo2J! zbY*g3bZ>G=Q(s9-Q*%>uMMYvoLo!KIGhbp%VlhQUMNd>;PgF2p0AE^8IBsljXl-F` zZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~ zX?kUHMMXAaa%Ew3Wl2*pUrAGQQ#4;wbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#4;i zMMX+dOH)H%MMXtWR9{4JPgF2p0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51cb zMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^k zb462ONmDdmMMW_)Us7UUbaG{7UukV{Y)Ml%Urb^#MMXn0MRovRT24z-bT)QnV{~tF zNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXcWNcq^ zWpZg@Y-xIBaz#Z&Q(;L{HD5(VHDYCFX>LV!0AE^8Q*<#gUsQE)Y-L|*ZE$Q!Ol>hm zN?J}hZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+WN>V{FUrS>}MMY3lUqoQa!E^5b51yJY;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMXtJ zF-b~KQ*%X1Ol>elMM_0VMMXtYQ*2hvb97;JX=7hwZ*FsRNlsHRUokRfa&K*4YIARHUuJGaMKyL|Y;|Qt0AE^8 zQ*=0AQet0pa%E*nYEyJHaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwE zNoqw?VM$XmUqwYRGG9$!a%pF1bZu{QbVYUmUs_XiGBRIZb#7^HX>@5}Y-xIBWM5-% zaCu*0Nl;UBQ!rmsb464zUsPXHGG9|MUs6+HNmMakMF3w~PE&L-Fm-Neadl;1aCCA> zQ*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzFke%1Vr*?>Q(;b1 zF<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc%HD5Mka%Ew3Wl2*vUrJI-Q#W5l zMMY3lUqomQ*<#fUteTtb97;DV`WKDV?|C=bTKt) zbY*g3bZ>HBbaG*7baP2mUqvxBWNBt*WpZV1V`X1-d2nS#Q!-yuGG9}4GB$EyZe(w5 zUtwcoWpi_1X>?_BVRUbDUvyz-0AE^8Q*<_VWn*-2a!F%TVM${}MME-0b^u>mPB~v+ zXKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR)| zb45i(F)(ChVQg$~V_|eY8a$$0LUv^<^b!9^_ zNlH>nQ#4;iMMY3kHeW<=PgGw3Us_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GG8$?VPtGy zb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29Y zF)?33Y;131Uv6(?WkWJWQd31=0AE^8Q*$?RWpib6c4b9vKtM-KNkT(dSYI( zPE&L;FkfF|Z*X~EZEtpEUt(cnYj?_BVRUbDUvyz-MKLp9Ut@1@d0%aBc4c2;NmFz&Ghae!bYE$7WpZJ3Z*o&JUqwY! zFke((Q#D^xG+zK;T251RG;m>Qa!E^5b5nCgLo!KIb5nCnVlhQUMNd;-NmO4{FkeLg zUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6b zb7^B=YIARHNmDUjQ*<_VWn*-2a#M3+Y;9yyVNO#rUokXcWNcq^WpZg@Y-xIBaz#Z& zQ*<Qa!E^5b5k~7MMXtLL@`Bn0AE^8Q*=0AQet0pa%E*n zQ*%>vG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABQ*<#fUsGjlWn*+P zb96~lG+#wibTn*bb8|^kb462ONmDdmMMW_*Urk?ZZ+B&KUt(`{Ze&GJQ*<#iUs7UU zbaG{7Uv6(?Wl2*sUqw(;bTK$zQet0pa%E*-Zf|5|Ut(c%Wl~cyUjScPPD@jCGi_mT zNmFxEb5nFQY-MwENmFx0Q(;L{bTn{bX>v(RQ*%>uMMXt3Wo~3eb^u>mPE&L=aA9e3 zNl;UCF*sjRVqbJ}Wo2J(Z)9a(VqtS-Q!!sfLo!KHP*ZdbZ>HBbaG*7baP2lVM$YTGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?%x zUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0 zQ(;L{bTn{bX>v(RQ*%=_UqwYlMMW_%WMyG&Y;R*>bY(?SQ$$}-Q$t^E0AE^8Q*<#f zUr1$PWM5)ob7e_PZ81e!PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ!-ykQ*%=_UsH56 zY-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlN<~FQP*h(;a8Fb)Uqw}HP*X%-MPE!} zFhxZ-Urk?VWnpARQd3M{0AE^8OF3U(XKr<0V|aKmH(y_FZ*py6Y+q?~WpZJ3Z*oac zV^efCc4cF9Z*oavQ(;MCMMXt4VqtS-MRovRT251RF*aXQa9?9@b#8QJWM5)ob7e_P zPB~v+XKr<0V|aKmGG9z@V{2b?_BVRUbDNmFz*aA9e3NlR06PB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GhZ<@VPtGyb7gXAVQgu7 zWpYJDMMXtyMRrnDUsNz(Q*<&mVrgV)a%E$5X>V>}Y+q?~WpZJ3Z*pIBVP^neT251R zF*RRbb#7^KUvPACUukV{Y)MmeGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?%x zUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0 zQ(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N>WQxLtjNjMNm{mPE%n?Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{ zG+#wUMMN@1b^u>mPB?CCZ)j~{Zf-VYWprU_Y&C3Ucx7@)PE%hoFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_%XJvF> zb98cPZf8Yy0AE^8IBsljXl-F`ZZ>3PbYW?1F*#~;Z*E_6VR&C;Z*5<2VRCb2a!F28 zUokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~ zX?kUHMMXtLF*0ajZe(m_Uv^<^b!ACTQ!rmQc42IFWnXkfMMY3kHeXLvUjScPPE&L- zF<(@5aBO8?X>D+9Nla}pMM_Xpb6QR~ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+WN>WQx zb45i(P*h(;a8Fb)Uqw}HQ!rmeUqwYjF-cNWFkebiOH)Q)MRr9+Pg6l(Q$=3@Us_H} zQ*$_DVQ^t%X>@r-c0fQ!Oi4mRSXf^(E;ImNT244_Y;S07VQy|VWMy<=X>2h$YIARH zUvpu2Uu17>UvOb^b7gW#PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_+Zgp*9WpZD2ZgXj8Ze?UeZ2(_dPE&L? zc4cF9Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMXq1MRovRT244_Y;S07VQy|VWMy<=X>2ku zWq5RDa&BR4Ut@1>b98cbV{~tFNlZ>tFkd%zVQh6}Uvxz_MMXJdZ*FsRa&=>LNlsH= zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+> zdS!A&MMXtLc2ZPdPE$c&F*j~?ZDM6|Uv+MCX=iR_WM6be0AE^8IBsljXl-F`ZZ>3P zbYW?1GB9v*X>DnAX?A5_X>?_BVRUbDUvxt;MRovRT244_Y;S07VQy|VWMy<=X>2uY zWq4(BNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_H zUvp)0X<=+>dS!A&MMXt1H)myZUu0!tX>DO_UvO_}ZgfR<0AE^8OH*_)IA20(bYE$7 zWpZJ3Z*pH^VRL0=aYa%~Q(pjIT251RIA2m?UvzS1Wl2+WQ*<Qa!E^5 zb51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABMMXq0MRovRT244_Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJD zX?RIXV?{+$Q#4;tR9^sJT251RF*09PWn*-2a$jO$b7e_Wb5mhSQ*%W{F*9FHUu0!r zY;131VRU6hP*Zbl0AE^8Q*<#hUsh#fbZ>HBVqtS-NlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC# zNmDgnMMW_(Ush#fbZ>HBX>D+9Lor2COH(#q0AE^8Q*<_VWn*-2a!F1&ZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z& zQ(;L{G+#wULo!8n0AE^DbTTquUv+M2ZfSIBVQgu7Wn^DtZ*X~EVM$YTF*9v%c4c2_ zbY*g3bZ>G=P-8_?F<)avR4`vuUsE(+Q!`&uQ(;L|F<(UhUs_HvGDUK7Z*omxZeeF- zaxpefb#!obbVYJ zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Zp zV{&C-bY)3XGG9qkG+$F;NmDdmMMX+dOH(&rMMXtWR9{4JPgF2p0AE^8Q*<rUs_H$ZftL8ZDDS1He_XVVQFkOaA9(DWpYVQQ(rMK zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIB zaz#Z&MLB0>bYFCDYh`Xlb^u>mPE&L;Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL! zY;S07VQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0 zUt@T9F*09FZ)0m;aBpmBV|hg~MMX7VNo{a!Lo!8EGhYB-T251RF)(#*X>oOBUvPAC zNmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^I zQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMYXpQ#D^UV{&C-bY)3XH(yFcMMY3l zUqov zG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABQ*<#fUsGjlWn*+Pb96~l zG+#wibTn*bb8|^kb462ONmDdmMMW_*Urk?WZgXXFbYE_7WMxHAQ*<#nUs7UUbaG{7 zUv6(?WnW@pb7fOQUrvHg;uWbZ>G=Q*%>cNmFx0MMXm~MN&&sGG72+ zT24z-bTKnuLTPkgX>?_BVRUbDWMxHm0AE^8IBsljXl-F`ZZ>3PbYW?1HgI8bb7gW# zPE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXA zVQgu7WpYJDMMXq1MRovRT24zjUtec#bzft6cri0>Wp`g;Y;131VRUbDNn=GgZDDv{ zb7^{IMRovRT247%UuSN0Ut@T9Ze>YOQ*%>vHg;uWbZ>G=Q*%>cNmFx0MMXtoQcF%# zUokgdUv6)5ZDDL*X>?_BVRUbDNmO4{FkeMQQ$b$5XBMMXn0 zNlH_5MNDEbMMXtKa8FcU0AE^DbT?*ia(7{JWJyv>T244_Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{ zWnpw>NmDXkNmFxEHD6P7G;C#ab4gQkMN?r(Q*<aA9(DWpYVQQ(rMKVqtS> zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z& zMKLgCZe(9?Vrpe$bVYUmUs_I6bTKerNM&JUUt(c%Wl2nJF-2NVIBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIB zaz#ZpV{&C-bY)3XGhazlHD6OG=P*ZbL zbT)QnV{~tFNmFxEVM$YSMMXtJGDT8LQ!!rvUs_I6bTKeHBbYW)z zUs_H$ZftL8ZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m-V{2bQa!E^SQ*%W{MMN=0b^u>mPE&L=aA9e3Nl;UCF*sjRVqbJ}Wo2J(Z)9a(VqtS- zQ!!sfLo!KHQ!!smVlhQUMN&&sF<(zqUjScPPE&LvG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKerQ)O&r zV{|cdbV*Y zV_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJD zMN?r(Q#D^jMME-0ZBk29HeUc=T247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGy zb7gXAVQgu7WpYJDMMXJdZ*FsRa&=>LNmDjoN>XA)MMZW{R9{4JPgF2p0AE^8OH*_< zc4cF9Z*oavQ(;MCMMXGmVR&D2X?kTvb^u>mPE&L-GjerqbZKp6UuAM~Z*oI1MN&&s zUjScPPE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#f zUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMXGYQ(tmvXJ~XqP)k#EF*sjR zVqbJ}Wo2J(Z)9a(VqtS-0AE^8Q*<#hUsh#fbZ>HBVqtS-NlrL!Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A& zMMYC#NmDgnMMXm~MQu_`Q#M}!Us_I6bTKwzY;131VRUbDUvzR|X>@Z*Q(;L^PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGy zb7gXAVQgu7WpYJDMMXt7WMy-7a&LJ_Q#M~kMRrnCH(yXxUjScPQ*=3WZ(nnCa%pa7 zX#ihZPD@jCIbvaRX=7h$Z*xgwQ*<#gV`yP=UvzR|X>@Z*V?{+ba%6LKVRU6hc0fQ! zOi4mRSXf^(E;ImNT2pi}Ghbh0Z*X~EZEtpEUtvj1VlYKeZBsB`MN~0gR4`vtGG9|M zUjScPPE&L-GGA6@V{~tFUt(c%Wl2y@IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mT zQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HeW?WL^4Ho z0AE^8IBsljXl-F`ZZ>3PbYW?1GB9v*X>DnAX?A5_X>?_BVRUbDUvzMAMRovRT244_ zY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGy zb7gXAVQgu7WpYJDLo!KHVq#2bFhxa0PgGw3Us_XiGc;dcb#7^HX>@5}Y-xIBWM6G> zc4c2_W?yb^Wq4y{aCBc`Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZHeXX=NmDgnMMYFFUsPXH zIbTyaUs6;tUjScPQ*<+DWpqhQZ7@YjP*Zd^c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgn zMMYXpQ#D^UV{&C-bY)3XH(yFcMMY3lUqo0{bV*oLUqw@NHFR}wY-LGGL~v6>UqwYlG<11zWkpg;Q%YX|Us_I6bTKhs zRCRD{WnXD+aBN9TZ7@YjP*ZbSPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q

Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2 zMMY3lUqoWQxMqfpCMMY0jL0?lvUjScPPE&L? zc4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ(seaVr*?>Q(;b1Fkdk= zVPtGyb7gXAVQgu7WpYJDMN?r(Q#4;iMKLyCRAp^&Z*pOBd0%#6Y;|QeUrk?dbaF*@ z0AE^DbT?sSc42N~Wl2ssUtec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;EWZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_ za%o{~X?kUHMMXtZHD5_nH(yg>NmDmpMMXtLX+?HYR9{puUjScPPE&L-Fm-Neadl;1 zaCCA>Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzFke%1Vr*?> zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc%HD5Mka%Ew3Wl2*vUrI$q zMNm{b97&6bY*g3 zbZ>G=Q*<2hwX>M?JbYEd)VQ_S1azipjQd4OFUs_I6bU0s9VqbJ}Wo1cI zb5nFQaA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8@bTKerQ)O&rV{|cd zbV*Y*Uqw@NG;C#ab4gQkMN?r(Q#4;iML1tmUv^<^b!A0ROH*_)IA2m?UvzS1WnXS@ zWMyAsVRK~wUs_H%Utec#bzft6cx`D(P*6@dZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZG+#+mH(yg> zNmDmpMMXtLPE%hoH(y_FZ*py6Y+q?~WpZJ3Z*oagUsNz(MKLvGX=Y|+a%FB~WnXl8 zaAieOOH)N(Q%GL`Us_I6b750OQcF{FKtM-KNkT(dSYI(PB?CCZ)j~{Zf-VY zWprU_Y&mIkWpZC>ZE$Q!PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXm~MN&&sH(vl>T2pj0XJvFrOl>hmN>EdC zT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sL zG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4JPgF2pMOAE5FkeMq zMMY9hQ*<#ibailSWnX1%Wo>0{bV*oLUqw@NHFR}wY-LGGL~v6>UqwYlG<11zWkpg` zN?!n9T251RF*adrY;R*>bZ>HBbaG*7baP2lVM$YSMMXGmVR&D2X?kTvQcF`XUjScP zPE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjl zWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMXDXOiOH)N(0AE^8Q*<&g zUs7UUbaG{7Uu$J~Ut@1=aA9&~NmFz*Y-MwENmFx0MME(~QcF`YUjScPPE&L-G+#n# zbYF61W@U0^ZewLbGDT2rZ2(_dPD@jCF*a##X>@5}Y-xIBa$js|b96~*MKfh?WJPuW zUteQ*VP9c%Wq4_HKtM-KNkT(kGA=SMH2_~)PB~v+XKr<0V|aKmGj3&fUtw%)Z)0I} zZ*oafb45ckMN&&sF<$^*T251RF)?3Mb#QEDUukV{Y)MRQFhxpGQ*<+JVQ@)Pb51yJ zY;S07VQy|QFk)eIX=7h%b8l`*Q!rmsbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_ za%o{~X?kUHMMXtZbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMYXpQ#D^UV{&C- zbY)3XLtjc#OH)H%MMXtWR9{4JPgF2pMOAE5L|;W;MMXDXOQa!E^SQ*%XAbTKerQ)O&rV{|cd zbV*Y(Uqw@NG;C#ab4hANQ(;L{GG9eSL@`Bn0AE^8IbUCAZgpQ{cz7{4Utex-a&2L3 zUukq@a$$6Da!F85IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+ zY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#M~yVM$XqUqwYlLo!8n0AE^8 zQ*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#p zUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{G+#wUF*ILIUuJ1+Y+q?^b7gXLMNTG=P*XHtQ#M~kMQu_`Q#4-yUs_I6bTKhsRCRD{ zWnXD+aBN9TZ81ekT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{< zL~u`3FkeMgY*15kMPEflLo!8DOH)T*0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5 zb51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yM zG+|_HUvp)0X<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*YnQ*<&haA{>@Wp`Q!!sfMN>*&NlHaUMMXt+P*ZdG~bTKktNpEvsNpEv>VRU6vUjScPPB?CCZ)j~{Zf-VYWprU_Y%wu# zVRCb2UuAM~Z*oI1MQLqNOJe|ET2pj0XJvFrOl>hmN>EdDGi_mTNmFx9IBsljXl-F` zZZR-oVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7 zWpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~# zN>WQxLtjNjMNm{vG;m>Q za!E^5b5nCgQ*<#fUsGjlWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMXGYOmPE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B= zYIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtL zQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMW_)Urk?QY;SI5Uv6(? zWl2s`MPD&7UqNhaZ)0C>Z)9afMMY3kbTKnuQet0pa%E*-Zf|5|NmDpqMNmsqNncV_ zUjScPPB?CCZ)j~{Zf-VYWprU_Y%w-zZgyd8X=Gn%bY*g3bZ>GtV{&C-bY(?pQcF{F z0AE^8Q*<#kUteKtY;R*>bY)~;aCCA>Q(;L{bTTtvQ*d8nZ*^{TWn^D)baG#5Zg6a2 zV`WKBIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJRVM$XnUqwt# zIbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2MMXq1MRovRT2pjzY)NBNbTKhwXkl_+ zbaG*7baP2#MN?r(V?{+%Vo6kAR4`vuF<(VbQ#M~vOH(sn0AE^8OF3U(XKr<0V|aKm zGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR)|b45i(IBj8g zUvp`CWkq%XUs_I6VM$YTHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#004mhe@Rm`UqwYlL@`Bn z0AE^8F)~GRa&K}?VQyh(WpX)1a&m8SNp5CuLo!8n0AE^8Q*=0AQet0pa%E*nYEyJH zaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYWUrk?S zZe&Gv0AE^8IBsljXl-F`ZZ>3PbYW?1F)(y_aAjX*a&m8SL@-5m0AE^8Q*<#iUqWeg zUukq@a$$6Da&1XPYye+cQ*>@+NmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mE zOH*@2MMY3lUqoZfS9KWnXY~a!FG;UsNz(MMQ1@ zUs_I6bU9^sV`Xr3X>V>rF-3L&Us_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNmFx0 zIb&~bb98cbV{}PVb4pT6Q*%W{MRrhBUqo2huaA9(DWnX1-a&K}rV{&C-bY(?pQcF%#Fkdk+ zaBp*IbZKvHUvx!MOH*?IUs_H%Utec#bzft6cy47$P);~*Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCI zUrAFoUsGX8Q#M~kMMXtoQcF%#UokgdUv6)5ZDDL*X>?_BVRUbDNmO4{FkeMQQ$}9^ zUs_XiH)d~gcVTj5Nm5W#b45>7Us6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ!-ygG<11z zWkmpAT251RF)?3Mb#QEDUukV{Y)MRQFhxpFQ*%W{Lo!KIb45i@R9^sJT251RIA2m? zUvzS1Wl2+WQ*<`cD zQ#fBmQ*<N06a&$>b zL~cbzMRra(Utec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;TXUsE<;MMXq#PgGw3 zUs_I6bTKktR%K&!Z*pH^VRL0kP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDjoMMW_&Urk?O zY;131VRU6hZ2(_dPE&L-GGA6@V{~tFUt(c%Wl2+WQ(;L{b45ilIbTg*XJvF>RB&Hm zY;131VRUbDMRovRT24z-bTKe>ZfS9KWnXY~a!FHkGi_mTNmFx9IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJD zMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N<~FQ zP*h(;a8Fb)Uqw}HP*X!+MPEfTXJvFnb^u>mPD@jCF)&|KWo%_*bTM;uNmFz*aA9e3 zNlR06Q*%W{V{AoIOH(pm0AE^8F)~GRa&K}?VQyh(WpX)1a&m8SNp5CuL@`Bn0AE^D zbTKktUu|i0WpZC)VRL0kP*Zb7R9{muUjScPPE%n?Q*<+JVQ@)Pb51yJY;S07VQy|Q zFk)eIX=7h%b8l`*Q(sebHg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A& zMMYC|G;C#ab4gQkMN?r(Q*<G= zPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0 zX<=+>dS!A&MMYC#NmDdmMMW_;Urk?fWnpY=Z)0C+ZgXXFbV*85ZAC>zc1}58UuSN0 zUt@T9F*jddZf|mJVQgP%bY*g3bZ>G=P*XHtQ#M~kMMQ8V{FUrS>}MMY3l zUqomPB?CCZ)j~{Zf-F&VPtGyb7gXAVQgu7 zWpYVuc11UIZ(nM2Z*ECWQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8q zQ(;puUqwYyY(+&xRAX&pY)oHTPE%hoGG9kbPeMUVUtdmNF*kH?Uutu2Zbe0Aa9?9= zH)d~gcVTj5NmMXjMP_g?UqwY@c6MJyMN(8>Pg6Nx0AE^DbTTquUt@1@d0%aBc4c2; zVPk7|VRB?&VM$D4Fhx^zF*9F6X>?y{bY*g3bZ>G~FkeMfF<(?LUsEz)Q!!rvUs_I6 zbTKerNM&JUUt(c%Wl2nJFhx>JYD{7MtBX<=+>dSzr^ZEtpEUukAvZf|9HV`Xr3 zUtvj5P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ!rmKG+|_HUvp)0X<=+>dS!A&MMYCLUsGX8Q#M~kMN}|fR9{m;UsE|>QdBWt0AE^8 zIBsljXl-F`ZZ>3PbYW?1GBRmyaCLNFVPs)&bY*g1aB^>SZ)0z4L@`Bn0AE^DbTK$} zZfS05bZKF1X?kU3Ut@1@c}Y-Hb5k&1MN}|fR9{mvUsEw(0AE^8IBsljXl-F`ZZ>3P zbYW?1GB|2;Z*E_6VR&C;Z*5;=VQg$-VPk7waA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLmHVQyq> zWnXq-Y;|QxQd4t9MN@P%aA9e3Nn%h_HeW?gR9|8MUs_HwXJs)nQ*>c;b#q2xV{~tF zc`-0YWpqVyaztfwV?}BJUs_I6bU0>pZew(5Z*ECOVrfn|ZftL8ZDDS1He_XVVQFkO zaA9(DWpYVQQ!rmKFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MMXt1GjL&Yb7fy;c4cmKUvx!MQ#W5lMMN=0b^u>mPE&L; zFkfF|Z*X~EZEtpEUt(cnYj?_B zVRUbDUvyz-MKLp9Ut@1@d0%aBc4c2;Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#{qF*IRhY+rL_a%o{~X?kUHMMXtZIbTIZR4`vu zUsFO~Q$b$bZ>G=Q*<&jUsG^jV{dhC zbY)~;aCCBCX>M?AVPj=UPB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)& zbY*fyQ(;L{G+#wbPE%hoGG9z@V{2bQ(;b1F<&t>VPtGyb7gXAVQgu7 zWpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~# zN>WQxLtjNjMNm{mPE&L-FkeVzVPs!o zVRL0kOl>elPg8SDVlYKTH(yO(Xk}q!MN(5SUjScPPD@jCHg;uWbZ>G=PB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A& zMMYC#NmDdmMMXGmVR&D2X?kTvb^u>mPD@jCF*9v%c4c2_bY*g3bZ>G=P-8_jVqtS- zMRovRT24zjUtec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;5;Q*<_VWn*-2a!F%T zVM${}MMY#~MRovRT244_Y;S07VQy|VWMy<=X>2hzX>N95Y-wa)X>?_BVRUbDL^4Ho z0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKer zQ)O&rV{|cdbV*YV_#}>Z*ECbbTe&Xa8q zQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ!`&lQ#D^xVM$XpUqwYqQcF`f zUqwYlP*h(;a8Fb)Uqw}HP*XTxMPEfvQ$k--PE&L-HgaWcZ+2y0a%E;^a%FB~Wl2*) zUqv)@d2nS#0AE^8Q*$vhUsGRWZ*X~EV`yP=b45^NQ(seGKtM-KNkT(dSYI( zPB?CCZ)j~{Zf-VYWprU_Y%wr!Z*ysMX>V>{bVD&kb^u>mQ*<`cDQ#fBmQ*<elN>WQ| zMMXm~MNd;QUjScPPE&L^Us7UUbaG{7NorGcG;m>Qa!E^SQ*%XAbTKerQ)O&rV{|cd zbV*Y(Uqw@NG;C#ab4hANQ(;L{GG9eSF*jdLUt@1>b98cbV{~6`Z)9ajN>WQxbTTn; zX=P(&cWHBFUt@1>b98cbV{~71Q*vF<(VRQ$$}$N<~FQMMZW{Q*<#i zUs7UUbaG{7Uv6(?Wl2*qUqwW4PgGw3Us_I6bTKerNM&JUUt(c%Wl2nJF-2NVIBslj zXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^ zWpZg@Y-xIBaz#ZpV{&C-bY)3XGG9qkb5k{6Q*<Qa!E^5 zb5k{6MMXtQQcF`rUqwYlP*h(;a8Fb)Uqw}HP*X%-MPE!}FhxZ}F-1~KQ%zq0Us_Xi zG-GdYc}Y`rF*#pCX>?y>Z*FsRUukq@a$$6Da#M6MGhae!bYE$7WpZJ3Z*oOcFke(( zQ!`&vGG72+T24zjUtec#bzft6cri0>Wp`g;Y;131VRUbDNmFz)ZDDXpQ*%x@ZftL8 zZDDS1F)(6bb7^B=YIARHNmDUjQ*<_VWn*-2a#M3+Y;9yyVNO#rUokXcWNcq^WpZg@ zY-xIBaz#Z&Q*<Qa!E^5b5k~7MMXtLIBj8gUvp`CWkq%X zUs_I6bTKktUvp?-a%E&+aCCA>PB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb! zVPs)&bY*fyOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXn0NmF4-Q!-ygN>Wp4 zMMXtZbTK(!Q*d8xVQXbyb7*05Wn^D;VP{fHR9{4JPgF2p0AE^8Q*<bZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXq0MRovRT251RIA2m?UvzS1Wl2+WQ*<b98cbV{~6`Z)9ajN>eajNmFxEb45i(MRrhAbTKnuQet0pa%E*-Zf|5|NmDXk zMMQ83PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYIT zUs_I6VM%R8Lo!8n0AE^8Q*<#mUs7UUbaG{7Uukq@a$$6Da!FHkG;m>Qa!E^SQ*%W{ zZEZz%0AE^8Q*nYDGmuF-dkzVlhQUMN=_f0AE^8IBsljXl-F`ZZ>3P zbYW?1F)?p+Xk~I=WpZ+FayDafWnpw>MQKt?Q*!`cT251RG;m>Qa!F8AbTK$zQet0p za%E*-Zf|5|Ut(c%Wm7R(PB~v+XKr<0V|aKmHeX+1 zY-wk1Wn^D%Wo=@0W=T_YG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YAB zMK@nfUtwfqaz%CkUs_XiGiPOVNla}pMM_XpbT)QnV{~tFNlrL!Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{ zHD5(VT250nUp8ZMWnpw>NmDmpN>WQxH(y0XMNm{?_BVRUbDNmFz*aA9e3NlR06PB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7 zWpYJDMMXt1Gha<#V{dMAbYEj(b96;^0AE^8Q*<#lVQg$~V_|e}a$j_EVQF-8NmF4- zQ*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^SQ*%W{MMW_%WMyG&Y;R*>bY(?SQ#D^u zQ#4;~0AE^8Q*<#iUqWegUukq@a$$6Da&SyVYye+cPB?CCZ)j~{Zf-VYWprU_Y&C3U zcx7@)PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGy zb7gXAVQgu7WpYJDMMXq0MRovRT24ziZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MK@<CH)LgFY<6L6 zNmO4&MMXt+0AE^8IbUCAZgpQ{cz7{3UteKtX=iR_WM5)+W@cq_NlrL!Y;S07VQy|V zWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMMXAWOV_#}>Z*ECbbTe&Xa8q

Q(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;u zNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YH(ygUvzS1WnXD@WpZJ3Z*oafbTn{bX>v(RYEyGXMP+eCQcF`a zUjScPPE&L;Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07VQy|VWMy<=X>2ku zX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9F*09FZ)0m;aBpmB zV|hg~MMW_*Urk?UWprO;Wo%`1WpYJQOH*_?ba`-PUukY;ZvbCfPE&L-HeqaRZ)0I} zZ*pIBa$#w7b4gQSNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXtLGdFW(Y-M9~UvF+-V{dMBVQFq< za$jR_aCu*2Z*FsRa&=>LX>V>tQcF`dUjScPPE&L-Gi`5nWnXD@WpZJ3Z*oacPB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGy zb7gXAVQgu7WpYJDMMXn0MN>9k0AE^8OE_+9Z)j~{Zf-VYWprU_Y&C3Ucx7@)PE%ho zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7 zWpYJDMMW_(XJvF>aBp*IbZKvHMRovRT251RHg;uWbZ>G=P);~*Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$Xp zUqwYjF-3L&Us_XiG-GdYc}Y-Hb5k&1MN}|fR9{mvUsEw(0AE^8IBsljXl-F`ZZ>3P zbYW?1Ic0cbWpH$9Z*D{}MRovRT23)CMRIa)a!p}wVP|D>IYn}EZ*oa)W^Y3>MN&&s zFkb*)T251RGi_mTNmFxEb5nFQY-MwENmFx0Q(;L{bTn{bX>v(RQ*%>uMMXtJF-3L& zUs_H$ZftL8ZDDS1He_XVVQFkJIcjrnZeMd@cwc01ZC`LdS!A&MMXt9 zWo~3&VRCX|c|~>rUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNl;EWZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~ zX?kUHMMXtLF)(ChVQg$~V_|eG=P-8_y zGDTA`UjScPPD@jCGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&LQ*<_VWn*-2 za#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Q za!E^5b5k^5MMXt8Yh`&~V{dJ6MRovRT2pi~GGAYHZfS05bZKF1X?kU3Ut@1@d0$~k zPB~v+XKr<0V|aKmH(y_FZ*py6Y+q?~WpZJ3Z*oacOH*@GbT)QnV{~tFNmFxEVM$YS zMMXtLP*ZbLb464zUsPXHL0?ljUs6+HNmMakMF3w~PE&L-HeqaRZ)0I}Z*pIBa$#w7 zb4gQSNmFx0MK@$+b98cVc}Y`qMMZW}Q!rmpR9^sJT251RF*9F6c4cF9Z*pH^VRL0k zQ(;MBMMW_)UqW_eV{~tFUukV{Y(p|db^u>mPE&L-GjerqbZKp6UuAM~Z*oL2MRq_y zM@&gVLs(c}GcGg$Us_XiIA26%b98cVc}Y`qMRrhBUjScPPB?CCZ)j~{Zf-VYWprU_ zY%(xqcywiQZeeU+V{dMAbaHiLbZ>G=OioiUUpIDPY;|Q{bVWBsMLA<{ZgX^Ubz^i% zPE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXA zVQgu7WpYJDMMXt+QdD0~Q$b%bG;VcmVr6n)W^8X^bYFBu0AE^8Q*<#jUte=*VRB_; zUt@1|ZgfdZPB~v+XKr<0V|aKmGG9z@V{2bmPB~v+XKr<0 zV|aKmGj3&fUtw%)Z)0I}Z*oaaIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVw zWMOc0WpYJDLor2m0AE^8Q*<#jUsG^jWnyn%Xk~10WpYVOX)r}oVM$InZftL8ZDDS1 zHe_XVVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1az#ZV_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ!`&lQ#D^xVM$XpUqwYq zMMXtWR9{4JPgF2pMOAE2Q#fBmUrb^!MMXDXOpZew(5Z*ECOVrfn| zZftL8ZDDS1He_XVVQFkOaA9(DWpYVQQ!rmKFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXt1GjL&Yb7fy;c4cmKUvx!M zQ#W5lMPqD5X;V30Q$b$dS!A&MMYC#NmDgnMMYXpQ#D^UV{&C-bY)3XH(yFpOH(&rMMXtWR9{4JPgF2p zMOAE5IA29yMMXDXOQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMMN=0b^u>mPB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^ zWpZg@Y-xIBaz#ZkFluveZeMm`Y;|QrF-2kkUs_I6bT)QnV{~tFNmFxEVM$YSMMW_; zUrk?fWnpY=Z)0C+ZgXXFbV*86b45i(c1}58UuSN0Ut@T9F*jddZf|mJVQgP%bY*g3 zbZ>G=P*ZbLF<(VRL~u`3UjScPPE&L-H(yd>UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(R zQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^p zF*IRhY+rL_a%o{~X?kUHMMXtLMR0IMb^u>mPB?CCZ)j~{Zf-F&VPtGyb7gXAVQgu7 zWpYVVb9O~JW^!+BUutu2Zb?#0PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^NFkeMQQ*%W{L{wvKV{A-cT2516F*09AOiw~VOkZD4Uokmma&K*4YIARH zMMYz5H)d~gcVTj5NmO4&W^i9cW^gcHMPqh$UqwYvQ$b%+R4`uvUs_I6bTe&Xa7j~h zQ*%>vG;C#ab4gQkMN?r(Q*<m zPE&L-HeXY4Ut@1|Zggd2Ut(c%Wl2mG=R9{5^Us_XiF)&|4Z*FsRa&=>LNmFx5Qd4t9MRrhBUqoQa!E^5b51yJY;S07VQy|Q zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+> zdS!A&MMXtLaCAj>0AE^DbTK$zQet0pa%E*-WMyM=Wo>0{bWl@tF*sjRVqbJ}Wo2J( zZ)9a(VqtS-KtM-KNkT(dSYI(PE&7eb45@_Qd4hJUqwJbM@&gVLs(c}GcGg$ zUs_XiH)d~gcVTj5Nm5Hwb45>7Us6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ!-ygG<11z zWkmpAT251RF*sjBX>?y{bY*g3bZ>HBVqtS-F*09GUt)D_a9?C^cWy;?0AE^8Q*<_V zWn*-2a!FHjQ(;L{b45i%GDT8LQ!!rvUs_XiH)d~gcVTj5Nm5H%PB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7 zWpYJDHe+&SVRU6lQ*%mEK`~!TV?{+pP*h(;a8Fb)Uqw}HP*Zb7Uqw$-L0?i%Q*<#l za%F9Ac4c33WoBh^Wo~0-NmD^zMKpAIaAidRUs_H}Q*<#lX>MtBX<=+>dS!B7Y-w|J zNohqjVr6G(ZbfzgUs_H$ZftL8ZDDS1He_XVVQFkJIcjrnZeMd@cwc01ZC`LdS!A&MMXt3Yh`&wQd4sPUs_H}Q*<_VWn*-2a!F%TVM${}MKfh?WJPuWUs_I6 zbTKerNM&JUUt(c%Wl2nJFhx*Pb4+3|MMXDXOoOBUvPACNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mE zK`~!TV?{+pP*h(;a8Fb)Uqw}HP*Zb7Uqv@^Wo%_(b7e(#0AE^8OH*_*Ghb3-UvzS1 zWnW`&ZgX^BX>?_BVRUbDNmFz*aA9e3NlR06Q*%W{WpPDPOH(sn0AE^8Q*NmDmpN>WQx zH(y0XMNm{V>{VqtS-Lo!8n0AE^8 zOH*_)IbUCMXkl_?WM6P}a$jL%V`X!5NlrL!Y;S07VQy|VWMy<=X>2kwX>M?JbYEd) zVQ_S1a$j(AZ**^CZ)`MRovRT2xb0bTK(!Q*d8xVQXbyb7*05Wn^D;VP^neT244_Y;S07VQy|V zWMy<=X>2hwX>M?JbYEd)VQ_S1azrsjb^u>mQ*<&iUte`@X>MtBX<=+>dSzr^V{dSI zUtvj8bTKn+Z+2y0X>?_BVRUbDNl;UBMN=_fQ*%XBFke((Q#4;wGhb3uVM$amUqt|4 zT247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Q za!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ#4;OG+|_HUvp)0X<=+>dS!A&MMXtLMME-0b^u>mPE&L^Us7UUbaG{7NmFxEbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^k zb462ONmDpqMMXGYOmPD@jCF)(#*X>oOBUvPACNmFz)ZDDXpQ*%x@ zZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^ zWpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k{6MMXtgPE$2sHe+&S zVRU6lQ$t@$QcF`qUqwYlP*h(;a8Fb)Uqw}HP*X!+MPEf@c49?#0AE^8IBsljXl-F` zZZ>3PbYW?1H*{}bYIARHNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMYvvX)r}aMRrnDUsNz(0AE^DbTn;mc4bLY zV?|F+Q*<#la%F9Ac4c33WoBh^Wo~0-NmO4&G<11zWkpX@GG72+T251RF)(#*X>oOB zUvPACNmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+ zY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5 zb5k{6MMXtgPE$2sHe+&SVRU6lQ$t@$MMXtWR9{4JPgF2pMOAE2Q$t@xUqwSPMN>*& zQcF`yUjScPPE&L=aA9e3Nn%h=IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MME-4Vnl9CVlhQUMNd>; zPgF2p0AE^8Q*<#fb#7^Kb!A_0baF{kbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(V zT250nUp8ZMWnpw>NmDmpN<~FQP*h(;a8Fb)Uqw}HP*XQwMPEfkGDUU(Us_H$ZftL8 zZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m-V{2bbZ>HBbaG*7baP2lVM${}ML2C?cwcjAdSyjYOH(jk0AE^D zbZ%uyQ*<+JVQ@)Pb51yJY;S07VQy|QFk)eIX=7h%b8l`*Q!rmsbT)QnV{~tFQ*&Z$ zZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZbTn*bb8|^kb462ONmFz*aA9e3NlR06 zQ#D^jMMYXpQ#D^UV{&C-bY)3XLtjc#OH)H%MMXtWR9{4JPgF2pMOAE2Q$t@xUqxb4 zOH*_)Fm-Neadl;1aCCA>Q%7G^FkeMPZUA3ePE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQS zNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#{qF*IRhY+rL_a%o{~X?kUHMMXtLMMXt8 zVQg$~V_|e?_BVRUbDNl;KuIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2 za#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#W5zVM$XrUqwYlZD~bp z0AE^8OH*_*Ghb3-UvzS1WnW`&ZgX^BX>?_BVRUbDNmFz*aA9e3NlR06Q*%W{aCAj> z0AE^8Q*<#iZEtpEUukq@a$$6Da!F8Ab45cjMN=?e0AE^8Q*<hmN>EdDHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwY)PE$2s zHe+&SVRU6lQ#W5qMMXtWR9{4JPgF2pMOAE5IA29yMMY9hQ*<#ibailSWnX1%Wo>0{ zbV*oLUqw@NHFR}wY-LGGL~v6>UqwYlG<11zWkpg`N?!n9T2pi~Fm-NeZfSIBVQgu7 zWn^DwX>4p?Zb?v1IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+ zY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&ZBsR0MO0r?H(yjRUs6j{F<$^*T2518 zNn=GsF-3MjKu1hTLPJV_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7 zWpYJDMN>3iNmDmpQ(;L{H(y0XMMYv#OHNZ?F*jddZf|mJVQgP%bY*g3bZ>G=R9{pu zUqwYzNM8V7T244_Y;S07VQy|VWMy<=X>2htba`-PUuAM~Z*oI1MN&&sF<$^*T251R zF)?3Mb#QEDUukV{Y)MRQFhxpIOH*@2MME-0Q!!rvUs_I6VM$InZftL8ZDDS1He_XV zVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1az#Z$F-3L&Us_I6bTKhwXkl_+baG*7baP2# zMKfh@W<_=YUs_H%Utec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;EWZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~ zX?kUHMMXtZG+#+mHeXX=NmDjoMMXtJGDT8LQ#W4#Us_H%Utec#bzft6criC$Uv6)5 zZDDL*X>?_BVRUbDNl;@`bT)QnV{~tFNn=xCNn=GtMME(~QcF`YUjScPPB?CCZ)j~{ zZf-VYWprU_Y&LLVa&u*JNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMXtJF-1>PbTKeM?JbYEd)VQ_S1a$j(AZ**^CZ)`V>xMq+7BQ#W5RGjL&Yb7fy; zc4cmKUvx!MQ#M~kMPdM7T251RF)(#*X>oOBUvPACNmFz)ZDDXpQ*%x@ZftL8ZDDS1 zF)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIB zaz#Z&Q*<Qa!E^5b5k{6MMXtgPE$2sHe+&SVRU6lQ$t@$ zMMXtWR9{4JPgF2pMOAE2Q$t@xUqvx7XJvF>WMyn+bY*fyb^u>mPB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIB zaz#Z$GDT8LQ#4-yUs_I6bTKktR%K&!Z*pH^VRL0kV^d*CV?{+VIbTg*XJvF>RB&Hm zY;131VRUbDMRovRT251QHeqmZWo~3eQcF{FKtM-KNkT(dSYI(Q*<#hUtecs zbYEy?Y;a|ANla}qMOsccZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2*qUrAGQQ#D^xbTn*b zb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMX+QMMY3lUqofZV_#}>Z*ECbUsH58c4cF9Z*o&}Vr*?>Q(;b1Fkdk=VPtGyb7gXA zVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=^UqwYlX?R6XQ*!`cT2518 zNmFz(Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07VQy|VWMy<=X>2kuX>M?J zbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~ zMMXtKGDUU(Us_H$ZftL8ZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m-V{2b< zVRCb2a!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRh zY+rL_a%o{~X?kUHMMXtLL@`Bn0AE^8IbUCAZgpQ{cz7{0Ze@30VQg$~V_|e}a!GAP zF)(ChVQg$~V_|eM?AVPj=UPB?CC zZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{GG9eZPB~v+XKr<0 zV|aKmGG9z@V{2bmPE%n?P);~*Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXn0 zMRovRT247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+X zG;m>Qa!E^SQ*%W{MLA<{ZgX^Ubz^i%Q#4;nQcF{GGBI#zWn*P`X>(;?V{dMAbaHiL zbYFB+bTxE!aBO8sN>WoZUqwYzLSIQrMMXtLMRrhBUqo3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJRVM$XqUqwn%Q)xv-MN@P!IbTz7 zUu|J)WnXh>VRB_;Uvyz-P*h)1OH?plL~u`3F<$^gY;R{pa&m8SNp5asasXdiPB?CC zZ)j~{Zf-VYWprU_Y%wu#VRCb2UuAM~Z*oI1MN&&sF<$^*T247%UuSN0Ut@T9F*9yu zcVA&_Y;R*>bZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^SQ*%W{MME(~b^u>m zPE&L-GGA6@V{~tFUt(c%Wl2srZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwYRF<(tzVQg$~ zV_|e2kuWq5RDa&BR4Ut@1>b98cbV{~tFNlZ>t zFkd%zVQh6}Uvxz^MMXJdZ*FsRa&=>LNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMXtLc2ZPdPE$c&F*a^>ZDM6| zUukZ1WoKn_UvxzPUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNmFx0L@`Bn0AE^8 zQ*<#fUr1$PWM5)ob7e_PZ7@YrOH*@9VlYKTH(yO(Xk}q!MN(5TUjScPPB~v+XKr<0 zV|aKmGj3&fUtw%)Z)0I}Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q

Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXGaY;131VRU6hZBR>g z0AE^8OH*_>Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#f zUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMXDXOvG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKerQ)O&rV{|cd zbV*Y2kuaB^vFX>@6JWnXD@WpZJ3Z*pIBIdf%nUt(ovX>LV!0AE^8OH*_)Ghb3-UvzS1 zWnXS@WMxTHbTn{bX>v(RQ*%>uMMXJZO<#6lY;bgPMRovRT244_Y;S07VQy|VWMy<= zX>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIL@-5m0AE^8Q*<#hUsh#fbZ>HBVqtS-NlrL! zY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_H zUvp)0X<=+>dS!A&MMYC#NmDgnMMW_(Ush#fbZ>HBX>D+9L^4Ho0AE^8OH*_)Ghb3- zUvzS1WnXS@WMxTHbTn{bX>v(RYEyGXMLAzhUv^<^aCCA-b^u>mPE&L-HeqaRZ)0I} zZ*pIBa$#w7b4gQSNlrL!Y;S07VQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvI zMMXt7WMy-7a&LJ_Q!-ygMRrnCGha|tUjScUb97;2YhPn%YhPwzX>341M@&gVLtip3 zGyq>(PE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNlrL!Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXtLIb&~b zb98cbV{}PVHD5|ZZbd~!c2ZL|UrG=P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCIUrAFoUsGX8Q#M~kMMZE-MQi|H zT251RHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^I zQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMW_;Urk?fWnpY=Z)0C+ZgXXFbV*81 zQ!rmPWMy<=X>2!kVQh6}Uvx!9MMZW_IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6D za!F8AG+$FTUqwYka8FcU0AE^8IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82 zP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sL zG+|_HUvp)0X<=+>dS!A&MMYCIUrAFpUsGX8Q#W5lMMXm~MN&&sIbQ%@T247%UuSN0 zUt@T9F*9yucVA&_Y;R*>bZ>G=Q*%W)VQg$~V_|emR8vkkZftL8ZDDS1 zHe_XVVQFkRWq4y{aCB*JZbblJT251RF*9FMVqbJ}Wo2J(Z)9ajQ*<UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(RQ*%>uMMXtVR9{j~Q*<#la%F9A zc4c33WoBh^Wo~0-NmDgnMKpAIaAidRUukY>bO2vkPB~v+XKr<0V|aKmGj3&fUtw%) zZ)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9Z zMRIa)a!GDxZ$(8#MME-0b^u>mPD?poUuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=ZACb3 zVR&D2X?kTvb^u>mPE&L-HD6z0Y;131VRU6=UvPACNmF4-Q*<&jUsG^jV{dhCbY)~; zaCCBCX>M?AVPj=UPB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fy zQ(;L{GhanaPB~v+XKr<0V|aKmGG9z@V{2b zT251RIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#fUsGjlWn*+Pb96~lGG9egbTn*b zb8|^*MN?r(Q!-ygML1tmUv^<^b!A0ROH*_)Ghb3-UvzS1WnXS@WMxTHGG9diUs_I6 zbTKeoGB9awaCLNFb98cLVQpVwWMOc0WpYJ!MMY0jUrAJ7MF3w~PD?po zUuSN0Ut@T9F*jddZf|mJVQgP%bY*g3bZ>G=P)k#DQ*<_VWn*-2a!FHjQ(;L{b45i( zG-6?MWkq%XUs_HvGDUK7Z*omxZeeF-azrvkb^u>mQ*<#jUteQyaCu*CZ+2y0VKPZf zVlYKcIbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82Q*%>vHg;uWbZ>G=Q*%>c zNmFx0MMXtUQ!!sjP*ZbLHeW?WMN~0gR4`vtLSIusUjScPPB~v+XKr<0V|aLNX-QC1 zb5nFSc4cF9Z*oafb5mhSQ*%W{MMX|iUokgdUv6)5ZDDL*X>?_BVRUbDNmO4{FkeM6 zHDqaKW@U0^ZewL%ba`-PMN&&sIA2pjUjScPPE&L=aA9e3NmFz&H(yd>UvzS1WnXD@ zWpZJ3Z*oafUr9?-b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABMPfxmGD%Z4Ut&yR zF-1j1PgGw|R4`uvUs_I6b3-vjP)lP{OH*MdS!A&MME-0PE%htWMy<=X>2!kVQh6}UvxzPUs_H%Utec#bzft6cri0>Wp`g; zY;131VRUbDNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%>uMMXt7WMy-7a&LJ_ zQ#4;iMRrhBUjScPPD@jCHg;uWbZ>G=Q*%>cNmFx0MKxk&XK8Llb^u>mPE&L^Us7UU zbaG{7NorGcG;m>Qa!E^SQ*%XAbTKerQ)O&rV{|cdbV*Y(Uqw@NG;C#ab4hANQ(;L{ zGG9eSF*09GUu1G`a9?h3WMxHAQ*<#iUs7UUbaG{7Uv6(?Wl2*qUqt|4T251RF)(#* zX>oOBUvPACNmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rms zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMYXpQ#D^UV{&C-bY)3X zH(yFcMMY3lUqo2hvZ*_EEZ)RU|VQyz-MF3w~PE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNmFz& zGhb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#{qF*IRhY+rL_a%o{~X?kUHMMXtLMMXt8ZDDv{ zb7^{IMN&&sLSF!1T2pi}F<)O{WMpz>b8~NINlrL!Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXtWR9{k4 zHeUc=T251RF)?3Mb#QEDUukV{Y)MRQFhxpFQ*%W{Lo!8AQ!!rvUs_I6bTn{bX>v(R zYEyGXLo!K9Qd2NrMM_0QMN@P#F>q;RV`X<~b7fy+Z*FsRa&=>LUvyJ+HFR}wY-LGG zL~vAJMMYCJUr9elN>EdCT244_Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A& zMK)t{Wnpw>NmFx5QcF{FMMXtWR9{4JPgF2pMOAE5FkeMqMMY9ePE&L-Gjw%uY-L|% zY-Md_ZgfdlR9{6?bTxE!aBO8sNhm zN?J}hZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2*qUrAGQQ#D^xbTn*bb8|^kb462ONmFz* zaA9e3NlR06Q#D^jMMX+dOH)K&MMXtWR9{4JPgF2pMOAE2Q$$}yUqwYjF-1~KQ%zq0 zUs_I6bTKwzY;131VRUbDUvzR|X>@Z*Q(;L{bTKnuQet0pa%E*-Zf|5|NmFz*aA9e3 zNlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zGhZ<@VPtGyb7gXAVQgu7WpYJDMMXtLMLA<{ZgX^Ubz^i%Q#oHsQcF{GGBI#zWn*P` zX>(;?V{dMAbaHiLbYFB+bTxE!aBO8sN>WoYUqwYzNMA`xMMXtLMRrnCLSIl+UqoF)~tRVPr~kZ*E3uY-L4KOH*@Db^u>mPE&L-F<(@5aBO8?X>D+9Nla}p zMM_djYDGmuF-21`UjScPPE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNmFz-c4cF9Z*oaa zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0 zX<=+>dS!A&MMYC#NmDgnMMXtLH)LgVbaHQbNmDmpMMZW}Q#fBxR9^sJT24z-bT)Qn zV{~tFNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VG;?WsWkq%XUs_XiH)d~gcVTj5Nl;EWZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXtLPgGx0PE&L-HgaWcZ+2y0a%E;^a%FB~Wl2*vUqv)@d2nS#0AE^8 zQ*<UvzS1WnXD@ zWpZJ3Z*oafbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLMME-0b^u>mPD?poUuSN0 zUt@T9F*9yucVA&_Y;R*>bZ>G=Q*%W)ZDDv{b7^{IMRovRT247%UuSN0Ut@T9F*9yu zcVA&_Y;R*>bZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXJdZ*FsRa&=>LNmDjoN>WpEMMXt+ zP*h(;a8Fb)UjScPPE%n?Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b51yJY;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0 zX<=+>dS!A&MMXtLMMN@1b^u>mPE&L-HD6zKZfS8}aCCBCX>D+9NmFxLPB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXA zVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqov(RYEyGXQ*<#fUsGjlWn*+Pb96~l zGG9egbTn*bb8|^*MN?r(Q!-ygML1tmUvg<@XmmwTQ*<#nUs7UUbaG{7Uv6(?WnW@p zb7cTuT251RG;m>Qa!F8AbTK$zQet0pa%E*-Zf|5|Ut(c%Wm7R`cDQ#fBmQ*<`cDQ!-ygQ*<3PbYW?1GB|2;Z*E_6VR&C;Z*5;=VQg$-VPk7waA9(DWpYVQQ(rMKVqtS>V_#}> zZ*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MK*JE za%pa7MN(690AE^8Q*<_VWn*-2a!FHjQ(;L{b45inWo~3eb^u>mPD@jBG-P3PVMTU8 zKu1hTLPJMtBX<=+>dSzr^V{dSINlaoeMMW_)Ute`@ zX>MtBUt@1@c}Y$=Utec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;5ub5nFSc4cF9 zZ*oafb5mhSQ*%W{MMY3kb45i|Fke((Q$t@Qa!E^5 zb5k{6MMXtQQcF`rUqwYlP*h(;a8Fb)Uqw}HP*X%-MPEfvQ%7G?PE&L-HgaWcZ+2y0 za%E;^a%FB~Wl2*V_#`=baG{3ZAnyLR4`vfQ#W5yQ({R|G+$FSUsN$)MN>3i zKtM-KNkT(dSYI(PE&L;Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07 zVQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9 zF*09FZ)0m;aBpmBV|hg~MMW_%Urk?RWpi|LZ+S&_0AE^8Q*=0Hb#7yHX>V>xMq+7B zIBsljXl-F`ZZ>3PbYW?1HgI8bb7gW#PE#;nF)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLF*9&sa&u*0Wp-t5bYFBu zQd2iyMMXq1MRovRT251RIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#fUsGjlWn*+P zb96~lGG9egbTn*bb8|^*MN?r(Q!-ygMKfh?WJPuWUs_I6bTKerNM&JUUt(c%Wl2nJ zF-2NVIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#p zUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3Xb4pT6Q*%W{MNm{NWX>Da+WpZ+FazipjQcF``0AE^8 zQ*=0Hb#7yHX>V>xMq+7BIBsljXl-F`ZZ>3PbYW?1HgI8bb7gW#PE#;nF)(6bb7^B= zYIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtL zF*9&sa&u*0Wp-t5bYFBuQd2iyMMXn0MMQ1@Us_I6bTKerNM&JUUt(c%Wl2nJFhx*P zbTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbFke%2Hg;uWbZ>G~b7E|5WK&^I zQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<v zG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*YWp`g;Y;131VRUbD zNmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!!stb7E|5WK&^I zQ!-yMG+|_HUvp)0X<=+>dS!A&MMYC#NmDjoMMXt8ZDDv{b7^{IMRovRT251RF)(#* zX>oOBUvPACNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEK`~!TV?{+pP*h(; za8Fb)Uqw}HP*Zb7Uqvx7XJvF>WMyn+bY*fyb^u>mPE&L?c4cF9Z*oaaIBsljXl-F` zZZR-oVRLC?Uutu2Zb?&gGi_mTQ(seaVr*?>Q(;b1Fkdk=VPtGyb7gXAVQgu7WpYJD zMN?r(Q#4;iMMN@1b^u>mQ*<|GZ*q5Ga%4$UbTxE!aBO8sN>WQ|MMXtVR9{j~Q*<#l za%F9Ac4c33WoBh^Wo~0-NmDdmMKpAIaAidRUs_XiWpPPkMPgD*Q(;L|Uqw?hUjScP zQ*<#hUtex%bY*g1VqtS-Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZGhazlHD6OG=Q#oH$FkeMQ0AE^8OF3U(XKr<0 zV|aKmHeX+1Y-wk1Wn^D%Wo=@0W=T_YG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!`&NG+|_HUvp)0X<=+>dS!A&MMXtL zH(yO(VPs@-MRovRT24ziZftL8ZDDS1He_XVVQFkNY-M<5a!F28UokLZVRLC?Uutu2 zZb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMXtLF*#>t zbYE_DZDM6|Uv+MCX=iR_WJPuWUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNmFz) zZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDUjQ*<_VWn*-2a#M3+Y;9yyVNO#r zUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k~7MMXtL zL^4Ho0AE^ENmFz&F<(t}bY*y7VqtS-NlZ>TUtec#bzft6crh|xOmAarUvO`1X=8as zGDSrIUs_XiH)d~gcVTj5Nl#OAMNd>;QchEJF*b5#ZEtpEUvgz;WpZV1V`WKGF<(VA zba`-PMF3w~PE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B= zYIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtL zQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMW_;Urk?QZ*FsRa&=>L zUv6(?Wl2g>OH(*sMMXt+P*Zd2htba`-PUuAM~Z*oNdUs_H$ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MME-4Qe;0AE^DbTK$}ZfS05bZKF1X?kU3Ut@1@c}Y$=Utec#bzft6criC$Uv6)5 zZDDL*X>?_BVRUbDNl;5ub5nFSc4cF9Z*oafb5mhSQ*%W{MMY3kb464zUsPXHL0?lj zUjScPPBAh?a&m8SO<`_fXJv9RF-K)|Np5p=VQyn(MRovRT251RF)&|9WnpArVqtS- zNla}pMN&&@OkyxaMK@nfUub1vWJOX_GG72+T2x6+IBsljXl-F`ZZ>3PbYW?1GBRmy zaCLNFVPs)&bY*g1aB^>SZ)0z4MF3w~R8~`TIc0cbWpH$9Z*D+9M@&gVLs(c}GcGg$ zUs_H%Utec#bzft6cx`D(P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCIUrAFoUsGX8Q#M~kMMXtU zQ(rMRUtex-a&2L3Uukq@a$$6Da!FKQR4`vfF*RgqW@cq_Wo~0-UvznJWkpg;Q$$}= zM_&M6T244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ(rMOVPtGyb7gXAVQgu7WpYJDL^4Ho0AE^8Q*<_VWn*-2a!F%TVM${}MLBSFb7)^; zVPk7WPh$XIT251RF*adrY;R*>bZ>HBbaG*7baP2lVM${}MKLgBWnpY=Z)0I}Wkpg` zFket(Z2(_dPE&L-H(yd>UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(RQ*%x+GDUK7Z*omx zZeeF-aydnEa&K};Zf0*qMMXm~MNm_8F*sjRVqbJ}Wo2J(Z)9a(VqtS-0AE^8OH*_< zc4cF9Z*oafb5mhSQ*%W{F*09GUt?%xV{2b*Wo|`nP)lO~Us_I6bTK(!LTPkgV{dMA zbYE$7WpZJ3Z*oI1MN&&sbTKnuLTPkgX>?_BVRUbD0AE^8IbUCAZgpQ{cz7{0Ze@30 zVQg$~V_|e}a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtLIb&~bb98cbV{}PVHeX6oWJN_qc2HDb zL~u`3Fkb*)T247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=ZAC;fMRovRT244_Y;S07 zVQy|VWMy<=X>2h$YIARHUvpu2Uu17>UvOb^b7gW#PE%hoFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXq0MRovRT251R zF*9F6X>?y{bY*g3bZ>G)GDT2rY5-qaPB?CCZ)j~{Zf-VYWprU_Y&C3Ucx7@)PE%ho zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7 zWpYJDMMX7oWpib8MRovRS}`$6b4+h%MQ&kYY-MR_0AE^8IBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMW_% zYIARHUv^<^b!9^`MPdM7T24zjUtec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbDNl;5p zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXc zWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#M~yVM$XqUqwYlG-6?MWkq%XUs_H%Utec#bzft6 zcriC$Uv6)5ZDDL*X>?_BVRUbDNl;KuIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mT zQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#W5zVM$Xr zUqwYlLor2COH(*s0AE^8OE_+9Z)j~{Zf-VYWprU_Y%wr&Z(nM2Z*E^^ZewgoPE%ho zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7 zWpYJDMN(o#MMP9%ZDVXVbZ=j3b8l{Da9?9=H)d~gcVTj5NmMXjMP_g?UqwY@c6MJy zMN(8>Pg6Nx0AE^8IbUCAZgpQ{cz7{3UteKtX=iR_WM6G%ZDMt1NmFz*aA9e3NlR06 zQ*%W{HeXF&aCCA-b^u>mPD@jCF*09PWn*-2a$jO$b7e_RIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z& zQ(;L{HD5(VF*#pNUuR`>UsP~kVQg$~V_|e}az%CkUs_I6bTxE!aBO8sN>WQ|MMXm~ zMNd;QUjScPPD@jCF*9F6c4cF9Z*pH^VRL0kQ(;MBMMW|&Urk?UWprOcX>?yQa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMXtJF-b~NQ!rmeN=$7q zMMX+QN<~FQQd4v_bailSWl2gza8zGKMN(5iUr9*&NlI9Aa8xp1MMXsbUs_I6bTTtvQ*d8nZ*^{TWn^D)baG#5 zZg6a2V`WKBIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJRVM$Xm zUqwt#IbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2HeXF&aCCA-b^u>mPE&L;Ghb71 zUt@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07VQy|VWMy<=X>2kuX>M?JbYF9Ha%Ev{ zUtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXq1MRovR zT251RIA2m?UvzS1Wl2+WQ*<WQx zb45i(P*h(;a8Fb)UjScPPE&L-Fmq^Oa%E&+aCCA>PB?CCZ)j~{Zf-VYWprU_Y%(xu zZg6#UUvqSFWnpb!VPs)&bY*fyMME)3Q(;L{GG9eXQd4O~MMYC|F*#pTa9?ddS!A&MMXt7VsCG3WnpebVgO%SPE&L-FkeVzVPs!oVRL0kOl>hm zT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{vG;m>Qa!E^5b51cb zMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^k zb462ONmDdmMMX7YWoKz_MRovRT2pi}G+$q1Z*X~EZEtpEUtuyyOkyxaP;FB%Uqw_g zUsNz(Q!-yuF<$^*T251RF*adrY;R*>bZ>HBbaG*7baP2lVM$InZftL8ZDDS1He_XV zVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1az#Z&Ib&~bb98cbV{}PVGG9tkQ)xv-MRrnC zGha|tUqoV_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7 zWpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqoIYn}EZ*oa)W^YAPbTn*bb8|^kb462ONmFz*aA9e3NlR06Q!!sf zMMXn0MRovRT251RGB96Xb#7^HX>@5}Y-xIBWM5-%aCu2gVlYKTF*9FZb#7^HX>?y> zZ*X}@P*ZbLGG9eSR4`vuUsE(+Q!`%xUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbD zNmFx0L^4Ho0AE^8Q*<+JVQ@)Pb51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YAPbTn*b zb8|^kb462ONmFz*aA9e3NlR06Q!!sfMMX4bX>MdiQd2cw0AE^8Q*$V_#`+b4g=UbTKhwXkl_+baG*7baP2# zMMYzFVnud9Ku1hTLPJnh0baG#5ZE$Q!Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzFke%1Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc%HD5Mk za%Ew3Wl2*vUrJI-Q#W5lMMY3lUqovG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKer zQ)O&rV{|cdbV*YWQxb45i(P*h(;a8Fb)Uqw}HP*Zb7Urb^!MMXm~MN&&sMqdD5 zT251RIA2m?UvzS1Wl2+WQ*<`cDQ#fBmQ*<Q(;b1 zFkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMKLm8ON0AE^8 zIbUCAZgpQ{cz7{3UteKtX=iR_WM6G%ZDMt1NmFz*aA9e3NlR)|b45iqUrk?dbaF*@ z0AE^8IbUCAZgpQ{cz7{0Ze@30VQg$~V_|e}a!FHjMME-0b^u>mPE&L;Fkez)UvzS1 zWnXJ$d0%61ZE#_7Wl2+XG;C#ab4hANMME(~b^u>mPB~v+XKr<0V|aKmGj3&fUtw%) zZ)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR)|b45i(L^4Ho0AE^8GG}Em zGgEY7bait^VPkY}a(OW|Qe|gpb97~LMRIa)a!zkWYEny6a{ymjPE&L^Us7UUbaG{7 zNmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjlWn*+Pb96~lIA29m zbTn*bb8|^kb462ONmDpqMMW|)Urk?SZE$R1V`X1xX>N31b#7^Kb!ACPQcF{GGBI#z zWn*P`X>(;?V{dMAbaHiLbYFB+bTxE!aBO8sN>5XBMMYCeUr9Qa!E^5b5k^5MMXtJGDUU(Us_I6bTKhsRCRD{WnXD+ zaBN9TZ7@YjQcF{FMMXm~MN=_f0AE^8Q*<#fUr1$PWM5)ob7e_PZ7@YpQ*%sWFhxZ- zUrk?VWnpARQd2Qs0AE^8Q*<#mUs7UUbaG{7Uukq@a$$6Da!FHkG;m>Qa!E^5b51yJ zY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_H zUvp)0X<=+>dS!A&MMXtLLor2m0AE^DbT?*ia(7{JWJyv%F<(n#MNd>;QchEJF*b5# zZEtpEUvgz;WpZV1V`WKGGhanCba`-PMF3w~PB~v+XKr<0V|aKmH(y_FZ*py6Y+q?~ zWpZJ3Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN>3iNmDjoQ(;L{HeW?WMME(~b^u>mQ*<+D zWpqhQZ7@YjP*Zd>ZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2 za#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Q za!E^5b5k{6MMXtgPE$2sHe+&SVRU6lQ$t@$QcF`qUqwYlP*h(;a8Fb)Uqw}HQ$$}y zUqwYyPE&L-Gjw%uY-L|%Y-Md_ZgfdlR9{6?bTxE!aBO8sNmR8~$gFkfF|cz9uAX?8I(FkfGDXbZ>HBbaG*7baP2l zVM$InZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXtLMLA<{ZgX^Ubz^i%Q#D^oQes6#MRrnCHeXOwUqo`cDQ!-yg zQ*<2xdVRCb2a!F28 zUokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~ zX?kUHMMXtLHE>~ab7e(hQd2fx0AE^8Q*<#lVQg$~V_|e}a$j_EVQF-8NmF4-P);~* zY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_H zUvp)0X<=+>dS!A&MMXtLIBj8gUvp`CWkpg;Q#W4#Us_I6bT)QnV{~tFNlrL!Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XoUqwYWX>N06a&$#bIbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82 zQ#4;wHeW?WZBkP?UjScPPD@jCF*a##X>@5}Y-xIBa$js|b96~*MKp71dSyj+0AE^D zbZm1;V^ef7F=J?9a$j_EVQF-8Nn=G*VM${}MN(6AF*9Oeb7^B=Z*z2VWnpbeR9{pu zUqw?lUs6j`Vo6gpUsE+-R54#gKtM-KNkT(dSYI(PD@jCF)(#*X>oOBUvPAC zNmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yy zVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k{6 zMMXtgPE$2sHe+&SVRU6lQ$t@$MMXtWR9{4JPgF2pMOAE2Q$t@xUqxefVnucUUs_I6 zbTKn+Z+2y0X>?_BVRUbDNl;@&Lor2DFkb*)T251RIA2m?UvzS1Wl2+WQ*<`cDQ#fBmQ*<IYn}EZ*oa)W^Y6?MRovRT2pi}GGAYAX>?_BUt(c% zWl2y|b465NQ!!rvUs_I6bTKktR%K&!Z*pH^VRL0kQ*%>cNmFx0MMN@1b^u>mPE&L- zFm-Neadl;1aCCA>Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zFke%1Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc%HD5Mka%Ew3 zWl2*vUrJI-Q#W5lMMY3lUqobY)+2Xkl_?WJyjqZftL8ZDDS1He_XVVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1 zaz#^NNmDXkMM_drX+=d-bTKeG=R9{puUqwYzLSF!1T251RF*adrY;R*>bZ>HBbaG*7baP2lVM$InZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXtLMLA<{ZgX^Ubz^i%Q#D^oQd4t9MMZW}Q#M~vR9{4JPgF2p0AE^D zbTKqvUt@1@d0%aBc4c2-GD%EgF-1^NPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN>ClMN~0gR4`vt zIbTyaUjScPPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1UokXcWNcq^WpZg@Y-xIBaz#ZkFluveZeMm`Y;|QrF-1;OUp8cAbYW?1H+Erc zb!A_4MF3w~PE&L?c4cF9Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAX zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMX1ZZe&Gv0AE^8Q*<+J zVQ@)Pb5nCubTn*bb8|^kb462ONmFz*aA9e3NlR06Q*%W{MME-0b^u>mPE&L-FkeVz zVPs!oVRL0kOl>hmT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmDXkNmFxEHD6P7G;C#a zb4gQkMN?r(Q*<V_#}>Z*ECbFke%2Hg;uWbZ>G~b7E|5 zWK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<TUtec#bzft6crh|xOmAarUvO`1X=8asGDSrIUs_I6 zbTKwzY;131VRUbDUvzR|X>@Z*Q(;MCMMXGaY;131VRU6hQd2NrZ2(_dPE&L-Fm-Ne zadl;1aCCA>Q*&BQIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+ zY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3Xb4pT6Q*%W{MNm{3PbYW?1HEd;gWpYVQQ(rMKVqtS> zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z& zMKL#LWprO?_BVRUbDNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtZHD5_nH(yg>NmDmpMMXtL zY(;ibR9{puUsH54HgaKZWN&R>VPj)ub8}y5bY*g3bZ>HBbYW)zUs_H%Utec#bzft6 zcri0>Wp`g;Y;131VRUbDNmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDUj zQ*<_VWn*-2a#M3+Y;9yyVNO#rUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k~7MMXtLIb&~bb98cbV{}PVL|;lpMMZW{R9{4JPgF2p0AE^D zbTngcaCu2iIbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82Q*%>vHg;uWbZ>G= zQ*%>cNmFx0MMXtUQ!!sjP*ZbLHeW?WMN}|fR9{mQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{ zbTn{bX>v(RQ*%=`UqwYlMME(~b^u>mPE&L-Ghae>Wn*-2a$jO$b7e_WVM$^|MMN=0 zb^u>mPD@jCIA2m?UvzS1Wl2+WQ*<uMMXtWQ*<#i zUs7UUbaG{7Uv6(?Wl2*qUqw$;UjScPPE&L-Fmq^Oa%E&+aCCA>PB?CCZ)j~{Zf-VY zWprU_Y%(%wZg6#UUtwfnaCBvIUvP47bZ=vCY(+&wF-1~KQ!`%xUs_I6bTKwzY;131 zVRUbDUvzR|X>@Z*Q(;MMMMXGaY;131VRU6hQd2NrZ2(_dPE&L^Us7UUbaG{7NorGc zG;m>Qa!E^SQ*%XAbTKerQ)O&rV{|cdbV*Y(Uqw@NG;C#ab4hANQ(;L{GG9eSH(yg< zY-MJ2MNm_8F*sjRVqbJ}Wo2J(Z)9a(VqtS-0AE^DbTKqvUt@1@d0%aBc4c2-GD%Eg zF-1^gQ!rmeR54#vFke$LUsEw(0AE^8Q*<#gUsQE)Y-L|*ZE$Q!Ol>hmN?J}hZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXAaa%Ew3Wl2*qUrAGQQ#D^xbTn*bb8|^kb462ONmFz*aA9e3NlR06 zQ#D^jMMX+dOH)K&MMXtWR9{4JPgF2pMOAE2Q$$}yUqwYjGDT8LQ%zq0Us_XiH)d~g zcVTj5Nknc%PgGx0PE&L-HgaWcZ+2y0a%E;^a%FB~Wl2*oUqv)@d2nS#0AE^8Q*=0A zQet0pa%E*nYEyJHaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw? zVM$XmUqwYRGhb3-UvzS1WnXD+aBN9aHeXC)F-1i~GDUU(Us_H$ZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A& zMME)3Qf+NaX)r}aMNd>;0AE^8Q*<#hUsh#fbZ>HBVqtS-Nl;EWZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XqUqwYRGha<#WMyG&Y;R*>bY(?QQ#N010AE^8IBsljXl-F`ZZ>3PbYW?1 zHEd;gWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXc zWNcq^WpZg@Y-xIBaz#Z&MKp6`VQxis0CRM5bZ>QRY(PLqOi4mRUotK-E;RsOT247% zUuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXm~MRovRT24z- zbTKe>ZfS9KWnXY~a!FHjT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYv zMNm{mPE&L?c4cF9Z*oacPB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC# zNmDgnMMW_;Urk?fWnpY=Z)0C+ZgXXFbV*85OH(ypMMXt+PB~v+XKr<0V|aKmH(y_F zZ*py6Y+q?~WpZJ3Z*oacQ#D^xH(y0XL~u`3UjScPPD@jCG;C#ab4gQkMPqD5QcF{F zQ!-xwUs_a2Q*<#oUsG^jZDDI=Uvp?-a%E&+bYW)zUs_H$ZftL8ZDDS1F)(6bb7^B= zYIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MME-4 zQf+NaX)r}aMNd>;0AE^DbT?*ia(7{JWJyv>Q*<+JVQ@)Pb51yJY;S07VQy|QFk)eI zX=7h%b8l`*Q!rmsbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZ zbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMXtVR9{j~Q*<#la%F9Ac4c33WoBh^ zWo~0-NmE8&MKpAIaAidRUs_I6bTKwzY;131VRUbDUvzR|X>@Z*Q(;L{b45itV{dMA zbaHiLbV*ZlN>g)1MMZW}Q!rmpR9{4JPgF2p0AE^8Q*=0AQet0pa%E*nYEyJHaA9e3 zNlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYSF<(tzXJvF> zPH$voUtw%)Z)0I}Z*oO;0AE^8OH*_)H(yd>UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(R zQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^p zF*IRhY+rL_a%o{~X?kUHMMXtLMPy|~b^u>mPE&L-GGA6@V{~tFUt(c%Wl2srZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXtZVM$XpUqwYkF-3L&Us_I6bTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS> zV_#}>Z*ECbUsH58c4cF9Z*o&}Vr*?>Q(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN@P% zY-MwENmFx0Q(;L{bTn{bX>v(RQ*%=^UqwYlGi7dMMRovRT2pj4W^ZzLVRB?iQcGG+ zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3XGhazlHD6OVEWnXe-W@U0^ZewLhQ#oHnG<11zWkmpAT2pi} zGhbh0Z*X~EZEtpEUtvj1VlhQfP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D) zHg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYCLUqw_gUsNz(Q#oH# zI9~u?T2518NmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RYEyGXMMXm~MRovRT251R zGBaONVqbJ}Wo2JuZ*FsRUukq@a$$6Da!FHkG;m>Qa!E^SQ*%W{Lor2COH*_)H(yd> zUvzS1WnXD@WpZJ3Z*oafGG9diUs_I6bTKwzY;131VRUbDUvzR|X>@Z*Q(;L{bTKnu zQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8# zMMXDcWpi|LZ+S^mHD5(Vc2ZL}Uro zF*IRhY+rL_a%o{~X?kUHMMXtLIb&~bb98cbV{}PVHeX6kQ!!sQWMy<=X>2!kVQh6} zUvx!9MMZW{R9{4JPgF2p0AE^8Q*NmDmpN>WQxH(y0XMNm{2uYWq4(B zNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0 zX<=+>dS!A&MMXtJGDS~QbTKeM?JbYEd)VQ_S1a$j(A zZ**^CZ)`V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3l zUqo2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9 zF*09FZ)0m;aBpmBV|hg~MMXn0NlH>vX+=dvQ!`&ga8FcU0AE^8Q*<_VWn*-2a!F!S zVM$^|MKfh?WJPuWUs_XiGi_mbNo_?^OH^M|GG9|NUjScPPE&L-H(yd>UvzS1WnXD@ zWpZJ3Z*oafbTn{bX>v(RYEyGXMME-0P*ZdG=Q*<2)Z zbY*g1X>D+9NlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%ho zG+|_HUvp)0X<=+>dS!A&MMXt$a7A_iUs_XiH)d~gcVTj5Nm5W#bTK$zQet0pa%E*- zZf|5|Ut(c%WkpX^Us6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ!`&hG<11zWkmpAT251R zF)?3Mb#QEDUukV{Y)MRQFhxpGQ*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzFke%1Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMOsc% zHD5Mka%Ew3Wl2*vUrI$qMNm{V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEK`~!TV?{+p zP*h(;a8Fb)Uqw}HQ!rmeUqwYyPE&L-Gjw%uY-L|%Y-Md_ZgfdlR9{6?bTxE!aBO8s zN2kwX>M?JbYEd)VQ_S1a$j(AZ**^CZ)`3PbYW?1GB|2;Z*E_6VR&C;Z*5;= zVQg$-VPk7waA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLsPb!}p0a$jj~bY*8{az$(aUs_I6bTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#>oF*IRhY+rL_a%o{~X?kUHMMXtLL@`Bn0AE^8OE_+9Z)j~{Zf-VYWprU_Y%w`% zb8l{6b76R2WN&R>aA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLgGb6;h0a&K~FWJPuWUs_I6b2VdZ zWnpqfc0fQ!Oi4mRSXf^(E;ImNT251RGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2 zZb?&LQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k^5MMXtKF-3L&Us_H$ZftL8ZDDS1He_XVVQFkJFmP{k zX>@6CZeMgmGDUU(Us_I6bTn{bX>v(WQ*<#nUs7UUbaG{7Uv6(?WnW@pb7fO8UqwSP zNm5fWUrb^#MMXtYOH(mlPgGw3Us_I6bTKnuLUv_ibZ>HBVqtS-NmF4-VnszbUsGRh zcW-iJMQs3IT251RF)?3Mb#QEDUukV{Y)MRQFhxpGQ*<+JVQ@)Pb51yJY;S07VQy|Q zFk)eIX=7h%b8l`*Q!rmsbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUH zMMXtZbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMYXpQ#D^UV{&C-bY)3XLtjco zMMY3lUqo3P zbYW?1F*#~;Z*E_6VR&C;Z*5<2VRCb2a!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMXtLF*0s-ZDM6|UuJA?VRS`g zQcF{F0AE^8Q*<+JVQ@)Pb51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YAPbTn*bb8|^k zb462ONmFz*aA9e3NlR06Q!!sfMMXm~MRovRT251RF*IL7X>?z5WoBh^Wo~0-VN*p? zOH*F}Us_H}Q*<#ia&>NWX>Da+WpZ+Fax`~nVRS`yKtM-KNkT(dSYI(PB~v+ zXKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D1UsH2pY;9yyVNO#rUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HeW?W zMMN@1b^u>mPE&L-HD6zKZfS8}aCCBCX>D+9NmFz-c4cF9Z*oaaIBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC# zNmDgnMMYXpQ#D^UV{&C-bY)3XH(yFpOH(&rMMXtWR9{4JPgF2pMOAE2Q#W5lUqwSP zNm5HwNMA)oQ%7GV_#}>Z*ECbbTe&Xa8qQ(;b1F<&t> zVPtGyb7gXAVQgu7WpYJDMN>3iNmDmpQ(;L{H(y0XMKoezb7e(#0AE^8Q*<#hUsh#f zbZ>HBVqtS-NlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMW_)Urk?RWnpY=Z)0I}Wkpa^ zHD7H2Us_I6VM$InZftL8ZDDS1He_XVVQFkKFllaZb#z~IbaG{3ZC_zzVQ_S1az#Z$ zGDT8LQ!-xwUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNlrL!Y;S07VQy|VWMy<= zX>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMMXn0MRovRT2pj4W^ZzLVRB?iPB?CCZ)j~{ zZf-VYWprU_Y&UjcY;|Q{bVWr^R9{j~Q*<#la%F9Ac4c33WoBh^Wo~0-NmDalMKpAI zaAidRUs_H}IbUCAZgpQ{cz7{0Ze@30VQg$~V_|e}a!F85IBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z& zML2C?cwcjAdSyj+0AE^8Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzUsH2pY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{G+#wUF*jdLUvgz( zY;131UukZ0WpZ>$N>XA)MMZW_IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F8A zG+$FTUqwYka8FcU0AE^8IBsljXl-F`ZZ>3PbYW?1F*#~;Z*E_6VR&C;Z*5<2VRCb2 za!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_ za%o{~X?kUHMMXtLF*0ajZe(m_Uv^<^b!ACXVnszzQ#M~uR9^sJT251RG;m>Qa!F!P zPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk= zVPtGyb7gXAVQgu7WpYJDMMXn0Nn%qrUrb^#MMXtVR9{b2Fkb*)T24z-b2VdMb98b= zc0fQ!Oi4mRSXf^(E;ImNT251RF)&|9WnpArVqtS-Nla}pMNm_8Hg;uWbZ>G=PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~ zX?kUHMMXtZVM$XpUqwYsVlYKTLorEGQ#fBmMNd>;0AFQpWB^}UPE&L-Fm-Neadl;1 zaCCA>Q*&BQIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO#pUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3Xb4pS{F<(n#MMXtWR9{4JPgF2p zMOAE2Q*%XMMME-0Q$}A>OH)T*0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51yJ zY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_H zUvp)0X<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*YUv6(?Wl2g>OH(*sMMXtWQ*<#iUs7UUbaG{7Uv6(?Wl2*wUqwW4 zPgGw3Us_H}Q*<#fb#7^Kb!A_0baF{kbTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS>V_#}> zZ*ECbFke%2Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#a zb4gQkMN?r(Q*<EdDGi_mTNmFx9IBslj zXl-F`ZZR-oVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXA zVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw> zNmD~#N<~FQP*h(;a8Fb)Uqw}HQ$$}yUqwYjGD%WXL|;-%Q%he=VlhQUMNd;kUr$sp zUjScPPB?CCZ)j~{Zf-VYWprU_Y&mIkWpZC>ZE$Q!PE%hoFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXDrWprOV_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ!-yk zQ*%=_UsH56Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlN>WQxL|;WkMNm{0AE^DbTngcaCu2nbTKnuLTPkgX>?_BVRUbD zQ!rmeR4`vuUsEz)Q!!rvUs_H$ZftL8ZDDS1He_XVVQFkKFllaZb#z~IbaG{3ZC_zz zVQ_S1azrvkb^u>mPB?CCZ)j~{Zf-VYWprU_Y%w=!ZggdGZeeU+X>?_BVRUbDNlsH= zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+> zdS!A&MMXtJF-3L&Us_I6bT)QnV{~tFNmFxEVM$YSMMW|&Urk?OY;131VRU6*VQyq! zV{dSINlrOmUuSN0Ut@T9F*jddZf|mJVQgP%bY*g3bZ>G=P)k#DQ!!sfMMXtWQ*&)p zUsE|>0AE^8Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^SQ*%W{IbTg*c42IAbaF*@ z0AE^8Q(;L{bTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06Q*%W{MMN=0b^u>mPB~v+ zXKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06 zPBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8#MK@$+b98cVc}Y_?UqwZBP*h(4Us_Xi zWpPPRQ*%XPQcF{GF*9v%c4c2_bY*g3bZ>G=R9{6?HD3TG=P*6@dZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLLor2DH(vl>T251RF*9v%c4c2_bY*g3bZ>G= zP*6@dZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXtLLo!8EH(vl>T247%UuSN0Ut@T9F*9yucVA&_Y;R*> zbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zF<&t>VPtGyb7gXAVQgu7WpYJDMMXn0MN&&sH(vl>T2pj0XJvFrOl>hmN>EdDGi_mT zNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t> zVPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250n zUp8ZMWnpw>NmD~#N<~FQP*h(;a8Fb)Uqw}HQ$$}yUqwYyPE&L-Gjw%uY-L|%Y-Md_ zZgfdlR9{6?bTxE!aBO8sNG~b7E|5WK&^IQ!`&N zG+|_HUvp)0X<=+>dS!A&MMYCNUqwY!Fke((Q$k-;L0dS!A& zMK)t{Wnpw>NmDXkNmDdmQ(;L{G+#wUN<~FQP*h(;a8Fb)Uqwz!RcugGH(y0xV{AoJ zL|*`3T247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+X zG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABMMXq0MRovRT247%UuSN0 zUt@T9F*9yucVA&_Y;R*>bZ>G=Q*<+JVQ@)Pb51yJY;S07VQy|QFk)eIX=7h%b8l`* zQ!!stbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtZbTn*bb8|^k zb462ONmFz*aA9e3NlR06Q#M~kMMXt1Fl1$6Y;131VRU6hP*X%-Z2(_dPD@jCGi_mT zNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&LQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k^5MMXt4b7^{I zMRovRT251RIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#fUsGjlWn*+Pb96~lGG9eg zbTn*bb8|^*MN?r(Q!-ygMKLsAOdS!A&MKxk& zXK8Llb^u>mPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5| zNmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8#MLA<{ZgX^Ubz^i% zQ#M~pQd4tMQ#D^jMMZW{R9{4JPgF2p0CRM5V{LFiKu1hTLPK9NE;24P0AE^8Q*G=P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMYCJUrAFpUsGX8Q#W5lMMXtZLSIExFke(( zQ$$}=Ltg-2T251RIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#fUsGjlWn*+Pb96~l zGG9egbTn*bb8|^*MN?r(Q!-ygMK)hkUu$J~MNmsqbTKnuQet0pa%E*-Zf|5|NmDXk zMF3w~PD@jCF*jdQVqbJ}Wo2J!bY*g3bZ>G=Q*<Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa) zW^YABLorEGQ*%;NGG9z$F-1j1PgGw|R4`uvUs_I6bT)QnV{~tFNn=xCNn=GtHDhdL zVRA)w0AE^8OH*_)GGA6@V{~tFUt(c%Wl2y@IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&g zGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HeW?W zF*#pNUuR`>UsP~kVQg$~V_|e}az%CkUs_I6bTKe>ZfS9KWnXY~a!FHjT244_Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0 zX<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{ZfS9KWnXY~a!FHkHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwY)PE$2s zHe+&SVRU6lQ#W5qQcF`eUqwYlP*h(;a8Fb)Uqw}HP*XQwMPEfXa%F5~VRL0gb^u>m zPB?CCZ)j~{Zf-VYWprU_Y&LLVa&u*JNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMXt1ICEimUvOb^b7fy?ZggdG zZeeUmPE#;nGB|2;Z*E_6VR&C;Z*5;=VQg$-VPk7waA9(DWpYVVHeW?WMMYvzR9^sJ zT251RF*09PWn*-2a$jO$b7e_Wb5mhSQ*%W{F*09PWn*-2a$jj}aBM^}MRovRT251R zF*09PWn*-2a$jO$b7e_Wb5mhSQ*%W{Lor2dQcF`XUjScPQ*<#hUtecsbYEy?Y;a|A zNla}pMNm_8Hg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ zZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwYqT250nUp8ZMWnpw>NmDmp zN>WQxH(y0XMNm{F<(@5aBO8?X>D+9Nmx{0 zMM_giUqobZ>G=Q*<_VWn*-2a!F1&ZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzF<(=2Vr*?>Q(;b1GG8$?VPtGyb7gXAVQgu7 zWpYJDMN?r(Q#M~kMMXq0MRovRT2518NlrL!Y;S07VQy|VWMy<=X>2kuX>M?JbYF9H za%Ev{UtwfnaCBvIMMXn0MRovRT251RF*adrY;R*>bZ>HBbaG*7baP2lVM$ObY(?SQ#W5wQ#N010AE^8IbUCAZgpQ{cz7{3 zUteKtX=iR_WM6G%ZDMt1NmFz*aA9e3NlR06Q*%W{H(yO(VPs@-MRovRT251RF*adr zY;R*>bZ>HBbaG*7baP2lVM%R8MKLgBWnpY=Z)0I}Wkpg`Fket@Z2(_dPB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@ zY-xIBaz#ZkFluveZeMm`Y;|QfWMy-7a&LJ>PE%htWMy<=X>2!kVQh6}UvxzPUs_I6 zbU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_* zbTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YIA2p=c42IFWkpa+Q*<#iUs7UUbaG{7 zUv6(?Wl2*wUqt|4T2518NlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXn0MRovRT2pj4W^ZzLVRB?i zQcf{4MRIa)a!p}wVP|D>IYn}EZ*oa)W^YABPgGx0PE&L-HgaWcZ+2y0a%E;^a%FB~ zWl2*rUqv)@d2nS#0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b5nCgQ*<#fUsGjl zWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMW|(Urk?UWprOoZ)9a(VQg$~V_|e} zaz%CkUs_I6bTKhsRCRD{WnXD+aBN9TZ81ekT244_Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw> zNmDXkNmFxEHD6P7G;C#ab4gQkMN?r(Q*<OH*@2MMY0kUs6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ#4;iG<11zWkmpAT24zi zZftL8ZDDS1He_XVVQFkJGG=mbZC`40Z*E^^ZewgoPE%hoFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMN@M{MMP9%ZDVXX zW^!+BUutu2Zf0;_W^gcHMPqh$UqwYyOH^M{R4`uvUs_I6bTTksQet0pa%E*-Yh`&~ zV{dJ6VRB_jQ*< zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z& zMME(~b^u>mPD@jCIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#fUsGjlWn*+Pb96~l zGG9egbTn*bb8|^*MN?r(Q!-ygMKp71dSyj+0AE^8Q*<_VWn*-2a!F%TVM${}MKLvB zOG=VpCyBVnszUGha<#X>N06a&%u|b$CTnbTKnuLTPkgX>?_B zVRUbDVgO%SPE&L-F<(@5aBO8?X>D+9Nla}pMM_Uob45i%F-cQ%MMY0kUjScPPB?CC zZ)j~{Zf-VYWprU_Y&C3Ucx7@)PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMX1bWpqV$0AE^8Q*<#fUr1$PWM5)o zb7e_PZ7@YrOH*@9VlYKTLo!8EF<$^*T24z-bT)QnV{~tFNmFxEVM$YSMMXGcVQ^t% zX>@r-b^u>mPD?poUuSN0Ut@T9F*jddZf|mJVQgP%bY*g3bZ>G=P)klYZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~ zX?kUHMMXtZG+#+mHeXX=NmDjoMMXtqWkq%XUs_I6bTKktR%K&!Z*pH^VRL0kQ*%>c zNmFx0MME(~b^u>mPE&L=aA9e3NlR06Q*%W`GDUU(Us_I6bTxE!aBO8sN>EdDHg;uW zbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRh zY+rL_a%o{~X?kUHMMXtZVM$XpUqwY)PE$2sHe+&SVRU6lQ#W5qMMXtWR9{4JPgF2p zMOAE5IA29yMMXm~Nm5fdUs6j`Mqf-~F-1j1Pg6l(PgF2p0AE^8Q*<#gUsQE)Y-L|* zZE$Q!Ol>elN>EdCT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{< zL~u`3FkeMgY*R2_MPEflLorEGQ!rmjQcF`uUqyCBMNd;gUsFb30AE^8Q*<#jUte=* zVRB_;Ut@1|ZgfdZPB~v+XKr<0V|aKmGG9z@V{2boOBUvPACNmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rms zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMYXpQ#D^UV{&C-bY)3X zH(yFcMMY3lUqovG;m>Qa!E^5b51yJY;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0 zX<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*YbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXDcWpi|LZ+S^mHeW?Wc2HDb0AE^DbTKkt zUv6o1WpZC)VRL0kQ*<#iUqWegUukq@a$$6Daz#{MQ!!rvUs_H%Utec#bzft6criC$ zUv6)5ZDDL*X>?_BVRUbDNl;5ub5nFSc4cF9Z*oafb5mhSQ*%W{MME-0QcF`ZUjScP zPE&L2hvZ*_EEZ)RU|VQyz-L^4Ho0AF8Y zcwt|1WprqAZ+AdILs(crLP=jSE;9gMT251RF)(#*X>oOBUvPACNmFxLPB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXA zVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqobZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+X zG;m>Qa!E^SQ*%W{MMN=0b^u>mPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnu zQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8# zMME(~b^u>mPE&L?c4cF9Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAX zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMXJqb#rK6Vqs%zMNd;T zUjScPQ*<#hUtex%bY*g1VqtS-Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLR9{m!UjScPPE&L- zFkeVzVPs!oVRL0kOl>hmT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYv zMNm{@Z*Q(;L?IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MMXDcWpi|LZ+S^mHD5(Vc2ZL|UrV_#}> zZ*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN>9k zMN~0gR4`vtIA2pYUjScPQ*<#hUteu$bY*g1VqtS-Nl;@&R9{muUjScPPD@jCF*#pf zb7*05Wn^D)baG!|V`F7=b4gA(ZftL8ZDDS1He_XVVQFkKGHGsbb#z~0WMOc0WpZC| za&L5RV{dFlOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MNDEaMNDEaMMZFQMRovR zT251RHg;uWbZ>G=VpCyBVnszmF-3L&Us_H}Q*&u}MQuPpM@&gVLs(c}GcGg$Us_H% zUtec#bzft6cri0>Wp`g;Y;131VRUbDNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(R zQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#~r zF*IRhY+rL_a%o{~X?kUHMMXtLMMXm~MN&&sLtg-2T251RF*RROVqbJ}Wo2JzWnpAx zazipjb^u>mPE&L-FkeVzVPs!oVRL0kOl>elP*Zd^c4cF9Z*oaaIBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC# zNmDgnMMX?vFhxZ-Urk?VWnpARQd2o!0AE^8Q*<#fUr1$PWM5)ob7e_PZ81e!PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGy zb7gXAVQgu7WpYJDHe+&SVRU6lQ!`&lQ#D^xVM$XpUqwYqMMXtWR9{4JPgF2pMOAE2 zQ#fBmUrb^!MMXn0MN&&sMqdD5T251RIA2m?UvzS1Wl3sNbTn{bX>v(RYEyGXQ*<#f zUsGjlWn*+Pb96~lGG9egbTn*bb8|^*MN?r(Q!-ygMKLp9Qet0pa%E*-X>D+9NmDjo zOky!bMMN@1b^u>mQ*<#lW^ZzLVRB?&VRK(}b#QEDNlH_5MMYC|HFR}wY-LGGL~u`3 zUqwYzGhYB-T2pi}GGAY3WprO?Wo&R|a!E{WF-2NVIBsljXl-F`ZZR-oVRLC?Uutu2 zZb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C- zbY)3XGG9qkb5k{6Q*<Qa!E^5b5k{6MMXtQQcF`rUqwYl zP*h(;a8Fb)Uqw}HP*X%-MPEuqMN(8SUs6+aF)?3Mb#QEDUukV{Y)M#DUqwn&PG3ZD zR54#gMF3w~PE&L;Ghb71Ut@1|Zggd2UvPACUukY|Y+++%NlrL!Y;S07VQy|VWMy<= zX>2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinppUuSN0Ut@T9F*09FZ)0m; zaBpmBV|hg~MMXm~NlH>vX+=dvQ!`&ga8FcU0AE^EQ%*Q;Y;S07VQy|VWMy<=X>2ku zX>M?JbYF9Ha%Ev{UtwfnaCBvIMF3w~PE%n?Q*%W_F-3L&Us_H}Q*<#lX>MtBX<=+> zdS!B7Y-w|JNlR))HDYCFX>LV!0AE^8Q*<#gUsQE)Y-L|*ZE$Q!Ol>elN>WQxb45i% zF-1>PGG72+T2pj0XJvFrOl>elN>EdDGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2 zZb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwE zNmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N<~FQP*h(;a8Fb) zUqw}HQ$$}yUqwYyPE&L-Gjw%uY-L|%Y-Md_ZgfdlR9{6?bTxE!aBO8sNG~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A& zMK)t{Wnpw>NmFx5Qb93aOJhYvMNm{HBVqtS-NlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMW_(Ush#fbZ>HB zX>D+9Lo!8DOH(#q0AE^8Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzUsH2pY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{G+#wUF*jdLUvgz( zY;131UukZ0WpZ>$N>Xe^MMZW_IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F8A zG+$FTUqwYka8FcU0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51cbMRIa)a!p}w zVP|D>IYn}EZ*oa)W^YABQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^kb462ONmDdm zMMW_)Us7UUbaG{7UukV{Y)Ml%Urb^#MMXq0MRovRT251RF)?3Mb#QEDUukV{Y)MRQ zF-1yRPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zFkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEOH*@2MMY3lUqov(RYEyGXQ*<#f zUsGjlWn*+Pb96~lGG9egbTn*bb8|^*MN?r(Q!-ygML1tmUv^<^b!A0ROH*_)IA2m? zUvzS1WnXS@WMyAsVRK~wUs_XiF*09YXJvF>Xk~10WpYVOZ7@YpQ*<+JVQ@)Pb51yJ zY;S07VQy|QFk)eIX=7h%b8l`*Q!rmsbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_ za%o{~X?kUHMMXtZbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMX+lPE$2sHe+&S zVRU6lQ$t@$QcF`qUqwYlP*h(;a8Fb)Uqw}HQ$$}yUqwYyR4`vsQ*<#gUsQE)Y-L|* zZE$Q!SX5s{N>ff>L~v9wUqwX#Us_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PBAh? za&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8@bTKerQ)O&rV{|cdbV*Y*Uqw@NG;C#ab4gQk zMN?r(Q#4;iML1tmUvg<@XmmwTQ*<#nUs7UUbaG{7Uv6(?WnW@pb7cTuT23)CMRIa) za!p}wVP|D>F*Z_VaBp&SMRIaYWpi_3XJtiGb5cuFbTe&Xa7j~hQ*%>vG;C#ab4gQk zMN?r(Q*<Q(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^j zMKxk&XK8Llb^u>rVsmp}b97;HbO2vkPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oaf zbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1G+!|^VPtGyb7gXAVQgu7WpYJDMMXtLIb&~b zb98cbV{}PVL0?KzOH)B#MMXt+P*h(;a8Fb)UjScPQ*<#hUtecsbYEy?Y;a|ANla}q zMOsccZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2*rUrAFnUsGX8Q#D^jMM_djQ#fBmMMY3l zUqofQ+L~v9w zUqwX#Us_I6bTKktR%K&!Z*pH^VRL0kV^d*CV?{+VF<(tzVQg$~V_|e2kwX>M?JbYEd)VQ_S1 za$j(AZ**^CZ)`VEWnXe-W@U0^ZewLhR9{6jba`-PMNd;VUjScP zPE&L-GGAYFXkl_?WM6P}a!F1&ZftL8ZDDS1He_XVVQFkKGHGsbb#z~0WMOc0WpZC| za&L5RV{dFlOinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXm~MN&&sHD3TZfS9KWnXY~a!FHkHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwY)PE$2sHe+&S zVRU6lQ#W5qMMXtWR9{4JPgF2pMOAE2Q#W5lUqv%#WpqV$0AE^8Q*=0AQet0pa%E*n zYEyJHaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYV zVr6G(ZbfzgUs_I6bTKktUvp?-a%E&+aCCA>PB?CCZ)j~{Zf-VYWprU_Y%(%wZg6#U zUtwfnaCBvIUvP47bZ=vCY(-2?IbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2Lo!KD zQ!!sMFllaZb#z~IbaG{3ZC_zzVQ_S1az%DUMNd;-NmO4v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLMMXq0MRovRT251RF)?3Mb#QEDUukV{ zY)MRQF-1yRPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ!-ykQ*%=_UsH56Y-MwENmFx0 zQ(;L{bTn{bX>v(RQ*%=_UqwYlN<~FQP*h(;a8Fb)Uqw}HP*X%-MPEflH(yO(Xk}q! zMN(5tUjScPPBAh?a&m8SO<`_fXJv9kF-3L&Us_XiH)d~gcVTj5Nm5g3MNd>;QchEJ zF*b5#ZEtpEUvgz;WpZV1V`WKGF<(VAba`-PMF3w~PD@jCHg;uWbZ>G=VpCyBVnszY zWo>YDc|~>rUs_I6bTxE!aBO8sN>EdDGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2 zZb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P%Y-MwE zNmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N>WQxLtjNjMNm{< zL~u`3FkeMgY*R#EMPEflLo!KHQ$$}Oky!bMMY0jNMBD>Fkb*)T247%UuSN0 zUt@T9Ze>YOOHMd$Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCIUrAFoUsGX8Q#M~kMMXtoQcF%#Uokgd zUv6)5ZDDL*X>?_BVRUbDNmO4{FkeMQQ%7F_Us_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3 zNlR06Q*%XAbTKerQ)O&rV{|cdbV*Y(Uqw@NG;C#ab4gQkMN?r(Q!-ygMKLp9Qet0p za%E*-X>D+9NmDjoOky!bMME(~b^u>mPB?CCZ)j~{Zf-VYWprU_Y%(}%b8l{6b76R2 zWN&R>V_|G;Vqs%zUvOb^b7gW#PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXm~MN(5XUsH5AW_503bZKvHNk(F6 zPE#;nHgI8bb7gW#Q#M~kF*9&sa&u*0Wp-t5bYFBuQ#fBmMPdM7T2pi}Ghbh0Z*X~E zZEtpEUtvj1VlYKeQ*%==Uqw_gUsNz(Q!-yuF<$^*T251Qa7;x|OJhJlM@&gVLs(c} zGcGg$Us_I6bT)QnV{~tFNn%rBNn%AsHDYCFX>LV!0AE^8Q*<#iUqWegUukq@a$$6D zazipjb^u>mPE&L-F<(@5aBO8?X>D+9Nla}qMM_#uIBsljXl-F`ZZR-oVRLC?Uutu2 zZb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C- zbY)3XGhazlHD6ObZ>G=V?{S)Wpi|LZ+S^$MMZW{R9^sJT251R zF*ssjb7^B=b98cPZfA3Ja%Ev{Nn=xVF)?FkVRBz|a$#w7b4g=GQ(;MCMMXq0MRq_y zM@&gVLs(c}GcGg$Us_I6bT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XoUqwYRHeXa_ZE$aL zVRCt2c42IFWkfMWb^u>mPB?CCZ)j~{Zf-VYWprU_Y%wx#b#z~EW?yn)Zf9jfGDT8L zQ!!rvUs_I6bT)QnV{~tFNmFxEVM$YSMMXm~MRovRT251RF*09Yb7*05Wn^D)baF{f zIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJKPB~v+XKr<0V|aKm zGG9z@V{2bQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#4;i zMKp71dSyj+0AE^DbTo5!VQ@)KIBsljXl-F`ZZ>3PbYW?1H+Ercb!A_4MMX|ibU9^i zVPb4$UukAZSaWhybT(gKVQyq!NlH_6HeX+EZ**TtQ*<#kUtei+UvzbFY-L|;X=`Ok zR9{6!Q*<&hX>(s~Z+2y0V{dMAbaHiLbZKI2Wl2*vUqw@NF*s>+Uu|!8WnW=)b7^O8 zVPb4$NmDmpMMXt5c42IFWkq&HG<11zWkpg`H(ygoUjScPPB~v+XKr<0V|aKmH(y_F zZ*py6Y+q?~WpZJ3Z*oacOHMd$Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCIUrAFoUsGX8Q#M~kMMXn0 zNl;TZUqwYyOHNZTUrAJ7PE%hoF<)P0Zee0W61VqtS-G)Zo0bVD&k zc0fQ!Oi4mRSXf^(E;ImNT251RGi_mTNorGbQ*<IYn}EZ*oa)W^Y3=MN&&sFkb*) zT251RF*jdQVqbJ}Wo2J!bY*g3bZ>G=Q*<W_503bZKvHNk(F6PB?CC zZ)j~{Zf-VYWprU_Y&LLVa&u*JNlsHRUokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2 za#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MKLpQVRCb2UuAY>ZggLCMN(5Y zUqwY@c49?#0AE^8Q*<#oUqWegUt@1>b97&6bY*g3bZ>G)F-1^qY5-qaPD@jCGi_mT zNmFxEb5nFQY-MwENmFx0Q(;L{bTn{bX>v(RQ*%>uMMXt4W@&C@MN(5UUjScPPB~v+ zXKr<0V|aKmGj3&fUtw%)Z)0I}Z*oavMKLgBWnpY=Z)0I}Wkpb9Z2(_dPB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@ zY-xIBaz#Z$F-cNWb5nCnX)r}aMNd>;0AE^8OF3U(XKr<0V|aKmH(y_FZ*py6Y+q?~ zWpZJ3Z*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN>3iNmDjoQ(;L{HeW?WMKoezb7e(#0AE^E zR!%r>Y;S07VQy|VWMy<=X>2)Vcw=R7bZKvHMF3w~PE&L^Us7UUbaG{7NmFxEbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^k zb462ONmDpqMMW_)Us7UUbaG{7UukV{Y)Ml?Urb^#MMXq0MRovRT23)CMRIa)a!p}w zVP|D>F*!k0LsDgMZ*p`+a&k>&b8}&5WkpkSQcF{GHg;uWbZ>G=Q*%>cNmFx0MN>3i z0AE^8IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82V^efCc4cF9Z*oavQ(;MC zMMXtJF-1~KQ!-xwUs_H$ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MKLgHb8l{6c42IFWkWJWQcF`ZUrAFm zUsGX8Q#4;iMF3w~PE&L-HeXY4Ut@1|Zggd2Ut(c%Wl2mY5VPj=qXlZVAUv+M2 zadl-$N>WQxbTTn;X=P(&cWHBFUt@1>b98cbV{~71Q*vF<(VRQ$$}$ zN<~FQMMYC|F*jdQVqbJ}Wo2J!bY*g3bZ>G=Q!-ygQ*<&jUs7UUbaG{7Ut@1>b97&6 zbY*g3bZ>G=Q!-ygL~u`3UjScPPE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNlrL!Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0 zX<=+>dS!A&MMXtLIb&~bb98cbV{}PVHD5|nZAC>zc2ZL|UrG=P)lP|bT)QnV{~tFNn=xCNn=GtMME-0QcF`Z zUjScPPD?poUuSN0Ut@T9F*jddZf|mJVQgP%bY*g3bZ>G=P);~*Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A& zMMYCIUrAFoUsGX8Q#M~kMMY#~MRovRT2pj0XJvFrOl>elN>EdCT244_Y;S07VQy|Q zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+> zdS!A&MK)t{Wnpw>NmFx5Qb93aOJhYvMNm{JYDz^#QdBTsQd4v>F<(@5aBO8?X>D+9Nmx{0MM_gL zUqovG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABQ*<#f zUsGjlWn*+Pb96~lG+#wibTn*bb8|^kb462ONmDdmMMXq0MRovRT2pi}GGAY9X>?_B zUt(c%Wl2y@IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MO0r?H(vl>T24z-bTwgea$$K%V@z#1MMX4o zX?kTvb^u>mQ*<|GZ*q5Ga%4$TOKL?=R9{j~Q*<#la%F9Ac4c33WoBh^Wo~0-NmDXk zMKpAIaAidRUs_XiF*9FZV{dSIUu|!8WnW=QOkyxaQ*<#iUqWegUukq@a$$6Da#Jv0 zMN~0gR4`vtGG9|MUjScPPE&J4F-3MjKu1hTLPJG~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmDXkNmFxE zHD6P7G;C#ab4gQkMN?r(Q*<G=P)krw zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXc zWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#W5zVM$XrUqwYlG-6?MWkq%XUs_XiF*09YZE196 za$jO$b7e_TP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5 zWK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXtaUsE_=0AE^8Q*<_VWn*-2a!F!SVM$^| zML2M8a9?6!V{1ir0AE^8IBsljXl-F`ZZ>3PbYW?1F*#~;Z*E_6VR&C;Z*5<2VRCb2 za!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_ za%o{~X?kUHMMXtLF*0ajZe(m_Uv^<^b!ACXZAC>;Q#M~uR9^sJT251RF*RRbb#7^K zUvPACUukV{Y)MmdT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4J zPgF2pMOAE2Q*%XMMME)3QcF`tUqwYzMPE--IbQ%@T251RHg;uWbZ>G=P);~*Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XpUqwYZaCLKNUt(cnYeiB^Q#D@zUs_H%Utec#bzft6cri0>Wp`g;Y;131 zVRUbDNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%>uMMXtJF-3L&Us_H}Q*<#o zUqWegUt@1>b97&6bY*g3bZ>HGWkq%XUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbD zNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sL zG+|_HUvp)0X<=+>dS!A&MMXtJGDUU(Us_HwXJs)lQ*?4^Zf8|=X>4;fQ*dl)bVX82 zQ*&bgUs_XiG;MEoWl2&_IBsljXl-F`ZZ>3PbYW?1H+Ercb!A_4MMY0eQ*<#la%F9A zc4c33WoBh^Wo~0-NmO4&G<11zWkpX@HD3T3PbYW?1F)?p+ zXk~I=WpZ+Fazy}NT24ziZftL8ZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m- zV{2b?_B zVRUbDNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLWMxHm0AE^8IBsljXl-F`ZZ>3PbYW?1WpPDL zQ!rmLFmQ5dZE19Ac4c2_bY*g3bZ>HBbVXA!UjScPPE&L-HeqaRZ)0I}Z*pIBa$#w7 zb4gQSNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%>uMMXtLIb&~bb98cbV{}PV zGha$mF<(hjb5nCgMMXt+Qd2cwP*h(;a8Fb)UjScPPE&L^Us7UUbaG{7NmFxEbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^k zb462ONmDpqMMXAWQ(tRkc|}l5Q*<#iUs7UUbaG{7Uv6(?Wl2*wUqt|4T251RF*RRb zb#7^KUvPACUukV{Y)MmdT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5Qb93aOJhYv zMNm{Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABMK)he zUvPACMRovRT2pj4W^ZzLVRB?iQcF-yIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mT zQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&MNd>;QchEJF*b5# zZEtpEUvgz;WpZV1V`WKGIbTIIba`-PMF3w~PE&L=aA9e3Nn%h=IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIB zaz#Z&MME-4Vp3B!Urb^#MMXtVR9{b2Fkb*)T247%UuSN0Ut@T9F*9yucVA&_Y;R*> zbZ>G=Q*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ#4;OG+|_HUvp)0X<=+>dS!A&MMXtL zMME(~b^u>mQ*=0AL}hbya&LJ_P*ZbLb47MkUsEw(Qd40`R4`vf0AE^8Q*<#lVQg$~ zV_|e}a$j_EVQF-8NmF4-PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMMXt8VQg$~V_|ebZ>G=ZACa?Y;131VRU6hZBR>g0AE^8Q*<#h zUsh#fbZ>HBVqtS-Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XqUqwYjF-3L&Us_I6VM$YT zGi_mTNmFx9IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&LQ*<_VWn*-2a#M3+Y;9yyVNO#p zUokXcWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k^5MMXtL zLor2m0AE^8IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO$DF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2*pUrAGQQ#4;wbTn*bb8|^kb462O zNmFz*aA9e3NlR06Q#4;iMMX+QMMY3lUqo@Z*Q(;L{bT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VMMXGaY;131 zVRU6hQd2lzZ2(_dPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafb4590Z*FsRa&=>L zNmFx5Q*%W{MRrhBUqoQa!E^5b5nCgMPqD9Q!rmiQ*%>uMMXtYPE=npFlK3T zb97&Hd2nS#Qd2fx0AE^8Q*<mPB?CCZ)j~{Zf-VYWprU_ zY%(%wZg6#UUtwfnaCBvIUvP47bZ=vCY(z3eb^u>mQ*<+DWpqhQZ7@YjP*Zd>ZDDXp zQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXc zWNcq^WpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k{6MMXtgPE$2s zHe+&SVRU6lQ$t@$MMXtWR9{4JPgF2pMOAE5L|;W;MMY9ePE&L-Gjw%uY-L|%Y-Md_ zZgfdlR9{6?bTxE!aBO8sN3P zbYW?1F*0v;bYE{~Uvgn?XJtb%MN&&sF<$^*T251RHg;uWbZ>G=V^d*CV?{+nF-3L& zUs_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|K zWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YF)&|KUu|J{X>E0FMNm_8F*sjR zVqbJ}Wo2J(Z)9a(VqtS-0AE^8Q*<#jVqtS>V_#`zb98cLVQoocQ*<#gV`yP=UvzR| zX>@Z*V?{+bX>(t1aAj^qc0fQ!Oi4mRSXf^(E;ImNT251RF*adrY;R*>bZ>HBbaG*7 zbaP2lVM$YTHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ zZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZVM$XpUqwYlMLA<{ZgX^Ubz^i%Q#W5q zQcF`eUqwYlc2ZL~UrQ(;b1F<&t> zVPtGyb7gXAVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlOkyxa zMK@nfUub1vWJOX_MPC44T244_Y;S07VQy|VWMy<=X>2k$YIARHUvpu2Uu17>Ut?ix zY+_+!YhQ3-a&u*JNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE%hoG+|_HUvp)0X<=+>dS!A&MMXt1GH79LWNc+$c42IFWl2(PMMYC|G;m>Qa!F!P zQ#M~kPgGxG0AE^DbTemVbV*EYFhxpIOKL?$QchEJF*9^^aBO8?Wo%__Wo~pySX5s{ zQ*vG;m>Q za!E^5b5nCgQ*<#fUsGjlWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMW_&UqNha zZ)0C>Z)9adF-1~SI9~u?T251RHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMW_-UsPpn zaBp&9a(Q2NVQh6}Lo!K9QcF`bUqwYlP*XNvL~u`3UjScPPE&L?c4cF9Z*oafb5mhS zQ*%W{F*RRJUuAM(b7fy)bYEp|WJOR@a{ymjQ*=0AUuJ1+Y+qqXP);~*Y;S07VQy|Q zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+> zdS!A&MMYCJUqwziUtec#bzft6crh_wUuAA#Vr*q!X=X`SZgg{UQ*<#gUtei+Uvpz& zY+-UqR4`vfH(y_NVQh6}MRr9tUte^2aAieQUsFY2QcF`oUjScPPE&L^Us7UUbaG{7 zNmFxEbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF-aydnEa&K};Zf0*qMN@P!Fke$;Y-M9~ zF>`cDQ#4;iQ*<Xk~10 zWpYVOZ7@YoQ*%m1MN(8SUs6+aF)?3Mb#QEDUukV{Y)M#DUqwn&F<(S*R54#gMF3w~ zPBLd@F*8$iVRUtKMqy)gZ*qA=F-3L&Us_I6bTTtvQ*d8nZ*^{TWn^D)baG#5Zg6a2 zV`WKBIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJRVM$XmUqwt# zIbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2F)&|EUu0=>aBp*EMRovRT244_Y;S07 zVQy|VWMy<=X>2)Wa&K*4YIARHNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMXtLc2Y}JUs6s}H(xk&baH8KXJ2$h z0AE^8Q*<#hUsh#fbZ>HBVqtS-Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XqUqwYRGGA6@ zV{~tFUukV{Y(z0db^u>mPE&LHBX>D+9Lo!8n0AE^DbTTquUv+M2ZfSIBVQgu7Wn^D%Z+2y0VM$O< zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#Z&Q#M~yVM$XpUqwY!Fke((Q#oH#IA2m!F<$^*T244_Y;S07 zVQy|VWMy<=X>2)Vcw=R7bZKvHL@-5m0AE^8Q*<#hUsh#fbZ>HBVqtS-NmFxEVM$YS zMMW_(Ush#fbZ>HBX>D+9Lo!8DOH(jk0AE^8IbUCAZgpQ{cz7{1UteKtY;R*Z*X}v(RQ*%>uMMXAWOmPD@jCIA2m?UvzS1Wl2+WQ*<mPB~v+XKr<0V|aKmGj3&f zUtw%)Z)0I}Z*l+tfd79Qa!E^5b51yJY;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ#4;OG+|_HUvp)0 zX<=+>dS!A&MMXtLMME-0QcF`qUjRgGZ)aCwa&Ad(Ze?-+Us_H%Utec#bzft6cri0> zWp`g;Y;131VRUbDNmFx0Ib&~bb98cbV{}PVb4pS{F<(n#MMXt+P*h(;a8Fb)UjScP zPD@jBG;?WsWkq&CKu1hTLPJQa!E^SQ*%XAbTKerQ)O&rV{|cdbV*Y(Uqw@NG;C#ab4hAN zQ(;L{GG9eSF*9FMVqbJ}Wo2J!ZE$Q!Q#M~rVlhQULor2m0AE^8Q*<_VWn*-2a!F85 zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ(seaVr*?>Q(;b1Fkdk=VPtGyb7gXA zVQgu7WpYJDMN?r(Q#D^jML2M8a9?6!V{1ir0AE^8Q*oF*IRhY+rL_ za%o{~X?kUHMMXAaa%Ew3Wl2+WN>V{FUrS>}MMY3lUqo@Z*Q(;L{ zbTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1GhZ<@VPtGyb7gXAVQgu7WpYJDMMXtLMLA<{ zZgX^Ubz^i%Q#oHsQcF{GGBI#zWn*P`X>(;?V{dMAbaHiLbYFB+bTxE!aBO8sN>5XB zMMYCcUr92huZ**v7 za$jX~a&K}(FhzC%UteQ*VP9o#WM5-pbYo~hKtotqK|)DiF)lLzUs_I6bTn{bX>v(W zQ*<#nUs7UUbaG{7Uv6(?WnW@pb7fO8UqwSQNm5W#bTKnuQet0pa%E*-Zf|5|NmE}* zOH*@BIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#v zUokXcWNcq^WpZg@Y-xIBaz#Z&MMY9mF<(q#F-1j1PgGw|R4`uvUs_H$ZftL8ZDDS1 zHe_XVVQFkKFmQ5dZE19Ac4c2_bY*g3bZ>HBbVD*lb^u>mPE&L-F<(@5aBO8?X>D+9 zNla}pMM_Xpb6QR~ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+WN>V{FUrS>}MMY3lUqoHBVqtS-NmF4- zVnszUGha<#WMyG&Y;R*>bY(?$0AE^8Q*=0AQet0pa%E*nYEyJHaA9e3NlR)|b462h zF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYjF-3L&Us_I6bTKhsRCRD{ zWnXD+aBN9TZ81ekT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4J zPgF2pMOAE2Q*%XMMMXn0MN&&sMqdD5T251RHg;uWbZ>G=P);~*Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$Xp zUqwYUVqs%zMRovRT251RF)(#*X>oOBUvPACNmFz)ZDDXpQ*%x@ZftL8ZDDS1F)(6b zb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z& zQ*<Qa!E^5b5k{6MMXtgPE$2sHe+&SVRU6lQ$t@$QcF`q zUqwYlP*h(;a8Fb)Uqw}HP*X!+MPEfRF=u6TUu0!$Wprh7MRovRT244_Y;S07VQy|Q zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7 zWpYJDGi7dMMRovRT2518Nn=GrGDUVkKu1hTLPJQa!E^SQ*%W{aBxL-0AE^8IbUCAZgpQ{cz7{0Ze@30VQg$~ zV_|e}a!FHjMME(~QcF`YUjScPPD@jCF*9v%c4c2_bY*g3bZ>G=P*Zb7G-6?MWkq%X zUs_I6bTn{bX>v(WQ*<#nUs7UUbaG{7Uv6(?WnW@pb7fO8UqwSPNm5W#bTKnuQet0p za%E*-Zf|5|NmE}*OH*@BIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2 za#M3+Y;9yyVNO#vUokXcWNcq^WpZg@Y-xIBaz#Z&MMY9mF<(q#F-1j1PgGw|R4`uv zUs_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDx zZ$(8@bTKerQ)O&rV{|cdbV*Y*Uqw@NG;C#ab4gQkMN?r(Q#4;iMME-0b^u>mPE&L- zGGA6@V{~tFUt(c%Wl2+WQ(;L{b45ilGGA6@V{~tFUukV{Y(p|db^u>mPE&L-G+$qH zXkl_?WM5-%b#8P?OinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXq0MRovRT251R zHg;uWbZ>G=Q*%>cNmFx0MKxk&XK8Llb^u>mPE&L-GGA6@V{~tFUt(c%Wl2srZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXtZVM$XpUqwYjF-3L&Us_I6bTe&Xa7k)Yb5nFQY-MwENoqw?VM$YT zG;m>Qa!E^SQ*%W{MKLjKZ+B&KUt(`{Ze&GLQ!`%xUs_H}Q*<#fUsGjlWn*+Pb96~l zbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF-aydnEa&K};Zf0*qMMYz5MN&&sG+zK;UuSrD zUvOn|b8l{8Y-x0PUv@A+KtotqK|)DiF)lLzUs_XiaBN9qQ*<#gV`yP=UvzR|X>@Z* zV?|S8Nn=GtQ({R}UsNz(R54#gPg6EuQcF`dUjScPPE%n?PB?CCZ)j~{Zf-F!VqtS> zV_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z& zMME(~b^u>mPD@jCHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAX zb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMX1ZZe&Gv0AE^8IBslj zXl-F`ZZ>3PbYW?1HgI8bb7gW#PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXn0MNd<7F)(vzVRB_;UvPACNlsHR zUotXjZg6#UUtwfnaCBvIUvP47bZ=vCY(+&=bU0>pZew(5Z*ECOVrfoOH(xO`aA9(D zWnX1>Wo~p|bVX8AHeW?WVgO%SPE&L-H(yd>UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(R zQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^p zF*IRhY+rL_a%o{~X?kUHMMXtLMME(~P*Zd@Z*Q(;L{bTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS>V_#}> zZ*ECbFke%2Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#a zb4gQkMN?r(Q*<V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGy zb7gXAVQgu7WpYJDMN>3iNmDjoQ(;L{HeW?WMR06IYye+haCB&LWnpArYh`&~V{&C- zbY(z5M@&gVLtip3GA=a$Us_H$ZftL8ZDDS1He_XVVQFkKFllaZb#z~IbaG{3ZC_zz zVQ_S1azimiQd4OFUs_I6bTKhsRCRD{WnXD+aBN9TZ81ekT244_Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A& zMK)t{Wnpw>NmDalNmDgnQ(;L{HD5(VN>WQxIA29YMNm{v(RQ*%x@ZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUH zMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMX7ba$$32LN#M} zcrh_WQ*<#mUs7UUbaG{7Uukq@a$$6Da!FG-Uqt|4T2pj4W^ZzLVRB?iQcF{GHg;uW zbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRh zY+rL_a%o{~X?kUHMMXtZVM$XpUqwYlPgGx0PE&L-HgaWcZ+2y0a%E;^a%FB~Wl2*( zUqv)@d2nS#0AE^8Q*<WoWUqwnxZ7@YeN<~UVMMY9mbTxE! zaBO8sNvG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa) zW^YABQ*<#fUsGjlWn*+Pb96~lG+#wibTn*bb8|^kb462ONmDdmMMXGYQ(tyrY;|Qt zP)k#EF*9FMVqbJ}Wo2J(Z)9ajQ#4;i0AE^8OH*_)Ghae!bYE$7WpZJ3Z*pyEMQi|H zT251RF*adrY;R*>bZ>HBbaG*7baP2lVM$InZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLMLA<{ZgX^U zbz^i%Q#D^oQcF`cUqwYlc2ZL|Ur?_BUt(c%Wl2zN zMO0r?F<$^*T251RF)&|9WnpArVqtS-Nla}qMOsccZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3 zWl2*qUrAGQQ#D^xbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#D^jMMX+QMMY3lUqomPE&L?c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2 zZb?&gGi_mTQ(seaVr*?>Q(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#4;iMKLmE zZE$R1V`X1rVPk7aN>XG+MMZW*a8FcU0AE^8Q*<2huZ**v7a$jX~a&K}&GDT8LQ!!rvUs_H$ZftL8ZDDS1He_XVVQFkJIcjrn zZeMd@cwc01ZC`LdS!A&MMXt6b98cPZf8YOQ*!`cT2pi}F<)O{WMpz> zb8~NINmF4-Q*<&jUsG^jV{dhCbY)~;aCCBCX>M?AVPj=UPB?CCZ)j~{Zf-VYWprU_ zY%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{GhanaPB~v+XKr<0V|aKmGG9z@V{2b< zZ)|B}c||fsMMXtWR9{k4IbQ%_V`F7=b3i~xOi4mRUotK-E;RsOT244_Y;S07VQy|V zWMy<=X>2k$YIARHUvpu2Uu17>Ut?ixY+_+!YhQ3-a&u*JNlsH=F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MMXt1HEwln zVr6n)b#8NMXKrO=MQs3IT2518NmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x@ zZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRh zY+rL_a%o{~X?kUHMMXtLMMXn0MN&&sL0bZ>HBbaG*7baP2l zVM$InZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXtLML2C?cwcjAdSyjYOH(#q0AE^8Q*<+JVQ@)Pb51yJ zY;S07VQy|QFk)eIX=7h%b8l`*Q(sebHg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0 zX<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<mPB~v+ zXKr<0V|aLOWl2y=V^efCc4cF9Z*oavQ(;MCMMXtLVp2;^Q(rMRUtex-a&2L3Uukq@ za$$6Da!FKQR4`vfMN>jw0AE^DbU0r`Wpi|LZ+S^hIbUCAZgpQ{cz7{4Utex-a&2L3 zUukq@a$$6Da!F8Ab5nFSc4cF9Z*oafb5mhSQ*%W{MMXt+R9{m!UjScPPD?m$Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXA zVQgu7WpYJDIdpk&WnXS#ZDmDv0AE^8Q*<#gUsQE)Y-L|*ZE$Q!Ol>elN>5XBMMXDX zO@Z*Q(;L{bTe&Xa7j~hPB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbFke%2Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0 zX<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<vG;m>Qa!E^5b5nCgQ*<#fUsGjl zWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMXq1MRovRT244_Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJD zF)(U#Z*E_9VQh6}Lo!8V0AE^8Q*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b51yJY;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0 zX<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*YZ)9afMMY3kbTKnuQet0pa%E*-Zf|5|NmDpqMN&&s zMPE`>UjScPPE&L-Fmq^Oa%E&+aCCA>PB?CCZ)j~{Zf-VYWprU_Y%(%wZg6#UUtwfn zaCBvIUvP47bZ=vCY(+&wGDT8LQ!`%xUs_H%Utec#bzft6criC$Uv6)5ZDDL*X>?_B zVRUbDNl;KuIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q#4;mQ#W5zVM$XrUqwYlLo!8DOH(*s0AF8p zY;#{{WprO*WMpzcKu1hTLPK9NE;9gMT251RF)(#*X>oOBUvPACNmFz)ZDDXpQ*%x@ zZftL8ZDDS1F)(6bb7^B=YIARHNmDRiQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^ zWpZg@Y-xIBaz#Z&Q*<Qa!E^5b5k{6MMXtgPE$2sHe+&S zVRU6lQ$t@$MMXtWR9{4JPgF2pMOAE2Q$t@xUqwVRMRovRT2pi}IbUCCbY*g3bZ>HB zV_|eG=P);~*Y;S07VQy|Q zFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+> zdS!A&MMYCJUrAFpUsGX8Q#W5lMMXtLPE&L-HEDEZa$$6Da$j_EVQF-8NmO4&F*j*+ zWpZJ3Z*pH_VRU6@Z*qA>QcF`rUjScPPE&L-GGA6@V{~tFUt(c%Wl3XGVM${}MME-0 zb^u>mQ*<|GZ*q5Ga%4$TOH*_-aA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMXtVR9{j~ zQ*<#la%F9Ac4c33WoBh^Wo~0-NmD{!MKpAIaAidRUs_I6bU0s9VqbJ}Wo1cIb5nFQ zaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwE zNmFx0Q(;L{IA29YGC5yOUuR`>UukZ0WpZ?1XlZVAUv+M2adl;1aBp)(Q*<&jUs7UU zbaG{7Ut@1>b97&6bY*g3bZ>G=Q#fBmQd2Qs0AE^8Q*<#kUte`@X>nh0baG#5ZE$Q! zQ*&BQIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#p zUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3Xb4pS{F<(n#MMXtWR9{4JPgF2pMOAE2 zQ*%XMMME)3QcF`uUqwYzMqf`;L0bZ>G= zQ*<#iUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b5nCgMMW_%WMyG&Y;R*>bY(?QQ#D_0 z0AE^8Q*=3EVRLC?Uukc1Nn=xVF)?FkVRBz|a$#w7b4g=GMKxn=WnpqfQ*<#hUrBFs zUrBFsbYXO5KtM-KNkT(dSYI(PE&I+GG9|)V{dMAbaHiLbV*QSMMYCEUsPXH zF<(+kQ(;MCMF3w~PE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6b zb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUH zMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^kb462ONmDpqMMW_*Urk?ZZ+B&K zUt(`{Ze&GJQ*<#iUs7UUbaG{7Uv6(?Wl2*wUqw(;bTK$zQet0pa%E*-Zf|5|Ut(c% zWl~cyUjScPPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTe&Xa7j~hPB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbF<(=3Hg;uWbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+> zdS!A&MMYC|G;C#ab4gQkMN?r(Q*<?_BVRUbDNl;5ub5nFSc4cF9Z*oafb5mhSQ*%W{MPy|~ zb^u>mPE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNlrL!Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMXtLIb&~b zb98cbV{}PVHD5|jQ!rmPWMy<=X>2!kVQh6}Uvx!9MMZW}Q#M~vR9{4JPgF2p0AE^D zbTK$}ZfS05bZKF1X?kU3Ut@1@c}Y`rF*9v%c4c2_bY*g3bZ>G=P-8_?F<(VgFke(( zQ#4;wGhYB-T251RF*09PWn*-2a$jO$b7e_TPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDMN?r(Q#M~k zMMN=0b^u>mPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z$F-cNlVoYf;MMXtVR9^sJUt@S-Uvy}4Z+AdI zLs(crLP=jSE;9gMT251RF*RRbb#7^KUvPACUukV{Y)MmeHg;uWbZ>G=PB?CCZ)j~{ zZf-F!VqtS>V_#}>Z*ECbbTe&Xa8oc}Q*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUH zMMXtZVM$XpUqwY)PE$2sHe+&SVRU6lQ#W5qMMXtWR9{4JPgF2pMOAE2Q#W5lUqvx6 zUrk?RWo%`1WpYJ!0AE^8Q*<#gUsQE)Y-L|*ZE$Q!Ol>elN>EdDGi_mTNmFx9IBslj zXl-F`ZZR-oVRLC?Uutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXA zVQgu7WpYJDMN@P%Y-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw> zNmD~#N<~FQP*h(;a8Fb)Uqw}HQ$$}yUqwYjF-cNWL|;l$OH)f zV_#}>Z*ECbbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJD zMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YGi7dMMRovRT2pi} zICXAmZfSIBVQgu7Wn^DtZ*X}@Q*<#iZEtpEUukq@a$$6Da!F85IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIB zaz#Z&MN>ClMN}|fR9{m;UsE|>0AE^8Q*<#lVQg$~V_|e}a$j_EVQF-8NmF4-Q*<#i zUs7UUbaG{7Uv6(?Wl2+XG;m>Qa!E^5b51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YAB zMMXt1Fl1$6Y;131VRU6hQd2iyP*XNvZ2(_dPE&L-F<(@5aBO8?X>D+9Nla}pMM_Uo zb45i%F-1>PF<$^*T24z-bT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XoUqwYVVr6G(Zbfzg zUs_H$ZftL8ZDDS1He_XVVQFkKIBIimZeMd@cwc01ZC_(yY;0m-V{2bv(oP*XNvMNd>;VgO%SPB?CC zZ)j~{Zf-VYWprU_Y%w`%b8l{6b76R2WN&R>aA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLmHVQyq> zWnXq-Y;|QxQe;I%P*XNvPgGw3Us_H$ZftL8ZDDS1He_XVVQFkRWq4y{aCB*JZbLCe zQcF`YUjScPPE&L=aA9e3Nl;UCF*sjRVqbJ}Wo2J(Z)9a(VqtS-Q!!sfLo!KHQ!!sm zVlhQUMNd>;QcF`YUjScPQ*<V_#}>Z*ECbbTe&X za8qQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJDF)(U#Z*E_9VQh6} zMMX|ibU9^iVPb4$UukAZSaWhybT(gKVQyq!NlH_6HeX+EZ**TtQ*<#kUtei+UvzbF zY-L|;X=`OkR9{6!Q*<&hX>(s~Z+2y0V{dMAbaHiLbZKI2Wl2*)Uqw@NF*s>+Uu|!8 zWnW=)b7^O8VPb4$NmD{!MMXt5c42IFWkq&HG<11zWkpg`LSIu%UjScPPE&L>bailS zWl2goF*IRhY+rL_a%o{~X?kUHMMXtZbTn*bb8|^kb462ONmFz*aA9e3NlR06 zQ#D^jMMYXpQ#D^UV{&C-bY)3XLtjc#OH)H%MMXtWR9{4JPgF2pMOAE5L|;W;MMXm~ zNm5fpUs6j`O3i0AE^8 zQ*<#hUqoedbaHQbUtx84NlaofMMXJZUu0!-baHQbNl;KuIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#rUokXcWNcq^WpZg@Y-xIBaz#Z& zMMZX0UsFL}0AE^8OF3U(XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*- zZf|5|NmFz*aA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8#ML2C?cwcjA zdSyj+0AE^8Q(;L?IBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJD zLor2COH(pm0AE^8IBsljXl-F`ZZ>3PbYW?1GB|2;Z*E_6VR&C;Z*5;=VQg$-VPk7w zaA9(DWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXc zWNcq^WpZg@Y-xIBaz#Z&MME-0Qd2fxQ*=0Hb#7yHX>V>xMq+7BQ!rmPaA9(DWpYVV zHeW?CGjL&Yb7fy;c4cmKUvx!NIA29YVgO%SPB?CCZ)j~{Zf-VYWprU_Y&C3Ucx7@) zPE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXA zVQgu7WpYJDMMW_)W* zX+;2ET2xk3bTKn>b#8QNZDn6&a&m8SKtM-KNkT(dSYI(PB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIB zaz#ZkFluveZeMm`Y;|QrGDU0vUs_I6bT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^DlQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XoUqwYj zGDT8LQ#M}!Us_H$ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ zZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MQM0NZ2(_dPE&L-Fmq^Oa%E&+aCCA>PB?CC zZ)j~{Zf-VYWprU_Y%(%wZg6#UUtwfnaCBvIUvP47bZ=vCY(+&wGDS~QGhYB-T251R zHg;uWbZ>G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5WK&^IQ!rmK zG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMXq0MRovRT2pj5UqoedbaHQbNlrL!Y;S07 zVQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0 zX<=+>dS!A&MMXt+P*h(4Us_I6bTKtwUv+M2abIwBa$jj}aBN9abTe&Xa7j~hPB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbFke%2Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0 zX<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<G=P*6@dZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLG-6?MWkq%XUs_I6bU0s9 zVqbJ}Wo1cIb5nFQaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q

Q(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;u zNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YL@`Bn0AE^DbTKktUu|i0WpZC)VRL0kP-8_z zRAX#0GGAY9X>?_BUt(c%Wn*k)bY^g0G-6?MWkp3rQ*<#iZEtpEUukq@a$$6Da!FKQ zMF3w~PE&I>X>N06a&$#)P)lP#Ku1hTLPJ3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJDLo!KIVM$XmUqwn% zQ)xv-MN@P!IbTz7Uu|J)WnXh>VRB_;Uvyz-QcF}{L~u`3Fkb*)T251RF*adrY;R*> zbZ>HBbaG*7baP2lVM$InZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXtLMLA<{ZgX^Ubz^i%Q#D^oQfx&< zMRrnCHeXOwUqoQa!E^5 zb51cbMRIa)a!p}wVP|D>IYn}EZ*oa)W^YABMR0UQb^u>mPD@jCF)(#*X>oOBUvPAC zNmFxLPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zFkdk=VPtGyb7gXAVQgu7WpYJDHe+&SVRU6lQ*%mEK`~!TV?{+pP*h(;a8Fb)Uqw}H zP*Zb7UqxefVnucUUs_I6bTK$zLTPkgX>?_BVRUbDUt(c%Wic>cOWp`g;Y;131VRUbDNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#~rF*IRhY+rL_a%o{~X?kUHMMXtLMMXGaY;131VRU6hZBR>g0AEQ|O} zb97~LR82!{Z*FB&VPb4$0AE^8Q*PF<$^*T247%UuSN0 zUt@T9F*jddZf|mJVQgP%bY*g3bZ>G=P-9bcHg;uWbZ>G=V^d*CV?{+pLo!8DOH(ml z0AE^8Q*<#fb7*05Wn^D)baF{fIBsljXl-F`ZZ>3PbYW?1GBRmyaCLNFVPs)&bY*g1 zaB^>SZ)0z4MMXq0MRovRT24z-bT)QnV{~tFNmFxEVM$YSMMX1ZZe&Gv0AE^8Q*<#f zUr1$PWM5)ob7e_PZ7@YpQ*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzFke%1Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN?r(Q#D^jMNDEaMMXDX zOG=PB?CCZ)j~{Zf-F!VqtS> zV_#}>Z*ECbbTe&Xa8of~Q*&Z$ZDdnnPE#^pF*IRhY+rL_a%o{~X?kUHMMXtZVM$Xq zUqwYlIALsTZ)0I}WkqdJOLhQXT251RG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h% zb8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMXtJ zGD%8LQ*%X1MMXtZbTTn;X=P(&cWHBFUt@1>b98cbV{~71Q*mPE&L^Us7UUbaG{7NmFxEbTn{b zX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#^pF*IRhY+rL_a%o{~X?kUHMMXtLQ*<#fUsGjlWn*+Pb96~lIA29mbTn*bb8|^k zb462ONmDpqMMW|(Urk?UWprOoZ)9a(VQg$~V_|e}az%CkUs_I6VM${}Lor2mKtM-K zNkT(dSYI(PE&L^Us7UUbaG{7NmFxEbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF- zaydnEa&K};Zf0*qMN@P!Fke$;Y-M9~F>`cDQ#4;iQ*<G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&X za8qAXb7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMW_-UsPpnaBp&9 za(Q2NVQh6}L^4Ho0AE^8IbUCAZgpQ{cz7{0Ze@30VQg$~V_|e}a!FHkHg;uWbZ>G= zPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8of~Q*&Z$ZDdnnPE#^pF*IRhY+rL_ za%o{~X?kUHMMXtZVM$XqUqwYlH)LgVbaHQbNmDpqMMZW{R9^sJT24ziZftL8ZDDS1 zHe_XVVQFkNY-M<5a!F28UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yy zVNO$DF*IRhY+rL_a%o{~X?kUHMMXtLF*s*sbYE_DZDM6|UukZ1WoKn_MRovRT2pjz zY)NBNbTKhwXkl_+baG*7baP2#MN?r(V?{+%Vo6kAR4`vuF<(VcOH(snPg6Eu0AE^8 zIbUCAZgpQ{cz9)TNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZG+#+mHeXX=NmDjoMMXtLVp2;^ zQ(rMRUtex-a&2L3Uukq@a$$6Da!FKQR4`vfMN>v!0AE^8Q*=0AQet0pa%E*nQ*%>v zG;m>Qa!E^5b5nCgQ*<#fUsGjlWn*+Pb96~lGG9egbTn*bb8|^kb462ONmDXkMMXDX zQ(tUlW^_eRQ*<#nUs7UUbaG{7Uv6(?WnW@pb7cTuT251RIc0cbWpH$9Z*D^}MN&&s zUjScPQ*<|GZ*q5Ga%4$TOIl7iZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)Qn zV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+WN>WQxb45i( zP*h(;a8Fb)Uqw}HP*Zb7Uqw$-IbTvvQ*<#la%F9Ac4c33WoBh^Wo~0-NmDsrMKpAI zaAidRUs_I6bTKtwUv+M2abIwBa$jj}aBN9abT)QnV{~tFNlrL!Y;S07VQy|QFk)eI zX=7h%b8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{ zHD5(VT250nUp8ZMWnpw>NmDmpN<~FQP*h(;a8Fb)Uqw}HP*XQwMPEfjF-cNOQ$}A! zMN>szPg6Nx0AE^DbTKktUuR`>Uub1)aAk5yOl>elP*Zd^c4cF9Z*oaaIBsljXl-F` zZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A& zMMYC#NmDgnMMX+lPE$2sHe+&SVRU6lQ#W5qQcF`eUqwYlP*h(;a8Fb)Uqw}HQ#fBm zUqwYyOH?plQcF{GF)?3Mb#QEDUukV{Y)M#DUqwn&Nnb>8R54#gMF3w~PE&L-G+$qH zXkl_?WM5-%b#8P?OinppUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXm~MRovRT2pj4 zW^ZzLVRB?iV?|F?Us6s}bTKw^Wo>VEWnXe-W@U0^ZewLhQ!rmeG<11zWkmpAT2518 zNmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF-aydnEa&K}; zZf0*qMMXtJGDUU(Us_I6bU0s9VqbJ}Wo1cfQ*<`cDQ!-ygQ*<HDXJtig0AE^8IBsljXl-F`ZZ>3PbYW?1F*a## zc42I3WM64?WpZJ3Z*oL1MRovRT2pjxWl2+XGi_mTNmFx9IBsljXl-F`ZZR-oVRLC? zUutu2Zb?%xUsH58c4cF9Z*o&}Vr*?>Q(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMN@P% zY-MwENmFx0Q(;L{bTn{bX>v(RQ*%=_UqwYlT250nUp8ZMWnpw>NmD~#N<~FQP*h(; za8Fb)Uqw}HP*X!+MPEf?QcF{GF)(#*X>oOBUvPACNmE5%R4`vfL~a0IT251RHg;uW zbZ>G=Q*%>cNmFx0MMN=0b^u>mQ*<#hUtecsbYEy?Y;a|ANla}qMOsccZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~ zX?kUHMMXAaa%Ew3Wl2*rUrAFnUsGX8Q#D^jMM_0QMNm{ zdS!A&MKp71dSyj+0AE^8Q(;L{bTKnuQet0pa%E*-Zf|5|NmFz*aA9e3NlR06Q*%W{ zMME-0b^u>mPD@jCF*jdQVqbJ}Wo2J!bY*g3bZ>G=Q*<2kuX>M?JbYF9Ha%Ev{UtwfnaCBvIMN?r(Q!-ygOinpp zUuSN0Ut@T9F*09FZ)0m;aBpmBV|hg~MMXtJF-cQ0UqwYyOH*MQ(;b1Fkdk=VPtGyb7gXAVQgu7WpYJD zMN?r(Q#D^jMKL#DOG=P*XKuQ#W5lMMQ8b6-zzWo~V6 zWMxxd0AF8Ycwt{>bzyR3Utwc$b!l>CKtMxSSV2NbUokE-0AE^8IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUH zMMW_%YIARHUv^<^b!9^`MN&&sa{ymjPB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSF zWnpb!VPs)&bY*feGiPOVUt?%ta$#e1WpYJ!0AE^8OE_+9Z)j~{Zf-VYWprU_Y%wr! zZ*ysMX>V>{bYpgHMRovRT251RF*adrY;R*>bZ>HBbaG*7baP2lVM$YTF*9FMVqbJ} zWo2J(Z)9ajQ*< zY;R*>bY(?SQ#W620AE^8Q(;L?IBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMXtLLor2COH(yp0AE^8Q*<+J zVQ@)mQ*%>vG;C#ab4hANQ(;L{bTn{bX>v(RYEyGXMMXn0MRovRT24zjUtec#bzft6 zcriC$Uv6)5ZDDL*X>?_BVRUbDNl;UBQ*<_VWn*-2a!FHjQ(;L{b45i(WMxHm0AE^8 zIBsljXl-F`ZZ>3PbYW?1HEd;gWpYVQQ(rMKVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1UokXcWNcq^WpZg@Y-xIBaz#Z&MKLpHWprO-Z)9a~Z)t9HMRovR zT244_Y;S07VQy|VWMy<=X>2k$YIARHUvpu2Uu17>Ut?ixY+_+!YhQ3-a&u*JNlsH= zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+> zdS!A&MMXt1FlBCJUvFY+Wn*+jb^u>mPB~v+XKr<0V|aKmH(y_FZ*py6Y+q?~WpZJ3 zZ*oacOHMd$Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^I zQ!!sLG+|_HUvp)0X<=+>dS!A&MMYCIUrAFoUsGX8Q#M~kMMXm~MN&&sI9~u?T251Q zHeqmZWo~3eP)lP#Ku1hTLPJWQxb45i(P*h(;a8Fb)Uqw}HP*Zb7Uqv=wO5XBMM_0QMN@P# zF>q;RV`X<~b7fy+Z*FsRa&=>LUvyJ+HFR}wY-LGGL~vAJMMYCWUr9V_#}>Z*ECbbTe&Xa8qQ(;b1 zGG8$?VPtGyb7gXAVQgu7WpYJDMN>6jNmDmpQ(;L{H(y0XMMYCWUqw_gUsNz(Q$$}= zLtg-2T251RF*ILab7*05Wn^DtZ*^{TNlZ>TUtec#bzft6crh|xOmAarUvO`1X=8as zGDSr?_BVRUbDNmO4& zQ#D@zUs_I6bTTtvQet0pa%E*-V{dMAbYE$7WpZJ3Z*oafbTn{bX>v(RQ*%x@ZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#^pF*IRhY+rL_ za%o{~X?kUHMMXtLMME-0QcF{GF*jdQVqbJ}Wo2J!bY*g3bZ>G=Q#fBm0AE^8IBslj zXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_ za%o{~X?kUHMMW_%YIARHUv^<^b!9^_MQs3IT2pj6bZ=jCbaH8KXKesqT251RIA2m? zUvzS1Wl2+WQ*<mQ*<+DWpqhQZ7@YjQcF{F zMMY9hQ*<#ibailSWnX1%Wo>0{bV*oLUqw@NHFR}wY-LGGL~v9vUqwYlG<11zWkpg` zHeUc=T2518NmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RYEyGXMMXq0MRovRT3Svx zZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_H zUvp)0X<=+>dS!A&MK)t{Wnpw>NmDXkNmDdmQ(;L{G+#wUN>WQxH(y0XMNm{?_BVRUbDNmFz*aA9e3 zNlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8#Lo!8BQ*<#nUs7UUbaG{7Uv6(? zWnW@pb7cTuT251RF*adrY;R*>bZ>HBbaG*7baP2lVM$YTF*9FMVqbJ}Wo2J(Z)9aj zQ*<G=PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qAXb7E|5 zWK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDdmMMXGpZ*X5?VPk7Wb^u>mPB?CC zZ)j~{Zf-VYWprU_Y&mIkWpZC>ZE$Q!PE%hoFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMXn0MNm^VUjScPPB?CCZ)j~{ zZf-VYWprU_Y%wr&d2nT4WpZ+Fazrvkb^u>mPE&L_Wq4y{aCB*JZbULgc0fQ!Oi4mR zSXf^(E;ImNT251RIA(QjV{~b6Zb?RBX-+t9Y;S07VQy|VWMy<=X>2xdVRCb2a!F28 zFkdk+VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1Fkdk=VPtGyb7gXA zVQgu7WpYJDMMW_)aA9(DWnX1>Wo~p|bVX8AH(y0XLo!8DOH)H%0AE^8Q*=0AQet0p za%E*nQ*%>vG;m>Qa!E^5b5nCgQ*<#fUsGjlWn*+Pb96~lGG9egbTn*bb8|^kb462O zNmDXkMMXGYQ(tmvXJ~XqP)k#EF*sjRVqbJ}Wo2J(Z)9a(VqtS-0AE^8Q*<#iUs7UU zbaG{7Uv6(?Wl2+XG;m>Qa!E^5b5nCgMLAzhUv^<^aCCA-b^u>mQ*=0Kb7pC7X>?^| z0AE^8OF3U(XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oafbTKnuQet0pa%E*-Zf|5|NmFz* zaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8q zQ(;b1G+!|^VPtGyb7gXAVQgu7WpYJDMMXtLIBj8gUvp`CWkq%XUs_I6bTKktUvp?- za%E&+aCCA>PB?CCZ)j~{Zf-VYWprU_Y%(%wZg6#UUtwfnaCBvIUvP47bZ=vCY(-2? zIbUCAZgpQ{cz7`~UrcXfYhQ40Y-wY8MKVQ2L^4Ho0AE^8Q*=0AQet0pa%E*nYEyJH zaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYYUrk?P zWoKz_MRovRT2pi}GGAY3WprO?Wo&R|a!E{WFhx*Pb4prHIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Zp zV{&C-bY)3Xb4pT6Q*%W{MNm{F<(@5aBO8? zX>D+9Nmx{0MM_ggUqobZ>G=Q*<#iUs7UUbaG{7Uv6(? zWl2+XG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ#4;OG+|_HUvp)0X<=+>dS!A&MMXtLMKLgBWnpY=Z)0I}Wkpa^LSJnF zUs_H$ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%ho zG+|_HUvp)0X<=+>dS!A&MKLgHb8l{6c42IFWkWJWQcF`YUrAGQQ#4;wbTn*bb8|^k zb462ONmFz*aA9e3NlR06Q#4;iMMVH#T2pj1V{dSINmFz&Gi`5nWnXD@WpZJ3Z*oac zP);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!!sL zG+|_HUvp)0X<=+>dS!A&MMXtZIA29nFke((Q$k-;L0G=Q*%>c zNmFx0MKLmEZE$R1V`X1rVPk7aN>g)1MMZW*a8FcU0AE^8Q*<#fb#7^Kb!A_0baF{k zbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D0UsH2pY;9yyVNO#q zUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HD5(VT250nUp8ZMWnpw>NmDmpN>WQxH(y0X zMNm{V_#}>Z*ECbFke%2Hg;uWbZ>G~ zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC|G;C#ab4gQkMN?r(Q*<G=VpCyBVnszXVqs%zMRovRT251R zF)(vzVRB_;UvPACNlrL!Y;S07VQy|VWMy<=X>2kwX>M?JbYEd)VQ_S1a$j(AZ**^C zZ)`Wp`g;Y;131VRUbDNl;EWZftL8ZDDS1 zF)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~ zX?kUHMMXtLLor2m0AE^EQ%*Q;Y;S07VQy|VWMy<=X>2hvZ*_EEZ)RU|VQyz-MF3w~ zQ*<#hUtecsbYEy?Y;a|ANla}pMNm_7N?J}hZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+W zN>WQxb45i(P*h(;a8Fb)Uqw}HQ!rmeUqwYyOH?plQcF{GF)?3Mb#QEDUukV{Y)M#D zUqwn&M_)v6R54#gMF3w~PB?CCZ)j~{Zf-VYWprU_Y&UdoUutu2Zb?p4UokLZVRLC? zUutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_a%o{~X?kUHMMXtz zOldGhMMZW}R9{puUjScPPE&LQa!E^5b5k*2MMXt7Wo>Y5VPj=UN>WpEQd2QsMMXtZ zG+#+mbTKzyQet0pa%E*-X>?_BVRUbDNmDjoMPfxna8FcU0AE^8IBsljXl-F`ZZR}r zWNcq^WpZg@Y-xIBa!GA=MK^SBUutu2Zb?p4UokLZVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVN)<)MMY9=MMXqZV{Kz>OkY|~Q(rMMUq?(&LP1PlUrt{!H*{}b zYIARHMMY+CUt?@HW^ZzLVRB?iR4`vfW^gcHMMYzFc3(wBQdD10Q#oG%Us_H}IBslj zXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO$DF*IRhY+rL_ za%o{~X?kUHMMXDhb6;+CY-~k#0AE^8Q*<&jUsG^jV{dhCbY)~;aCCBCX>M?AVPj=U zPB?CCZ)j~{Zf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{GG9eZPB~v+ zXKr<0V|aKmGG9z@V{2bNmDmpN<~FQP*h(;a8Fb)Uqw}HP*XQwMPEfj zGDTBGUs6j`MqdD5T244_Y;S07VQy|VWMy<=X>2k$YIARHUvpu2Uu17>Ut?ixY+_+! zYhQ3-a&u*JNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%ho zG+|_HUvp)0X<=+>dS!A&MMXt4Zgp&IMRovRT244_Y;S07VQy|VWMy<=X>2hzX>N95 zY-wa)X>?_BVRUbDLor2COH(ml0AE^8Q*<_VWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B= zYIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{G+#wU zHDz*Pb7e(NIbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82Q#4;wHeW?W0AE^8 zQ*=0AQet0pa%E*nQ*%>vG;m>Qa!E^5b5nCgQ*<#fUsGjlWn*+Pb96~lGG9egbTn*b zb8|^kb462ONmDXkMMXGYQ(tyrY;|QtP)k#EF*sjRVqbJ}Wo2J(Z)9a(VqtS-0AE^8 zQ*<#gV`yP=UvzR|X>@Z*V?{P>Wo~D5Xhl#3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJDLor2C zOH(vo0AE^ENmFz=Wq4y{aCB*JZa_dsOi4mRSXf^(E;ImNT23)CMRIa)a!p}wVP|D> zG)Zo0bVXBh0AE^8Q*<&gUte`@X>MtBX<=+>dSzr^V{dSINlaoeMMW_)Ute`@X>MtB zUt@1@c}Y`rF*9v%c4c2_bY*g3bZ>G=P);~*Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!`&NG+|_HUvp)0X<=+>dS!A&MMXtZIbTIZR4`vu zUsFS0Q$k+=Us_H}IbUCAZgpQ{cz7{4Utex-a&2L3Uukq@a$$6Da!F82V^efCc4cF9 zZ*oavQ(;MCMMXt4VqtS-MRovRT247%UuSN0Ut@T9F*9yucVA&_Y;R*>bZ>G=PB?CC zZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGy zb7gXAVQgu7WpYJDMMXJdZ*FsRa&=>LNmDjoN>Xh_MMZW{R9{4JPgF2p0AE^8Q*<#h zUsh#fbZ>HBVqtS-Nn=xCNn=GtL^4Ho0AE^DbTKn+Z+2y0Vqs%zcVTj5Nl;EWZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_ za%o{~X?kUHMMXtZHeW?lFke((Q#fB!H(vl>T251RG;m>Qa!E^5b51cbMRIa)a!p}w zVP|D>IYn}EZ*oa)W^YABLo!KHQ*%;NGG9z$F-1j1PgGw|R4`uvUs_H}IbUCAZgpQ{ zcz7{3UteKtX=iR_WM6G%ZDMt1NmFz*aA9e3NlR)|b45irUrk?OWMpzhb^u>mPE&L- zF<(@5aBO8?X>D+9Nla}qMM_#uIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_V zWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#ZpV{&C-bY)3XGhazlHD6O< zNmDgnMMX+QMMY3lUqob8~NINmFx0P*h)1Q!rluUs_I6bTKnuLUv_ibZ>HB zVqtS-NmF4-VnsznGDUU(Us_I6bTn{bX>v(RQ*%x@ZftL8ZDDS1F)(6bb7^B=YIARH zNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtLLo!K9 zPg8S6N=$7qMMX+QN<~FQQd4v_bailSWl2gza8zGKMN(5iUr9*&NlI9Aa8xp1MMXsbUs_H}Q*<#iUqWegUukq@ za$$6Da&T-#Yye+cPE&L-G+#n#bYF61W@U0^ZewLbF-1^qZ2(_dPD?m$Y;S07VQy|V zWMy<=X>2uYWq4(BNlsH=F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE%hoG+|_HUvp)0X<=+>dS!A&MMXt1HfLpYUvzJ4Wo}<{baH8KXGL}ZUs_H%Utec# zbzft6cri0>Wp`g;Y;131VRUbDNn=GhV{dMAbaHiLbV*}MV?{+pc2HDbL~u`3Fkb*) zT2518NmFz&Ghb3-UvzS1WnXS@WMxTHbTn{bX>v(RQ*%x+GDUK7Z*omxZeeF-aydnE za&K};Zf0*qMMXtJF-3L&Us_XiZe>YRb6QR~ZftL8ZDDS1F)(6bb7^B=YIARHNmFz) zZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;nF*IRhY+rL_a%o{~X?kUHMMXAaa%Ew3Wl2+W zN>V{FUrS>}MMY3lUqoZfS9KWnXY~a!FG`UsNz( zMMQ1@Us_I6bTxE!aBO8sN>WQxb45i%GD&t!VlhQUMN=_f0AF8Ycwt{~b#i52c4=~S zbzy8kKtotqK|)DiF)lLzUs_H}Q*<_VWn*-2a!F!SVM$^|MKLm8ON0AE^UY*2PnUjScPPE&L>bailSWl2g>OH*@2MME(~Pg62q0AE^8OE_+9Z)j~{ zZf-VYWprU_Y%(x#a%pX8bZK^FUukq@a$$6Da$j^fX>(sF*8tMa&u)$b8l`&X>4UhQ*!`cT251RGi_mTNmFx9IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&LQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIBaz#Z& zQ*<Qa!E^5b5k^5MMXtKGDUU(Us_I6bTe&Xa7j~hPBAh? za&m8SO<`_fXJv9ZMRIa)a!GDxZ$(pdG;C#ab4gQkMN?r(Q*<b97&6bY*g3bZ>G=Q*<v(RYEyGXL@`Bn0AE^8Q*=0AQet0p za%E*nQ*%>vG;m>Qa!E^5b51yJY;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uW zbZ>G~b7E|5WK&^IQ!-yMG+|_HUvp)0X<=+>dS!A&MMXtZbTKerQ)O&rV{|cdbV*Y< zUqw@NG;C#ab4gQkMN?r(Q#fBmMMN@1b^u>VR83!UWoKz~bY*f>O+##NZe>(qVr*pq zUs_I6bTKerNM&JUUt(c%Wl2nJFhx*Pb4+3|MMXn0Nm5fVUqwYvR9^sJT2pjxWl2y@ zIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#Z&MPgD*Q*<#iZEtpEUukq@a$$6Da!FKQMN>jw0AE^8Q*<#h zUqoedbaHQbUtx84NlaoeMMXJZUu0!-baHQbNlrOmUuSN0Ut@T9F*jddZf|mJVQgP% zbY*g3bZ>G=P*ZbLbT)QnV{~tFNmFxEVM$YSMMXtLMMZX0UsE|>0AE^8Q*<#kUte`@ zX>nh0baG#5ZE$Q!Q*<+JVQ@)Pb51yJY;S07VQy|QFk)eIX=7h%b8l`*Q!rmsbT)Qn zV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZbTn*bb8|^kb462ONmFz* zaA9e3NlR06Q#D^jMMYXpQ#D^UV{&C-bY)3XLtjc#OH)H%MMXtWR9{4JPgF2pMOAE2 zQ$t@xUqvx6Urk?RWo%`1WpYJ!0AE^8OF3U(XKr<0V|aKmH(y_FZ*py6Y+q?~WpZJ3 zZ*oacPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1 zF<&t>VPtGyb7gXAVQgu7WpYJDMN>3iNmDjoQ(;L{HeW?WMQv$CYye+cPD@jCF*9FM zVqbJ}Wo2J(Z)9ajQ*<3PbYW?1GBRmyaCLNFVPs)& zbY*g1aB^>SZ)0z4MNCdPUtec#bzft6crh|xOmAarUvO`1X=8asGDSs0GDT8LQ#D@z zUs_H%Utec#bzft6cri0>Wp`g;Y;131VRUbDNlrL!Y;S07VQy|VWMy<=X>2kuX>M?J zbYF9Ha%Ev{UtwfnaCBvIMMXJdZ*FsRa&=>LNmDalN>Wp4MMXt+P*h(;a8Fb)UjScP zPE&IV{&C-bY(?tZBk29VM${}KtM-KNkT(dSYI(PE&L=aA9e3 zNl;UCF*sjRVqbJ}Wo2J(Z)9a(VqtS-Q!!sfLo!KHQ!!stG+#_&F-1j1PgGw|R4`uv zY;R*>Y-M9_ZgxOGM@&gVLtip3GA=a$Us_I6bTKhsRCRD{WnXD+aBN9TZ7@YjP*Zd^ zc4cF9Z*oaaIBsljXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sL zG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMYXpQ#D^UV{&C-bY)3XH(yFcMMY3lUqoQa!F!PQ#M~kPgGxG0AE^8Q*=0AQet0pa%E*nYEyJH zaA9e3NlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYUW@&C@ zMN(5SUjScPPE&L-H(yd>UvzS1WnXD@WpZJ3Z*oafbTn{bX>v(RQ*%>uMMZ6GMRovR zT251RF*adrY;R*>bZ>HBbaG*7baP2lVM$YTF*9FMVqbJ}Wo2J(Z)9ajQ*<Y;R*>bY(?SQ#D_00AE^8OH*?;Y-Mg|bZA9(KtM-KNkT(dSYI

(PE&L=aA9e3NlR06Q*%W`F-3L&Us_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06 zPB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GG8$? zVPtGyb7gXAVQgu7WpYJDMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{ zIA29YF*ILIUt@A*VRU6*Zf|5|NlH>nQ*<&haA{>@Wp`Q!!sfMN>*&NlHaUMMXtWQ*<#iUs7UUbaG{7Uv6(?Wl2*wUqwW4PgGw3 zUs_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PB?CCZ)j~{Zf-F!VqtS>V_#}>Z*ECb zbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7WpYJDMMYC|F)&|K zWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YGBjUJUuR`>UukZ0WpZ?1b#7^K zb!A_0Z*xUbQ!!rvUs_I6bU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PB?CCZ)j~{Zf-F! zVqtS>V_#}>Z*ECbbTe&Xa8qQ(;b1GG8$?VPtGyb7gXAVQgu7 zWpYJDMMYC|F)&|KWo%_*bTM;uNmDpqMN@P%Y-MwENmFx0Q(;L{IA29YHDYCFX>LV! z0AE^8Q*<mPB?CCZ)j~{Zf-VY zWprU_Y%(}%b8l{6b76R2WN&R>V_|G;Vqs%zUvOb^b7gW#PE%hoFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_(Xkl(- zY-L||VQh6}Nm6V@MN@P%aA9e3Nn%h_HeW?gR9|8MUs_H%Utec#bzft6criC$Uv6)5 zZDDL*X>?_BVRUbDNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tF zQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZG+#+mHeXX=NmDjoMMXtJF-1~K zQ#W4#Us_I6bTKtwUv+M2abIwBa$jj}aBN9abTe&Xa7j~hPB?CCZ)j~{Zf-F!VqtS> zV_#}>Z*ECbFke%2Hg;uWbZ>G~b7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC| zG;C#ab4gQkMN?r(Q*<V_#}>Z*ECbbTe&Xa8qQ(;b1F<&t>VPtGyb7gXAVQgu7WpYJDMMXn0MRovRT247%UuSN0Ut@T9 zF*9yucVA&_Y;R*>bZ>G=Q*<&jUsG^jV{dhCbY)~;aCCBCX>M?AVPj=UPB?CCZ)j~{ zZf-VYWprU_Y%(xuZg6#UUvqSFWnpb!VPs)&bY*fyQ(;L{G+#wbPE%hoGG9z@V{2b< zZ)|B}c||fsMMW_%WMyG&Y;R*>bY(?QQ#W620AE^DbTKktUv6o1WpZC)VRL0kP)k#D zQ*<_VWn*-2a!FHjQ(;L{b45i(R9{XxUtec#bzft6criC$Uv6)5ZDDL*X>?_BVRUbD zNmDgnR4`vfMF3w~PE&L-GGA6@V{~tFUt(c%Wl2+WQ(;L{b45ilGGA6@V{~tFUukV{ zY(p_cb^u>mPE&L;Ghb3-UvzS1WnW`&ZgX^BX>?_BVRUbDNmFz*aA9e3NlR06Q*%W{ zLo!8BOH*_)IA2m?UvzS1WnXS@WMyAsVRK~wUs_XiH)d~gcVTj5Nohq-R9{j~Q*<#l za%F9Ac4c33WoBh^Wo~0-NmDRiMKpAIaAidRUs_H}Q*=0AQet0pa%E*nYEyJHaA9e3 zNlR)|b462hF)&|KWo%_*bTM;uNmDXkMN@P%Y-MwENoqw?VM$XmUqwYYYh`&~V{dJ6 zMRovRT24z-b2VjcaCCV^c0fQ!Oi4mRSXf^(E;ImNT2pjoaY;~4IBsljXl-F`ZZR-o zVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^WpZg@Y-xIB zaz#Z&MPgD*Q*<#iZEtpEUukq@a$$6Da!FKQMN>jw0AE^8Q*<#mUs7UUbaG{7Uukq@ za$$6Da!FHkG;m>Qa!E^SQ*%W{Lor2AQ*<#nUs7UUbaG{7Uv6(?WnW@pb7cTuT244_ zY;S07VQy|VWMy<=X>2h$YIARHUvpu2Uu17>UvOb^b7gW#PE%hoFk)eIX=7h%b8l`* zQ*<+JVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ(rMOVPtGyb7gXAVQgu7WpYJDMMW_(b97;H zbYE{`YGq?|MQs3IT251RHg;uWbZ>G=Q*%>cNmFx0MLBSFb7)^;VPk7WPg8RMUs_I6 zbU0s9VqbJ}Wo1cIb5nFQaA9e3NlR06PBAh?a&m8SO<`_fXJv9ZMRIa)a!GDxZ$(8@ zbTKerQ)O&rV{|cdbV*Y*Uqw@NG;C#ab4gQkMN?r(Q#4;iMKLp9Qet0pa%E*-X>D+9 zNmDpqOky!bMME(~b^u>mPD@jBH)C&YaA9&~MN&&sb3i~xOi4mRSXf^(E;ImNT2pj0 zXJvFrOl>elN>EdCT244_Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+JVQ^D)Hg;uWbZ>G~ zb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MK)t{Wnpw>NmFx5QcF{FMMXtWR9{4J zPgF2pMOAE5FkeMqMMY9hQ*<#ibailSWnX1%Wo>0{bV*oLUqw@NHFR}wY-LGGL~v6> zUqwYlG<11zWkpg`N?!n9T247%UuSN0Ut@T9F*ILaVQg$~V_$S~VQF-8NmF4-Q*%W{ zGB;mSUvP47aA9X*bY)*}ZeL?>aCu*0b8~5DZbfzgUs_XiH)d~gcVTj5Nm5HrIBslj zXl-F`ZZR-oVRLC?Uutu2Zb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#pUokXcWNcq^ zWpZg@Y-xIBaz#Z&MNd>;QchEJF*b5#ZEtpEUvgz;WpZV1V`WKGIA29Hba`-PMF3w~ zPE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQSNmFz-c4cF9Z*oaaIBsljXl-F`ZZR-oVRLC? zUutu2Zb?&gGi_mTQ!rmsb7E|5WK&^IQ!!sLG+|_HUvp)0X<=+>dS!A&MMYC#NmDgn zMMXtLIb&~bb98cbV{}PVH(yFcMMZW}Q#fBxR9{4JPgF2p0AE^8Q*<&gUte`@X>MtB zX<=+>dSzr^V{dSINlaofMMW_)Ute`@X>MtBUt@1@c}Y`rF*9v%c4c2_bY*g3bZ>G= zP-8_?GhanTR4`vuUsE<;Q#D@zUs_H$ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXz zbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0X<=+>dS!A&MKLgHb8l{6c42IFWkWGV zQcF`YUrAGQQ#4;wbTn*bb8|^kb462ONmFz*aA9e3NlR06Q#4;iMMVH#T24ziZftL8 zZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE%hoG+|_HUvp)0 zX<=+>dS!A&MLB76UvqSFX>Mmlb^u>mPB~v+XKr<0V|aKmGj3&fUtw%)Z)0I}Z*oaa zIBsljXl-F`ZZ>3PbYW?1GB9awaCLNFb98cLVQpVwWMOc0WpYJDL^4Ho0AE^8Q*<_V zWn*-2a!F1&ZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzUsH2pY;9yyVNO#pUokXc zWNcq^WpZg@Y-xIBaz#Z&Q(;L{G+#wUF*0RsaBN{?WnW@pV{1uDQd4t9MMZW*a8FcU z0AE^8Q*<WoWUqwnqMMYC|GBI#z zWn*P`X>(;?V{dMAbaHiLbYFB+bTxE!aBO8sN?_BVRUbDNl;5pIBsljXl-F`ZZR-oVRLC?Uutu2 zZb?&gGi_mTQ*<_VWn*-2a#M3+Y;9yyVNO#qUokXcWNcq^WpZg@Y-xIBaz#Z&Q#4;m zQ#M~yVM$XqUqwYlLo!8DOH(*s0AE^8Q*<#iUqW_eV{~tFUt(c%Wl2+ENn%AsF*9F6 zc4cF9Z*pI0ZE$QvF-3L&Us_I6bTKerNM&JUUt(c%Wl2nJFhx&Ob4+3|MMXm~NmFx0 zMNd>;0AE^8Q*<#hUsh#fbZ>HBVqtS-NlrL!Y;S07VQy|QFk)eIX=7h%b8l`*Q*<+J zVQ^D)Hg;uWbZ>G~b7E|5WK&^IQ!rmKG+|_HUvp)0X<=+>dS!A&MMYC#NmDgnMMW_; zUrk?Qa%Ew3WnXi2Z*pO0WkqcOUs_I6bU0~mb6;X%b7eG1ZfSHxF-3MjKu1hTLPJ2kuX>M?JbYF9H za%Ev{UtwfnaCBvIMNCdPUtec#bzft6crh|xOmAarUvO`1X=8asGDSs0F-cQlNmDXk zMM_drX+=dvQ*<#oUsG^jZDDI=Uvp?-a%E&+bYW*wOH^M(a8Fb)UjScPPB~v+XKr<0 zV|aKmGj3&fUtw%)Z)0I}Z*oafbT)QnV{~tFNlrL!Y;S07VQy|QFk)eIX=7h%b8l`* zQ*<+JVQ^D1UsH2pY;9yyVNO#rUokXcWNcq^WpZg@Y-xIBaz#Z&Q(;L{HeW?WMME(~ zb^u>mPE&L-Fm-Neadl;1aCCA>Q*<+JVQ@)Pb51yJY;S07VQy|QFk)eIX=7h%b8l`* zQ!rmsbT)QnV{~tFQ*&Z$ZDdnnPE#>oF*IRhY+rL_a%o{~X?kUHMMXtZbTn*bb8|^k zb462ONmFz*aA9e3NlR06Q#D^jMMYXpQ#D^UV{&C-bY)3XLtjc#OH)H%MMXtWR9{4J zPgF2pMOAE2Q$t@xUqwSQMN>>)QcF`!UjScPPE&L-HeqaRZ)0I}Z*pIBa$#w7b4gQS zNl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnnPE#;n zF*IRhY+rL_a%o{~X?kUHMMXtLML1z>Y;R*>bY(?SQ#W620AE^8Q*<#hUsh#fbZ>HB zVqtS-Nl;EWZftL8ZDDS1F)(6bb7^B=YIARHNmFz)ZDDXzbT)QnV{~tFQ*&Z$ZDdnn zPE#;nF*IRhY+rL_a%o{~X?kUHMMXtZVM$XqUqwYRGGA6@V{~tFUukV{Y(p|db^rh_ zb9rraVPXI-b98caVPXI-b7*sPa&%#004``@b7%lAWO;6Ld2IkLWO;6LbaDVLXKr;a zc4cyNX>V=-E@y6aE_P*db7^mGUvdC0a%F5`E@XLb04{Q6Y+){NY;*uFX>MtB04{KB zbS`IabO0`NWq5P|E@o+NX#g&AZ)9O~VE`^=XkTV>VQpn!Xk>B#E@fz6W^!R|WdJT` zV`E=scw=R7bYFB~Vr*pqE_7mZa{w-BZfSI1VRCX|c>peEX>Ms>VRCX|c>peCVRT_G za%F5Ta&G`GWO;63ZE0fwE@WYJVE`^-b8`SLV{dJ3Wo~o;00000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000R0000500002000000002U0RR910002U0RR910000~E&u=k000020000000008 z0000000004000000000X0000B00002000000000WFaQ7m0000WFaQ7m0000WwEzGB z000030000100008000000000O000000000f0000300002000000000$<{90{{R300000000000000000000XyFL}00000n-~KC0000000000 z000000RR910000000000000005dZ)H0{{R3000000000000000000001NsaA00000 j_5c6?0000000000000000RR91000000000000000J0#7R literal 0 KcmV+b0RR6000031 diff --git a/third_party/prebuild/x86_64/libslog.so b/third_party/prebuild/x86_64/libslog.so index b476618dc715be24fd75bd5c89a168b0dd9c60a1..01b75e405aa1eb9d1a221806aa5c7355a1c40f7e 100755 GIT binary patch delta 63771 zcmV(#`Q!%Rx&@f329OvMAYuRj00000KmY&$00000n2wPuHh)|~0RR91003M<0RR91 z00000AOHXW00031000I6006i~0RR91006i~ApigX006i~ApigX004Lq00000001as z0000000000AOHXW00062000I6007uV0RR91007uVApigX007uVApigX002M&00000 z002M&000000FmDjB9I>e000000FWO6000000FWO60000003-zf0000003-#I5&=$s zxJCg000000xJDrW00000xJDrW00000NC^M{00000NC^M{000000RR91000002LS*8 z5di=I>;M1&G5`Po*#H0l{r~^~9smFU4*&oF-2eap0s#O3m;e9(00000N&o-=00000 z%m4rY000004FLcErT_o{?*IS*0001g0HXi^07n1-0CWHV0JQ)B0FnRz0P_F<0LB0S z0F(d#0I>i7000000KxzO09gP4073u&00;p90Dk}g09OD204M+e0000003iSX0RI30 z0B`^R000000JZ=C06PEx00000000000Pz3-000000672v0Q>*|00{s90PX;jG65Es zU|azNf8qcD0Qmp_000000G z0MP&d0Db@f0Hgo_0I~o801yEH00jX60O0002{000000000d0000*0001T000000002^e*gdg$^ZZW0000000000xBvhE zQ~&?~vj6}9yZ`_IRR910000002>}2A00000n*aa+y#N3JmjD0&00000JpcdzS^xk5 z00000ssI20Bme*a0000000000zW@LL0000000000h5!Hn00000+5i9m00000#Q*>R z&j0`bB>(^b09yb60GR*)000000000000#j80000000000000000PvHs>@Sf-9FxH8 zOaT^?F##8sxETQulZ*unle`2Fm+V{t43lsL7$FJ(0000000000001fg000L700000 z00000000#L000}4F#!{okX!)>B{u*706zc#000000000006+i$01*HH03ZMW00000 z03!eZ07R290TUf8000000000(00000000000000N000000000wlQ97o0Z)@L0T(?B z000000000p0001E000000001M000000001G00000000000000Y0000u000000000n z0000G0001AmjPJ;8xbV{00000004sk002_}004HAF#!`zf&c&j00000HUIzs00000 z00000Gynhq00000bpQYWSO5S3U;qFB0000000000Z2$lO00000kpKVyi2wiqivR!s zP5=M^djJ3cmXk3769J8rF#!_|a{vGUEdT%j00000r;}j?BROOM00000004ym00000 z003_Q004&o000vJ000000018V00000004ae00000004LZ00000006#|VFe=%dH?_b z0000000000E0gU47aa`%006H5001Tc007GX005r=001=r00000000h?F#!{QUH||9 z00000YybcNFaQ7m000000000000000MgRZ+00000kN^Mx00000od5s;000006aWAK zumAu600000W&i*HT>t<8000000000000000)Bpeg00000jsO4v000000000082|tP zoB#j-&Hw-a;Q#;t0000000000000000C4~S0D%Ai z000000MY;e00000000000Ac_D09=zX0UH4+lTip4G1LhF01^NT0MOe20000005Sjo z0000001^uT01^NT01(*#000000F(d#0000009ltYJpmU<9t8jZ5&#PTV3Pm<00000 zRsaA100000-va;u5&#PTpx^)i00000Gynhq00000lLP<&5&#PT(8&M*00000H2?qr z00000)05!{7Xi000000ImT501^NT003(M00000 z0D%Ai0000002l)R01^NT06=~K000000Hpu`0000007eV|01^NImlr$%5dp225j+7G zVUY#^01^NT0HB@#0000005kvq000000Q?C601^NT01(^&000000ABzA000000Nn@x z01^NT03gBu000000KNbK000000GbK_01^NT0N~dE0000004@Lk0000000NgGF98=Z zGztI!5&#PTklg?P00000G5`Po00000eE|Rf5&#PT5NZGb00000Gynhq00000E0f_4 z7Xgl!F+Bkn84?Zv01yBa05Dh~0000000000000000G*c+JOLL;_5%O_5&#PTu(tpJ z00000O#lD@00000UI_pI5dakcz?mTc000002oL}O00000?hF6`5&#PT5a$2@00000 zTmS$700000)stZm7Xb^GAuj000005(NMN5&#PTaOMC200000Q~&?~00000J^}y$5&#PT z;BNo`00000xd8wG00000?*{+?5&#PTAk6>(000000s;U400000ehB~o5&#QE0AS1j z000000KNbK0000000;p901^NT0N`f;000000BQgL000000A2(D01^NT08q0400000 z02%=R00000089V?03wqy0TTi3ld%gI0TY)IJOLLOegXgh5&#PT0MP&d00000TmS$7 z00000Ete5I0T%&Ali>>&87%<-01*Hc0AN@l0000001yBG000000B4sWF98<;{g)9u z0T(ey0RR9J01E&hX#fBK0001R000000000^3;+NU01E)n;s5{u0001v000000001? zlK~bNlQ0$tDbREP0000003QJW000000H6W@01^NT0C3U(000000DJ%d000000C$%$ zJpmU1_miOs7a2MX000sI3jlE900000002|~00000004@UVGtKdm>Dt7Xgx!K@}GnG6w(v5&#PTu&4k400000!2kdN00000&XZvf7Xj{* zK@}HaJOls$5&#PTAc_D000000y8!?I00000gAD)x5&#PTaOwa600000G5`Po00000 z83X_T5&#PTP_O_100000`~m;~00000TL1t65&#PTkYxY>00000ZvX%Q00000C6i$g z7cn9X000sI3jk2z000000037200000007tl000sI3jm;O00000001-r00000007pL zK@}I1Pyqxj5&#SU%<2FD0000000000000007Y6_U5&#PTaHjwO00000F#!Mo00000 zh?C(C7n6_*29u@<5&?~uAujg00000001Nb00000007pP5j+7GNumJ&01^NT z0KjSh0000005kvq0000000IpF01^NT0C4930000009*h70000000#;H01^NT0PxZP z000000E_?t000000DF@`8y7L31^@sO01E)%o&W#<0000(000000000|0{{RL01E)X zfB*mh000270RR910001xmk~Sx7iBmD000sI3ji>H00000004^s00000004jm000sI z3jn~F00000003?P00000000OC000sI3jhF!00000000*P00000002%2000pH6#$@# zApigX0003H00000006K6000q_F#!`{ISl{+5&#PTaOeO400000YybcN00000KL`K- z5&#PTP`Cg900000O8@`>00000tO@`C5&#PT5ZC|!00000{{R3000000r2qf`5&#PT zFz5gP00000G5`Po00000ACmzJ7XdVv5j+7Gf5-;_01^NT08qsM000000Qms`00000 z0I&uC01^NT05G2b000000P+C<00000009XA01^NT0D!{)0000005<^u000000Hh26 z01^NT0C4310000009*h7000000Lujc01*Hc0MMx+0000001yBG000000LKCV01^NT zS^&^`00000006}S00000006`Y000sI3jpxI00000001Ka00000003qL000sI3jk2c z00000000I80000000312000sI3jm;T00000001Hb00000006<0;SLuW5di=I5&#PT z@YVnT00000OaK4?00000fRjNL7a6$;000sI3jmPY00000001%o00000008ZiK@}GP zmzN000000000gli>>&0kxCi4i_br00000!vFvP z00000o(cc}5&#PTfT;ig00000JOBUy00000qLTp@7a7F_000sI3ji>G00000008>{ z00000006s_K@}GnLIwZ;5&#PTu$=$^00000sQ>@~00000gp;8O7XgQp;SLuWw*vqG z5&#PTAcp_|00000+yDRo00000(UVaK7XiMLp$QimEC>Jq5&#PT0Js1E00000O#lD@ z00000c#~le7Xbv50Tvg3wgmtH5&#PTAYuRj00000x&QzG00000^Z)<=5&#PTK;HlW z00000Q~&?~00000>H`1(5&#PTAmji500000TmS$700000as~hZ5&#PTV4eT~00000 zH2?qr00000_6q<25&#PT5Z(X)00000WB>pF000001O)&95&#QA0N~F6000000D%Ai z000000J{VL01^NT0N{%N0000009yb6000000LKXc01^NT0ASGo0000009*h700000 z0ArH@78e0;lK~bN8N31j01^NT0PuAH000000Nexs0000007H}E4i^DGlVK1SmNx+i z5kR^C000000Q>;}000000Lqh52p4}|3;+NU01E(M;{X5v00014000000001|2LJ#P z01E)1)&Kwi0000?000000002c0RR9J01E&xYybcN0001K000000001{1pojN01E(M zn*aa+0000|0RR910000x2><{R01E(M$p8QV0001K000000000b4gdfU02LAd;He=1 z000000000000000e3ubC0T&sW2><{Q02Kg$c_9D*0000G5C8xG0002nlc5P00ppWl z5ElWvlK~1B0XLT+F98<;Lzgi<0T+Kt4FCWV01E)%=l}o!0000k000000001n3;+NU z01E(syZ`_I000080RR910000E3;+NU005U4JOL2_ zGM6zu0T%&Wlc5P089oXC01^NT0MOk40000005Sjo0000007;Xf2^VE<0ssIK01E)X z(EtDd00013000000001P3;+NU01E)X;{X5v0001200000000202><{Q02KgWX(0dr z000085C8xG0000P4gdfU02Kf*SRnua00000000000002=4FCWklQ97k8B_!S01^NT z0N`Q(000000KowO0000003?%92p5xp8VD&c000000002Hli>~*f8YlI01^NT0C2Pb000000PO$(000000GtH?01^NT z0AQK`000000P_F<0000001^lQ01^NT01(Om0000005t#r0000000RgB01*Hc07z*e z0000000;m8000000M-To01^NT05G8d0000002cxP000000FDCy01^NTe*i#*00000 z007 z00000003(V000sI3jk2y00000002w?00000001Wf000sI3jkoX00000007AV00000 z003qH000sI3jjdZ00000002w?00000000aI000sI3jl!A00000004>r00000005Z_ z000sI0F!4B5gBm>000sI3jn~E00000008v>00000007F9u?rV}#0&rc5&#PTAm#u7 z00000OaK4?00000Ne2J`5&#PTz^MQL0000000000b^rhX5&#PT5a|E_00000H2?qr z00000761SMAOHZ9FB=g7`IA8#7cplD000sI3jm62j)7XfIO5j+7GlUNTJ0eX``6&I5*92jA&2mk;Q01E&R zzyJUM0002j000000001u2LJ#P01E&htpET30001b000000000F2><{R01E)X!~g&Q z0001w000000002O0RR9J01E(+YXATM0001%000000000olQA3@G2RRS01^NT0MO=3D{2p}y zlYSt$RYzrXQ)O&sOmAmUVRUE!RBvx=L1SZOb8`SxZ*Oc>zxZe~nrb99qkAvs)0ZfSHwW@i9Q zZ)ZtvX>?a_a%*#NVPj=bVRUE!Uter#Vq;%pb#iiLZggLBX=ieDZE0=*M`d(ZZ*psM zaA9L*P+@dv07-6XbVg}xWl&*sXhv^xQ)O&sOmAnGuuuURlg1%24M$~kQ*UEyWpq$s zbZC?IA$Q)q1fLvm$dbW>$)W=wBqOmAarP+@dv07i0UWm9ErW(Z7gXGUpkWpk7BBUY1EBx-+5Z)ZnkbWn0{ zV`X!5P+@dv0CHtvWNc|}YXEa}a&lv6asYF5a${k1UvmIcbYXIIb606}XaI9`a&BX7 zZ~$jtcW-iQQ*dEpWl&*sXaHwlb7gF1OmAmIX>tHmZ*OctV`F7=b606}XiaZqWdKuj za${k1Q)O&sOmAmIX>uw6RBvx=O>1OnasX#vb8lm7WpqYqY-LbkbZ7u)UvP47V@7Fg zWl&*sXp_h!XDL)~Z){U&ZAWEv090>pY*T1WVRQggZ*OcpY*T1$Lv(Dj zE+v!!8FOfDXJvE%b7*a0bO3W`ZDe!+b7*a2bZnEsCLRTCYh-D1vjHb!0to^D0RRC2 z0{{V&YbhO90RR910RRC21ONm80RRL50RRC20RRL5000310RRC20RRC20{{U40RRI4 z000000RRO60RRI40RRC21ONd50RRC20RRC20RRC20RRL51ONm80RRM($tfd~>M15C z0RRR71ONm81ONd50{{U40RRC20{{U40RRI40RRC20RRC21ONe(D=HaL0RRC21ONd5 z1ONd51ONa40RRL51ONm80RRC20RRC20RRC21ONm80RRC22mk>91ONd50RR910RRL5 z0RRI41ONd51ONj70RRI41ONd50h4J0z@5C8xG000006lrM<000O8K@I=_5C8xGmywnR000L7OAY`4 z5C8xGav5m}000I6Rt^9F5C8xG6KQD;000F5Vh#WR5C8xGbsA|20Dk}k05uK(01yBG z0CX8?2><{B0BjBb000000JugW0000000;m8000000Dxrx000000LVrm0000000;m8 z0000006=8`00000002-S0000000;m800000002-S0000003c8y0000000;m800000 z0EGbo0000005DJ?0Dk}g000O800000004>s0RR91002NxApigX000O8000000058y z0RR91002->ApigX000O800000005Q&0RR91003Z6ApigX000O800000005f-0RR91 z003}MApigX000O800000005r>0RR91004kcApigX000O80Dk}g000200RaF20001x zP$2*S0000800000000250RaF20001>P$2*S00008000000002D0RaF200026P$2*S z00008000000002H0RaF20002MP$2*S00008000000002L0RaF20002cP$2*S00008 z000000002P0e=Ai00000;7}m|000002mk;800000%>e-b00000@K7ND000002mk;8 z00000*#Q9n0000008t?T000002mk;800000=K%o#000005K$oj000002mk;800000 z?g0S+00000AW`Y0000000;m80000000RO6 z0000006s0RR91005v=ApigX000O8000000058y0RR91006L5ApigX000O8 z00000005Q&0RR910Dl0$R3QKW00008000000001+0RaF20002cR3QKW0000800000 z0001=0RaF20002sR3QKW0000800000000200RaF20002+R3QKW000080000000025 z0RaF200000RUrTX00008000000002D0RaF20000GRUrTX0Dk}g2mk;800000y8!_J z00000AXOm%000002mk;800000zX1UN00000FjXM{000002mk;800000!vO&R00000 zKvf|C000002mk;800000%>e-b00000P*ouS000002mk;800000*#Q9n00000U{xUi z000002mk;80Dk}g0OtV#000000B}_y0000000;m8000000PX<+000000Dx5?00000 z00;m8000000Qdm`000000FYH70000000;m80000000RO6000000H9SN0000000;m8 z0000001E;E000000I*dd0000000;m80000002TrP0Dk}g006*MApigX000O800000 z000~U0RR91007WcApigX000O800000001Kb0RR91007`sApigX000O800000001Wf z0RR91008h+ApigX000O800000001ol0RR9100011ApigX000O800000001-s0RR91 z000nHA%6e>00008000000000z0s#O30000WRv`cY00008000000000)0s#O30000m zRv`cY00008000000000@0s#O30000$Rv`cY00008000000000{0s#O30000`Rv`cY z0000800000000110s#O30001BRv`cY000080Dk}g00000TLJ+900000a8@Az00000 z2mk;800000WC8&I00000fL0*@000002mk;800000ZUO-S00000kX9i8000002mk;8 z00000aRLDV00000pjIIO000002mk;800000bpinZ00000uvQ@e000002mk;800000 zcz*%`000000Kiru0000000;m8000000Dl4j000000MJ$;0000000;m8000000EGep z000000N_?30000000;m8000000Ehws000000Pt2J0000000;m8000000E_|w00000 z0037Z0000000;m8000000FMFz000000DllyApigX000O800000005E#0RR91001CY zApigX000O800000006WB0RR91001yoApigX000O800000005N&0RR91002N&ApigX z000O800000005Z+0RR91002-|ApigX000O800000005l=0RR91003ZDApigX0Dk}o z000000001>0s#O30001RS0MlZ00008000000001}0s#O30001hS0MlZ0000800000 z000250s#O30001xS0MlZ00008000000002E0s#O30001>S0MlZ00008000000002K z0s#O300026S0MlZ00008000000Dk}g!U6#R00000z*ivv000002mk;800000#sUEV z00000&{rV<000002mk;800000$^roZ00000;8!64000002mk;800000&H@1d00000 z@K+%K000002mk;800000)&cuQ0000000#g700961 z0000000000060k@0000000#g700IC2000000000006Ng)6L000070000I00000000000001}Ng)6L000070000L00000 z000000Dk}gut^~R000002LJ#7761SM0000000000xJe-Z000002LJ#77XSbN00000 z00000z)2wh000002LJ#77ytkO0000000000$Vnjp000002LJ#782|tP0000000000 z&`BWx000002LJ#78vp z0000000#g703QGV00000000000O&~}0000000#g703ZMW00000000000Psm600000 z00#g703iSX00000000000QgBE0000000#g703rYY0000000000002rM0000000#g7 z0DmL^0000000000000O|ApigX000L7001Tc0000000000000n5ApigX000L7001Wd z0000000000000t00000000000EkK<0000000#g705|{u z00000000000FX){0000000#g706G8w00000000000GLW40000000#g706YKy00000 z000000H8`C0000000#g706hQz00000000000H{hK0000000#g706qW!0Dk}g00000 z006K`ApigX000L7002J#0000000000006j3ApigX000L7002M$0000000000006*B zApigX000L7002S&00000000000078JApigX000L7002V(0000000000007WRApigX z000L7002Y)00000000000Dl13N+AFM000070000+00000000000002sN+AFM00007 z0000-00000000000002!N+AFM000070000;00000000000002+N+AFM000070000< z00000000000002^N+AFM000070000=000000000000000OCbON0Dk}g2LJ#7OaK4? z00000000002umRV000002LJ#7O#lD@00000000005KAEd000002LJ#7PXGV_00000 z000007)v1l000002LJ#7Pyhe`0000000000AWI000070001E00000000000001pOCbON000070001F0000000000 z0001xOCbON000070001G00000000000001(OCbON000070001H00000000000001> zOCbON000070001I00000000000001}OCbON000070Dk}gXaE2J0000000000uuCBT z000002LJ#7Y5)KL0000000000xJw}b000002LJ#7YXATM0000000000z)K+j00000 z2LJ#7ZU6uP0000000000$V(vr000002LJ#7Z~y=R0000000000&`Tiz000002LJ#7 zaR2}S0Dk}g000000N6_*0000000#g70CE5T00000000000N_g@0000000#g70CWHV z00000000000O(600000000#g70C@la00000000000Pss80000000#g70D1rb00000 z000000QgHG0000000#g70DAxc00000000000Dk~XApigX000L7004Xd0000000000 z000O~ApigX000L7004ae0000000000000n7ApigX000L7004df00000000000000000000#g70FVFx00000000000FX=} z0000000#g70FeLy00000000000GLc60000000#g70FnRz00000000000H91E00000 z00#g70G0p%00000000000H{nM0Dk}g000L7005T&0000000000006K|ApigX000L7 z005W(0000000000006j5ApigX000L7005Z)0000000000006*DApigX000L7005c* z00000000000078LApigX000L7005i-0000000000007WTApigX000L70Dl0T00000 z000000002kOd$XO000070001=00000000000002sOd$XO000070001>0000000000 z0002!Od$XO000070001?00000000000002+Od$XO000070001@00000000000002^ zOd$XO000070001^000000Dk}g0000008JqP000002LJ#7qyPW_00000000002u&dX z000002LJ#7r2qf`00000000005KSQf000002LJ#7rT_o{00000000007)>Dn00000 z2LJ#7rvLx|0000000000AWb0v000002LJ#7r~m)}0000000000D1S{M0000000#g7 z0I2`~000000000005DA<0000000#g70IC200000000000060w{0000000#g70IUE2 z000000000006O(6gP000070002M z00000000000Dk}gs7)aN000002LJ#7!TR00000 z00000$W0*t000002LJ#7#sB~S0000000000&`lu#0Dk}g00#g70LcIV0000000000 z0N70-0000000#g70LuUX00000000000N_m_0000000#g70L%aY00000000000O(C2 z0000000#g70L=gZ00000000000PsyA0000000#g70L}ma00000000000QgNI00000 z00#g70DsQ_00000000000000^ApigX000L7007Vc0000000000000P1ApigX000L7 z007Yd0000000000000n9ApigX000L7007ni0000000000000Px#0000000000a84lr00000 z2LJ#7>Hq)$0000000000cupYz000002Y&zn0P6q%00000000000Dw**0000000#g7 z0PFw&00000000000EkW@0000000#g70PX+)00000000000FX{00000000#g70Pp|+ z00000000000GLi80000000#g70Pz3-00000000000H97G0000000#g70P+9;0Dk}g z00000005{?ApigX000L7008p<0000000000006K~ApigX000L7008v>0000000000 z006j7ApigX000L7008y?0000000000006*FApigX000L7008#@00000000000078N zApigX000L7008&^00000000000Dl0`P9XpQ000070002_00000000000002kP9XpQ z000070002`00000000000002sP9XpQ000070002{00000000000002!P9XpQ00007 z0002|00000000000002+P9XpQ000070002}00000000000002^P9XpQ0Dk}g2LJ#7 z{r~^~000000000008b$R000002LJ#7{{R3000000000002u~pZ000002LJ#700961 z00000000005Kkch000002LJ#70s#O300000000007*8Pp000002LJ#70|5X400000 z00000AWtCx000002LJ#71b+bl000000000004Pr(0000000#g700jX60000000000 z05DG>0000000#g700;p90000000000060$}0000000#g700{vA000000000006z>$|0PoMAOL6!0002#F#rGm|0PQEAOL6#0002#ApigW|0P26AOL6$ z0002#5dZ)G|9>Sq^B@3d4gdfE=>Y%#|NkX2^B@3d4*&oF>G1yl|NkW_^B@3d5C8xG z>EQnV|NkW-^B@3d5dZ)H>CpcF|NkW#^B@3d5&!@I>A?Q~|NkWt^B@3d6951J>9GF) z|NkWl^B@3d6aWAK>7f4q|NkWd^B@3d6#xJL>5%^a|9}4_`tl$EXchnf0O^4K|Ns9b z^70@6Xcqtg0O@f4|Ns9b>hd4}Xczzh0O?@<|Ns9b;_@H>Xc+(i0O?Tv|Ns9b+VUU( zXc_&f|Ns9b(()hxXd3_k0O>IP|Ns9b%JLupXdD0l0O=t9|Ns9b!tx*hXdM6m z0O=6^|9}7gCA#t;0B9Zn008L#{{R2~C9?7$0B9co008Om{r~^}C93iu0B9fp008OW z{r~^}C8F{m0B9iq008OG{r~^}C7SXe0B9lr008O0{r~^}C6e+W0B9os008N*{r~^} zC5rMO0B9rt008Nr{r~^}C4%xG0B9uu008Nb{eS=e|0R0zAOL740002#fc^jf|0Qzr zAOL750002#aQ*-P|0QbjAOL760002#VEzC9|0QDbAOL770002#Q2qb^|0P=TAOL78 z0002#K>h#!|0PoLAOL790002#F#Z4k|0PQDAOL7A0002#ApQUU|0P25AOL7B0002# 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 zZU6uP07MQT0%Qsf2tf+~00000JOBUy3<>}MXlnoeB$J)~7zIWSKmvuA$_)V;222V7 z09b36@&o}c4Lkq<0E7wv03dAt|5BGN1pyd;P!6C10-g#EC_xS&LJk;04iG{P2tf+~ z0000q0002Q3IG70GXMX&00000LJkm&0znQKh66zkAcF))4zM5scM1+5K@J!}4iG{P z2tf+~0000i0002|3IG5IZU6u200000K@Jdx0znQKg9AhkFam7~4j4fW5J3(IOA7!t z00000Bme*aEDHbt$Zh}ssQ>@~06`8Ag91bjAOdL$4iG^O2tf+~000008~^|SR0{wA zP;Qs%5&;@YbPE6gaBlzqGynhq07MQTW(p1nMGF7`000008~^|SlnVd=kZ%9~LjV8( z07MQTc?u2)K??u?00000L;wH)v06`8Ah5|tj7=r^#4ln|W3Jw@S4iG^O2uBM500000JOBUy zYzzPZD0Bb+jhAf(0URMs0SXQ%K@K264j4iX5JC4hTXE0000005kvq0K5(W0Qi9a|LvEp2mu#DdkPL9K@J!}4iG{P2uBM500000 z8~^|S^bP<3uz~;o$p8QV07MQT0)Pq*2t*4200000JOBUy6b}FZV1obuEdiJQ1pym> zM+y!oK@K264j4iX5JC06`8Ag91bjAb$!D5J3(IK??u? z00000OaK4?+z$W%2!xjc2?0t9ED!(yxP<@zoB)&F`xcjM2>}=hWDo!VAcg<`{FjXh z0UZIYm#YZ@DGIa@007X2|NjU9m);2hApx?M3IP}mL;wH){15;Dn1}!WwwG-S0T^IJ z4lsiTM-H$I0~`Vh4lqFuC_xS&LJk;04iG{P2uce8001li002Z0000n*|Nqwj0000% z4iJU{K@J#$14Irm0#*tR7(osYK@JE)3jhEB001-q0049m006*>|NkSGl?nkTBme*a z04x9i0IU%J0Jw|)|GoeK002P_5QYLl4j6+2L=G?lOOv4c6b9T8002mgml_KJ8e;qr z00790|Nl1u0000%4iJU{K@J#$14Irm0*nd{7(osYK@JE+3jhEB001Na001l!007vH z|NoBw0000%4iJL^L=GSVMhXrPK@JE(3jhEB002Y)002}H002Oa|Nr>`mu?FIASdGr z4lqFuC_xS&LJk;04iG{P2uTY700000OaK4?oDu*4_>cep2$yXO0XIHb4oFW9P*x5| zMh-wE0002&5&!_Wk^lc`00000K@Jdu0z?il0#*tR5J3(IL<;}_0000S0000K6951J zl9%cd0UCca6951plK=lT00000L=GTp3JwTC3jhEB0000i0000~6951}lK=k(0ssI2 zK@Jdx0znQKg9Aqnum}S`0SXQnK@Jc>4hTjI0000i0001l6951pl>h&}00000K@Jdx z0znQKg9AhkFamrE4j4fW5J3(IL<;}_0000i0027xv=aaTu$2G*0s;U406`8Ah5|tj z7=r^x4zLJ+3Jw@S4iG^O2u2G400000L;wH)N?ZNS&8*4FNI+L>B-6u$`Bx4FNg^gckq+V4j!i4FNI+ zycYlf7@wEw5dj(o+!p`m55dj)z{1*TKSfBs@UjP6A07MQTa0(6xObb~G4hTUD z8~^|S92fuqn4kauQ~&?~07MQTehLl8-#7@(Kx5dj(ooEQKAIG~s65dj(o zychrgSfH2c5dj)T+!z1=c%c9PWB>pF07MQT0#6DK2t^A3000008~^|S{1^ZL$e{oK zYybcN07MQT0#XVN2uce8000008~^|S92o!r7@?O65dj)TJQ)B0NTL7#Q~&?~07MQT zehLlH@$ z$f1|I3;`MjoEZQB_@S4&3;`NOycqxhD5C%WGynhq07MQTW(p1nMGF7`000008~^|S z+!+7>NTUD$WB>pF07MQT0!#`H2uKS6000008~^|S{22fMn4*^|5dj(|92x)s*rNac zUjP6A07MQTZVCQ}%n4|yyjsTP1`xcjc5CJF##2Nqq;G>tS5CIwnmAA(4?0t5dj(oWE%hg5T%z& z5dj(ogc|?=Fr}Aj5dj(oq#FPLaHW@u5dj(o#2Wwrprw}z5dj(ovGBaHf|E5&;?pWE=nhu%?$v5&;?pgd6|> zz^0c<5&;?pq#OVM(59E_5dj(o#2f$s@TQll5&;?p&MCpr@BA69FPAY#jgqNT~n+G5`Po07MQTWC{)lMGF7` z000006aWAKj2!>~XsG}H9JhfJ0c!+*fMoyx000000000000000KxF^`0000000000 z000000RR9100000l??y@000000RR9100000p$z~4000000RR9100000!wmoc00000 z0RR9100000(hUFr000000RR9100000+zkK#000000RR9100000>J0z@0001601f~E z0000004fdu0000001N;C0000007z8;0000001W^D000000Lp0000000sa6 z000000Qd<200000015yA000000C)}n0000001E&B0000002lxO0000000RI300000 z02oOj0000000IC2000000KgIe0000002BZK0000000#g70000002crN000000Ej{W z0000000#g70000069B+800000000O8000000077hm!cT~J~1#f0000000960|8D>Q z0006200000008j+|8D>Q000Ow00000008;_|8D>Q004iJvFuj^*hV3fF##2ShE)In z00000mQ?@%00000rd0p{00000wp9QC00000##I0S00000)>Qxi00000=2ZXy00000 z_Ei7?00000237z7000007FGZN00000CRP9d00000HdX)t00000Mpgg-00000R#pH2 z00000W>x?I00000c2)oY0001g0ESio000000G3t&000000H#&|000000Jc^D00000 z0LE4T000000M=Fj000000OnQz000000QOb@0000000vh80000002WsO00000047%e z0000005(?u0000007h2;0000009IE3000000A^PJ000000CraZ0001g004$p00000 z005R(00000005>}00000006dE000000072U00000007ok00000008D!00000008z^ z00000000J900000000(P00000001Uf00000001^v00000002f<000000035400000 z003rK00000004Ga0001g0001nSO5S30001%SO5S30001{SO5S30002CSO5S30002S zSO5S30002iSO5S30002ySO5S30002?SO5S300006SpWb40000MSpWb40000cSpWb4 z0000sSpWb40000+SpWb400011SpWb40001HSpWb40001XSpWck00000hFJgr00000 zmRSG*00000rda?000000wpjoG00000##sOW00000)>!}m00000=2-v$00000_E`V` z0000023i0B000007FqxR00000CRzXh00000Hd+7x00000Mp^&>00000R$2f600000 zW?BFM00000c3J>`000000ESus000000G3(+000000H#_1000000Jd5H000000LEGX z000000M=Rn000000Onc%000000QOn{0000000vtC0000002W&S00000047@i00000 z05)3y0000007hE?0000009IQ7000000A^bN000000Crn{00000004$t00000005R- z00000005?200000006dI000000072Y00000007oo00000008D&00000008z|00000 z000JD00000000(T00000001Uj00000001^z00000002f@000000035800000003rO z00000004G>TmS$70001nTmS$70001%TmS$70001{TmS$70002CTmS$70002STmS$7 z0002iTmS$70002yTmS$70002?TmS$700006T>t<80000MT>t<80000cT>t<80000s zT>t<80000+T>t<800011T>t<80001HT>t<80001gc3l7f00000hFt&v00000mR$e< z00000rd00000 z005?600000006dM000000072c00000007os00000008D+00000008!100000000JH z00000000(X00000001Un00000001^%00000002f{000000035C00000003rS0001g z0001XU;qFB0001nU;qFB0001%U;qFB0001{U;qFB0002CU;qFB0002SU;qFB0002i zU;qFB0002yU;qFB0002?U;qFB00006VE_OC0000MVE_OC0000cVE_OC0000sVE_OC z0000+VE_OC00011VE_OC0001HVE_O|00000c3}Vj00000hG75z00000mSF$@00000 zreOd800000wqXDO00000#$f;e00000)?oku00000=3xK;00000_Fs0RR91000F5 z000000058y0RR91000F500000005Q&0RR91000F500000005f-0RR91000F500000 z005r>0RR91000F500000004ig0RaF20000500000000250RaF200005000000002D z0RaF200005000000002H0RaF200005000000002L0RaF200005000000002P0RaF2 z00005000000002Z0RaF200005000000002l0RaF20000500000004gg=K%o#00000 z1poj500000?g0S+000001poj500000_yGX`000001poj5000000|Eg6000001poj5 z000003jzTE000001poj50000076JhP000001poj50000090CCV000001poj500000 zBLV>c000001poj5004gg04D+g0000000jU50000004)Lm0000000jU50000005k#t z0000000jU50000006hW$0000000jU50000007L=-0000000jU50000008Ih`00000 z00jU50000008s(~0000000jU50000009FD40000000jU5004gg003J80RR91000F5 z00000003kH0RR91000F500000003?R0RR91000F5000000040U0RR91000F500000 z004CY0RR91000F500000004Lb0RR91000F500000004gi0RR91000F500000004yo z0RR91000F5004gg0001p0s#O300005000000001t0s#O300005000000001w0s#O3 z00005000000001z0s#O300005000000002A0RaF200005000000001$0s#O300005 z000000001)0s#O300005000000001;0s#O300005004gg00000paKB^000001poj5 z00000r~&~1000001poj500000uL1!8000001poj500000xB>wH000001poj500000 zz5)RN000001poj500000!U6#R000001poj500000#sUEV000001poj500000$^roZ z000001pqq$000000L}sd0000000jU5000000M-Hl0000000jU5000000NVlq00000 z00jU5000000OSGz005Ce6PKtX0T_Si0s#O300000000000002)0s#O30000100000 z0002<0s#O300002000000002{0s#O30000300000000010|5X4000040000000006 z0|5X40000G000000000C0|5X400005000000000I0|5X40000600000005VtBLN|Q zg#iHo000000000000000iU9!t000000RR9100000kO2Vz000000ssI200000mH`0( z000000{{R300000n*jj;000001ONa400000p8){?000001poj500000ssRB200000 z1^@s600000uK@u7000002LJ#70001g0Ji}F0000000;m8000000J{MJ0000000{s9 z000000KWkN00000015yA000000K)+R0000001E&B000000L=jb0000001N;C00000 z0NDWn0000001W^D000000OtV#0000001f~E000000PX<+0000001p5F0001g008&_ z0RR91000mG00000000950RR91000pH00000000XD0RR91000sI00000000&O0RR91 z000vJ00000000~U0RR91000yK00000001Kb0RR91000#L00000001Wf0RR91000&M z00000001ol0RR91000*N0001g0000q0s#O30000O000000000z0s#O30000P00000 z0000)0s#O30000Q000000000@0s#O30000R000000000{0s#O30000S0000000011 z0s#O30000T00000000160s#O30000U000000001F0s#O30000V0001g00000ZUO-S z00000AOHXW00000aRLDV00000ApigX00000bpinZ00000A^-pY00000cme?c00000 zBLDyZ00000e*ysj00000Bme*a00000g#rNp00000B>(^b00000hynos00000CIA2c z00000i~<1w00000CjbC{000000FMFz0000004M+e000000FnX$0000004V?f00000 z0JH%C0000004e|g000000F?p(0000004o3h000000GR>-0000004x9i000000G$E> z0000004)Fj000000H6W^0000004@Lk000000H^{100000051T400000006H70RR91 z001xm00000006iG0RR91001!n00000006!M0RR91001%o00000006=Q0RR91001)p z000000071U0RR91001-q00000007DY0RR91001=r00000007Pc0RR91001@s00000 z007nk0RR91001{2000000002n0s#O30000u000000002w0s#O30000vm)R!)kAL_H z00000000000000000000000930|1aC00000000000000000000000931ONy!00000 z000000000000000000931pqKK00000000000000000000000931^~b`0000000000 z0000000000000932LOmd000000Dk}g00000000000000300;m`RR9100000000000 z000000000300{taRR91000000000000000000003015yAVgLXD000000000000000 z0000301E&hVgLXD0000000000000000000301N=k>Hq)$00000000000Dk}g00000 z0{{&G*y;cP000000000000000000000{{*HkRJg6000000000000000000000{{;I zxFi7p000000000000000000000{{>JxJDrW000000000000000000000{{^K$VMRm z0000000000000000000015E%D0N6$$0000000000000000000000RIM02oOj00000 z00000000000000000RIN002-S0000000000000000000000RIO060RR*L;8P(000000 zkN^Mx000000RaF20RR;M&{!b=000001ONa4000006afGL0RR;M)L0<^000001ONa4 z00000Bmn>b0sspDK#TwY00000AO`>d00000E&%`l0RR;M*jOO|E&u=k00aO400000 z06hT!0096M0N_|50000000aO400000089Y@0096M0NhxYqAUR}f3Rc#0000000000 z000000BHdL00ICD0Pti00000000000000000DJ)e00ICD06=8`000000000000000 z0FnU!0096M06h($0002>000000002R0{{RL01E&BYXATM0001i z000000002e0{{RL01E&>egFUf0001`000000002v0{{RL005H*77+pXlK~bNVG0BQ z01^NT0HB@#0000005kvq0000002l-S01^NT01(^&000000ABzA0000003!qd01^NT z03gBu000000KNbK0000005b#t01^NT0N~dE0000004@Lk0000007a8Q8y7K71ONaM z01E(+-2eap0000o00000000131ONaM01E&RY5)KL0000q000000001LlR+C70e+J~ z8y6Xp1ONaK02BZ)SRnua00000000000001)lR+C7Nv#9`01^NT0I;_J0000008Ib@ z000000KWtP01*Hc0Kl0c000000001^NIlQ#+xF00000N(KM` z5&#PTaOMC200000Q~&?~00000Rt5k75&#PT;BNo`00000xd8wG00000Z3X}U5&#PT zAk6>(000000s;U400000fd&8o5&#PTV9Wpj06+i$0KNbK000000Fnj(01^NT0N`f; z000000BQgL000000GkE?01^NT08q040000002%=R000000HX!~03wqy0TThglTip4 z0n?LF2p1XV1^@sO01E&B(EtDd00017000000002>lTip40SS}g4i_072LJ#O02KgW zSRnua0000G000000000dli>~*0Xvi74i_;^2LJ#P01E&hX#fBK0001R000000001H z2LJ#P01E)n;s5{u0001v000000001Xli>~*F^mTQ01^NT0MK**0000003QJW00000 z0GkH@01^NT0C3U(000000DJ%d000000H~AU4i^Ezli>~*8R-WA01^NT0C3^}00000 z08{_~000000QHmM4i`xg2mk;Q01E)1tpET3000220ssI20000W2mk;Q01E)n2mk;Q z01E)Hr~m)}0002N000000001NlR*_10Th=JJOLMBfCvBp5&#PTAc_D000000y8!?I z00000jtBq%5&#PTaOwa600000G5`Po00000nFs&?5&#PTP_O_100000`~m;~00000 zrU(E45&#PTkYxY>00000ZvX%Q00000v6Dd+7ctlf000sI3jk2z000000037200000 z0083%000sI3jm;O00000001-r00000008ilK@}G<1PK5D5&#SU%<2FD0000000000 z000003JCxJ5&#PTaHjwO00000F#!Mo00000sh2T50T%%tli>>&0YH=C3l~XB2><{R z01E)%XaE2J0000q00000000172><{R01E&R-2eap0000o000000001I2><{R01E)% z-~a#s0001F000000001Vli>>&0h5#A3l{;Yli>>&0lkyq3l|yD2><{R01E&xnE(I) z0000a0RR910002rli>>&N%RQ-01^NT0KjSh0000005kvq00000000UA01^NT0C493 z0000009*h70000001pZP01^NT0PxZP000000E_?t00000034H{2^TRz3IG5S01E)% zo&W#<0000(000000000|3IG5S01E)XfB*mh000270RR910001Elc5P0Wp)Yx01^NT z05E_6000000E++s000000FVj*01^NT0Kk|4000000B!&P000000G00000009sH000000KW000000002;3IG5S01E&R z*Z=?k0003000000000043jhET01E&x=l}o!0000olR*j}0V$JV5Ep+u3jhET01E(6 z#Q*>R0002_0RR910000~3jhET01E&xp8x;=0002;0RR910001E3jhET01E(s!vFvP z0000t0RR910001S3jhET01E(c00000#Q^{S00000l?wm>5&#PT@W22700000BLM&a z00000rwaf85&#PTP|5%R000001_A&800000ybAyT5&#PTpm6{I00000A_D*b00000 z&XZvf7a8IU000sI3jpxe00000002w?00000008ilVGtJ?1q=WH5&#PTklO$N00000 zG5`Po000006PFP@0T%%$mk~Sx7a1@N000sI3jkoZ00000002e+00000002Li5j+7G z0aKR|JOLL0X_pZ^0T+LN3;+NU01E&x&j0`b00022000000001q3;+NU01E(6y#N3J z0002C0ssI20001%3;+NU01E(c)Bpeg000040RR910001^3;+NT02KfbX(0dr00008 z00000000243;+NU01E)1+5i9m0002w000000002T3;+NU01FZTz>@#~00000^#A|> z00000)|U}H0T%)5mk~Sx7cu?}000sI3jl!C00000005i-00000000aP000sI3jiRe z00000002e+00000000=5F+Bkn88s0A01^NQ07z8;00000000000000005q2|JpmUn zNDTl05&#PTpy>br00000!vFvP00000Hv|9x5&#PTfT;ig00000JOBUy00000caz}` z7a6Gz000sI3ji>G00000008>{000000038)F+Bkn8Ep*!01^NT0I;0^000000I2`~ z000000EL$^JpmU1sFyK40T&s&4FCWV01E&hhX4Qo0002o000000002gmoYs77Xjv% zF+Bkn84wNt01^NT006iE0000008Ib@0000003(;-J^>d2LYLt_0T+K(4gdfW01E&h zVgLXD0002G000000001F4gdfW01E&>-v9sr0000~000000001P4gdfW01E&h-&TI}ZQ=5&#PTK)L_`00000`~d&}00000 zN0%W%0T+K;4*&oX01E(M;{X5v00014000000001G4*&oX01E)1)&Kwi0000?00000 z0001U4*&oX01E&xYybcN0001K000000001c4*&oX01E(Mn*aa+0000|0RR910001s z4*&oX01E(M$p8QV0001K000000001%4*&oV02LAd;He=1000000000000000o0lO$ z0T&sv4*&oW02Kg$c_9D*0000G5C8xG0002Pmmxs`7ndMG0T==Qmmxs`7XcHOQ9%J0 z0VkJHK>-(kI}iW>5&#PT;OGDV00000E&u=k00000N)P}55&#PTfaCxG00000OaK4? z00000R1g3F5&#PTAl3i?00000a{vGU00000U=RQR5&#PTu-O0r00000>;M1&00000 zeGmWu5&#PTK)e6|000002mt^900000hY$b&5&!^~S3v<00hyOkK>-&5t(Q?j0T&s~ z5C8xY01E)n-2eap0000o000000002kmr+3h7k~H=000sI3jn~;00000003A300000 z000OP000sI3jo05000000037200000000&d000pH6#!sqApigX000OO00000001Qs z000mG6#y_;ApigX0000000000001!&000sI3jp9^00000006-O000000027?000sI z0GFpi0TD4x5dZ)Z01E&x00000 z0001Gm!U!d7k_vW000sI3jlDm00000008X(00000004&(000sI3jko600000008p< z00000005B@000sI3jh$x00000001=r00000005y8000pH6#z(SApigX000O800000 z006KN000sI3ji>o00000000*P00000006}i000sI3x5DWg#Z8m0002q0RR910002k z5dZ)Z01E(+*8l(j0000?000000002#5dZ)Z01E)1-v9sr0000~000000002;5dZ)Z z01E)XmH+?%0002;00000000015&!@Z02KgmSRnua00008000000000P5&!@a01E)n zX#fBK01p5FGynhq00000B@zGt5|c3j6MsJv000sI3jn~B00000008v>00000002!A z000sI3jk2y00000002w?00000003YT000sI3jkoX00000007AV00000003|j000sI z3jjdZ00000002w?00000004jz000sI3jl!A00000004>r00000004^;000sI0FyHT z5gn}(000sI3jn~E00000008v>00000006ua000t`F#!{Q&=LRu5&#PTAm#u700000 zOaK4?00000+Y$f(5&#PTz^MQL00000000000uulL5&#PT5a|E_00000H2?qr00000 z6B7UcAOHZ9GXW6=FB1R&5|c3j6E#N@000sI3jmewU?00V@k-Zee0W@%?eX>4UsVRUGha7h7|HB4`3Np5L$OmAmFXJu}5 zP+@dv08?~wV_|etWo%|lZ)ZelasX3oZ)Z$zV`~6OZfSHwW@ncVN&#mFb98cUV{LG^ zXi5Pi0TXj*ZD(b4KtM-KNkT(kGA=SMHMfdO0U7}YQ)q2RWptOHOaWIRb7*a2bZkIC zM@&gVLtip3GA=a$WNdF|Uvp)2Y-M(3Y?t*+0b>wJb3<=#W@%?rXl+G!X>)X!S4{z4 z4`*L@Z*pr>aA9L*P+@dvm$Xd*BM?S%Wo1)kY-UVvXGUpkWpk5}B@>tFO#wI;OmAmL zWpq$-Z)0V1b3<=#W@%?oVRUGhAWi{P6ijbtNp5L$S8sA_b8ul}Wl&*sXqR(N0d)>X zWpqMykKu1hTLPK9NE;24P08?~wV_|eeX>tHi za%paKQ)O&sOmAlZS8{1|WmIodXia5pmmW_6G!%1ma&lv6azH>wOi4mRUotK-E;W}? zPXQDSQe|OeMsja$Q)o?PZI@(E0b&nB^(n# zKu1hTLPK9NE;24P0CQ+4UsVRUGh;Zgw?5pZ>Mb3i~xOi4mRUotK-E;X0;QUOIC zM`d(OZ)ZVgWo~p(VRUE!XJ2z=Y-UVvXGUpkWpkH1QvuNmLvm$dbW>!Q)o?PZI{ke0a6lkXl-P4KtM-KNkT(kGA=SMHJ2Y%0cH_QZ)ZnkbWn0{V`X!5 zP+@dvmxNUTLlsPKXH#W#LvLQ)q3M##I413s7lfOlfm;P+@dvxBFEA zB>|H_0R@*JR{HLXR{<^(kRt#900000 zkRt#900000cn+7sR{<^(2r>Ww000002r>Ww00000A_A8JSOG2yFf;%F00000Ff^As zSOGQ?z%&2=00000z%&2=00000$PJf*SOG2)h(Z7W00000h(Z7W00000z!I0jSOG2y zNL2s;00000NL82mSOGQ?a8&>R00000a8&>R00000kPMeXSphB$0Ac_D000000Ac_D z0FyBs6PJ)#0U#0}VgLXD0000WVgLXD00022h?l}y0WJ#6>Hq)$0002Y>X-Ui0X7oY z>Hq)$0002k>Hq)$0002EG?PXJ9+zNR0T2?99{~UW0001x9{~UW0000a1($+a0WK1_ zBmn>b0002EBmn>b0001_9g{`{9+%)+0T2qfMj-$I0002EMwj|p0X7QAMj-$I0002U zMwdEU0X7QQMj-$I0002kMwfb90X7mCNg)6L0000ONdW)=0002!2A9HH0WTa-ApigX z0000`0RR91001xu00000000000001!F&q<@AY1_u9Y9zi0000005Dhq000000H9F- z0000000000005IQ921vdTmcvYFj$v*Tme26a99BV00000a3BBx000007ytkOOP9@D i0V@jNcmV(a0002u6qf>B0X71{jh8xI0VV+e0RR6?0*R z;s5{u(*OVf%m4rYY5)KLW&i*H00000x&QzG000000000000000u>b%7K>z>%z5oCK z0000000000MgRZ+m;e9(EdT%jU;qGr089V?0NMZm0LuUX0M-Bi0CNBU000000Hgo_ z000000Ez$r0LK6T00#g70CxZY0JZ=C09OD20J8u900000000000EGYm0Av6F0N(%r z07C!(0M7sb09yb607U=*000000KfnM00000000000NDTl0FwX!000000001g004Oa z0012T005Ez0000000000006xJ00000006E400000000000027x001HY0000000000 z005={006uI004pj002+`0000000000007DW006K600000007Pa000000000000000 z003+N001rk001)p004ae007BM000000001C0002e00000000000001J0000000000 z000000001`0000U000230002E0002N0002j0000F000000002Z00000lU)TDe*gdg z0Ga>*0EYko000000E_?t0000004e|g000000Nwxq0MGyc0NVfn000000N4Nk0Ehqp z0G|K=0IUE2000000A2t90Eqwq0J{JH0000000jU50DAxc0KxzO0I~o80000007(D< z0C)fZ0FD3v01f~E0N?-s0Mq~gW&i*H006@P0018V006lF004^s002J#007Yd003tI z00000003|R00000006H500000006}R004mi002_}0000000000007+p0024w00000 z004#n000dD00000006`Q006a<{9od5s;r~m)}kN^Mxo&W#<00000N&o-=#sB~SmH+?%3jhEBv;Y7A z+yDRo00000ssI20H~;_uWdHyG;Q#;t0000000000P5=M^00000000000001&e^>zz zmx7N07Lz~$1OW__F##U|0+TTT7X=vr000(~F##V11ONa46O%Ck6PK`B0R)#!kpT>o z@C7K7a0U!17XSbNHUIzsDF6Tf3IG5AB>(^b0000000000000005&!@I000005tA_i z6Gb%u0000000000002G!0000000000002t>0000000000002Dz000000000000000 z002h-000000000000000002^xF#!_=CIA2cR+B*i7nhKc0SF-*00000000000000d z00000000000000q0000v0000alQ97k4PO8N000000000003nkx0T+J;0000@00000 z0000L00000000000001D0000_0000000000000100001l000000000&0001h0001E z000000001P0000000000000000000~0001d000170001y000000001#000000000) z0001T000000000l00062kCQP06MtO*003G50000000000005u>00000005x?00000 z004df00000002<{001`t001xm002k;005N$001KZ005Z)003D400000003zK0040S z0000000000005i-00000004sk0049V00000004FX00000004gg000~S0Dk~700000 z0001^000000001@000000001~0001|0001W0000O0001+0002U0000W000210000$ z0000n0000K00000000000001Q000000002h0000000000000000001O0001300000 z0001&0001b00000000000Fyca76IRr5egSEd00000005r>000sI3jknS000000062000000000&P000sI3jiQ-00000006B3 z000000074c000sI0F!4I5dkifK^YfGqz3>15&#PT;Jg3;00000UjP6A00000CI#sB~S0000~000000000l0ssIK01E(sVE_OC z0002t0RR910001d0RR9J01E&xS^xk50002u000000000?0000Y005JR4-o<0lK~DF z0fCcY7Z(|C0ssIK01E){v;Y7A000170000000024lVKMZ83zFX01*Hc03awK00000 z01yBG0000009cdJ3Ks!>lR+65F(Lr~01^NT0B~3U000000C)fZ000000M7{k01^NT z0HDGE000000FD3v000000H2fL7#A^~0ssIK01E)%W&i*H0000l0RR910001y0ssIK z01E(Mwg3PC0001d000000002^lR+650dS|2><{R01E&>!T z$^ZZW0000o00000000090{{RL01E(Mp#T5?0000t0{{R3000160000I01E&hRR910 z0001Y000000001^laUb@F{23p01^NT03g8t0000009OD2000000LcLW01^NT03cle z0000008|110000003Va#5*L%O5(p`r$^ZZW00000000000002Y1pojN01E&xm;e9( z0000;0RR910000zlMxCR0qv9F5*Gn}lhFznF%SU&01^NT05Dhp0000005kvq00000 z01O5I01^NT0IN|Rli?T_0Y#Hx7Z(9nlR+65Ns|Ep z01^NT03cfc0000005kvq000000D}qu01^NT06@n80000009*h7000000IvrC01^NT z0N}O&000000E_?t0000004|g9AQu@>0{{RL01E)Xa{vGU0002d0RR910000HlR+65 zO*R7n01^NT03dS!000000Ga>*000000R03201^NT0I-Yz000000B!&P000000ObP! z01^NT0APCn0000008#<~000000I&c601=Zh0TW5O3IG5S01E&>$N&HU0001N00000 z0000g2mk;Q01E)%xBvhE00030000000001`0000I01E&B$N&HU0000o000000002_ zlK~DF0kxB17Z-nJ1pojN01E(+j{pDw0000Q0ssI20000=2LJ#P01E(6u>b%700011 z0RR910000b3IG5S01E&>#Q*>R00017000000000w1pojM02KfbDIov=0000G00000 z0002E0ssIK01E&RZ2$lO0002x0RR910000D2LJ#P01GMru&w|A000009{~UW00000 zMgjl;5&#PTaAN=f00000Y6AcO00000c9Rhb7a4^C000sI3jn~k00000002w?00000 z006v`5egR>VFv&J5&#PTV7veT00000G5`Po00000Hk08J7XgTq(Fzv<7n4C57XfgS z@gNsrhX4Qo5&#PT5UT(H00000rUC!}00000bOita5dakcz$hUA000002mk;800000 zEC~Pr5&#PTaJv8i0000000000YLgKP z7Ye`y000sI3jpAklUf)i87Kq*01^NQ0Psfu00000000000000006vpJ85c>{0ssIK z01E(c$p8QV0002P000000000S2mk;Q01E(6ng9R*0000y000000000`1ONaM01E&R zasU7T000070RR9100004li?B<0Roee5f=eGlMxCR8MOld01^NT0C0K$000000OJ4v z000000EU1ONa40002^ zm+@i&7XiJKkr5Xess;c65&#PT5U2nE00000^Z@_>00000f0yxM0T+MY2><{R01E&x z!vFvP0001400000000171^@sO01E(cw*UYD0000?000000002N0RR9J01E)HTmS$7 z0001K000000000L1pojN01E&hjsO4v0001K0RR910001{3jhER02KfrDIov=00000 z000000002}2><{R005I`7ZCwjlaUb@0j!gO6&IHfUI7G?)Cv><#FIf87h%f^000sI z3jnal00000001rk00000000LH000sI3jk2W00000002w?00000007wt000sI3jlz+ z00000008U&00000007kn000sI3jh$R00000008^|0000000456VHXzxvy(v?7XjLn z;Sv`C$CKd_7foLR000sI3jnaS00000003A300000008d^000sI3jmPA0000000372 z00000005c`000mG6#(!jApigX0000000000004Ch001GAF#!`vBm@8e5&#PTP*VT^ z00000?f?J)00000c?19e5&#PT0L1_R00000Jpcdz00000JqG{)5&#PTu&@9C00000 zpa1{>00000aFY=V7k_;Q000sI3jm;`00000008v>00000000XG000sI3jiRE00000 z008p<00000004^x000sI3jnZ@00000002G$00000004{w000sI3jmOK00000007+q z00000005^2000sI3jkoa00000002w?00000003zT000sI3t9khzW@LL0000~00000 z0002r1ONaM01E)HiU0rr0002;000000000@1pojM02Kf*C?Nm<00008000000000> z0RR9J01E&xSpWb40000q000000002%lR+65VZ#If01^NT0I-Mv000000QCR>00000 z0EYIH z01^NT01&tU00000089V?0000002h;C7Z(}s1ONaM01E)HivR!s0002>000000002H zlK~DFe?}000000CoTX z01^NT0N}^~0000005t#r0000002TlM03ZMWliwf_0fdwBAQu^<1^@sO01E(crvLx| z0001-000000000pm+@i&7h&%J000sI3jn~r00000002w?00000006uP000sI3jjd9 z00000002|~000000071U000sI3jiR=00000002w?00000004{z000sI3jlDY00000 z008y?00000008NeVHXzx?2{1+7Xh}D5egTR5F!{s^#%X{5&#PTz^woP00000?f?J) z00000LIwZ;5&#PT5S{=400000dH?_b00000vjG4A5&#PT5L^HN00000os)qgA2DAF z000sI3jmV!Z5&#PTP`&^F00000YybcN00000Wdr~K5&#PTpu_+G00000R{#J200000Cj$Tg z5&#PT&~X3&00000Gynhq00000#0CHW5&#PTfWZI&00000R{#J2000001p)v75&#PT z@RR@m00000tO5W4000000AF8cZEtRqmm{>3S|mP`uOx&OY;R{wZ)0l!RBvx=O?7l- zcua3&YqK#WcL57YZfSHwZ*FExX>*gNCc2YvCmIb&ZgX^DY;09?WpYVmleH%~7hhj& zX<}nvV|8+JWo~p|b7^OCbZu#Fmwtx<8IxluF_WSwe3L9GTC+eZ7y%AdaAaY0WkYXn zW=v^wbeD0A0T`3_D?SQva%paKW?y4yYm+i8Z3uI8a${k1Uvra4EoZaYEt3I1RBvx= zPjF>!0C#d}bY%ckZ*Oc;Wnp9ha%Ev;090>pY)xxqX>tHpY(ZmVWpi^^ zX>@2!Z)9b&s4rpye*gji0RRC20{{U40RRL51ONd50RRC20RRC21ONm80RRC20RR91 z0RRL51ONd51ONd51ONa40RRC20RRC20{{U40RRI4000001pos80RRC21ONd50RRC2 z0RRC21ONm81ONd51ONd51ONj70RRC2000310RRL50{{U4lb|vRldLi%YX$%W00aO7 z0096200964009640096200965009620096800aO500962009620096200aO500aO5 z00aO400aO8009620096200aO500;m900aO50096200aO700aO500aO700RI7lVLL@ zDFgrm00aO800aO5009620096400aO700RI40096200aO50096200fi4GaZxQGZqm9 z009620096200RI700aO4lMOT(e*gdh0096Z3jhER0000W0001W8fggt00RKF3jhEB z0000100sbS3jhER000000000KX=x1r00;oW3jhER0001&k(LGk00#if3jhER0001T z8EFXs00scp3jhER0000JX=x1r00jW!3jhER0001W8fggt00aQG3jhERe*gdgbQx(0 z00062?F#?^000002pAy%000002mk;8000005LEyG000007#JY{000002mk;800000 z&{O~b0000003aa%000002mk;80000003aa%00000ARr+C000002mk;800000F5&00000007V+ApigX000O800000 z003;_00000007`1e<1(>00008000000001X;s5{u0002+ARzz%00008000000001j z;s5{u00000At3+&00008000000001x;s5{u0000GAt3+&00008000000001&;s5{u z0000WAt3+&00008000000001?;s5{u0000mAt3+&00008e*gdg00000tl|Iw00000 zKp`Oj000002mk;800000wBi5&00000P$3}z000002mk;800000zv2J@00000U?Cv@ z000002mk;800000#o_<}00000a3LW8000002mk;800000%;Eq500000fFU6O00000 z2mk;800000f6(Fp000000FWUe0000000;m8000000M_CF000000H7fu0000000;m8 z000000NvsM000000I(q;0000000;m8000000OsNV000000Kg$30000000;m800000 z0PW%c000000MH>J0000000;m8000000QTYl00000e*oYiApigX000O800000008>p z00000008hIApigX000O8000000095u000000000YApigX000O800000000Ez00000 z000moApigX000O800000000f+00000001B&ApigX000O800000000-`00000001x| zApigXe*gdo000000000Q;{X5v0000$A|U_(00008000000000U;{X5v0000`A|U_( z00008000000000X;{X5v0001BA|U_(00008000000000e;{X5v0001RA|U_(00008 z000000000k;{X5v0001hA|U_(0000800000e*gdgG2;LL00000kRl-f000002mk;8 z00000HRAvP00000pdujv000002mk;800000IO6~S00000up%J<000002mk;800000 zJL3QV00000z#<_4000002mk;800000UE%-$00000&>|rK000002mk;800000KH~rY ze*gdg0N^4a0000000;m80000007Byc000000PrFq0000000;m80000007l~g00000 z001K)0000000;m80000007>Hj0000001zV~0000000;m80000008!%r0000003ahF z0000000;m80000009fMy0000005BsVe*gdg000O800000003d*00000002NEApigX z000O800000003v>00000002-UApigX000O800000003*_00000003YkApigX000O8 z00000003{}00000003|!ApigX000O8000000049200000004j^ApigX000O8e*gdg z0001Y;{X5v0001xBOw3)00008000000001g;{X5v0002MBOw3)00008000000001l z;{X5v0002cBOw3)00008000000001r;{X5v0002sBOw3)00008000000001w;{X5v z0002+BOw3)00008000000001&f8ziE0000003;y*000002mk;800000o#Oxi00000 z5F{Z0000002mk;800000qT>Jn00000AS59G000002mk;800000sN(`000002mk;800000F5&0000000;m800000 z07&8h000000Kg<600000e*g#o00000002|s00000007V=ApigX000O800000003Cx z00000007`5ApigX000O800000003a(00000008hLApigX000O800000003m-00000 z0000bApigX000O800000003y>00000000mrApigX000O800000e*ge%;s5{u0000W zB_RL+00008000000001X;s5{u0000mB_RL+00008000000001j;s5{u0000$B_RL+ z00008000000001x;s5{u0000`B_RL+00008000000001&;s5{u0001BB_RL+00008 z000000001?;s5{ue*gdga3vuC000002mk;800000tl|Iw00000fF&US000002mk;8 z00000wBi5&00000kR>4i000002mk;800000zv2J@00000pd}#y000002mk;800000 z#o_<}00000uq7b?000002mk;800000%;Eq500000z$GC7e*gdg00;m8000000MOz9 z000000MI2N0000000;m8000000M_CF000000N^Dd0000000;m8000000NvsM00000 z0PrOt0000000;m8000000OsNV00000001T-0000000;m8000000PW%c0000001zf2 z0000000;m8e*gdg008#l00000001B+ApigX000O800000008>p00000001y1ApigX z000O8000000095u00000002NHApigX000O800000000Ez00000002-XApigX000O8 z00000000f+00000003YnApigX000O800000000-`e*gdg0001RCLsU-0000800000 z0000Q;{X5v0001hCLsU-00008000000000U;{X5v0001xCLsU-00008000000000X z;{X5v0001>CLsU-00008000000000e;{X5v00026CLsU-00008000000000k;{X5v z0002MeHj0000008l3(0000000;m80000008!%r000000AME}0000000;m800000 ze*jqH00000003|&ApigX000O800000003d*00000004j|ApigX000O800000003v> z000000059DApigX000O800000003*_00000005vTApigX000O800000003{}00000 z006KjApigX000O8000000049200000e*gf$Cm{d;00008000000001Y;{X5v0002c zCm{d;00008000000001g;{X5v0000G7$E=v000010002600000000000000W7$E=v z000010001u00000000000001>A0Yq$000060000700000000000001}A0Yq$e*gdg z1^@s6F8}}l0000000000upc1+000001^@s6FaQ7m0000000000xE~<^000001^@s6 zH2?qr0000000000z#kz1000001^@s6O8@`>0000000000$R8m9000001^@s6P5=M^ z0000000000&>tZH000001^@s6e`Ejv00000000000N5WP0000000sa60D1rb00000 z000000N@`X0000000sa60LlOW00000000000O%hf0000000sa60M!5h0000000000 z0Pr6n0000000sa60NDTl00000000000Qesv0000000sa60N(%r00000e*gdg004j* zApigX000L7000310000000000004*@ApigX000L700062000000000000590ApigX z000L7000930000000000005X8ApigX000L7000C40000000000005vGApigX000L7 z000F50000000000005{Oe<1(>00007000060000000000000268X*7x0000700008 z00000000000002E8X*7x000070000900000000000002M8X*7x000070000C00000 z000000002U8X*7x000070000D00000000000002c8X*7x00007e*gdg4gdfE00000 z00000*cu@K000002LJ#74*&oF0000000000;2I$S000002LJ#75C8xG0000000000 z=o%pa000002LJ#76951J0000000000@ERci000002LJ#76aWAK0000000000_!=Pq z000002LJ#76#xJLe*gdg00000000{y0000000#g702TlM000000000000OApigX000L70015U z0000000000001x>ApigX000L7001BW0000000000001}}ApigX000L7001EX00000 z00000002N6ApigX000L7001KZ0000000000002lEApigX000L7001Na0000000000 z002-MApigXe*gdn0000b0000000000000138zBGy000070000c00000000000001B z8zBGy000070000d00000000000001J8zBGy000070000e00000000000001R8zBGy z000070000f00000000000001Z8zBGy000070000ge*gdg0000000000fEytI00000 z2LJ#7D*ylh0000000000h#MgQ000002LJ#7EC2ui0000000000kQ*TY000002LJ#7 zEdT%j0000000000m>VGg000002LJ#7E&u=k0000000000pc^3o000002LJ#7F#rGn z00000e*gdg0H_-w0000000#g705Sjo00000000000I(Y&0000000#g705bpp00000 z000000Js|=0000000#g705kvq00000000000Kgj|0000000#g705$*s0000000000 z0LU950000000#g705<>t00000000000MHvDe*gdg000L7001}u0000000000007t< zApigX000L70024w0000000000007_{ApigX000L70027x0000000000008J4ApigX z000L7002Ay0000000000008hCApigX000L7002Dz0000000000008(KApigX000L7 ze*geJ00000000000000093cPz000070000$00000000000000893cPz000070000% z00000000000000G93cPz000070000(00000000000000O93cPz000070000)00000 z000000000W93cPz000070000+00000e*gdg00000C>$XG000002LJ#7M*si-00000 z00000FdQKO000002LJ#7NB{r;0000000000I2<7W000002LJ#7N&o-=0000000000 zKpY_e000002LJ#7OaK4?0000000000NE{&m000002LJ#7PXGV_0000000000e^4AD z0000000#g708sz{000000000009YI$0000000#g708#(|00000000000AL&;00000 z00#g708;<}00000000000B9T`0000000#g708{_~00000000000B{^30000000#g7 z0961000000000000C*fB00000e*gyn003410000000000004j-ApigX000L700372 z0000000000004*_ApigX000L7003A3000000000000592ApigX000L7003D400000 z00000005XAApigX000L7003G50000000000005vIApigX000L7003J6e*gdg00000 z0001}93cPz000070001900000000000002693cPz000070001A00000000000002E z93cPz000070001B00000000000002M93cPz000070001C00000000000002U93cPz z000070001E0000000000e*gdg&>SHE000002LJ#7W&i*H0000000000*c>4M00000 z2LJ#7X8-^I0000000000;2a?U000002LJ#7XaE2J0000000000=o}#c000002LJ#7 zX#fBK0000000000@Ejok000002LJ#7Y5)KL0000000000_#7bse*gdg00#g70BZmM z00000000000012!0000000#g70B!&P000000000000nSi000002LJ#7hX4Qo0000000000pdBFq00000e+K{n0Ehqp00000000000H_@y z0000000#g70Eqwq00000000000I(e)0000000#g70Ez$r00000000000Jt3?00000 z00#g70E++s00000000000Kgp~0000000#g70E_?t00000000000LUF70000000#g7 z0FD3ve*gdg00000007V(ApigX000L70055w0000000000007t>ApigX000L7005By z0000000000007_}ApigX000L7005H!0000000000008J6ApigX000L7005K#00000 z00000008hEApigX000L7005N$0000000000e*ggZ9U%Y!000070001%0000000000 z000009w7h#000070001&0000000000000089w7h#000070001(00000000000000G z9w7h#000070001)00000000000000O9w7h#000070001+00000000000000W9w7h# ze*gdg2LJ#7oB#j-0000000000C>|jI000002LJ#7p8x;=0000000000FdiWQ00000 z2LJ#7pa1{>0000000000I36JY000002LJ#7p#T5?0000000000Kpr6g000002LJ#7 zq5uE@0000000000NFE^o000002LJ#7f1>~Z000000000008kzw0000000#g70H*)| z000000000009YO&0000000#g70H^=}00000000000AL;=0000000#g70I2`~00000 z000000B9Z|0000000#g70IC2000000000000B{~50000000#g70IL8100000e*gdg z004L%ApigX000L7006820000000000004j000070002D00000000000001}9w7h#00007 z0002E0000000000000269w7h#000070002I00000000000002E9w7h#000070002J z00000000000002M9w7h#000070002L00000000000002U9w7h#00007e*gdgzyJUM z0000000000&>kTG000002LJ#7!2kdN0000000000*d8GO000002LJ#7!Te000002LJ#7#sB~S0000000000 z@E#!m000002LJ#7#{d8Te*gdg000000Qepu0000000#g70LTCU00000000000018$ z0000000#g70LcIV000000000000(ek000002LJ#7 z;Q#;t00000e*gdg07!%E2uOEQqW|NkXY(jWk60RR91>CpfG|NkXQ(jWk60ssI2 z>A?U0|NkXI(jWk60{{R3>9GI*|NkXA(jWk61ONa4f9atA|Ns9bGSVObXaxWO0O^qb z|Ns9bD$*bTXa)cP0O^4L|Ns9bBGMoLXa@iQ0O@f5|Ns9b8qy#DXb1oR0O?@=|Ns9b z64D?5XbAuS0O?Tw|Ns9b3eq3|XbJ!T0O>&g|Ns9b0@5G=XbS)U0O>IQ|Ns9b`q3Z& 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 z002P_5QYLl4j6+2L=G?llL`(PK@Jc>4hTgH0000009*h705lQ+07$3*|2mglHvu;$ zT@FY{4p3SSNJb7o0(A~ZPYzI84oF50KmY&$Bme*alo9{{D5;k^IRPRDyb=HaV5yfn zIRPG*fH?sK2ILX|0GO$lia7xq1_ToT0NAOQsyP7~1|$;z00^p=$~gfVDMS+h0BEZJ z|BL_t002Y|AOceg4hTsL0000002}}S0Av#Y0NASk|4f&SIRO_2gcAS&2&mA zq!R!DIIEXBJ^>mA#1jAjXseexJ^>mgNfI{`8VJQM%`aIBZgI{`8ZbQAyp*sTBm>;RX(Faa5tA3Oma2DB6a z0En%ZLOcO72J93706?yndOQId1`HJd0AQ|{dOQId1}qf-0D!KSx;z0I222$I0Kl%7 z+B^Xo25c1o006I-`aA&|282uurG z3JwTC3mgCd0F)O10LZfc|5pG2002Y|AZiK@2ucfC3JwTC3mgCd0JIkX00^`H|6Bk7 z002Y|AOc7V4hTdG0000002}}S0Mr)%07$c!+C2dp2J{yI0C=;Px;_CKW)v6z0JyXN z|2+Tz002Y|Aae>12tf+~0000002}}S05li?0NAtt|6Bk7002Y|AOc1T4hTjI00000 z02}}S08|(N02s9Y|4aY?002Y|AbSc92tf+~0000002}}S0CX4t07$f#+C2dpCX^Te z0C=?j|5N|~002Y|Ab$!D2t^A30000002}}S0JInY0JyZ5dOQIdf7BQN0NAwu|6Bk7 z002Y|AOc4U4hTgH0000002}}S0Q49D02sCZ|6Bk7002Y|AOc4U4hTgH0000002}}S z02CPj09dvE|1JOk002Y|AY=*-2tf+~0000002}}S05ll@0BE)U|1JOk002Y|AY=*- z2tf+~0000002}}S2LMzV004NkmwG$_8h>;d005Y^|Nm?N0000)4j=+W3JwTI3jhEB z000~S005L3008K<|Nkxk0000)4j^O-4hTUD00000000~S006WZ008*4|Nk`r0000) z4j^j^4hTUD00000000~S007h(000=a|Nl$?0000)4j_064hTdG00000001Na00#i{ z82|uCwwD4z0U`z*8UO(BwwEeG0U8NB8UO$gxBvefw^2d?X9Sb*1uTCMRR91000000 z000000002cQ~&?~000000000000001000000000M3jhEB00001000000000Y3jhEB z00001000000000)3jhEB00001000000000}3jhEB0000100000000183jhEB00001 z000000001M3jhEB003J64gdfE00000s|x@C000003;+NC00000@J9du000004FCWD z00000oXP+I0000082|tP000002pAy%000008vpXdM6m000001^@s600000I0yg$000003IG5A00000`3nF5000003jhEB z000007ytkO000000{{R300000Xc{2^000000ssI200000U=IKQ000006aWAK00000 z2LJ#7000007XSbN00000kT?JU000002LJ#70000J0Jtjv0000000;m8000000N4zd zQb++lF(@kl000000RR90ZvX%Q00IC2000000Pz3+ZvX%Q0AeWs000000Qvv_ZvX%Q z0DF_+1y=(o7$K7}0Tq8HNB{r;0000sNB{r;0000+NB{r;00011NB{r;0001HNB{r; z0001XNB{r;0001nNB{r;0001%NB{r;0001{NB{r;0002CNB{r;0002SNB{r;0002i zNB{r;0002yNB{r;0002?NB{r;00006NdN!<0000MNdN!<004ggCP@GQ00000Hc0>g z00000Mo9nw00000R!IN=00000W=Q}500000c1ZvL00000hDiVb00000mPr5r00000 zrbz$*00000wn+d000000#z_DG00000)=2;W00000=1Bkm00000_DKK$0000021)<` z000007D@mB004gg047QR0000005(bh0000007gmx0000009Hx>000000A@-600000 z0Cq|M000000ES8c000000G3Js000000H#U+000000Jcg1000000LDrH000000M<$X z000000Om>n000000QO1%0000000v6{0000002WIC004gg001US00000001^i00000 z002fy000000034?00000003r700000004GN00000004$d00000005Rt00000005>- z00000006d2000000072I00000007oY00000008Do00000008z&00000000I|00000 z000(D004gg0000cOaK4?0000sOaK4?0000+OaK4?00011OaK4?0001HOaK4?0001X zOaK4?0001nOaK4?0001%OaK4?0001{OaK4?0002COaK4?0002SOaK4?0002iOaK4? z0002yOaK4?0002?OaK4?00006O#lD@0000MO#puY00000CQSeU00000HcbEk00000 zMoj>00000 z006d6000000072M00000007oc00000008Ds00000008z+00000000J100000004g$ zPyhe`0000cPyhe`0000sPyhe`0000+Pyhe`00011Pyhe`0001HPyhe`0001XPyhe` z0001nPyhe`0001%Pyhe`0001{Pyhe`0002CPyhe`0002SPyhe`0002iPyhe`0002y zPyhe`0002?Pyhe`00006Q2+n{004gg7Eu5I00000CQ$$Y00000HcEkD00000c2NKT00000hEV_j00000mQerz00000rcnR@00000 zwow2800000#!&zO00000)=>Ze00000=1~9u00000_E7);0000022ub3001Na02WdJ z00000047oZ0000005(zp0000007g;(0000009I0y;RR=ZARzz%0000100030|NsC0 z|Ns910000100030|Ns9k;s5{u00005000000000p;s5{u00005000000000v;s5{u z00005000000000#;s5{u00005000000000);s5{u00005000000000;;s5{u00005 z000000001gQ{n&s000001poj500000SmFQx000001poj500000VB!D(000001poj5 z00000Wa0n-000001poj500000XyO0>000001poj500000Y~la_000001poj500000 zcH#g4000001poj500000g5m%G000001poj50001g0FdGU0000000jU5000000GHwb z0000000jU5000000HNXl0000000jU5000000IcEw0000000jU5000000JP!&00000 z00jU5000000Keh@0000000jU5000000L9_}0000000jU5000000Lp z00000000F5000000095u00000000F50001g00004;{X5v00005000000000D;{X5v z00005000000000N;{X5v00005000000000Q;{X5v00005000000000U;{X5v00005 z000000000X;{X5v00005000000000e;{X5v00005000000000k;{X5v000050001g z00000G2;LL000001poj500000HRAvP000001poj500000IO6~S000001poj500000 zJL3QV000001poj500000UE%-$000001poj500000KH~rY000001poj500000LgN4c z000001poj500000M&keg000001pokl0000007>Hj0000000jU50000008!%r00000 z00jU50000009fMy0000000jU5000000Ab?*0000000jU5000000B7R>0000000jU5 z000000Bhp_0000000jU5000000B_>}0000000jU5000000CVF20000000jUW00000 z004L600000000F500000004jE0001yK@*qAQvn!%gyR4J000000000000000isJwP z000000RR9100000kK+IU000000ssI200000m*W5c000000{{R300000o#Oxi00000 z1ONa400000qT>Jn000005C8xG00000sN(00000000UA00000003;_00000000XB00000004I400000 z000aC00000004sG00000000dD00000005BU00000000gE00000005Wb00000000jF z00000e*gfX;s5{u0000G0000000022;s5{u0000H000000002A;s5{u0000I00000 z0002L;s5{u0000J000000002R;s5{u0000K000000002Y;s5{u0000L000000002c z;s5{u0000M000000002i;s5{u0000N00000e*gdg-QoZM000007ytkO00000=HdVV z0000082|tP00000?cx9c000008UO$Q00000_Tm5l000008vpOV ze*gdg02ku`0000003ZMW0000002<=}0000003iSX0000003PE20000003rYY00000 z03qW50000003!eZ0000004U=C0000003-ka00000050PI0000003`qb0000005RhL z00000044wc0000005#(P0000004D$de*gdg0021S00000001Ze00000002AV00000 z001cf00000003R$00000001fg00000002JY00000001ih00000002Vc00000001li z00000002hg00000001oj00000002qj00000001rk00000002?r00000001ule*gdg z00013;{X5v0000m000000001C;{X5v0000n000000001I;{X5v0000o000000001M z;{X5v0000p000000001Q;{X5v0000q000000001U;{X5v0000r000000001Y;{X5v z0000s000000001g;{X5v0000tml;?AkAFA_00000000000000000000000930|00p z00000000000000000000000931OQ?w00000000000000000000000931pp{300000 z000000000000000000931^~D#00000000000000000000000932LO;b000000Dk}g z00000000000000300;o^M*si-0000000000000000000300{sPNB{r;0000000000 z0000000003015zLQUCw|0000000000000000000301E(sQUCw|000000000000000 z0000301N<}$^ZZW00000000000Dk}g000000{{&GsLB8U00000000000000000000 z0{{*H2=xE}000000000000000000000{{;IF!=xg000000000000000000000{{>J z2pAy%000000000000000000000{{^K7#JY{0000000000000000000015E%D04NwC z0000000000000000000000RIM0B9N^0000000000000000000000RIN001B%00000 z00000000000000000RIO001bLa#{gKe?TZ90000004M+e0000002BZK00ICD0H9R> z000000O0RR*Lz#}0500000kN^Mx000000RaF20RR;MkSHMl00000 z1ONa4000006afGL0RR;Mlqewp000001ONa400000Bmn>b0sspDz<&S$00000j0XS! z00000E&%`l0RR;Mm?$9tH2?qr00aO40000006hT!0096M0H7!#0000000aO400000 z089Y@0096M0Gucx0000000ftTUI8C}X8`~J0sspDKvVz#000000000000000X#oHL z0sspDfK&hg000000000000000d;tIe0sspD&{O~b000000000000000k^uk!0RR;M z04N~<000000RR9100000p#cB@0RRyI7#JY{000000000000000$N>NV0sspe01#CG z0000000000000000Mr2h0096H00RkbD3RnUF00ICD0KmSNdR_r03U2}c0096G0Du#hs$Kyme|-V~0000E00{K} z0000000000000000FVLz0096L001B%0000000000000000G$E=0096J04NwC00000 z00000000000Hy)}0096L0PrUv0000000000000000JH)C00ICD0D#H>0000002}}S z000000I~uA00ICDDgc1W00000000~S00000006@R00031698x$ApigX0000000000 z007yO(Fzwa^8x?>5&#PTpu7M800000G5`Po00000{{jF25&#PT;JE+*00000lmGw# z000005|iN=7cnpc000sI3jk1u000000034100000002n?000sI3jlDy00000001-q z00000002~%Az%R)0cexq7#Dwg0{{RL01E)1bpQYW0002&0ssI20001x0{{RL01E)n zzW@LL0000?000000001*0{{RL01E)Hi2wiq0002>000000001}0{{RL01E(MTL1t6 z00020000000002B0{{RL01E&haR2}S00023000000002S0{{RL005Kc7!d*6li?T_ zN$mpw01^NT0N}g;000000ABzA000000Qds{01^NT0MM@h000000NDTl0000000;yC z01^NT0I;|K0000004@Lk0000002-6=AQu@U1ONaM01E(cSpWb40000q000000000r zlkp%I0ZEhbAQu^31ONaK02Bc5Cm{d;00000000000001Flkp%I8F&N$01^NT0N};| z0000009*h7000000Ed(DAQu6flkp%IVWb2A01^NT0I;$E0000006GEy000000J{VL z01^NT01&nS0000007n1-000000Llaa01^NT0Pt7<000000672v000000NMlq01^NT z0HDVJ0000004@Lk000000O*tPAQv(G1ONaM01E)1y#N3J0000s00000000091pojN z01E)n#{d8T0000k000000000Nm+@i&7Xc}k@nQiN0Wz2IVgVNcJ(uxf0T%&Lm+@i& z7cpc7000sI3jhFb00000003A3000000046Z000sI3jnZL00000004LZ00000004%U z@nQiNf0_jV01^NT0AOzb000000J8xA000000H*~201^NT0DxZr000000006200000 z0K^3V01^NT06@k70000008{_~000000MG>h01^NT0Dxft000000O0`u000000Oth& z01^NT05Dnr000000O9}u000000PqC>03rYYlQRJkmk?wD9+MUd5*afF000sI3jpx6 z00000003M700000002Uh5egR>Rt5k75dakcASfXK000005C8xG00000Uy~6E7XfpV z5egSEg$4is5&#PTa998U00000cmMzZ00000o(2E_5&#PTpuzwE00000jsO4v00000 zu9Fc87cs;J000sI3jp9|00000001um00000007el000sI3jkoY00000004Xd00000 z007{V5egRp`I8X}7a1W3000sI3jjdE00000002|~00000001qM;Sv`~Ne2J`5&#PT zke&bl00000%mM%a00000SO)+A5&#PTpv3?H00000OaK4?00000V+Q~L5&#PTpqBsu z00000J^%m!00000Ym?y;7a4yC000sI3jlzb000000077U00000005Aa;Sv`Ctdl_* z7h$9a000sI3jn}<00000005f-00000006QF000sI3jjdM00000001%o00000006xQ z000sI3jkoD00000001`w00000007Dd000sI3jiQh00000004IY00000007mK;Sv`y z{09I45&#PTAi)3t00000R{#J2000002M7QF5&#PTAYA|e00000R0041000006qAt= z7cnRZ000sI3;>+U000000000000000001rs000sI3ji>f00000002k<00000007F9 z;S3i6LX(jZ7Xf6Gkr5X$ZU_JX5&#PTFjxQp00000Gynhq00000fCvBp5&#PTu)qKS z00000WB>pF00000jgyfP7Xhr3kr5XG!jq8^7Xj9jkr5Y3>j(e<5&#PTAX@+c00000 zGynhq00000_Xq$05&#PTK*s<800000TmS$7000001_=NF5&#PT;I;q&00000i~s-t z000006O&;V7a2GS000sI3jn}#00000007Ye00000002poVHX!oTnPXG5&#PTAaei! z00000ng9R*00000b_oCg5&#PTu#5lz00000ZU6uP00000gb4ru5&#PTV0!=n00000 zQUU+~00000l?ea<5tA_i6G^QJ000sI3jjdK00000003+N00000006fM000sI3jpA_ z000000093000000007Ae000sI3jhGf00000001%o00000007jJVHXzx?vr5`7k>c? z000sI3jmOh00000000^S00000000mQ000sI3jk2D0000000342000000015e000sI z3jjdH00000003M700000001Wn000pH6#x(^ApigX000mG000000024)000sI3jh#p z000000089y00000002S?000sI3n~Dxt^fc40000V0RR910000~3IG5S01E(cV*mgE z0001L0{{R30001HlR+658F~r;01^NT0Km5Z00000089V?000000Em-885bFy3IG5S z01E(MyZ`_I0000o0000000021lR+650l$+$85aS_lR+650o;>885d#l3IG5S01E&R zs{jB10001{0ssI2000303IG5R02KhhC?Nm<00008000000000A3jhET01E(cy8r+H z0002w000000000Z3jhET01E)HhX4Qo0002>000000000oli>^(8AS^K01^NT0N|GZ z0000007d`+0000008x|S3>O*F4gdfW00;o^M*si-00000000000001Oli>^(Nr4Lh z01^NT0C33w000000K)(P0000001N~G01^NT08p9$0000006YKy000000GkW|01^NT z01$Ej0000000#j8000000Faa63>N{Wli>^(0m+l$3>O*P3jhET01E(cdH?_b0002v z000000002>li>^(0SA*|3l{+~lVJ-N0Z@}+3m1Q63;+NU01E(sQUCw|0002O00000 z0001T3;+NU01E&RzW@LL0000~000000001d3;+NU01E){!vFvP00017000000001p z3;+NU01E)%y#N3J0001F000000001y3;+NU01E(Me*gdg00016000000001~3;+NU z01FZTP_+O600000TmS$700000wv%BC7n6t$7#Zda000sI3jh#k00000008v_00000 z008lmVG9=l1d~w=7a1)L000sI3jh$P00000008s>000000023YQ4AM;M1&00000G!6g&5&#PT5UKzG00000`~Uy|00000K9^B%0T%&Kmr-v47Xf6K zQEvek0fd)PZvhv7qz(W85&#PTu(bdH00000SO5S300000vy5&#PT0L1_R00000Jpcdz00000;|>4-5&#Pl0I;wC000000H6Q>00000 z0PvSlZvhv70}lWI5&#PTpril*00000^#A|>000005)S|X5&#PTAdLV300000^8f$< z0000091j2h5&#PTu#o@&00000J^}y$00000F%JL$5&#PTkaz$900000-2ngq00000 zL=OM}5&#PTV7LGP00000OaK4?00000RSy6F5&#QY0C2wm0000008{_~000000A3FO z01^NT0I-Sx000000P+9;000000BsKd01*Hc05B*a0000000;m8000000EG_#01^NT z05Dkq0000005kvq000000FjqraRC=us}BGG5&#PTu!sNv00000^#A|>00000xeovU z5&#PTAiw|s00000OaK4?00000%ntwn5&#PTprrr+00000$p8QV00000+z$W%5&#PT z5V!yU00000OqZc?0UsF-5C8xY01E)HivR!s0002>000000000Tm+^4{7k@Dj000sI z3jpxN00000002w?00000002A?000sI3jmOs00000008p=00000002r5000sI3jmOu z00000004Ob000000034H000sI3jpww00000008{}00000003hU000sI3jpBA00000 z001=r000000049l001BW0FyHT5dn~w@o@nc8K@8d01^NT0C1-O000000Gt2-00000 z0I!$vaRC=$!w>)f5&#PTz`g(g00000OaK4?00000%@6u zg8@pHG=u?Dmz;zFbeA860V)hoa%paKQ)O&sOmAnGf`tJz5@vH{Wotk{M@&gVLtip3 zGA=cj>xBVgmyL-54wrL=0ezQ^i2(?g3x@$u2vl!xY)^1yZkK+C0qqW7Wo~2uW^{6O zZew9|WtV@60T!3eh5-nZdoBx?zK8)2m*9v2RF^=B0d1F!i2)9m#)$zi6<=Rsb8}yF zbYXII0Ay@$XJ2V^w?iUCEJkct7&murgw!zYE)qBh00000001}$00000001x* zmpYFDE)r-R00000003wm00000008+5mwJx@E)rrX00000003es00000006`Rm%5Ju zE($0s00000001Z}m-3GRHWIii00000006iv00000007twmpYIEE)tM9000000059U z00000003YQmwJ!^E)noY00000008hu00000000`3tp^*I)Q|xb5)eoL0000001!w3 z0000008k2-`j7!G4Pa6L000000ANx8005H_A`_ReS^)%?OpyT`5`aS9C00000C>WPAlL0moXc{2^00000Xc_?k00000m<5-5 zlL0RgARzz%00000AOQdX0002+2ba2&0WJ~%C?Nm<0002+CjkHe0000W0hjud0X7Nn zCjkHe0000!lK~