Browse Source

mark attr distance

pull/1573/head
lichun 4 years ago
parent
commit
3425ffea01
2 changed files with 152 additions and 92 deletions
  1. +127
    -92
      ge/graph/build/memory/graph_mem_assigner.cc
  2. +25
    -0
      ge/graph/build/memory/graph_mem_assigner.h

+ 127
- 92
ge/graph/build/memory/graph_mem_assigner.cc View File

@@ -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);
}
}
}


+ 25
- 0
ge/graph/build/memory/graph_mem_assigner.h View File

@@ -204,6 +204,31 @@ class GraphMemoryAssigner {

Status UpdateRefOpOffsetReverse(const NodePtr &node);

bool IsOutputVisitedByMultiStream(const NodePtr &peer_out_node, int64_t out_anchor_index);

void UpdatePrevNodeInputDesc(const NodePtr &prev_node,
const vector<int64_t> &prev_node_input_index_vec,
int64_t distance);

void UpdateCurNodeInputDesc(const NodePtr &cur_node, int64_t cur_node_input_index, int64_t distance);

size_t GetMemoryOffset(const HybridMemAssignerPtr &mem_assigner,
const NodePtr &peer_out_node,
const OutDataAnchorPtr &peer_out_anchor);

void 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);

void 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);

MemoryOffsetMap memory_offset_;
ge::ComputeGraphPtr compute_graph_;
HybridMemAssignerPtr mem_assigner_;


Loading…
Cancel
Save