Unverified Commit 0ef1c2f9 authored by Jai Menon's avatar Jai Menon Committed by GitHub

Merge pull request #243 from NervanaSystems/bob/static_compiler

Bob/static compiler
parents 7b9b35d3 1ac8d820
...@@ -106,12 +106,14 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND ...@@ -106,12 +106,14 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
set(SRC ${SRC} set(SRC ${SRC}
codegen/code_writer.cpp codegen/code_writer.cpp
codegen/compiler.cpp codegen/compiler.cpp
codegen/execution_engine.cpp
runtime/cpu/call_frame.cpp runtime/cpu/call_frame.cpp
runtime/cpu/cpu_backend.cpp runtime/cpu/cpu_backend.cpp
runtime/cpu/cpu_manager.cpp runtime/cpu/cpu_manager.cpp
runtime/cpu/cpu_kernels.cpp runtime/cpu/cpu_kernels.cpp
runtime/cpu/emitter.cpp runtime/cpu/emitter.cpp
runtime/cpu/external_function.cpp runtime/cpu/external_function.cpp
runtime/cpu/memory_handler.cpp
runtime/cpu/tensor_view.cpp runtime/cpu/tensor_view.cpp
) )
# LLVM binary builds are typically built without RTTI # LLVM binary builds are typically built without RTTI
......
This diff is collapsed.
...@@ -27,10 +27,18 @@ namespace ngraph ...@@ -27,10 +27,18 @@ namespace ngraph
namespace codegen namespace codegen
{ {
class module; class module;
class execution_state; class Compiler;
class StaticCompiler;
class HeaderCache;
} }
} }
namespace clang
{
class HeaderSearchOptions;
class CompilerInstance;
}
class ngraph::codegen::module class ngraph::codegen::module
{ {
public: public:
...@@ -38,39 +46,57 @@ private: ...@@ -38,39 +46,57 @@ private:
std::unique_ptr<llvm::Module> m_module; std::unique_ptr<llvm::Module> m_module;
}; };
class ngraph::codegen::execution_state : public llvm::SectionMemoryManager class ngraph::codegen::Compiler
{ {
public: public:
execution_state(); Compiler();
~execution_state(); ~Compiler();
std::unique_ptr<llvm::Module> compile(const std::string& source);
void set_precompiled_headers_enabled(bool state) { precompiled_headers_enabled = state; }
bool is_precompiled_headers_enabled() { return precompiled_headers_enabled; }
void set_debuginfo_enabled(bool state) { debuginfo_enabled = state; }
bool is_debuginfo_enabled() { return debuginfo_enabled; }
std::unique_ptr<llvm::Module> compile(const std::string& source, const std::string& name = "");
bool add_module(std::unique_ptr<llvm::Module>&);
void finalize(); private:
};
template <typename ftype> class ngraph::codegen::StaticCompiler : public llvm::SectionMemoryManager
std::function<ftype> find_function(const std::string& func_name) {
{ public:
auto f = m_execution_engine->getPointerToNamedFunction(func_name); StaticCompiler();
~StaticCompiler();
return f_cast<ftype>(f); void set_precompiled_headers_enabled(bool state) { m_precompiled_headers_enabled = state; }
} bool is_precompiled_headers_enabled() { return m_precompiled_headers_enabled; }
void set_debuginfo_enabled(bool state) { m_debuginfo_enabled = state; }
bool is_debuginfo_enabled() { return m_debuginfo_enabled; }
void add_header_search_path(const std::string& path);
std::unique_ptr<llvm::Module> compile(const std::string& source);
private: private:
llvm::ExecutionEngine* m_execution_engine; std::unique_ptr<clang::CompilerInstance> m_compiler;
std::string jit_error; bool m_precompiled_headers_enabled;
bool precompiled_headers_enabled; bool m_debuginfo_enabled;
bool debuginfo_enabled; std::string m_source_name;
std::vector<std::string> m_extra_search_path_list;
template <typename signature> bool is_version_number(const std::string& path);
std::function<signature> f_cast(void* f) void use_cached_files();
};
class ngraph::codegen::HeaderCache
{
public:
bool is_valid() const { return m_headers_valid; }
bool set_valid() { return m_headers_valid = true; }
void add_path(const std::string& path) { m_include_paths.push_back(path); }
void add_file(const std::string& path, std::unique_ptr<llvm::MemoryBuffer>& code)
{
m_headers.insert(std::make_pair(path, std::move(code)));
}
const std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>>& get_header_map() const
{ {
return static_cast<signature*>(reinterpret_cast<signature*>(f)); return m_headers;
} }
const std::vector<std::string>& get_include_paths() const { return m_include_paths; }
private:
std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> m_headers;
std::vector<std::string> m_include_paths;
bool m_headers_valid;
}; };
// ----------------------------------------------------------------------------
// 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 <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include "ngraph/codegen/execution_engine.hpp"
using namespace ngraph;
codegen::ExecutionEngine::ExecutionEngine()
: m_execution_engine{nullptr}
{
}
codegen::ExecutionEngine::~ExecutionEngine()
{
}
bool codegen::ExecutionEngine::add_module(std::unique_ptr<llvm::Module>& module)
{
if (module)
{
if (!m_execution_engine)
{
m_execution_engine = llvm::EngineBuilder(move(module))
.setEngineKind(llvm::EngineKind::JIT)
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setErrorStr(&m_jit_error)
.create();
if (!m_execution_engine)
{
return false;
}
}
}
else
{
return false;
}
return true;
}
void codegen::ExecutionEngine::finalize()
{
if (m_execution_engine)
{
m_execution_engine->finalizeObject();
m_execution_engine->runStaticConstructorsDestructors(false);
}
else
{
throw std::runtime_error(
"Error in finalize: " +
(m_jit_error.empty() ? "Could not create an execution engine" : m_jit_error));
}
}
// ----------------------------------------------------------------------------
// 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 <llvm/ExecutionEngine/MCJIT.h> // forces JIT to link in
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Option/Arg.h>
namespace ngraph
{
namespace codegen
{
class ExecutionEngine;
}
}
class ngraph::codegen::ExecutionEngine
{
public:
ExecutionEngine();
~ExecutionEngine();
bool add_module(std::unique_ptr<llvm::Module>& module);
void finalize();
template <typename ftype>
std::function<ftype> find_function(const std::string& func_name)
{
auto f = m_execution_engine->getPointerToNamedFunction(func_name);
return f_cast<ftype>(f);
}
private:
llvm::ExecutionEngine* m_execution_engine;
std::string m_jit_error;
template <typename signature>
std::function<signature> f_cast(void* f)
{
return static_cast<signature*>(reinterpret_cast<signature*>(f));
}
};
/* // ----------------------------------------------------------------------------
Copyright 2016 Nervana Systems Inc. // Copyright 2017 Nervana Systems Inc.
Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
You may obtain a copy of the License at // You may obtain a copy of the License at
//
http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
//
Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
limitations under the License. // ----------------------------------------------------------------------------
*/
#include <cassert> #include <cassert>
#include <dirent.h> #include <dirent.h>
...@@ -29,10 +28,37 @@ ...@@ -29,10 +28,37 @@
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
#include "file_util.hpp" #include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
using namespace std; using namespace std;
std::string ngraph::file_util::get_file_name(const std::string& s)
{
string rc = s;
auto pos = s.find_last_of('/');
if (pos != string::npos)
{
rc = s.substr(pos + 1);
}
return rc;
}
std::string ngraph::file_util::get_file_ext(const std::string& s)
{
string rc = get_file_name(s);
auto pos = rc.find_last_of('.');
if (pos != string::npos)
{
rc = rc.substr(pos);
}
else
{
rc = "";
}
return rc;
}
string ngraph::file_util::path_join(const string& s1, const string& s2) string ngraph::file_util::path_join(const string& s1, const string& s2)
{ {
string rc; string rc;
...@@ -79,20 +105,22 @@ size_t ngraph::file_util::get_file_size(const string& filename) ...@@ -79,20 +105,22 @@ size_t ngraph::file_util::get_file_size(const string& filename)
void ngraph::file_util::remove_directory(const string& dir) void ngraph::file_util::remove_directory(const string& dir)
{ {
struct stat status; struct stat status;
if (stat(dir.c_str(), &status) == -1) if (stat(dir.c_str(), &status) != -1)
{ {
return; 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());
} }
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) void ngraph::file_util::remove_file(const string& file)
...@@ -117,7 +145,7 @@ bool ngraph::file_util::make_directory(const string& dir) ...@@ -117,7 +145,7 @@ bool ngraph::file_util::make_directory(const string& dir)
string ngraph::file_util::make_temp_directory(const string& path) string ngraph::file_util::make_temp_directory(const string& path)
{ {
string fname = path.empty() ? file_util::get_temp_directory() : path; string fname = path.empty() ? file_util::get_temp_directory() : path;
string tmp_template = file_util::path_join(fname, "aeonXXXXXX"); string tmp_template = file_util::path_join(fname, "ngraph_XXXXXX");
char* tmpname = strdup(tmp_template.c_str()); char* tmpname = strdup(tmp_template.c_str());
mkdtemp(tmpname); mkdtemp(tmpname);
...@@ -129,7 +157,7 @@ string ngraph::file_util::make_temp_directory(const string& path) ...@@ -129,7 +157,7 @@ string ngraph::file_util::make_temp_directory(const string& path)
std::string ngraph::file_util::get_temp_directory() std::string ngraph::file_util::get_temp_directory()
{ {
const vector<string> potential_tmps = {"NERVANA_AEON_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"}; const vector<string> potential_tmps = {"NGRAPH_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"};
const char* path = nullptr; const char* path = nullptr;
for (const string& var : potential_tmps) for (const string& var : potential_tmps)
...@@ -161,7 +189,7 @@ vector<char> ngraph::file_util::read_file_contents(const string& path) ...@@ -161,7 +189,7 @@ vector<char> ngraph::file_util::read_file_contents(const string& path)
char* p = data.data(); char* p = data.data();
size_t remainder = file_size; size_t remainder = file_size;
size_t offset = 0; size_t offset = 0;
while (remainder > 0) while (f && remainder > 0)
{ {
size_t rc = fread(&p[offset], 1, remainder, f); size_t rc = fread(&p[offset], 1, remainder, f);
offset += rc; offset += rc;
...@@ -197,12 +225,16 @@ void ngraph::file_util::iterate_files(const string& path, ...@@ -197,12 +225,16 @@ void ngraph::file_util::iterate_files(const string& path,
else else
files.push_back(file); files.push_back(file);
}, },
true); recurse);
for (auto f : files) for (auto f : files)
{
func(f, false); func(f, false);
}
for (auto f : dirs) for (auto f : dirs)
{
func(f, true); func(f, true);
}
} }
void ngraph::file_util::iterate_files_worker( void ngraph::file_util::iterate_files_worker(
...@@ -218,18 +250,23 @@ void ngraph::file_util::iterate_files_worker( ...@@ -218,18 +250,23 @@ void ngraph::file_util::iterate_files_worker(
switch (ent->d_type) switch (ent->d_type)
{ {
case DT_DIR: case DT_DIR:
if (recurse && name != "." && name != "..") if (name != "." && name != "..")
{ {
string dir_path = file_util::path_join(path, name); string dir_path = file_util::path_join(path, name);
iterate_files(dir_path, func, recurse); if (recurse)
{
iterate_files(dir_path, func, recurse);
}
func(dir_path, true); func(dir_path, true);
} }
break; break;
case DT_LNK: break; case DT_LNK: break;
case DT_REG: case DT_REG:
name = file_util::path_join(path, name); {
func(name, false); string file_name = file_util::path_join(path, name);
func(file_name, false);
break; break;
}
default: break; default: break;
} }
} }
......
/* // ----------------------------------------------------------------------------
Copyright 2016 Nervana Systems Inc. // Copyright 2017 Nervana Systems Inc.
Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
You may obtain a copy of the License at // You may obtain a copy of the License at
//
http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
//
Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
limitations under the License. // ----------------------------------------------------------------------------
*/
#pragma once #pragma once
...@@ -27,6 +26,8 @@ namespace ngraph ...@@ -27,6 +26,8 @@ namespace ngraph
class ngraph::file_util class ngraph::file_util
{ {
public: public:
static std::string get_file_name(const std::string&);
static std::string get_file_ext(const std::string&);
static std::string path_join(const std::string& s1, const std::string& s2); static std::string path_join(const std::string& s1, const std::string& s2);
static size_t get_file_size(const std::string& filename); static size_t get_file_size(const std::string& filename);
static void remove_directory(const std::string& dir); static void remove_directory(const std::string& dir);
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#pragma once #pragma once
#include <cinttypes>
#include <cstddef> #include <cstddef>
#include <cstdint>
// CBLAS types and wrappers // CBLAS types and wrappers
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <memory> #include <memory>
#include "ngraph/codegen/compiler.hpp" #include "ngraph/codegen/execution_engine.hpp"
#include "ngraph/runtime/manager.hpp" #include "ngraph/runtime/manager.hpp"
namespace ngraph namespace ngraph
...@@ -33,7 +33,7 @@ namespace ngraph ...@@ -33,7 +33,7 @@ namespace ngraph
class CPUManager : public Manager class CPUManager : public Manager
{ {
protected: protected:
ngraph::codegen::execution_state exec_state; ngraph::codegen::ExecutionEngine exec_state;
public: public:
virtual std::shared_ptr<Backend> allocate_backend() override; virtual std::shared_ptr<Backend> allocate_backend() override;
......
...@@ -89,7 +89,7 @@ namespace ngraph ...@@ -89,7 +89,7 @@ namespace ngraph
}; };
} }
// ET element type // T element type
// FMT array format (fmt::V for vector, etc.) // FMT array format (fmt::V for vector, etc.)
// BASE select array/matrix // BASE select array/matrix
template <typename T, template <typename T,
...@@ -128,4 +128,4 @@ namespace ngraph ...@@ -128,4 +128,4 @@ namespace ngraph
} }
} }
} }
} }
\ No newline at end of file
This diff is collapsed.
...@@ -94,6 +94,15 @@ namespace ngraph ...@@ -94,6 +94,15 @@ namespace ngraph
void EMITTER_DECL(EmitAsin); void EMITTER_DECL(EmitAsin);
void EMITTER_DECL(EmitAcos); void EMITTER_DECL(EmitAcos);
void EMITTER_DECL(EmitAtan); void EMITTER_DECL(EmitAtan);
private:
void generate_call(const std::vector<TensorViewInfo>& inputs,
const std::vector<TensorViewInfo>& outputs,
std::shared_ptr<Function> function);
std::string emit_vector(const TensorViewInfo&, const std::string& name = "");
std::string emit_array1d(const TensorViewInfo&, const std::string& name = "");
std::string emit_matrix(const TensorViewInfo&, const std::string& name = "");
}; };
} }
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "ngraph/codegen/code_writer.hpp" #include "ngraph/codegen/code_writer.hpp"
#include "ngraph/codegen/compiler.hpp" #include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
#include "ngraph/descriptor/input.hpp" #include "ngraph/descriptor/input.hpp"
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp" #include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/output.hpp" #include "ngraph/descriptor/output.hpp"
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
#include "ngraph/pass/memory_layout.hpp" #include "ngraph/pass/memory_layout.hpp"
#include "ngraph/pass/topological_sort.hpp" #include "ngraph/pass/topological_sort.hpp"
#include "ngraph/runtime/cpu/call_frame.hpp" #include "ngraph/runtime/cpu/call_frame.hpp"
#include "ngraph/runtime/cpu/cpu_backend.hpp"
#include "ngraph/runtime/cpu/emitter.hpp" #include "ngraph/runtime/cpu/emitter.hpp"
#include "ngraph/runtime/cpu/external_function.hpp" #include "ngraph/runtime/cpu/external_function.hpp"
#include "ngraph/runtime/utils.hpp" #include "ngraph/runtime/utils.hpp"
...@@ -81,26 +83,17 @@ ...@@ -81,26 +83,17 @@
using namespace std; using namespace std;
using namespace ngraph::runtime::cpu; using namespace ngraph::runtime::cpu;
using ngraph::descriptor::layout::DenseTensorViewLayout; static const std::string s_output_dir = "cpu_codegen";
extern "C" void class StaticInitializers
allocate_aligned_buffer(size_t size, size_t alignment, char** allocated, char** aligned_ptr)
{ {
size_t allocation_size = size + alignment; public:
*allocated = static_cast<char*>(malloc(allocation_size)); StaticInitializers() { ngraph::file_util::remove_directory(s_output_dir); }
*aligned_ptr = *allocated; };
size_t mod = size_t(*aligned_ptr) % alignment;
if (mod != 0) static StaticInitializers s_static_initializers;
{
(*aligned_ptr) += (alignment - mod);
}
}
extern "C" void free_aligned_buffer(void* allocated) using ngraph::descriptor::layout::DenseTensorViewLayout;
{
free(allocated);
}
#define TI(x) type_index(typeid(x)) #define TI(x) type_index(typeid(x))
...@@ -192,37 +185,25 @@ void ExternalFunction::compile() ...@@ -192,37 +185,25 @@ void ExternalFunction::compile()
TU += TU +=
R"(// Generated by the NGraph CPU backend R"(// Generated by the NGraph CPU backend
#include <algorithm>
#include <cmath> #include <cmath>
#include <memory>
#include <vector> #include <vector>
#include <Eigen/Dense> #include <Eigen/Dense>
#include "ngraph/runtime/cpu/cpu_kernels.hpp" #include "ngraph/runtime/cpu/cpu_kernels.hpp"
#include "ngraph/runtime/cpu/eigen_utils.hpp" #include "ngraph/runtime/cpu/eigen_utils.hpp"
#include "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph::runtime::cpu::eigen; using namespace ngraph::runtime::cpu::eigen;
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);
)"; )";
TU << "// Declare any functions that are not main\n"; TU << "// Declare all functions\n";
for (shared_ptr<Function> f : pass_manager.get_state().get_functions()) for (shared_ptr<Function> f : pass_manager.get_state().get_functions())
{ {
if (f != m_function) TU << "extern \"C\" void " << f->get_name() << "(\n";
{ TU << " const std::vector<void*>& inputs,\n";
TU << "extern \"C\" void " << f->get_name() << "(\n"; TU << " const std::vector<void*>& outputs);\n";
TU << " const std::vector<void*>& inputs,\n";
TU << " const std::vector<void*>& outputs);\n";
}
} }
TU << "\n"; TU << "\n";
...@@ -232,27 +213,37 @@ extern "C" void free_aligned_buffer(void* allocated); ...@@ -232,27 +213,37 @@ extern "C" void free_aligned_buffer(void* allocated);
TU << " const std::vector<void*>& inputs,\n"; TU << " const std::vector<void*>& inputs,\n";
TU << " const std::vector<void*>& outputs)\n"; TU << " const std::vector<void*>& outputs)\n";
TU << "{\n"; TU << "{\n";
TU.indent++; TU.indent++;
TU << "// Allocate the memory pool\n";
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
TU << "char* allocated_buffer_pool;\n";
TU << "char* aligned_buffer_pool;\n";
TU << "allocate_aligned_buffer(" << temp_pool_size << ", 64"
<< ", &allocated_buffer_pool, &aligned_buffer_pool);\n";
TU << "\n";
TU << "// Define temporary tensors\n"; bool temporaries_used = false;
for (shared_ptr<Node> node : current_function->get_ordered_ops()) for (shared_ptr<Node> node : current_function->get_ordered_ops())
{ {
for (descriptor::Tensor* tensor : node->liveness_new_list) if (node->liveness_new_list.size() > 0)
{ {
TU << tensor->get_element_type() << "* " << tensor->get_name() << " = (" temporaries_used = true;
<< tensor->get_element_type() << "*)(aligned_buffer_pool + " break;
<< tensor->get_pool_offset() << ");\n";
} }
} }
TU << "\n"; if (temporaries_used)
{
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
TU << "// Allocate the memory pool\n";
TU << "ngraph::runtime::cpu::MemoryHandler memory_handler(" << temp_pool_size << ", "
<< ngraph::runtime::cpu::alignment << ");\n";
TU << "\n";
TU << "// Define temporary tensors\n";
for (shared_ptr<Node> node : current_function->get_ordered_ops())
{
for (descriptor::Tensor* tensor : node->liveness_new_list)
{
TU << tensor->get_element_type() << "* " << tensor->get_name() << " = ("
<< tensor->get_element_type() << "*)(memory_handler.get_ptr("
<< tensor->get_pool_offset() << "));\n";
}
}
TU << "\n";
}
TU << "// Define inputs\n"; TU << "// Define inputs\n";
size_t arg_index = 0; size_t arg_index = 0;
...@@ -283,13 +274,10 @@ extern "C" void free_aligned_buffer(void* allocated); ...@@ -283,13 +274,10 @@ extern "C" void free_aligned_buffer(void* allocated);
} }
TU << "\n"; TU << "\n";
TU << "// Define tensor views\n";
TU << "\n";
for (shared_ptr<Node> node : current_function->get_ordered_ops()) for (shared_ptr<Node> node : current_function->get_ordered_ops())
{ {
auto& n = *node; // Work around a compiler warning (*node inside typeid may have effects auto& n = *node; // Work around a compiler warning (*node inside typeid may have effects
// with shared pointers, which is fine here but clang doesn't like it.) // with shared pointers, which is fine here but clang doesn't like it.)
auto handler = dispatcher.find(type_index(typeid(n))); auto handler = dispatcher.find(type_index(typeid(n)));
if (handler == dispatcher.end()) if (handler == dispatcher.end())
{ {
...@@ -311,8 +299,6 @@ extern "C" void free_aligned_buffer(void* allocated); ...@@ -311,8 +299,6 @@ extern "C" void free_aligned_buffer(void* allocated);
handler->second(&emitter, node.get(), this, in, out); handler->second(&emitter, node.get(), this, in, out);
} }
TU << "\nfree_aligned_buffer(allocated_buffer_pool);\n";
TU.indent--; TU.indent--;
// End TU // End TU
...@@ -321,34 +307,33 @@ extern "C" void free_aligned_buffer(void* allocated); ...@@ -321,34 +307,33 @@ extern "C" void free_aligned_buffer(void* allocated);
// TODO: Cleanup and make this a utility function // TODO: Cleanup and make this a utility function
string output_dir = "cpu_codegen";
string function_name = m_function->get_name(); string function_name = m_function->get_name();
file_util::remove_directory(output_dir); file_util::make_directory(s_output_dir);
file_util::make_directory(output_dir); string filename = file_util::path_join(s_output_dir, function_name + "_codegen.cpp");
string filename = file_util::path_join(output_dir, function_name + "_codegen.cpp");
ofstream out(filename); ofstream out(filename);
string code = TU.get_code(); string code = TU.get_code();
out << code; out << code;
out.close(); out.close();
ngraph::codegen::execution_state estate; codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
#if NGCPU_PCH #if NGCPU_PCH
estate.set_precompiled_headers_enabled(true); compiler.set_precompiled_headers_enabled(true);
#endif #endif
#if NGCPU_DEBUGINFO #if NGCPU_DEBUGINFO
estate.set_debuginfo_enabled(true); compiler.set_debuginfo_enabled(true);
#endif #endif
auto llvm_module = estate.compile(code, function_name + "_codegen.cpp"); auto llvm_module = compiler.compile(code);
if (llvm_module == nullptr) if (llvm_module == nullptr)
{ {
throw runtime_error("function failed to compile"); throw runtime_error("function failed to compile");
} }
estate.add_module(llvm_module); execution_engine.add_module(llvm_module);
estate.finalize(); execution_engine.finalize();
m_compiled_function = estate.find_function<EntryPoint_t>(function_name); m_compiled_function = execution_engine.find_function<EntryPoint_t>(function_name);
assert(m_compiled_function); assert(m_compiled_function);
m_is_compiled = true; m_is_compiled = true;
......
// ----------------------------------------------------------------------------
// 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 "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph;
runtime::cpu::MemoryHandler::MemoryHandler(size_t byte_size, size_t alignment)
: m_allocated_buffer_pool(nullptr)
, m_aligned_buffer_pool(nullptr)
{
if (byte_size > 0)
{
size_t allocation_size = byte_size + alignment;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool;
size_t mod = size_t(m_aligned_buffer_pool) % alignment;
if (mod != 0)
{
m_aligned_buffer_pool += (alignment - mod);
}
}
}
runtime::cpu::MemoryHandler::~MemoryHandler()
{
if (m_allocated_buffer_pool != nullptr)
{
free(m_allocated_buffer_pool);
}
}
// ----------------------------------------------------------------------------
// 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 <cstddef>
#include <memory>
namespace ngraph
{
namespace runtime
{
namespace cpu
{
class MemoryHandler;
}
}
}
class ngraph::runtime::cpu::MemoryHandler
{
public:
MemoryHandler(size_t pool_size, size_t alignment);
~MemoryHandler();
void* get_ptr(size_t offset) const { return m_aligned_buffer_pool + offset; }
private:
char* m_allocated_buffer_pool;
char* m_aligned_buffer_pool;
};
...@@ -20,35 +20,47 @@ ...@@ -20,35 +20,47 @@
using namespace ngraph; using namespace ngraph;
using namespace std; 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, runtime::cpu::CPUTensorView::CPUTensorView(const ngraph::element::Type& element_type,
const Shape& shape) const Shape& shape)
: runtime::TensorView(std::make_shared<ngraph::descriptor::PrimaryTensorView>( : runtime::TensorView(std::make_shared<ngraph::descriptor::PrimaryTensorView>(
std::make_shared<ngraph::TensorViewType>(element_type, shape), "external", true, true)) std::make_shared<ngraph::TensorViewType>(element_type, shape), "external", true, true))
, m_allocated_buffer_pool(nullptr)
, m_aligned_buffer_pool(nullptr)
{ {
m_descriptor->set_tensor_view_layout( m_descriptor->set_tensor_view_layout(
std::make_shared<ngraph::descriptor::layout::DenseTensorViewLayout>(*m_descriptor)); std::make_shared<ngraph::descriptor::layout::DenseTensorViewLayout>(*m_descriptor));
m_buffer_size = m_descriptor->get_tensor_view_layout()->get_size() * element_type.size(); 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); if (m_buffer_size > 0)
{
size_t allocation_size = m_buffer_size + runtime::cpu::alignment;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool;
size_t mod = size_t(m_aligned_buffer_pool) % alignment;
if (mod != 0)
{
m_aligned_buffer_pool += (alignment - mod);
}
}
} }
runtime::cpu::CPUTensorView::~CPUTensorView() runtime::cpu::CPUTensorView::~CPUTensorView()
{ {
free_aligned_buffer(m_allocated); if (m_allocated_buffer_pool != nullptr)
{
free(m_allocated_buffer_pool);
}
} }
char* runtime::cpu::CPUTensorView::get_data_ptr() char* runtime::cpu::CPUTensorView::get_data_ptr()
{ {
return m_buffer; return m_aligned_buffer_pool;
} }
const char* runtime::cpu::CPUTensorView::get_data_ptr() const const char* runtime::cpu::CPUTensorView::get_data_ptr() const
{ {
return m_buffer; return m_aligned_buffer_pool;
} }
void runtime::cpu::CPUTensorView::write(const void* source, size_t tensor_offset, size_t n) void runtime::cpu::CPUTensorView::write(const void* source, size_t tensor_offset, size_t n)
......
...@@ -52,7 +52,7 @@ public: ...@@ -52,7 +52,7 @@ public:
void read(void* p, size_t tensor_offset, size_t n) const override; void read(void* p, size_t tensor_offset, size_t n) const override;
private: private:
char* m_allocated; char* m_allocated_buffer_pool;
char* m_buffer; char* m_aligned_buffer_pool;
size_t m_buffer_size; size_t m_buffer_size;
}; };
...@@ -19,23 +19,26 @@ ...@@ -19,23 +19,26 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "ngraph/codegen/compiler.hpp" #include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
using namespace std; using namespace std;
using namespace ngraph;
TEST(codegen, simple_return) TEST(codegen, simple_return)
{ {
constexpr auto name = "test.cpp";
constexpr auto source = R"(extern "C" int test() { return 2+5; })"; constexpr auto source = R"(extern "C" int test() { return 2+5; })";
ngraph::codegen::execution_state estate; codegen::Compiler compiler;
auto module = estate.compile(source, name); codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module); ASSERT_NE(nullptr, module);
estate.add_module(module); execution_engine.add_module(module);
estate.finalize(); execution_engine.finalize();
auto func = estate.find_function<int()>("test"); auto func = execution_engine.find_function<int()>("test");
ASSERT_NE(nullptr, func); ASSERT_NE(nullptr, func);
int result = func(); int result = func();
...@@ -44,18 +47,19 @@ TEST(codegen, simple_return) ...@@ -44,18 +47,19 @@ TEST(codegen, simple_return)
TEST(codegen, pass_args) TEST(codegen, pass_args)
{ {
constexpr auto name = "test.cpp";
constexpr auto source = R"(extern "C" int test(int a, int b) { return a+b; })"; constexpr auto source = R"(extern "C" int test(int a, int b) { return a+b; })";
ngraph::codegen::execution_state estate; codegen::Compiler compiler;
auto module = estate.compile(source, name); codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module); ASSERT_NE(nullptr, module);
estate.add_module(module); execution_engine.add_module(module);
estate.finalize(); execution_engine.finalize();
auto func = estate.find_function<int(int, int)>("test"); auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func); ASSERT_NE(nullptr, func);
int result = func(20, 22); int result = func(20, 22);
...@@ -64,7 +68,6 @@ TEST(codegen, pass_args) ...@@ -64,7 +68,6 @@ TEST(codegen, pass_args)
TEST(codegen, include) TEST(codegen, include)
{ {
constexpr auto name = "test.cpp";
constexpr auto source = constexpr auto source =
R"( R"(
#include <cmath> #include <cmath>
...@@ -74,15 +77,17 @@ TEST(codegen, include) ...@@ -74,15 +77,17 @@ TEST(codegen, include)
} }
)"; )";
ngraph::codegen::execution_state estate; codegen::Compiler compiler;
auto module = estate.compile(source, name); codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module); ASSERT_NE(nullptr, module);
estate.add_module(module); execution_engine.add_module(module);
estate.finalize(); execution_engine.finalize();
auto func = estate.find_function<int(int, int)>("test"); auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func); ASSERT_NE(nullptr, func);
int result = func(20, 2); int result = func(20, 2);
......
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