Unverified Commit abdbe348 authored by Jai Menon's avatar Jai Menon Committed by GitHub

Merge pull request #236 from NervanaSystems/bob/codewriter4

Bob/codewriter4
parents 797b2796 28795d7f
......@@ -21,6 +21,7 @@ set (SRC
descriptor/tensor.cpp
descriptor/tensor_view.cpp
descriptor/tuple.cpp
file_util.cpp
function.cpp
log.cpp
node.cpp
......@@ -53,7 +54,6 @@ set (SRC
ops/tuple.cpp
ops/unary_elementwise_arithmetic.cpp
ops/unary_elementwise.cpp
pass/collect_functions.cpp
pass/dump_sorted.cpp
pass/liveness.cpp
pass/manager.cpp
......@@ -104,6 +104,7 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
# Add sources for the CPU backend
# and all its dependencies
set(SRC ${SRC}
codegen/code_writer.cpp
codegen/compiler.cpp
runtime/cpu/call_frame.cpp
runtime/cpu/cpu_backend.cpp
......@@ -111,6 +112,7 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
runtime/cpu/cpu_kernels.cpp
runtime/cpu/emitter.cpp
runtime/cpu/external_function.cpp
runtime/cpu/tensor_view.cpp
)
# LLVM binary builds are typically built without RTTI
# The built-in headers are in a version-specific directory
......
......@@ -12,22 +12,23 @@
// See the License for the specific language governing permissions and
// ----------------------------------------------------------------------------
#pragma once
#include "code_writer.hpp"
#include "ngraph/pass/pass.hpp"
using namespace std;
using namespace ngraph;
namespace ngraph
codegen::CodeWriter::CodeWriter()
: indent(0)
, m_pending_indent(true)
{
namespace pass
{
class CollectFunctions;
}
}
class ngraph::pass::CollectFunctions : public FunctionPass
string codegen::CodeWriter::get_code() const
{
public:
bool run_on_function(std::shared_ptr<ngraph::Function>) override;
return m_ss.str();
}
private:
};
void codegen::CodeWriter::operator+=(const std::string& s)
{
*this << s;
}
......@@ -12,39 +12,61 @@
// See the License for the specific language governing permissions and
// ----------------------------------------------------------------------------
#include "ngraph/pass/collect_functions.hpp"
#include "ngraph/function.hpp"
#pragma once
#include <sstream>
#include <string>
#include "ngraph/log.hpp"
#include "ngraph/node.hpp"
#include "ngraph/ops/function_call.hpp"
#include "ngraph/ops/op.hpp"
#include "ngraph/util.hpp"
using namespace std;
using namespace ngraph;
using namespace ngraph::pass;
namespace ngraph
{
namespace codegen
{
class CodeWriter;
}
}
bool CollectFunctions::run_on_function(shared_ptr<ngraph::Function> func)
class ngraph::codegen::CodeWriter
{
set<shared_ptr<ngraph::Function>> functions;
deque<shared_ptr<ngraph::Function>> stack;
stack.push_back(func);
public:
CodeWriter();
std::string get_code() const;
void operator+=(const std::string&);
while (stack.empty() == false)
size_t indent;
template <typename T>
friend CodeWriter& operator<<(CodeWriter& out, const T& obj)
{
shared_ptr<ngraph::Function> f = stack.front();
stack.pop_front();
functions.insert(f);
traverse_nodes(f, [&](shared_ptr<Node> node) {
shared_ptr<op::FunctionCall> fc = dynamic_pointer_cast<op::FunctionCall>(node);
if (fc)
std::stringstream ss;
ss << obj;
for (char c : ss.str())
{
if (c == '\n')
{
stack.push_back(fc->get_function());
out.m_pending_indent = true;
}
});
}
else
{
if (out.m_pending_indent)
{
out.m_pending_indent = false;
for (size_t i = 0; i < out.indent; i++)
{
out.m_ss << " ";
}
}
}
out.m_ss << c;
}
get_state().set_functions(functions);
return out;
}
return false;
}
private:
std::stringstream m_ss;
bool m_pending_indent;
};
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// ----------------------------------------------------------------------------
#include <iostream>
#include <clang/CodeGen/ObjectFilePCHContainerOperations.h>
#include <clang/Driver/DriverDiagnostic.h>
#include <clang/Driver/Options.h>
......@@ -191,11 +193,15 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
// Create and execute action
CodeGenAction* compilerAction = new EmitCodeGenOnlyAction();
Clang->ExecuteAction(*compilerAction);
std::unique_ptr<llvm::Module> rc;
if (Clang->ExecuteAction(*compilerAction) == true)
{
rc = compilerAction->takeModule();
}
buffer.release();
return compilerAction->takeModule();
return rc;
}
bool execution_state::add_module(std::unique_ptr<llvm::Module>& module)
......
......@@ -59,9 +59,9 @@ public:
size_t size() const;
void set_pool_offset(size_t);
size_t get_pool_offset() const;
const element::Type& get_element_type() const { return m_element_type; }
static std::string make_tensor_name(const Node* node, size_t value_index);
void set_is_output() { m_is_output = true; }
protected:
const element::Type& m_element_type;
PrimaryTensorView* m_primary_tensor_view;
......
/*
Copyright 2016 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
limitations under the License.
*/
#include <cassert>
#include <dirent.h>
#include <fcntl.h>
#include <fstream>
#include <ftw.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "file_util.hpp"
using namespace std;
string ngraph::file_util::path_join(const string& s1, const string& s2)
{
string rc;
if (s2.size() > 0)
{
if (s2[0] == '/')
{
rc = s2;
}
else if (s1.size() > 0)
{
rc = s1;
if (rc[rc.size() - 1] != '/')
{
rc += "/";
}
rc += s2;
}
else
{
rc = s2;
}
}
else
{
rc = s1;
}
return rc;
}
size_t ngraph::file_util::get_file_size(const string& filename)
{
// ensure that filename exists and get its size
struct stat stats;
if (stat(filename.c_str(), &stats) == -1)
{
throw std::runtime_error("Could not find file: \"" + filename + "\"");
}
return stats.st_size;
}
void ngraph::file_util::remove_directory(const string& dir)
{
file_util::iterate_files(dir,
[](const string& file, bool is_dir) {
if (is_dir)
rmdir(file.c_str());
else
remove(file.c_str());
},
true);
rmdir(dir.c_str());
}
void ngraph::file_util::remove_file(const string& file)
{
remove(file.c_str());
}
bool ngraph::file_util::make_directory(const string& dir)
{
if (mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
{
if (errno == EEXIST)
{
// not really an error, the directory already exists
return false;
}
throw std::runtime_error("error making directory " + dir + " " + strerror(errno));
}
return true;
}
string ngraph::file_util::make_temp_directory(const string& path)
{
string fname = path.empty() ? file_util::get_temp_directory() : path;
string tmp_template = file_util::path_join(fname, "aeonXXXXXX");
char* tmpname = strdup(tmp_template.c_str());
mkdtemp(tmpname);
string rc = tmpname;
free(tmpname);
return rc;
}
std::string ngraph::file_util::get_temp_directory()
{
const vector<string> potential_tmps = {"NERVANA_AEON_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"};
const char* path = nullptr;
for (const string& var : potential_tmps)
{
path = getenv(var.c_str());
if (path != nullptr)
{
break;
}
}
if (path == nullptr)
{
path = "/tmp";
}
return path;
}
vector<char> ngraph::file_util::read_file_contents(const string& path)
{
size_t file_size = get_file_size(path);
vector<char> data;
data.reserve(file_size);
data.resize(file_size);
FILE* f = fopen(path.c_str(), "rb");
if (f)
{
char* p = data.data();
size_t remainder = file_size;
size_t offset = 0;
while (remainder > 0)
{
size_t rc = fread(&p[offset], 1, remainder, f);
offset += rc;
remainder -= rc;
}
fclose(f);
}
else
{
throw std::runtime_error("error opening file '" + path + "'");
}
return data;
}
std::string ngraph::file_util::read_file_to_string(const std::string& path)
{
std::ifstream f(path);
std::stringstream ss;
ss << f.rdbuf();
return ss.str();
}
void ngraph::file_util::iterate_files(const string& path,
std::function<void(const string& file, bool is_dir)> func,
bool recurse)
{
vector<string> files;
vector<string> dirs;
file_util::iterate_files_worker(path,
[&files, &dirs](const string& file, bool is_dir) {
if (is_dir)
dirs.push_back(file);
else
files.push_back(file);
},
true);
for (auto f : files)
func(f, false);
for (auto f : dirs)
func(f, true);
}
void ngraph::file_util::iterate_files_worker(
const string& path, std::function<void(const string& file, bool is_dir)> func, bool recurse)
{
DIR* dir;
struct dirent* ent;
if ((dir = opendir(path.c_str())) != nullptr)
{
while ((ent = readdir(dir)) != nullptr)
{
string name = ent->d_name;
switch (ent->d_type)
{
case DT_DIR:
if (recurse && name != "." && name != "..")
{
string dir_path = file_util::path_join(path, name);
iterate_files(dir_path, func, recurse);
func(dir_path, true);
}
break;
case DT_LNK: break;
case DT_REG:
name = file_util::path_join(path, name);
func(name, false);
break;
default: break;
}
}
closedir(dir);
}
else
{
throw std::runtime_error("error enumerating file " + path);
}
}
string ngraph::file_util::tmp_filename(const string& extension)
{
string tmp_template =
file_util::path_join(file_util::get_temp_directory(), "ngraph_XXXXXX" + extension);
char* tmpname = strdup(tmp_template.c_str());
// mkstemp opens the file with open() so we need to close it
close(mkstemps(tmpname, static_cast<int>(extension.size())));
string rc = tmpname;
free(tmpname);
return rc;
}
void ngraph::file_util::touch(const std::string& filename)
{
// inspired by http://chris-sharpe.blogspot.com/2013/05/better-than-systemtouch.html
int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0666);
assert(fd >= 0);
close(fd);
// update timestamp for filename
int rc = utimes(filename.c_str(), nullptr);
assert(!rc);
}
bool ngraph::file_util::exists(const std::string& filename)
{
struct stat buffer;
return (stat(filename.c_str(), &buffer) == 0);
}
int ngraph::file_util::try_get_lock(const std::string& filename)
{
mode_t m = umask(0);
int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0666);
umask(m);
if (fd >= 0 && flock(fd, LOCK_EX | LOCK_NB) < 0)
{
close(fd);
fd = -1;
}
return fd;
}
void ngraph::file_util::release_lock(int fd, const std::string& filename)
{
if (fd >= 0)
{
remove_file(filename);
close(fd);
}
}
/*
Copyright 2016 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
limitations under the License.
*/
#pragma once
#include <functional>
#include <string>
#include <vector>
namespace ngraph
{
class file_util;
}
class ngraph::file_util
{
public:
static std::string path_join(const std::string& s1, const std::string& s2);
static size_t get_file_size(const std::string& filename);
static void remove_directory(const std::string& dir);
static bool make_directory(const std::string& dir);
static std::string make_temp_directory(const std::string& path = "");
static std::string get_temp_directory();
static void remove_file(const std::string& file);
static std::vector<char> read_file_contents(const std::string& path);
static std::string read_file_to_string(const std::string& path);
static void iterate_files(const std::string& path,
std::function<void(const std::string& file, bool is_dir)> func,
bool recurse = false);
static std::string tmp_filename(const std::string& extension = "");
static void touch(const std::string& filename);
static bool exists(const std::string& filename);
static int try_get_lock(const std::string& filename);
static void release_lock(int fd, const std::string& filename);
private:
static void iterate_files_worker(const std::string& path,
std::function<void(const std::string& file, bool is_dir)> func,
bool recurse = false);
};
......@@ -33,6 +33,7 @@ Function::Function(const std::shared_ptr<Node>& result,
, m_ordered_ops_valid(false)
, m_instance_id(m_next_instance_id.fetch_add(1))
{
m_result->set_is_output();
traverse_nodes(this, [&](shared_ptr<Node> node) { m_ops.push_back(node); });
}
......
......@@ -118,6 +118,10 @@ bool Node::is_output() const
void Node::set_is_output()
{
m_is_output = true;
for (descriptor::Output& output : get_outputs())
{
output.get_tensor().set_is_output();
}
}
std::string Node::get_node_id() const
......
......@@ -35,6 +35,9 @@ bool pass::DumpSorted::run_on_module(vector<shared_ptr<ngraph::Function>>& funct
{
for (shared_ptr<Function> f : functions)
{
out << "=====================================================================\n";
out << f->get_name() << " start\n";
out << "=====================================================================\n";
for (const shared_ptr<Node>& node : f->get_ordered_ops())
{
out << node->get_name() << "(";
......@@ -67,6 +70,9 @@ bool pass::DumpSorted::run_on_module(vector<shared_ptr<ngraph::Function>>& funct
out << " F " << tensor->get_name() << "\n";
}
}
out << "=====================================================================\n";
out << f->get_name() << " end\n";
out << "=====================================================================\n";
}
}
......
......@@ -101,7 +101,6 @@ bool pass::Liveness::run_on_call_graph(list<shared_ptr<Node>>& ops)
}
for (Tensor* tensor : outputs)
{
NGRAPH_INFO << "found output";
node->liveness_live_list.insert(tensor);
node->liveness_free_list.erase(tensor);
......
......@@ -18,6 +18,8 @@
#include "ngraph/function.hpp"
#include "ngraph/log.hpp"
#include "ngraph/node.hpp"
#include "ngraph/ops/function_call.hpp"
#include "ngraph/ops/reduce.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/pass/pass.hpp"
......@@ -36,10 +38,37 @@ void ngraph::pass::Manager::initialize_default_passes()
{
}
static void find_functions(shared_ptr<Function> f, set<shared_ptr<Function>>& funcs)
{
funcs.insert(f);
for (shared_ptr<Node> node : f->get_ops())
{
shared_ptr<op::FunctionCall> fc = dynamic_pointer_cast<op::FunctionCall>(node);
if (fc)
{
find_functions(fc->get_function(), funcs);
}
shared_ptr<op::Reduce> reduce = dynamic_pointer_cast<op::Reduce>(node);
if (reduce)
{
find_functions(reduce->get_reduction_function(), funcs);
}
}
}
void ngraph::pass::Manager::run_passes(shared_ptr<Function> func)
{
vector<shared_ptr<Function>> fs = {func};
get_state().set_functions(fs);
// find all functions
set<shared_ptr<Function>> tfs;
find_functions(func, tfs);
get_state().set_functions(tfs);
vector<shared_ptr<Function>> fs;
for (shared_ptr<Function> f : get_state().get_functions())
{
fs.push_back(f);
}
for (shared_ptr<PassBase> pass : m_pass_list)
{
......@@ -77,40 +106,6 @@ void ngraph::pass::Manager::run_passes(shared_ptr<Function> func)
}
}
}
// for (shared_ptr<ModulePass>& p : m_module_passes)
// {
// p->set_state(get_state());
// p->run_on_module(fs);
// }
// for (Function* f : fs)
// {
// for (shared_ptr<FunctionPass> p : m_function_passes)
// {
// p->set_state(get_state());
// p->run_on_function(f);
// }
// }
// for (Function* f : fs)
// {
// NGRAPH_INFO;
// for (shared_ptr<NodePass> p : m_node_passes)
// {
// for (Node* node : f->get_ops())
// {
// NGRAPH_INFO;
// p->set_state(get_state());
// p->run_on_node(node);
// }
// }
// }
// for (shared_ptr<CallGraphPass>& p : m_call_graph_passes)
// {
// p->set_state(get_state());
// p->run_on_call_graph(func->get_ordered_ops());
// }
}
ngraph::pass::ManagerState& ngraph::pass::Manager::get_state()
......
......@@ -23,7 +23,7 @@
using namespace std;
using namespace ngraph;
vector<shared_ptr<Function>>& ngraph::pass::ManagerState::get_functions()
const vector<shared_ptr<Function>>& ngraph::pass::ManagerState::get_functions()
{
return m_function_list;
}
......
......@@ -30,7 +30,7 @@ namespace ngraph
class ngraph::pass::ManagerState
{
public:
std::vector<std::shared_ptr<Function>>& get_functions();
const std::vector<std::shared_ptr<Function>>& get_functions();
template <typename T>
void set_functions(const T& collection)
......
......@@ -26,9 +26,14 @@ using namespace std;
using namespace ngraph;
using namespace ngraph::descriptor;
pass::MemoryLayout::MemoryLayout(size_t alignment)
: m_alignment(alignment)
{
}
bool pass::MemoryLayout::run_on_call_graph(std::list<std::shared_ptr<Node>>& node_list)
{
MemoryManager mm;
MemoryManager mm(m_alignment);
for (shared_ptr<Node> node : node_list)
{
for (Tensor* tensor : node->liveness_new_list)
......
......@@ -33,9 +33,11 @@ namespace ngraph
class ngraph::pass::MemoryLayout : public CallGraphPass
{
public:
MemoryLayout(size_t alignment = 1);
virtual bool run_on_call_graph(std::list<std::shared_ptr<Node>>&) override;
private:
size_t m_alignment;
};
class ngraph::pass::MemoryManager
......
......@@ -17,6 +17,7 @@
#include <memory>
#include "ngraph/common.hpp"
#include "ngraph/log.hpp"
#include "ngraph/runtime/ndarray.hpp"
namespace ngraph
......
......@@ -15,50 +15,51 @@
#include <algorithm>
#include "call_frame.hpp"
#include "ngraph/runtime/cpu/tensor_view.hpp"
using namespace std;
using namespace ngraph::runtime::cpu;
CallFrame::CallFrame(EntryPoint compiled_function,
size_t n_outputs,
size_t n_inputs,
const TensorViewPtrs& temps,
const std::vector<std::shared_ptr<CallFrame>>& callees)
: m_n_outputs(n_outputs)
, m_n_inputs(n_inputs)
, m_tensor_views(n_outputs + n_inputs + temps.size())
, m_compiled_function(compiled_function)
, m_callees(callees)
CallFrame::CallFrame(EntryPoint compiled_function)
: m_compiled_function(compiled_function)
{
copy(temps.begin(), temps.end(), m_tensor_views.begin() + m_n_outputs + m_n_inputs);
}
void CallFrame::tensor_call(
const std::vector<std::shared_ptr<ngraph::runtime::TensorView>>& inputs,
const std::vector<std::shared_ptr<ngraph::runtime::TensorView>>& outputs)
const std::vector<std::shared_ptr<ngraph::runtime::TensorView>>& input_tvs,
const std::vector<std::shared_ptr<ngraph::runtime::TensorView>>& output_tvs)
{
copy(outputs.begin(), outputs.end(), m_tensor_views.begin());
copy(inputs.begin(), inputs.end(), m_tensor_views.begin() + m_n_outputs);
vector<void*> inputs;
vector<void*> outputs;
for (size_t i = 0; i < input_tvs.size(); i++)
{
shared_ptr<runtime::cpu::CPUTensorView> tv =
static_pointer_cast<runtime::cpu::CPUTensorView>(input_tvs[i]);
inputs.push_back(tv->get_data_ptr());
}
for (size_t i = 0; i < output_tvs.size(); i++)
{
shared_ptr<runtime::cpu::CPUTensorView> tv =
static_pointer_cast<runtime::cpu::CPUTensorView>(output_tvs[i]);
outputs.push_back(tv->get_data_ptr());
}
// Invoke compiled computation
m_compiled_function(this, m_tensor_views, m_callees);
// Don't hold onto inputs/outputs
fill_n(m_tensor_views.begin(), m_n_outputs + m_n_inputs, nullptr);
m_compiled_function(inputs, outputs);
}
void CallFrame::operator()(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& arguments,
const std::vector<std::shared_ptr<ngraph::runtime::Value>>& results)
{
// TODO: Check types of args and result
std::vector<std::shared_ptr<ngraph::runtime::TensorView>> inputs;
for (auto argument : arguments)
vector<shared_ptr<ngraph::runtime::TensorView>> inputs;
for (shared_ptr<ngraph::runtime::Value> argument : arguments)
{
argument->collect_tensor_views(inputs, argument);
}
std::vector<std::shared_ptr<ngraph::runtime::TensorView>> outputs;
for (auto result : results)
vector<shared_ptr<ngraph::runtime::TensorView>> outputs;
for (shared_ptr<ngraph::runtime::Value> result : results)
{
result->collect_tensor_views(outputs, result);
}
......
......@@ -32,19 +32,16 @@ namespace ngraph
{
class CallFrame;
using EntryPoint = std::function<void(ngraph::runtime::cpu::CallFrame*,
ngraph::runtime::TensorViewPtrs&,
const std::vector<std::shared_ptr<CallFrame>>&)>;
using EntryPoint_t = void(const std::vector<void*>& inputs,
const std::vector<void*>& outputs);
using EntryPoint = std::function<EntryPoint_t>;
// Compile and execute graphs
class CallFrame : public ngraph::runtime::CallFrame
{
public:
CallFrame(EntryPoint compiled_function,
size_t n_outputs,
size_t n_inputs,
const TensorViewPtrs& temps,
const std::vector<std::shared_ptr<CallFrame>>& callees);
CallFrame(EntryPoint compiled_function);
/// @brief Invoke the function with values matching the signature of the function.
///
......@@ -53,30 +50,13 @@ namespace ngraph
operator()(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& inputs,
const std::vector<std::shared_ptr<ngraph::runtime::Value>>& outputs);
/// @brief Invoke the function with tuples pre-expanded to their underlying tensor views.
void tensor_call(const TensorViewPtrs& inputs, const TensorViewPtrs& outputs);
void set_return() { m_return = true; }
std::shared_ptr<TensorView> get_tensor_view(size_t i) { return m_tensor_views[i]; }
template <typename ET>
ParameterizedTensorView<ET>* get_parameterized_tensor_view(size_t i)
{
return m_tensor_views[i]->get_parameterized_tensor_view<ET>();
}
template <typename ET>
typename ET::type* get_tensor_view_data(size_t i)
{
return &get_parameterized_tensor_view<ET>(i)->get_vector()[0];
}
/// @brief Invoke the function with tuples pre-expanded to their underlying
/// tensor views.
void tensor_call(const std::vector<std::shared_ptr<TensorView>>& inputs,
const std::vector<std::shared_ptr<TensorView>>& outputs);
protected:
size_t m_n_outputs;
size_t m_n_inputs;
TensorViewPtrs m_tensor_views;
bool m_return;
EntryPoint m_compiled_function;
std::vector<std::shared_ptr<CallFrame>> m_callees;
};
}
}
......
......@@ -13,12 +13,22 @@
// ----------------------------------------------------------------------------
#include "ngraph/runtime/cpu/cpu_backend.hpp"
#include "ngraph/runtime/cpu/tensor_view.hpp"
#include "ngraph/runtime/external_function.hpp"
using namespace ngraph::runtime::cpu;
using namespace ngraph;
using namespace std;
std::shared_ptr<ngraph::runtime::CallFrame>
CPUBackend::make_call_frame(const std::shared_ptr<ExternalFunction>& external_function)
std::shared_ptr<ngraph::runtime::CallFrame> runtime::cpu::CPUBackend::make_call_frame(
const std::shared_ptr<ExternalFunction>& external_function)
{
return external_function->make_call_frame();
}
std::shared_ptr<ngraph::runtime::TensorView>
runtime::cpu::CPUBackend::make_primary_tensor_view(const ngraph::element::Type& element_type,
const Shape& shape)
{
auto rc = make_shared<runtime::cpu::CPUTensorView>(element_type, shape);
return dynamic_pointer_cast<runtime::TensorView>(rc);
}
......@@ -22,11 +22,18 @@ namespace ngraph
{
namespace cpu
{
class CPUBackend : public Backend
static size_t alignment = 64;
class CPUBackend : public runtime::Backend
{
public:
virtual std::shared_ptr<ngraph::runtime::CallFrame> make_call_frame(
const std::shared_ptr<ngraph::runtime::ExternalFunction>& external_function);
std::shared_ptr<ngraph::runtime::CallFrame> make_call_frame(
const std::shared_ptr<ngraph::runtime::ExternalFunction>& external_function)
override;
std::shared_ptr<ngraph::runtime::TensorView>
make_primary_tensor_view(const ngraph::element::Type& element_type,
const Shape& shape) override;
};
}
}
......
......@@ -37,25 +37,24 @@ namespace ngraph
using DynamicStrides = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
using VectorStrides = Eigen::Stride<Eigen::Dynamic, 1>;
template <typename ET>
using DynamicArray =
Eigen::Array<typename ET::type, Eigen::Dynamic, Eigen::Dynamic>;
template <typename T>
using DynamicArray = Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic>;
template <typename ET>
using EigenArrayBase = Eigen::Map<DynamicArray<ET>, 0, DynamicStrides>;
template <typename T>
using EigenArrayBase = Eigen::Map<DynamicArray<T>, 0, DynamicStrides>;
template <typename ET>
using DynamicMatrix = Eigen::
Matrix<typename ET::type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
template <typename T>
using DynamicMatrix =
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
template <typename ET>
using EigenMatrixBase = Eigen::Map<DynamicMatrix<ET>, 0, DynamicStrides>;
template <typename T>
using EigenMatrixBase = Eigen::Map<DynamicMatrix<T>, 0, DynamicStrides>;
template <typename ET>
using DynamicVector = Eigen::Matrix<typename ET::type, Eigen::Dynamic, 1>;
template <typename T>
using DynamicVector = Eigen::Matrix<T, Eigen::Dynamic, 1>;
template <typename ET>
using EigenVectorBase = Eigen::Map<DynamicVector<ET>, 0, VectorStrides>;
template <typename T>
using EigenVectorBase = Eigen::Map<DynamicVector<T>, 0, VectorStrides>;
namespace fmt
{
......@@ -114,10 +113,10 @@ namespace ngraph
};
}
// ET element type
// T element type
// FMT array format (fmt::V for vector, etc.)
// BASE select array/matrix
template <typename ET,
template <typename T,
typename FMT,
typename BASE,
typename STRIDES = DynamicStrides>
......@@ -126,26 +125,19 @@ namespace ngraph
using base = BASE;
public:
EigenWrapper(typename ET::type* t, const FMT& fmt)
EigenWrapper(T* t, const FMT& fmt)
: base(t, fmt.l0, fmt.l1, STRIDES(fmt.s0, fmt.s1))
{
}
EigenWrapper(
typename ET::type* t,
T* t,
const std::shared_ptr<ngraph::descriptor::layout::DenseTensorViewLayout>&
layout)
: base(t, layout->get_size(), 1, DynamicStrides(1, 1))
{
}
EigenWrapper(CallFrame* call_frame, const TensorViewInfo& tensor_view_info)
: EigenWrapper(
call_frame->get_tensor_view_data<ET>(tensor_view_info.get_index()),
FMT(tensor_view_info))
{
}
template <typename U>
EigenWrapper& operator=(const U& other)
{
......@@ -154,17 +146,17 @@ namespace ngraph
}
};
template <typename ET, typename FMT = fmt::V>
using EigenArray1d = EigenWrapper<ET, FMT, EigenArrayBase<ET>>;
template <typename T, typename FMT = fmt::V>
using EigenArray1d = EigenWrapper<T, FMT, EigenArrayBase<T>>;
template <typename ET, typename FMT = fmt::M>
using EigenArray2d = EigenWrapper<ET, FMT, EigenArrayBase<ET>>;
template <typename T, typename FMT = fmt::M>
using EigenArray2d = EigenWrapper<T, FMT, EigenArrayBase<T>>;
template <typename ET, typename FMT = fmt::M>
using EigenMatrix = EigenWrapper<ET, FMT, EigenMatrixBase<ET>>;
template <typename T, typename FMT = fmt::M>
using EigenMatrix = EigenWrapper<T, FMT, EigenMatrixBase<T>>;
template <typename ET, typename FMT = fmt::V>
using EigenVector = EigenWrapper<ET, FMT, EigenVectorBase<ET>, VectorStrides>;
template <typename T, typename FMT = fmt::V>
using EigenVector = EigenWrapper<T, FMT, EigenVectorBase<T>, VectorStrides>;
}
}
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -17,6 +17,7 @@
#include <string>
#include <vector>
#include "ngraph/codegen/code_writer.hpp"
#include "ngraph/node.hpp"
#include "ngraph/runtime/cpu/external_function.hpp"
#include "ngraph/runtime/tensor_view_info.hpp"
......@@ -24,7 +25,6 @@
#define EMITTER_DECL(E) \
E(const ngraph::Node* n, \
ExternalFunction* ef, \
FunctionMap& function_map, \
const std::vector<TensorViewInfo>& inputs, \
const std::vector<TensorViewInfo>& outputs)
......@@ -37,14 +37,15 @@ namespace ngraph
class Emitter
{
protected:
std::string TU;
codegen::CodeWriter TU;
public:
Emitter()
: TU("")
: TU()
{
}
std::string& GetTU() { return TU; }
std::string get_code() { return TU.get_code(); }
codegen::CodeWriter& get_code_writer() { return TU; }
void EMITTER_DECL(EmitNop);
void EMITTER_DECL(EmitAdd);
void EMITTER_DECL(EmitDot);
......
......@@ -22,6 +22,7 @@
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/function.hpp"
#include "ngraph/runtime/cpu/call_frame.hpp"
#include "ngraph/runtime/external_function.hpp"
#include "ngraph/runtime/tensor_view_info.hpp"
......@@ -41,32 +42,22 @@ namespace ngraph
using OpFunction = std::function<void(Emitter*,
const ngraph::Node*,
ExternalFunction*,
FunctionMap&,
const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs)>;
using OpMap = std::unordered_map<std::type_index, OpFunction>;
using EntryPoint = std::function<void(
ngraph::runtime::cpu::CallFrame*,
ngraph::runtime::TensorViewPtrs&,
const std::vector<std::shared_ptr<ngraph::runtime::cpu::CallFrame>>&)>;
class ExternalFunction : public ngraph::runtime::ExternalFunction
{
public:
ExternalFunction(const std::shared_ptr<ngraph::Function>& function,
bool release_function = true);
std::shared_ptr<ngraph::runtime::CallFrame> make_call_frame();
std::vector<std::shared_ptr<CallFrame>>& get_callees() { return callees; }
protected:
void compile(FunctionMap& function_map);
void compile();
size_t m_n_inputs;
size_t m_n_outputs;
ngraph::descriptor::TensorViewPtrs m_temp_views;
EntryPoint compiled_function;
std::vector<std::shared_ptr<CallFrame>> callees;
EntryPoint m_compiled_function;
};
}
}
......
// ----------------------------------------------------------------------------
// 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 <memory>
#include "cpu_backend.hpp"
#include "tensor_view.hpp"
using namespace ngraph;
using namespace std;
extern "C" void
allocate_aligned_buffer(size_t size, size_t alignment, char** allocated, char** aligned_ptr);
extern "C" void free_aligned_buffer(void* allocated);
runtime::cpu::CPUTensorView::CPUTensorView(const ngraph::element::Type& element_type,
const Shape& shape)
: runtime::TensorView(std::make_shared<ngraph::descriptor::PrimaryTensorView>(
std::make_shared<ngraph::TensorViewType>(element_type, shape), "external", true, true))
{
m_descriptor->set_tensor_view_layout(
std::make_shared<ngraph::descriptor::layout::DenseTensorViewLayout>(*m_descriptor));
m_buffer_size = m_descriptor->get_tensor_view_layout()->get_size() * element_type.size();
allocate_aligned_buffer(m_buffer_size, runtime::cpu::alignment, &m_allocated, &m_buffer);
}
runtime::cpu::CPUTensorView::~CPUTensorView()
{
free_aligned_buffer(m_allocated);
}
char* runtime::cpu::CPUTensorView::get_data_ptr()
{
return m_buffer;
}
const char* runtime::cpu::CPUTensorView::get_data_ptr() const
{
return m_buffer;
}
void runtime::cpu::CPUTensorView::write(const void* source, size_t tensor_offset, size_t n)
{
if (tensor_offset + n > m_buffer_size)
{
throw out_of_range("write access past end of tensor");
}
char* target = get_data_ptr();
memcpy(&target[tensor_offset], source, n);
}
void runtime::cpu::CPUTensorView::read(void* target, size_t tensor_offset, size_t n) const
{
if (tensor_offset + n > m_buffer_size)
{
throw out_of_range("read access past end of tensor");
}
const char* source = get_data_ptr();
memcpy(target, &source[tensor_offset], n);
}
// ----------------------------------------------------------------------------
// 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 <memory>
#include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/types/element_type.hpp"
namespace ngraph
{
namespace runtime
{
namespace cpu
{
class CPUTensorView;
}
}
}
class ngraph::runtime::cpu::CPUTensorView : public ngraph::runtime::TensorView
{
public:
CPUTensorView(const ngraph::element::Type& element_type, const Shape& shape);
virtual ~CPUTensorView();
char* get_data_ptr();
const char* get_data_ptr() const;
/// @brief Write bytes directly into the tensor
/// @param p Pointer to source of data
/// @param tensor_offset Offset into tensor storage to begin writing. Must be element-aligned.
/// @param n Number of bytes to write, must be integral number of elements.
void write(const void* p, size_t tensor_offset, size_t n) override;
/// @brief Read bytes directly from the tensor
/// @param p Pointer to destination for data
/// @param tensor_offset Offset into tensor storage to begin reading. Must be element-aligned.
/// @param n Number of bytes to read, must be integral number of elements.
void read(void* p, size_t tensor_offset, size_t n) const override;
private:
char* m_allocated;
char* m_buffer;
size_t m_buffer_size;
};
......@@ -179,6 +179,8 @@ namespace ngraph
const vtype get_vector() const { return m_elements; }
operator const vtype() const { return m_elements; }
operator vtype() { return m_elements; }
void* data() { return m_elements.data(); }
const void* data() const { return m_elements.data(); }
bool operator==(const NDArrayBase<T>& other) const
{
return m_shape == other.m_shape && m_elements == other.m_elements;
......
......@@ -18,8 +18,11 @@
#include <vector>
#include "ngraph/descriptor/tensor_view.hpp"
#include "ngraph/log.hpp"
#include "ngraph/runtime/ndarray.hpp"
#include "ngraph/runtime/value.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/util.hpp"
namespace ngraph
{
......@@ -42,7 +45,6 @@ namespace ngraph
}
public:
TensorView() {}
virtual ~TensorView() {}
template <typename ET>
ParameterizedTensorView<ET>* get_parameterized_tensor_view()
......@@ -75,6 +77,29 @@ namespace ngraph
/// @param n Number of bytes to read, must be integral number of elements.
virtual void read(void* p, size_t tensor_offset, size_t n) const = 0;
// This is for unit test only
template <typename T>
bool operator==(const NDArrayBase<T>& ndarray) const
{
bool rc = false;
if (get_shape() == ndarray.get_shape())
{
std::vector<T> lhs(ndarray.get_vector().size());
read(lhs.data(), 0, ndarray.get_vector().size() * sizeof(T));
rc = (lhs == ndarray.get_vector());
}
return rc;
}
template <typename T>
std::vector<T> get_vector()
{
size_t element_count = shape_size(get_shape());
size_t size = element_count * sizeof(T);
std::vector<T> rc(element_count);
read(rc.data(), 0, size);
return rc;
}
protected:
std::shared_ptr<ngraph::descriptor::TensorView> m_descriptor;
};
......
......@@ -27,9 +27,10 @@ namespace ngraph
{
public:
TensorViewInfo(size_t index,
const std::shared_ptr<const ngraph::descriptor::TensorView>& descriptor)
std::shared_ptr<const ngraph::descriptor::TensorView> descriptor)
: m_index(index)
, m_layout(descriptor->get_tensor_view_layout())
, m_tensor_view(descriptor)
{
}
......@@ -46,9 +47,20 @@ namespace ngraph
return std::static_pointer_cast<LT>(m_layout);
}
std::shared_ptr<const ngraph::descriptor::TensorView> get_tensor_view() const
{
return m_tensor_view;
}
const ngraph::descriptor::Tensor& get_tensor() const
{
return m_tensor_view->get_tensor();
}
protected:
size_t m_index;
std::shared_ptr<ngraph::descriptor::layout::TensorViewLayout> m_layout;
std::shared_ptr<const ngraph::descriptor::TensorView> m_tensor_view;
};
}
}
......@@ -26,6 +26,7 @@ set (SRC
copy.cpp
build_graph.cpp
eigen.cpp
file_util.cpp
input_output_assign.cpp
main.cpp
op.cpp
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// ----------------------------------------------------------------------------
// 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 <random>
#include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "ngraph/file_util.hpp"
using namespace std;
using namespace ngraph;
TEST(file_util, path_join)
{
{
string s1 = "";
string s2 = "";
EXPECT_STREQ("", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "";
string s2 = "/test1/test2";
EXPECT_STREQ("/test1/test2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "";
string s2 = "/test1/test2/";
EXPECT_STREQ("/test1/test2/", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "";
string s2 = "test1/test2";
EXPECT_STREQ("test1/test2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/x1/x2";
string s2 = "";
EXPECT_STREQ("/x1/x2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/x1/x2/";
string s2 = "/";
EXPECT_STREQ("/", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/x1/x2";
string s2 = "/test1/test2";
EXPECT_STREQ("/test1/test2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/x1/x2/";
string s2 = "test1/test2";
EXPECT_STREQ("/x1/x2/test1/test2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/x1/x2";
string s2 = "test1/test2";
EXPECT_STREQ("/x1/x2/test1/test2", file_util::path_join(s1, s2).c_str());
}
{
string s1 = "/";
string s2 = "test1/test2";
EXPECT_STREQ("/test1/test2", file_util::path_join(s1, s2).c_str());
}
}
TEST(file_util, get_temp_directory)
{
string tmp = file_util::get_temp_directory();
EXPECT_NE(0, tmp.size());
}
......@@ -113,3 +113,24 @@ TEST(tensor, read_write)
test_read_write<element::Float32>({1.0, 3.0, 5.0});
test_read_write<element::Int64>({-1, 2, 4});
}
TEST(tensor, output_flag)
{
pass::Manager pass_manager;
pass_manager.register_pass<pass::TopologicalSort>();
pass_manager.register_pass<pass::Liveness>();
auto arg0 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
auto add = make_shared<op::Add>(arg0, arg0);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{1});
auto f0 = make_shared<Function>(add, rt, op::Parameters{arg0});
pass_manager.run_passes(f0);
EXPECT_TRUE(f0->get_result()->is_output());
for (descriptor::Output& output : f0->get_result()->get_outputs())
{
const Tensor& t = output.get_tensor();
EXPECT_TRUE(t.is_output());
}
}
......@@ -21,7 +21,6 @@
#include "ngraph/log.hpp"
#include "ngraph/ngraph.hpp"
#include "ngraph/pass/collect_functions.hpp"
#include "ngraph/pass/dump_sorted.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/pass/topological_sort.hpp"
......@@ -172,11 +171,11 @@ TEST(topological_sort, collect_functions)
"h");
pass::Manager pass_manager;
pass_manager.register_pass<pass::CollectFunctions>();
pass_manager.run_passes(h);
set<string> expected = {"f", "g", "h"};
auto functions = pass_manager.get_state().get_functions();
vector<string> fnames;
for (shared_ptr<Function> func : functions)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment