|
|
@@ -1941,7 +1941,7 @@ Status GraphMemoryAssigner::AssignBufferPoolMemory() { |
|
|
|
|
|
|
|
// if producer and customers in the same stream, or customers on the same stream when producer not assign a stream, |
|
|
|
// then return false. |
|
|
|
static bool IsOutputVisitedByMultiStream(const NodePtr &peer_out_node, int64_t out_anchor_index) { |
|
|
|
bool GraphMemoryAssigner::IsOutputVisitedByMultiStream(const NodePtr &peer_out_node, int64_t out_anchor_index) { |
|
|
|
GE_IF_BOOL_EXEC(peer_out_node->GetOpDesc() == nullptr, return true); |
|
|
|
int64_t unique_stream_id = peer_out_node->GetOpDesc()->GetStreamId(); |
|
|
|
|
|
|
@@ -1963,9 +1963,9 @@ static bool IsOutputVisitedByMultiStream(const NodePtr &peer_out_node, int64_t o |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static void UpdatePrevNodeInputDesc(const NodePtr &prev_node, |
|
|
|
const vector<int64_t> &prev_node_input_index_vec, |
|
|
|
int64_t distance) { |
|
|
|
void GraphMemoryAssigner::UpdatePrevNodeInputDesc(const NodePtr &prev_node, |
|
|
|
const vector<int64_t> &prev_node_input_index_vec, |
|
|
|
int64_t distance) { |
|
|
|
GE_IF_BOOL_EXEC(prev_node == nullptr, return); |
|
|
|
auto prev_node_op_desc = prev_node->GetOpDesc(); |
|
|
|
GE_IF_BOOL_EXEC(prev_node_op_desc == nullptr, return); |
|
|
@@ -2007,7 +2007,9 @@ static void UpdatePrevNodeInputDesc(const NodePtr &prev_node, |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void UpdateCurNodeInputDesc(const NodePtr &cur_node, int64_t cur_node_input_index, int64_t distance) { |
|
|
|
void GraphMemoryAssigner::UpdateCurNodeInputDesc(const NodePtr &cur_node, |
|
|
|
int64_t cur_node_input_index, |
|
|
|
int64_t distance) { |
|
|
|
GE_IF_BOOL_EXEC(cur_node == nullptr, return); |
|
|
|
GE_IF_BOOL_EXEC(cur_node->GetOpDesc() == nullptr, return); |
|
|
|
auto input_desc = cur_node->GetOpDesc()->GetInputDesc(cur_node_input_index); |
|
|
@@ -2032,7 +2034,113 @@ static void UpdateCurNodeInputDesc(const NodePtr &cur_node, int64_t cur_node_inp |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
size_t GraphMemoryAssigner::GetMemoryOffset(const HybridMemAssignerPtr &mem_assigner, |
|
|
|
const NodePtr &peer_out_node, |
|
|
|
const OutDataAnchorPtr &peer_out_anchor) { |
|
|
|
NodeIndexIO node_index_io(peer_out_node, peer_out_anchor->GetIdx(), kOut); |
|
|
|
string symbol; |
|
|
|
size_t matched_mem_offset = mem_assigner->GetPriorityAssinger()->GetAnchorDataOffset(node_index_io, symbol); |
|
|
|
if (matched_mem_offset == kInvalidOffset) { |
|
|
|
// peer_out_anchor not assign MemoryBlock, we search the peer_out_anchor's data in continous memory |
|
|
|
matched_mem_offset = peer_out_node->GetOpDesc()->GetOutputOffset().at(peer_out_anchor->GetIdx()); |
|
|
|
} |
|
|
|
return matched_mem_offset; |
|
|
|
} |
|
|
|
|
|
|
|
void GraphMemoryAssigner::CheckNeedCalcDistAndUpdateVisitInfo( |
|
|
|
map<size_t, pair<NodePtr, vector<int64_t>>> &mem_block_visit_info, |
|
|
|
size_t matched_mem_offset, |
|
|
|
const NodePtr &peer_out_node, |
|
|
|
const OutDataAnchorPtr &peer_out_anchor, |
|
|
|
bool &is_need_calc_distance) { |
|
|
|
auto iter = mem_block_visit_info.find(matched_mem_offset); |
|
|
|
// cannot find visit info, peer_out_node must be a producer and this data is the first time to be visited. |
|
|
|
if (iter == mem_block_visit_info.end()) { |
|
|
|
if (IsOutputVisitedByMultiStream(peer_out_node, peer_out_anchor->GetIdx())) { |
|
|
|
vector<int64_t> temp; |
|
|
|
mem_block_visit_info.insert(std::make_pair(matched_mem_offset, std::make_pair(nullptr, temp))); |
|
|
|
is_need_calc_distance = false; |
|
|
|
return; |
|
|
|
} else { |
|
|
|
vector<int64_t> temp = {-1}; |
|
|
|
// producer's prev_node_index set to -1 as default |
|
|
|
mem_block_visit_info.insert(std::make_pair(matched_mem_offset, std::make_pair(peer_out_node, temp))); |
|
|
|
is_need_calc_distance = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (mem_block_visit_info[matched_mem_offset].first == nullptr) { // multi-stream visit, no need to calculate |
|
|
|
is_need_calc_distance = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (peer_out_node->GetOpDesc()->GetStreamId() != |
|
|
|
mem_block_visit_info[matched_mem_offset].first->GetOpDesc()->GetStreamId()) { |
|
|
|
// cur node and peer_out_node not in the same stream, no need to calculate |
|
|
|
is_need_calc_distance = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
is_need_calc_distance = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// calculate distance, update visit info, update prev_node input desc, update cur node input desc |
|
|
|
void GraphMemoryAssigner::CalcDistanceAndUpdateDesc(map<size_t, pair<NodePtr, vector<int64_t>>> &mem_block_visit_info, |
|
|
|
size_t matched_mem_offset, |
|
|
|
const map<string, int64_t> &node_index_in_stream, |
|
|
|
NodePtr &node, |
|
|
|
const InDataAnchorPtr &in_data_anchor, |
|
|
|
bool &is_need_skip) { |
|
|
|
int64_t distance = -1; |
|
|
|
auto prev_node = mem_block_visit_info[matched_mem_offset].first; |
|
|
|
auto prev_node_input_index_vec = mem_block_visit_info[matched_mem_offset].second; |
|
|
|
GE_IF_BOOL_EXEC(prev_node == nullptr, is_need_skip = true; return); |
|
|
|
if (prev_node_input_index_vec.size() == 1 && prev_node_input_index_vec[0] == -1) { |
|
|
|
// prev_node is producer and the data is just be produced(not visited by other node) |
|
|
|
GE_IF_BOOL_EXEC(prev_node->GetOpDesc() == nullptr, is_need_skip = true; return); |
|
|
|
if (prev_node->GetOpDesc()->GetStreamId() == -1) { // producer not assigned a stream |
|
|
|
distance = 0; |
|
|
|
} else if (node_index_in_stream.find(prev_node->GetName()) == node_index_in_stream.end()) { |
|
|
|
distance = 0; |
|
|
|
} else { |
|
|
|
distance = node_index_in_stream.at(node->GetName()) - node_index_in_stream.at(prev_node->GetName()) - 1; |
|
|
|
} |
|
|
|
mem_block_visit_info[matched_mem_offset].first = node; |
|
|
|
mem_block_visit_info[matched_mem_offset].second.clear(); |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} else { // the data is visit by other customer just before. |
|
|
|
if (prev_node_input_index_vec.empty()) { |
|
|
|
GELOGW("Missing prev node[%s] input index.", prev_node->GetName().c_str()); |
|
|
|
is_need_skip = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (prev_node == node) { // scene: multiple anchors of a node access the same data |
|
|
|
vector<int64_t> prev_next_distances; |
|
|
|
GE_IF_BOOL_EXEC(prev_node->GetOpDesc() == nullptr, is_need_skip = true; return); |
|
|
|
auto input_desc = prev_node->GetOpDesc()->GetInputDesc(prev_node_input_index_vec[0]); |
|
|
|
if (!ge::AttrUtils::GetListInt(input_desc, ATTR_NAME_DATA_VISIT_DISTANCE, prev_next_distances)) { |
|
|
|
GELOGW("Get ATTR_NAME_DATA_VISIT_DISTANCE failed."); |
|
|
|
is_need_skip = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (prev_next_distances.size() != kPrevNextDistanceNum) { |
|
|
|
GELOGW("Size of prev_next_distance is not 2."); |
|
|
|
is_need_skip = true; |
|
|
|
return; |
|
|
|
} else { |
|
|
|
distance = prev_next_distances[0]; //use the same prev_distance of previous anchor |
|
|
|
} |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} else { |
|
|
|
distance = node_index_in_stream.at(node->GetName()) - node_index_in_stream.at(prev_node->GetName()) - 1; |
|
|
|
UpdatePrevNodeInputDesc(prev_node, prev_node_input_index_vec, distance); |
|
|
|
mem_block_visit_info[matched_mem_offset].first = node; |
|
|
|
mem_block_visit_info[matched_mem_offset].second.clear(); |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} |
|
|
|
} |
|
|
|
UpdateCurNodeInputDesc(node, in_data_anchor->GetIdx(), distance); |
|
|
|
} |
|
|
|
|
|
|
|
void GraphMemoryAssigner::MarkNodeDistanceAttr(const ComputeGraphPtr &compute_graph, |
|
|
|
NodePtr &node, |
|
|
@@ -2046,105 +2154,32 @@ void GraphMemoryAssigner::MarkNodeDistanceAttr(const ComputeGraphPtr &compute_gr |
|
|
|
auto peer_out_node = peer_out_anchor->GetOwnerNode(); |
|
|
|
GE_IF_BOOL_EXEC(peer_out_node == nullptr, continue); |
|
|
|
|
|
|
|
NodeIndexIO node_index_io(peer_out_node, peer_out_anchor->GetIdx(), kOut); |
|
|
|
std::string symbol; |
|
|
|
size_t matched_mem_offset = mem_assigner_->GetPriorityAssinger()->GetAnchorDataOffset(node_index_io, symbol); |
|
|
|
if (matched_mem_offset == kInvalidOffset) { |
|
|
|
// peer_out_anchor not assign MemoryBlock, we search the peer_out_anchor's data in continous memory |
|
|
|
matched_mem_offset = peer_out_node->GetOpDesc()->GetOutputOffset().at(peer_out_anchor->GetIdx()); |
|
|
|
} |
|
|
|
auto matched_mem_offset = GetMemoryOffset(mem_assigner_, peer_out_node, peer_out_anchor); |
|
|
|
|
|
|
|
auto iter = mem_block_visit_info.find(matched_mem_offset); |
|
|
|
// cannot find visit info, peer_out_node must be a producer and this data is the first time to be visited. |
|
|
|
if (iter == mem_block_visit_info.end()) { |
|
|
|
if (IsOutputVisitedByMultiStream(peer_out_node, peer_out_anchor->GetIdx())) { |
|
|
|
vector<int64_t> temp; |
|
|
|
mem_block_visit_info.insert(std::make_pair(matched_mem_offset, std::make_pair(nullptr, temp))); |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
vector<int64_t> temp = {-1}; |
|
|
|
// producer's prev_node_index set to -1 as default |
|
|
|
mem_block_visit_info.insert(std::make_pair(matched_mem_offset, std::make_pair(peer_out_node, temp))); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (mem_block_visit_info[matched_mem_offset].first == nullptr) { // multi-stream visit, no need to calculate |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (peer_out_node->GetOpDesc()->GetStreamId() != |
|
|
|
mem_block_visit_info[matched_mem_offset].first->GetOpDesc()->GetStreamId()) { |
|
|
|
// cur node and peer_out_node not in the same stream, no need to calculate |
|
|
|
continue; |
|
|
|
} |
|
|
|
bool is_need_calc_distance = false; |
|
|
|
CheckNeedCalcDistAndUpdateVisitInfo(mem_block_visit_info, matched_mem_offset, peer_out_node, |
|
|
|
peer_out_anchor, is_need_calc_distance); |
|
|
|
if (!is_need_calc_distance) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// now mem_block_visit_info must contains that memory_block |
|
|
|
// steps: calculate distance, update visit info, update prev_node input desc, update cur node input desc |
|
|
|
int64_t distance = -1; |
|
|
|
auto prev_node = mem_block_visit_info[matched_mem_offset].first; |
|
|
|
auto prev_node_input_index_vec = mem_block_visit_info[matched_mem_offset].second; |
|
|
|
GE_IF_BOOL_EXEC(prev_node == nullptr, continue); |
|
|
|
if (prev_node_input_index_vec.size() == 1 && prev_node_input_index_vec[0] == -1) { |
|
|
|
// prev_node is producer and the data is just be produced(not visited by other node) |
|
|
|
GE_IF_BOOL_EXEC(prev_node->GetOpDesc() == nullptr, continue); |
|
|
|
if (prev_node->GetOpDesc()->GetStreamId() == -1) { // producer not assigned a stream |
|
|
|
distance = 0; |
|
|
|
} else if (node_index_in_stream.find(prev_node->GetName()) == node_index_in_stream.end()) { |
|
|
|
// prev_node is ge local op |
|
|
|
distance = 0; |
|
|
|
} else { |
|
|
|
distance = node_index_in_stream.at(node->GetName()) - node_index_in_stream.at(prev_node->GetName()) - 1; |
|
|
|
} |
|
|
|
mem_block_visit_info[matched_mem_offset].first = node; |
|
|
|
mem_block_visit_info[matched_mem_offset].second.clear(); |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} else { // the data is visit by other customer just before. |
|
|
|
if (prev_node_input_index_vec.empty()) { |
|
|
|
GELOGW("Missing prev node[%s] input index.", prev_node->GetName().c_str()); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (prev_node == node) { // scene: multiple anchors of a node access the same data |
|
|
|
vector<int64_t> prev_next_distances; |
|
|
|
// 1. do not need to update prev_node's input desc, because it must be updated when the first anchor visit it. |
|
|
|
// 2. we use the same distance of previous anchor to keep this value the same. |
|
|
|
// 3. update visit info's prev_node_input_index_vec |
|
|
|
if (prev_node->GetOpDesc() == nullptr) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
auto input_desc = prev_node->GetOpDesc()->GetInputDesc(prev_node_input_index_vec[0]); |
|
|
|
if (!ge::AttrUtils::GetListInt(input_desc, ATTR_NAME_DATA_VISIT_DISTANCE, prev_next_distances)) { |
|
|
|
GELOGW("Get ATTR_NAME_DATA_VISIT_DISTANCE failed."); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (prev_next_distances.size() != kPrevNextDistanceNum) { |
|
|
|
GELOGW("Size of prev_next_distance is not 2."); |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
distance = prev_next_distances[0]; //use the same prev_distance of previous anchor |
|
|
|
} |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} else { |
|
|
|
// now, prev_node must be customer because if cur node and prev node not on the same stream, then it will be |
|
|
|
// continue at IsOutputVisitedByMultiStream. |
|
|
|
distance = node_index_in_stream.at(node->GetName()) - node_index_in_stream.at(prev_node->GetName()) - 1; |
|
|
|
UpdatePrevNodeInputDesc(prev_node, prev_node_input_index_vec, distance); |
|
|
|
mem_block_visit_info[matched_mem_offset].first = node; |
|
|
|
mem_block_visit_info[matched_mem_offset].second.clear(); |
|
|
|
mem_block_visit_info[matched_mem_offset].second.push_back(in_data_anchor->GetIdx()); |
|
|
|
} |
|
|
|
bool is_need_skip = false; |
|
|
|
CalcDistanceAndUpdateDesc(mem_block_visit_info, matched_mem_offset, node_index_in_stream, node, |
|
|
|
in_data_anchor, is_need_skip); |
|
|
|
if (is_need_skip) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
UpdateCurNodeInputDesc(node, in_data_anchor->GetIdx(), distance); |
|
|
|
|
|
|
|
auto input_desc = node->GetOpDesc()->GetInputDesc(in_data_anchor->GetIdx()); |
|
|
|
bool is_end_of_inputmem_lifecycle = false; |
|
|
|
|
|
|
|
// if is_end_of_inputmem_lifecycle is true, indicating that cur node is the last customer of this data, |
|
|
|
// then we need to delete the visit info of the block in case that the memblock be reused and visited. |
|
|
|
if (ge::AttrUtils::GetBool(input_desc, ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE, is_end_of_inputmem_lifecycle) && |
|
|
|
is_end_of_inputmem_lifecycle) { |
|
|
|
GELOGD("ATTR_NAME_IS_END_OF_INPUTMEM_LIFECYCLE is true"); |
|
|
|
auto iter2 = mem_block_visit_info.find(matched_mem_offset); |
|
|
|
if (iter2 != mem_block_visit_info.end()) { |
|
|
|
mem_block_visit_info.erase(iter2); |
|
|
|
auto iter = mem_block_visit_info.find(matched_mem_offset); |
|
|
|
if (iter != mem_block_visit_info.end()) { |
|
|
|
mem_block_visit_info.erase(iter); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|