Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
N
ngraph
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ngraph
Commits
1c78e9f3
Commit
1c78e9f3
authored
Sep 19, 2017
by
Robert Kimball
Committed by
GitHub
Sep 19, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #126 from NervanaSystems/bob/liveness4
add liveness pass
parents
0344dca9
d3f3bb1b
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
516 additions
and
144 deletions
+516
-144
CMakeLists.txt
src/CMakeLists.txt
+2
-0
input.cpp
src/ngraph/descriptor/input.cpp
+10
-0
input.hpp
src/ngraph/descriptor/input.hpp
+4
-0
output.cpp
src/ngraph/descriptor/output.cpp
+10
-0
output.hpp
src/ngraph/descriptor/output.hpp
+2
-0
tensor.cpp
src/ngraph/descriptor/tensor.cpp
+19
-1
tensor.hpp
src/ngraph/descriptor/tensor.hpp
+21
-1
tensor_view.hpp
src/ngraph/descriptor/tensor_view.hpp
+12
-2
node.cpp
src/ngraph/node.cpp
+5
-3
node.hpp
src/ngraph/node.hpp
+9
-4
parameter.hpp
src/ngraph/ops/parameter.hpp
+0
-1
dump_sorted.cpp
src/ngraph/pass/dump_sorted.cpp
+74
-0
dump_sorted.hpp
src/ngraph/pass/dump_sorted.hpp
+39
-0
liveness.cpp
src/ngraph/pass/liveness.cpp
+123
-120
liveness.hpp
src/ngraph/pass/liveness.hpp
+3
-2
visualize_tree.cpp
src/ngraph/pass/visualize_tree.cpp
+94
-0
visualize_tree.hpp
src/ngraph/pass/visualize_tree.hpp
+46
-0
parameter.cpp
src/ops/parameter.cpp
+0
-7
CMakeLists.txt
test/CMakeLists.txt
+1
-1
pass_liveness.cpp
test/pass_liveness.cpp
+42
-2
No files found.
src/CMakeLists.txt
View file @
1c78e9f3
...
...
@@ -24,6 +24,7 @@ set (SRC
ngraph/shape.cpp
ngraph/pass/assign_tensors.cpp
ngraph/pass/call_pass.cpp
ngraph/pass/dump_sorted.cpp
ngraph/pass/liveness.cpp
ngraph/pass/manager.cpp
ngraph/pass/memory_layout.cpp
...
...
@@ -31,6 +32,7 @@ set (SRC
ngraph/pass/propagate_types.cpp
ngraph/pass/topological_sort.cpp
ngraph/pass/tree_pass.cpp
ngraph/pass/visualize_tree.cpp
ngraph/runtime/call_frame.cpp
ngraph/runtime/eigen/external_function.cpp
ngraph/runtime/eigen/tensor_view.cpp
...
...
src/ngraph/descriptor/input.cpp
View file @
1c78e9f3
...
...
@@ -33,3 +33,13 @@ std::shared_ptr<Node> Input::get_node()
{
return
m_node
->
shared_from_this
();
}
const
Tensor
&
Input
::
get_tensor
()
const
{
return
m_output
.
get_tensor
();
}
Tensor
&
Input
::
get_tensor
()
{
return
m_output
.
get_tensor
();
}
src/ngraph/descriptor/input.hpp
View file @
1c78e9f3
...
...
@@ -16,6 +16,8 @@
#include <memory>
#include "ngraph/descriptor/tensor.hpp"
namespace
ngraph
{
class
Node
;
...
...
@@ -47,6 +49,8 @@ namespace ngraph
size_t
get_index
()
const
{
return
m_index
;
}
const
Output
&
get_output
()
const
{
return
m_output
;
}
Output
&
get_output
()
{
return
m_output
;
}
const
Tensor
&
get_tensor
()
const
;
Tensor
&
get_tensor
();
protected
:
Node
*
m_node
;
// The node we are an input for
...
...
src/ngraph/descriptor/output.cpp
View file @
1c78e9f3
...
...
@@ -35,3 +35,13 @@ std::shared_ptr<Node> Output::get_node() const
{
return
m_node
->
shared_from_this
();
}
const
Tensor
&
Output
::
get_tensor
()
const
{
return
m_tensor_view
->
get_tensor
();
}
Tensor
&
Output
::
get_tensor
()
{
return
m_tensor_view
->
get_tensor
();
}
src/ngraph/descriptor/output.hpp
View file @
1c78e9f3
...
...
@@ -42,6 +42,8 @@ namespace ngraph
std
::
shared_ptr
<
TensorView
>
get_tensor_view
()
const
{
return
m_tensor_view
;
}
void
add_input
(
Input
*
input
);
const
std
::
set
<
Input
*>&
get_inputs
()
const
{
return
m_inputs
;
}
const
Tensor
&
get_tensor
()
const
;
Tensor
&
get_tensor
();
protected
:
Node
*
m_node
;
...
...
src/ngraph/descriptor/tensor.cpp
View file @
1c78e9f3
...
...
@@ -13,12 +13,30 @@
// ----------------------------------------------------------------------------
#include "ngraph/descriptor/tensor.hpp"
#include "ngraph/node.hpp"
using
namespace
ngraph
;
using
namespace
descriptor
;
Tensor
::
Tensor
(
const
element
::
Type
&
element_type
,
PrimaryTensorView
*
primary_tensor_view
)
Tensor
::
Tensor
(
const
element
::
Type
&
element_type
,
PrimaryTensorView
*
primary_tensor_view
,
const
Node
*
parent
,
size_t
value_index
)
:
m_element_type
(
element_type
)
,
m_primary_tensor_view
(
primary_tensor_view
)
,
m_is_output
{
false
}
,
m_is_input
{
parent
->
is_parameter
()}
,
m_is_persistent
{
false
}
,
m_name
{
parent
->
get_node_id
()
+
"_"
+
std
::
to_string
(
value_index
)}
,
m_next_view_id
{
0
}
{
}
std
::
string
Tensor
::
get_next_view_name
()
{
return
m_name
+
"_TV"
+
std
::
to_string
(
m_next_view_id
++
);
}
std
::
ostream
&
ngraph
::
descriptor
::
operator
<<
(
std
::
ostream
&
out
,
const
Tensor
&
tensor
)
{
out
<<
"Tensor("
<<
tensor
.
get_name
()
<<
")"
;
return
out
;
}
src/ngraph/descriptor/tensor.hpp
View file @
1c78e9f3
...
...
@@ -16,9 +16,12 @@
#include <memory>
#include <vector>
#include <iostream>
namespace
ngraph
{
class
Node
;
namespace
element
{
class
Type
;
...
...
@@ -33,14 +36,31 @@ namespace ngraph
{
friend
class
PrimaryTensorView
;
private
:
Tensor
(
const
Tensor
&
)
=
delete
;
Tensor
&
operator
=
(
const
Tensor
&
)
=
delete
;
Tensor
(
const
element
::
Type
&
element_type
,
PrimaryTensorView
*
tensor_view
);
Tensor
(
const
element
::
Type
&
element_type
,
PrimaryTensorView
*
tensor_view
,
const
Node
*
parent
,
size_t
value_index
);
std
::
string
get_next_view_name
();
public
:
bool
is_output
()
const
{
return
m_is_output
;
}
bool
is_input
()
const
{
return
m_is_input
;
}
bool
is_persistent
()
const
{
return
m_is_persistent
;
}
const
std
::
string
&
get_name
()
const
{
return
m_name
;
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
,
const
Tensor
&
);
protected
:
const
element
::
Type
&
m_element_type
;
PrimaryTensorView
*
m_primary_tensor_view
;
bool
m_is_output
;
bool
m_is_input
;
bool
m_is_persistent
;
std
::
string
m_name
;
size_t
m_next_view_id
;
};
}
}
src/ngraph/descriptor/tensor_view.hpp
View file @
1c78e9f3
...
...
@@ -17,9 +17,12 @@
#include "ngraph/descriptor/tensor.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/type.hpp"
#include "log.hpp"
namespace
ngraph
{
class
Node
;
namespace
descriptor
{
class
Tensor
;
...
...
@@ -41,6 +44,7 @@ namespace ngraph
virtual
~
TensorView
()
{}
virtual
const
Tensor
&
get_tensor
()
const
=
0
;
virtual
Tensor
&
get_tensor
()
=
0
;
const
std
::
string
&
get_name
()
const
{
return
m_name
;
}
std
::
shared_ptr
<
const
TensorViewType
>
get_tensor_view_type
()
const
{
...
...
@@ -51,6 +55,7 @@ namespace ngraph
{
return
m_tensor_view_layout
;
}
void
set_tensor_view_layout
(
const
std
::
shared_ptr
<
TensorViewLayout
>&
tensor_view_layout
)
{
m_tensor_view_layout
=
tensor_view_layout
;
...
...
@@ -59,6 +64,7 @@ namespace ngraph
protected
:
std
::
shared_ptr
<
const
TensorViewType
>
m_tensor_view_type
;
std
::
shared_ptr
<
TensorViewLayout
>
m_tensor_view_layout
;
std
::
string
m_name
;
};
// A PrimaryTensorView owns the tensor. All other views are the result
...
...
@@ -66,10 +72,14 @@ namespace ngraph
class
PrimaryTensorView
:
public
TensorView
{
public
:
PrimaryTensorView
(
const
std
::
shared_ptr
<
const
TensorViewType
>&
tensor_view_type
)
PrimaryTensorView
(
const
std
::
shared_ptr
<
const
TensorViewType
>&
tensor_view_type
,
const
Node
*
parent
,
size_t
value_index
)
:
TensorView
(
tensor_view_type
)
,
m_tensor
(
tensor_view_type
->
get_element_type
(),
this
)
,
m_tensor
(
tensor_view_type
->
get_element_type
(),
this
,
parent
,
value_index
)
{
// Set the name in the parent TensorView.
// This can't be done until after the m_tensor is constructed.
m_name
=
m_tensor
.
get_next_view_name
();
}
virtual
const
Tensor
&
get_tensor
()
const
override
;
...
...
src/ngraph/node.cpp
View file @
1c78e9f3
...
...
@@ -57,8 +57,9 @@ void Node::assign_tensors()
size_t
i
=
0
;
for
(
auto
tvt
:
tensor_view_types
)
{
auto
tensor_view_descriptor
=
make_shared
<
descriptor
::
PrimaryTensorView
>
(
tvt
);
m_outputs
.
emplace_back
(
this
,
i
++
,
tensor_view_descriptor
);
auto
tensor_view_descriptor
=
make_shared
<
descriptor
::
PrimaryTensorView
>
(
tvt
,
this
,
i
);
m_outputs
.
emplace_back
(
this
,
i
,
tensor_view_descriptor
);
i
++
;
}
i
=
0
;
...
...
@@ -68,7 +69,8 @@ void Node::assign_tensors()
size_t
arg_index
=
0
;
for
(
descriptor
::
Output
&
output
:
arg
->
get_outputs
())
{
m_inputs
.
emplace_back
(
this
,
i
++
,
argno
,
arg_index
++
,
output
);
m_inputs
.
emplace_back
(
this
,
i
,
argno
,
arg_index
++
,
output
);
i
++
;
}
argno
++
;
}
...
...
src/ngraph/node.hpp
View file @
1c78e9f3
...
...
@@ -17,6 +17,7 @@
#include <set>
#include <string>
#include <vector>
#include <unordered_set>
#include <iostream>
...
...
@@ -29,6 +30,7 @@ namespace ngraph
{
class
Input
;
class
Output
;
class
Tensor
;
}
/// Nodes are the backbone of the graph of Value dataflow. Every node has
...
...
@@ -51,7 +53,7 @@ namespace ngraph
virtual
~
Node
();
public
:
///
A "one-liner" describing this node.
///
The class name, must not contain spaces
virtual
std
::
string
description
()
const
=
0
;
/// Propagate types and check arguments for consistency
...
...
@@ -66,9 +68,6 @@ namespace ngraph
const
std
::
multiset
<
Node
*>&
users
()
const
{
return
m_users
;
}
std
::
string
get_name
()
const
{
return
m_name
;
}
void
set_name
(
const
std
::
string
&
name
)
{
m_name
=
name
;
}
virtual
std
::
string
get_node_id
()
const
;
/// Return true if this has the same implementing class as node. This
...
...
@@ -104,7 +103,13 @@ namespace ngraph
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
,
const
Node
&
);
std
::
vector
<
descriptor
::
Input
>&
get_inputs
()
{
return
m_inputs
;
}
const
std
::
vector
<
descriptor
::
Input
>&
get_inputs
()
const
{
return
m_inputs
;
}
std
::
vector
<
descriptor
::
Output
>&
get_outputs
()
{
return
m_outputs
;
}
const
std
::
vector
<
descriptor
::
Output
>&
get_outputs
()
const
{
return
m_outputs
;
}
std
::
unordered_set
<
descriptor
::
Tensor
*>
liveness_live_list
;
std
::
unordered_set
<
descriptor
::
Tensor
*>
liveness_new_list
;
std
::
unordered_set
<
descriptor
::
Tensor
*>
liveness_free_list
;
protected
:
Nodes
m_arguments
;
...
...
src/ngraph/ops/parameter.hpp
View file @
1c78e9f3
...
...
@@ -42,7 +42,6 @@ namespace ngraph
std
::
string
description
()
const
override
{
return
"Parameter"
;
}
virtual
void
propagate_types
()
override
;
virtual
std
::
string
get_node_id
()
const
override
;
protected
:
Function
*
m_function
;
...
...
src/ngraph/pass/dump_sorted.cpp
0 → 100644
View file @
1c78e9f3
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include <fstream>
#include "dump_sorted.hpp"
#include "ngraph/ngraph.hpp"
#include "util.hpp"
using
namespace
ngraph
;
using
namespace
std
;
pass
::
DumpSorted
::
DumpSorted
(
const
string
&
output_file
)
:
m_output_file
{
output_file
}
{
}
bool
pass
::
DumpSorted
::
run_on_call_list
(
list
<
Node
*>&
nodes
)
{
ofstream
out
{
m_output_file
};
if
(
out
)
{
for
(
const
Node
*
node
:
nodes
)
{
out
<<
node
->
get_node_id
()
<<
"("
;
vector
<
string
>
inputs
;
for
(
const
descriptor
::
Input
&
input
:
node
->
get_inputs
())
{
inputs
.
push_back
(
input
.
get_tensor
().
get_name
());
}
out
<<
join
(
inputs
);
out
<<
") -> "
;
vector
<
string
>
outputs
;
for
(
const
descriptor
::
Output
&
output
:
node
->
get_outputs
())
{
outputs
.
push_back
(
output
.
get_tensor
().
get_name
());
}
out
<<
join
(
outputs
);
out
<<
"
\n
"
;
for
(
const
descriptor
::
Tensor
*
tensor
:
node
->
liveness_live_list
)
{
out
<<
" "
;
if
(
contains
(
node
->
liveness_new_list
,
tensor
))
{
out
<<
"N "
;
}
else
if
(
contains
(
node
->
liveness_free_list
,
tensor
))
{
out
<<
"F "
;
}
else
{
out
<<
"L "
;
}
out
<<
tensor
->
get_name
()
<<
"
\n
"
;
}
}
}
return
false
;
}
src/ngraph/pass/dump_sorted.hpp
0 → 100644
View file @
1c78e9f3
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include <string>
#include "call_pass.hpp"
namespace
ngraph
{
namespace
pass
{
class
DumpSorted
;
}
class
Node
;
}
class
ngraph
::
pass
::
DumpSorted
:
public
CallBase
{
public
:
DumpSorted
(
const
std
::
string
&
output_file
);
virtual
bool
run_on_call_list
(
std
::
list
<
Node
*>&
)
override
;
private
:
const
std
::
string
m_output_file
;
};
src/ngraph/pass/liveness.cpp
View file @
1c78e9f3
...
...
@@ -14,111 +14,112 @@
#include <exception>
#include <sstream>
#include <unordered_set>
#include "log.hpp"
#include "ngraph/ngraph.hpp"
#include "ngraph/pass/assign_tensors.hpp"
#include "ngraph/pass/liveness.hpp"
#include "util.hpp"
#include "log.hpp"
using
namespace
std
;
using
namespace
ngraph
;
bool
pass
::
Liveness
::
run_on_call_list
(
list
<
Node
*>&
ops
)
{
// list<Node*> live_list;
// list<Node*> free_list;
// list<Node*> new_list;
// currently_live = list();
// size_t i = 0;
// for (i, exop in enumerate(reversed(ops)
// for(auto it=ops.rbegin(); it!=ops.rend(); it++)
// {
// Node& exop = **it;
// input_tensor_decls = list()
// for (auto input_decl : exop.get_inputs())
// {
// if (is_interesting(input_decl.tensor_decl))
// {
// input_tensor_decls.append(input_decl.tensor_decl);
// }
// }
// output_tensor_decls = list()
// for (output_decl : exop.output_decls)
// {
// if (is_interesting(output_decl.tensor_decl))
// {
// output_tensor_decls.append(output_decl.tensor_decl);
// }
// }
// free_tensor_decls = list();
// new_tensor_decls = list();
// for tensor_decl in input_tensor_decls + output_tensor_decls
// {
// if tensor_decl not in currently_live
// {
// // this is the last node that value is seen in
// // delete it at the end of the op
// currently_live.append(tensor_decl);
// free_tensor_decls.append(tensor_decl);
// }
// }
// live_list.insert(0, list(currently_live))
// for output_decl in output_tensor_decls
// {
// if output_decl in currently_live
// {
// new_tensor_decls.append(output_decl);
// currently_live.remove(output_decl);
// }
// }
// free_list.insert(0, free_tensor_decls);
// new_list.insert(0, new_tensor_decls);
// }
// // Anything marked as output must remain live for the remainder of the graph
// // Add outputs to live_list and remove from free_list
// outputs = list();
// seen = list();
// for i, exop in enumerate(ops)
// {
// for tensor in live_list[i]
// {
// if tensor.is_output and tensor not in outputs
// {
// outputs.append(tensor);
// }
// }
// for tensor in outputs
// {
// if tensor not in live_list[i]
// {
// live_list[i].append(tensor);
// }
// if tensor in free_list[i]
// {
// free_list[i].remove(tensor);
// }
// if tensor in new_list[i]
// {
// if tensor in seen
// {
// new_list[i].remove(tensor);
// }
// else
// {
// seen.append(tensor);
// }
// }
// }
// exop.liveness_live_list = live_list[i];
// exop.liveness_new_list = new_list[i];
// exop.liveness_free_list = free_list[i];
// }
// self.validate_liveness(ops)
unordered_set
<
descriptor
::
Tensor
*>
currently_live
;
for
(
auto
it
=
ops
.
rbegin
();
it
!=
ops
.
rend
();
it
++
)
{
Node
&
exop
=
**
it
;
exop
.
liveness_live_list
.
clear
();
exop
.
liveness_new_list
.
clear
();
exop
.
liveness_free_list
.
clear
();
unordered_set
<
descriptor
::
Tensor
*>
input_tensor_decls
;
for
(
auto
input_decl
:
exop
.
get_inputs
())
{
descriptor
::
Tensor
&
tensor
=
input_decl
.
get_tensor
();
if
(
is_temporary
(
tensor
))
{
input_tensor_decls
.
insert
(
&
tensor
);
}
}
unordered_set
<
descriptor
::
Tensor
*>
output_tensor_decls
;
for
(
auto
output_decl
:
exop
.
get_outputs
())
{
descriptor
::
Tensor
&
tensor
=
output_decl
.
get_tensor
();
if
(
is_temporary
(
tensor
))
{
output_tensor_decls
.
insert
(
&
tensor
);
}
}
unordered_set
<
descriptor
::
Tensor
*>
free_tensor_decls
;
unordered_set
<
descriptor
::
Tensor
*>
new_tensor_decls
;
unordered_set
<
descriptor
::
Tensor
*>
all_tensor_decls
=
input_tensor_decls
;
for
(
auto
decls
:
{
input_tensor_decls
,
output_tensor_decls
})
{
for
(
descriptor
::
Tensor
*
tensor_decl
:
decls
)
{
if
(
!
contains
(
currently_live
,
tensor_decl
))
{
// this is the last node that value is seen in
// delete it at the end of the op
currently_live
.
insert
(
tensor_decl
);
free_tensor_decls
.
insert
(
tensor_decl
);
}
}
}
exop
.
liveness_live_list
=
currently_live
;
for
(
descriptor
::
Tensor
*
output_decl
:
output_tensor_decls
)
{
if
(
contains
(
currently_live
,
output_decl
))
{
new_tensor_decls
.
insert
(
output_decl
);
currently_live
.
erase
(
output_decl
);
}
}
exop
.
liveness_free_list
=
free_tensor_decls
;
exop
.
liveness_new_list
=
new_tensor_decls
;
}
// Anything marked as output must remain live for the remainder of the graph
// Add outputs to live_list and remove from free_list
unordered_set
<
descriptor
::
Tensor
*>
outputs
;
unordered_set
<
descriptor
::
Tensor
*>
seen
;
for
(
Node
*
exop
:
ops
)
{
for
(
descriptor
::
Tensor
*
tensor
:
exop
->
liveness_live_list
)
{
if
(
tensor
->
is_output
())
{
outputs
.
insert
(
tensor
);
}
}
for
(
descriptor
::
Tensor
*
tensor
:
outputs
)
{
exop
->
liveness_live_list
.
insert
(
tensor
);
exop
->
liveness_free_list
.
erase
(
tensor
);
if
(
contains
(
exop
->
liveness_new_list
,
tensor
))
{
if
(
contains
(
seen
,
tensor
))
{
exop
->
liveness_new_list
.
erase
(
tensor
);
}
else
{
seen
.
insert
(
tensor
);
}
}
}
}
validate_liveness
(
ops
);
return
false
;
}
...
...
@@ -140,30 +141,32 @@ void pass::Liveness::check_dependencies(
}
}
// bool pass::Liveness::is_interesting(tensor_decl)
// {
// return
// tensor_decl.is_persistent == false &&
// tensor_decl.is_constant == false &&
// tensor_decl.is_compile_only == false;
// }
// void pass::Liveness::validate_liveness(ops)
// {
// dead_tensors = set();
// for i, exop in enumerate(ops)
// {
// active = set(exop.liveness_live_list);
// active |= set(exop.liveness_new_list);
// active |= set(exop.liveness_free_list);
// if bool(dead_tensors.intersection(active)) is True
// {
// raise RuntimeError("Liveness: Dead tensors intersect active tensors");
// }
// for tensor in exop.liveness_free_list
// {
// dead_tensors.add(tensor);
// }
// }
// }
bool
pass
::
Liveness
::
is_temporary
(
const
descriptor
::
Tensor
&
tensor
)
{
return
tensor
.
is_persistent
()
==
false
&&
tensor
.
is_input
()
==
false
;
// && tensor.is_constant() == false
// && tensor.is_compile_only() == false;
}
void
pass
::
Liveness
::
validate_liveness
(
const
list
<
Node
*>&
ops
)
{
unordered_set
<
descriptor
::
Tensor
*>
dead_tensors
;
for
(
const
Node
*
exop
:
ops
)
{
auto
active
=
exop
->
liveness_live_list
;
active
.
insert
(
exop
->
liveness_new_list
.
begin
(),
exop
->
liveness_new_list
.
end
());
active
.
insert
(
exop
->
liveness_free_list
.
begin
(),
exop
->
liveness_free_list
.
end
());
for
(
const
descriptor
::
Tensor
*
tensor
:
active
)
{
if
(
contains
(
dead_tensors
,
tensor
))
{
throw
runtime_error
(
"Liveness: Dead tensors intersect active tensors"
);
}
}
dead_tensors
.
insert
(
exop
->
liveness_free_list
.
begin
(),
exop
->
liveness_free_list
.
end
());
}
}
src/ngraph/pass/liveness.hpp
View file @
1c78e9f3
...
...
@@ -15,6 +15,7 @@
#pragma once
#include "call_pass.hpp"
#include "ngraph/descriptor/tensor.hpp"
namespace
ngraph
{
...
...
@@ -33,6 +34,6 @@ public:
void
check_dependencies
(
const
std
::
vector
<
std
::
shared_ptr
<
CallBase
>>&
)
const
override
;
private
:
// bool is_interesting(tensor_decl
);
// void validate_liveness(std::list<Node*>
ops);
bool
is_temporary
(
const
descriptor
::
Tensor
&
);
void
validate_liveness
(
const
std
::
list
<
Node
*>&
ops
);
};
src/ngraph/pass/visualize_tree.cpp
0 → 100644
View file @
1c78e9f3
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include <fstream>
#include "visualize_tree.hpp"
#include "ngraph/node.hpp"
#include "util.hpp"
using
namespace
ngraph
;
using
namespace
std
;
bool
pass
::
VisualizeTree
::
run_on_tree
(
std
::
shared_ptr
<
Node
>
base_node
)
{
// map<size_t, list<node_ptr>> dependent_nodes;
traverse_nodes
(
base_node
,
[
&
](
Node
*
node
)
{
for
(
auto
arg
:
node
->
get_arguments
())
{
m_ss
<<
add_attributes
(
arg
.
get
());
m_ss
<<
add_attributes
(
node
);
m_ss
<<
" "
<<
arg
->
get_node_id
()
<<
" -> "
<<
node
->
get_node_id
();
m_ss
<<
";
\n
"
;
}
});
render
();
return
false
;
}
pass
::
VisualizeTree
::
VisualizeTree
(
const
string
&
file_name
)
:
m_name
{
file_name
}
{
}
std
::
string
pass
::
VisualizeTree
::
add_attributes
(
const
Node
*
node
)
{
string
rc
;
if
(
!
contains
(
m_nodes_with_attributes
,
node
))
{
m_nodes_with_attributes
.
insert
(
node
);
rc
=
get_attributes
(
node
);
}
return
rc
;
}
std
::
string
pass
::
VisualizeTree
::
get_attributes
(
const
Node
*
node
)
{
stringstream
ss
;
if
(
node
->
is_parameter
())
{
ss
<<
" "
<<
node
->
get_node_id
()
<<
" [shape=box color=blue]
\n
"
;
}
else
{
ss
<<
" "
<<
node
->
get_node_id
()
<<
" [shape=ellipse color=black]
\n
"
;
}
return
ss
.
str
();
}
void
pass
::
VisualizeTree
::
render
()
const
{
#if GRAPHVIZ_FOUND
auto
tmp_file
=
m_name
+
".tmp"
;
ofstream
out
(
tmp_file
);
if
(
out
)
{
out
<<
"digraph ngraph
\n
{
\n
"
;
out
<<
m_ss
.
str
();
out
<<
"}
\n
"
;
out
.
close
();
stringstream
ss
;
ss
<<
"dot -Tpng "
<<
tmp_file
<<
" -o "
<<
m_name
;
auto
cmd
=
ss
.
str
();
auto
stream
=
popen
(
cmd
.
c_str
(),
"r"
);
pclose
(
stream
);
remove
(
tmp_file
.
c_str
());
}
#endif
}
src/ngraph/pass/visualize_tree.hpp
0 → 100644
View file @
1c78e9f3
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include <sstream>
#include <string>
#include <set>
#include "ngraph/pass/tree_pass.hpp"
namespace
ngraph
{
namespace
pass
{
class
VisualizeTree
;
}
class
Node
;
}
class
ngraph
::
pass
::
VisualizeTree
:
public
TreeBase
{
public
:
VisualizeTree
(
const
std
::
string
&
file_name
);
bool
run_on_tree
(
std
::
shared_ptr
<
Node
>
)
override
;
private
:
std
::
string
add_attributes
(
const
Node
*
node
);
std
::
string
get_attributes
(
const
Node
*
node
);
void
render
()
const
;
std
::
stringstream
m_ss
;
std
::
string
m_name
;
std
::
set
<
const
Node
*>
m_nodes_with_attributes
;
};
src/ops/parameter.cpp
View file @
1c78e9f3
...
...
@@ -42,10 +42,3 @@ void Parameter::assign_function(Function* function, size_t index)
}
void
Parameter
::
propagate_types
()
{}
std
::
string
ngraph
::
op
::
Parameter
::
get_node_id
()
const
{
stringstream
ss
;
ss
<<
"parameter_"
<<
m_instance_id
;
return
ss
.
str
();
}
test/CMakeLists.txt
View file @
1c78e9f3
...
...
@@ -64,5 +64,5 @@ target_link_libraries(unit-test ${CMAKE_DL_LIBS})
add_dependencies
(
unit-test ngraph libgtest eigen
)
add_custom_target
(
check
COMMAND
${
PROJECT_BINARY_DIR
}
/test/unit-test
COMMAND
${
PROJECT_BINARY_DIR
}
/test/unit-test
\
${
ARGS
}
DEPENDS unit-test
)
test/pass_liveness.cpp
100755 → 100644
View file @
1c78e9f3
...
...
@@ -20,14 +20,54 @@
#include "gtest/gtest.h"
#include "ngraph/pass/liveness.hpp"
#include "ngraph/pass/assign_tensors.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/pass/propagate_types.hpp"
#include "ngraph/pass/topological_sort.hpp"
#include "ngraph/pass/liveness.hpp"
#include "ngraph/pass/visualize_tree.hpp"
#include "ngraph/pass/dump_sorted.hpp"
#include "ngraph/ngraph.hpp"
#include "test_tools.hpp"
#include "log.hpp"
using
namespace
std
;
using
namespace
ngraph
;
namespace
ng
=
ngraph
;
TEST
(
liveness
,
test
)
TEST
(
pass
,
liveness
)
{
string
image
=
"liveness.png"
;
string
dump_file
=
"liveness.txt"
;
pass
::
Manager
pass_manager
;
auto
visualize
=
make_shared
<
pass
::
VisualizeTree
>
(
image
);
auto
topological_sort
=
make_shared
<
pass
::
TopologicalSort
>
();
auto
propagate_types
=
make_shared
<
pass
::
PropagateTypes
>
();
auto
assign_tensors
=
make_shared
<
pass
::
AssignTensors
>
();
auto
liveness
=
make_shared
<
pass
::
Liveness
>
();
auto
dump_sorted
=
make_shared
<
pass
::
DumpSorted
>
(
dump_file
);
pass_manager
.
register_pass
(
visualize
);
pass_manager
.
register_pass
(
topological_sort
);
pass_manager
.
register_pass
(
propagate_types
);
pass_manager
.
register_pass
(
assign_tensors
);
pass_manager
.
register_pass
(
liveness
);
pass_manager
.
register_pass
(
dump_sorted
);
auto
graph
=
make_test_graph
();
size_t
node_count
=
get_node_count
(
graph
);
pass_manager
.
run_passes
(
graph
);
auto
sorted
=
pass_manager
.
get_sorted_list
();
// for (const Node* node : sorted)
// {
// INFO << *node;
// for (const descriptor::Tensor* tensor : node->liveness_live_list)
// {
// INFO << " " << *tensor;
// }
// }
// auto x = ng.variable(axes=[]).named('x');
// auto y = ng.variable(axes=[]).named('y');
// auto w1 = ng.variable(axes=[]).named('w1');
...
...
@@ -48,7 +88,7 @@ TEST(liveness, test)
// return exc;
// lg = LivenessGraph(exc.exop.ops)
// lg.layout_memory()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment