.WithAttr("_outside", "O1"));
Node* recv2 = RecvAtHost(ops::NodeOut(key_constant, 0), "F1", "O2",
{DT_FLOAT, DT_FLOAT}, shape2.opts());
- Node* h = Binary(ops::NodeOut(recv2, 0), e,
+ Node* h = Binary(ops::NodeOut(recv2, 1), e,
shape2.opts()
.WithName("H")
.WithAttr("_encapsulate", "F1")
{"outside_compilation_O1_host_compute"}},
{{"outside_compilation_O2_host_compute"},
"XlaHostCompute",
- {"D:o:0", "F:o:0"},
+ {"F:o:0", "D:o:0"},
{{"Tinputs", gtl::ArraySlice<DataType>({DT_FLOAT, DT_FLOAT})},
{"Toutputs", gtl::ArraySlice<DataType>({DT_FLOAT})},
{"ancestors",
Node* recv2 = RecvAtHost(ops::NodeOut(key_constant, 0), "F1", "O2",
{DT_FLOAT, DT_FLOAT}, b2.opts());
- Node* g = Binary(e, ops::NodeOut(recv2, 1),
+ Node* g = Binary(e, ops::NodeOut(recv2, 0),
b2.opts()
.WithName("G")
.WithControlInputs({recv2, e})
.WithAttr("_encapsulate", "F1")
.WithAttr("_outside", "O2"));
- Node* h = Binary(ops::NodeOut(recv2, 0), e,
+ Node* h = Binary(ops::NodeOut(recv2, 1), e,
b2.opts()
.WithName("H")
.WithAttr("_encapsulate", "F1")
// Expect two subgraphs
EXPECT_EQ(segments.size(), 2);
- std::vector<string> expected0{"add0", "add1", "add2", "add3"};
+ std::vector<string> expected0{"add6", "add8"};
for (const auto& ex : expected0) {
EXPECT_TRUE(segments[0].first.find(ex) != segments[0].first.end())
<< "Missing expected node " << ex;
}
- std::vector<string> expected1{"add6", "add8"};
+ std::vector<string> expected1{"add0", "add1", "add2", "add3"};
for (const auto& ex : expected1) {
EXPECT_TRUE(segments[1].first.find(ex) != segments[1].first.end())
<< "Missing expected node " << ex;
ASSERT_TRUE(g != nullptr);
OptimizeGraph(flr0_, &g);
const char* e0 = R"P(
-(n3:float, n2:float) -> (n3:float) {
+(n2:float, n3:float) -> (n2:float) {
}
)P";
EXPECT_EQ(e0, DebugString(g.get()));
std::vector<Node*> order;
// Test reverse post order generates expected ordering.
- GetReversePostOrder(g, &order, /*stable_comparator=*/NodeComparatorID());
- EXPECT_TRUE(ExpectBefore({{"t3", "t2"}}, order, &error));
+ GetReversePostOrder(g, &order, /*stable_comparator=*/NodeComparatorName());
+ EXPECT_TRUE(ExpectBefore({{"t2", "t3"}}, order, &error));
}
}
} // namespace
// name, the value is the new unique name.
std::unordered_map<string, string> uniquified_names_;
- // Index of NodeDefs in node_defs_ with all inputs already converted.
- std::vector<int> ready_;
+ // Index of NodeDefs in node_defs_ with all inputs already converted. We use a
+ // (sorted) set so nodes are created in the order defined in the GraphDef.
+ std::set<int> ready_;
// Mapping between index within node_defs_ and the number of inputs that
// still need to be converted.
}
}
if (pending_count == 0) {
- ready_.push_back(n);
+ ready_.insert(n);
}
pending_count_.push_back(pending_count);
}
void UpdatePendingCountAndReady(
const std::vector<gtl::InlinedVector<int, 4>>& outputs, int o,
- std::vector<int>* pending_count, std::vector<int>* ready) {
+ std::vector<int>* pending_count, std::set<int>* ready) {
for (size_t i = 0; i < outputs[o].size(); ++i) {
const int output = outputs[o][i];
(*pending_count)[output]--;
if ((*pending_count)[output] == 0) {
- ready->push_back(output);
+ ready->insert(output);
}
}
}
// inputs, pending_counts_ with the number of inputs for each node and
// outputs_ with the outputs of each node).
while (!ready_.empty()) {
- int o = ready_.back();
- ready_.pop_back();
+ int o = *ready_.begin();
+ ready_.erase(ready_.begin());
++processed;
inputs.clear();
bool has_data_back_edge = false;
string b = "/job:a/replica:0/task:0/cpu:1";
a1 = FloatInput(scope_a_.WithOpName("A1"));
auto c = Const(scope_a_.WithOpName("A1/_0").WithControlDependencies(a1), {});
- _Send(scope_a_.WithOpName("A1/_1"), c, "edge_1_A1", a, 82, b);
+ _Send(scope_a_.WithOpName("A1/_1"), c, "edge_3_A1", a, 82, b);
ExpectMatchA();
auto recv =
- _Recv(scope_b_.WithOpName("A1/_2"), DT_FLOAT, "edge_1_A1", a, 82, b);
+ _Recv(scope_b_.WithOpName("A1/_2"), DT_FLOAT, "edge_3_A1", a, 82, b);
auto id = Identity(scope_b_.WithOpName("A1/_3"), recv);
b1 = FloatInput(scope_b_.WithOpName("B1"));
Combine(scope_b_.WithOpName("B2").WithControlDependencies(id), b1, b1);
string a = "/job:a/replica:0/task:0/cpu:0";
string b = "/job:a/replica:0/task:0/cpu:1";
a1 = FloatInput(scope_a_.WithOpName("A1"));
- auto c = Const(scope_a_.WithOpName("A1/_0").WithControlDependencies(a1), {});
+ _Send(scope_a_.WithOpName("A1/_0"), a1, "edge_1_A1", a, 82, b);
+ auto c = Const(scope_a_.WithOpName("A1/_2").WithControlDependencies(a1), {});
// NOTE: Send 0 A1/_1 -> A1/_2 is not necessarily needed. We could
// use A1/_0 -> A1/_4 as the control as a minor optimization.
- _Send(scope_a_.WithOpName("A1/_1"), c, "edge_1_A1", a, 82, b);
- _Send(scope_a_.WithOpName("A1/_4"), a1, "edge_2_A1", a, 82, b);
+ _Send(scope_a_.WithOpName("A1/_3"), c, "edge_3_A1", a, 82, b);
ExpectMatchA();
auto recv1 =
- _Recv(scope_b_.WithOpName("A1/_2"), DT_FLOAT, "edge_1_A1", a, 82, b);
- auto id1 = Identity(scope_b_.WithOpName("A1/_3"), recv1);
+ _Recv(scope_b_.WithOpName("A1/_4"), DT_FLOAT, "edge_3_A1", a, 82, b);
+ auto id1 = Identity(scope_b_.WithOpName("A1/_5"), recv1);
auto recv2 =
- _Recv(scope_b_.WithOpName("A1/_5"), DT_FLOAT, "edge_2_A1", a, 82, b);
+ _Recv(scope_b_.WithOpName("A1/_1"), DT_FLOAT, "edge_1_A1", a, 82, b);
b1 = FloatInput(scope_b_.WithOpName("B1"));
Combine(scope_b_.WithOpName("B2"), recv2, b1);
FloatInput(scope_b_.WithOpName("B3").WithControlDependencies(id1));
"node { name: 'D' op: 'Mul' attr { key: 'T' value { type: DT_FLOAT } }"
" input: ['A', 'B'] }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);D(Mul)|"
- "A->D;B->D:1");
+ "A(Input);B(Input);C(Mul)|"
+ "A->C;B->C:1");
}
TEST_F(OptimizerCSETest, Simple_ThreeEquivalent) {
"node { name: 'E' op: 'Mul' attr { key: 'T' value { type: DT_FLOAT } }"
" input: ['A', 'B'] }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);E(Mul)|"
- "A->E;B->E:1");
+ "A(Input);B(Input);C(Mul)|"
+ "A->C;B->C:1");
}
TEST_F(OptimizerCSETest, Simple_WithFixups) {
"node { name: 'E' op: 'Mul' attr { key: 'T' value { type: DT_FLOAT } }"
" input: ['C', 'D'] }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);D(Mul);E(Mul)|"
- "A->D;B->D:1;D->E;D->E:1");
+ "A(Input);B(Input);C(Mul);E(Mul)|"
+ "A->C;B->C:1;C->E;C->E:1");
}
TEST_F(OptimizerCSETest, Simple_Commutative) {
"node { name: 'D' op: 'Mul' attr { key: 'T' value { type: DT_FLOAT } }"
" input: ['B', 'A'] }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);D(Mul)|"
- "A->D:1;B->D");
+ "A(Input);B(Input);C(Mul)|"
+ "A->C;B->C:1");
}
static bool IsNotMultiply(const Node* n) { return n->type_string() != "Mul"; }
" input: ['A', 'B'] attr { key: 'shape'"
" value { shape: { dim: { size: 37 name: 'SAME_NAME' } } } } }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);D(Mul)|"
- "A->D;B->D:1");
+ "A(Input);B(Input);C(Mul)|"
+ "A->C;B->C:1");
}
TEST_F(OptimizerCSETest, Simple_SameOps_SameAttrs2) {
" attr { key: 't' value { type: DT_INT32 } }"
" attr { key: 'a' value { i: 3 } } }");
EXPECT_EQ(DoCSE(),
- "A(Input);B(Input);D(Mul)|"
- "A->D;B->D:1");
+ "A(Input);B(Input);C(Mul)|"
+ "A->C;B->C:1");
}
TEST_F(OptimizerCSETest, SameConstants) {
"node { name: 'D' op: 'Mul' attr { key: 'T' value { type: DT_INT32 } }"
" input: ['A', 'B'] }");
EXPECT_EQ(DoCSE(),
- "B(Const);D(Mul)|"
- "B->D;B->D:1");
+ "A(Const);D(Mul)|"
+ "A->D;A->D:1");
}
TEST_F(OptimizerCSETest, DifferentConstants) {
"n/_0(Const);n/_1(Const);n/_2(Const);n/_3(Const);"
"n/_4(Const);n/_5(Const);n/_6(Const);n/_7(Const)|");
// In theory, there are 2^4 possible correct output of CSE. In this
- // test, it happens to eliminate the first 4 nodes.
- EXPECT_EQ(DoCSE(), "n/_4(Const);n/_5(Const);n/_6(Const);n/_7(Const)|");
+ // test, it happens to eliminate the last 4 nodes.
+ EXPECT_EQ(DoCSE(), "n/_0(Const);n/_1(Const);n/_2(Const);n/_3(Const)|");
}
static void BM_CSE(int iters, int op_nodes) {