Commit 64ac3775 authored by Jayaram Bobba's avatar Jayaram Bobba Committed by Scott Cyphers

Enable DEX only build of ngraph (#1424)

* Optionally get rid of codegen from the CPU backend

* Rename option variable

* Merge fixes

* Merge

* Remove extra changes

* remove dex only exclusions (#1429)

* Unconditionally pick  m_direct_execution if NGRAPH_DEX_ONLY

* Style fix
parent 6a6fd41a
......@@ -17,6 +17,7 @@
cmake_minimum_required (VERSION 3.1)
include(cmake/Modules/git_tags.cmake)
NGRAPH_GET_VERSION_LABEL()
string(REGEX MATCH "([0-9]+)\.([0-9]+)\.([0-9]+)" NGRAPH_VERSION_SHORT "${NGRAPH_VERSION_LABEL}")
......@@ -90,6 +91,7 @@ option(NGRAPH_INTERPRETER_ENABLE "Control the building of the INTERPRETER backen
option(NGRAPH_DISTRIBUTED_ENABLE "Add distributed mode to the CPU backend" FALSE)
option(NGRAPH_DEBUG_ENABLE "Enable output for NGRAPH_DEBUG statements" FALSE)
option(NGRAPH_ONNX_IMPORT_ENABLE "Enable ONNX importer" FALSE)
option(NGRAPH_DEX_ONLY "Build CPU DEX without codegen" FALSE)
if (NGRAPH_ONNX_IMPORT_ENABLE)
option(NGRAPH_USE_SYSTEM_PROTOBUF "Use system provided Protobuf shared object" FALSE)
......@@ -232,11 +234,13 @@ include(cmake/external_gtest.cmake)
include(cmake/external_json.cmake)
include(cmake/external_eigen.cmake)
include(cmake/external_mkldnn.cmake)
if (NGRAPH_USE_PREBUILT_LLVM OR DEFINED LLVM_TARBALL_URL)
include(cmake/external_llvm_prebuilt.cmake)
else()
include(cmake/external_llvm.cmake)
endif()
include(cmake/external_tbb.cmake)
if (NGRAPH_HALIDE)
......
......@@ -19,6 +19,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIN_NGRAPH_LIBRARY")
include_directories(ngraph)
add_subdirectory(resource)
add_subdirectory(ngraph)
if (NGRAPH_TOOLS_ENABLE)
......
......@@ -71,7 +71,7 @@ add_custom_target(header_resource
# The conditional is a hack. I want to use EXCLUDE_FROM_ALL and OPTIONAL but that does not
# seem to be working for me.
if (NGRAPH_CPU_ENABLE OR NGRAPH_GPU_ENABLE)
if ((NGRAPH_CPU_ENABLE AND NOT NGRAPH_DEX_ONLY) OR NGRAPH_GPU_ENABLE)
add_library(codegen SHARED ${SRC})
set_target_properties(codegen PROPERTIES VERSION ${NGRAPH_VERSION} SOVERSION ${NGRAPH_API_VERSION})
add_dependencies(codegen header_resource libmkldnn libeigen)
......
......@@ -18,10 +18,7 @@ set(SRC
cpu_backend.cpp
cpu_builder.cpp
cpu_call_frame.cpp
cpu_emitter.cpp
cpu_external_function.cpp
cpu_kernel_emitters.cpp
cpu_kernel_utils.cpp
cpu_kernels.cpp
cpu_layout_descriptor.cpp
cpu_tensor_view_wrapper.cpp
......@@ -93,6 +90,15 @@ set(SRC
pass/cpu_workspace_insertion.cpp
)
if (NOT NGRAPH_DEX_ONLY)
set(SRC
${SRC}
cpu_emitter.cpp
cpu_kernel_emitters.cpp
cpu_kernel_utils.cpp
)
endif()
if (NGRAPH_TBB_ENABLE)
include(${TBB_ROOT}/cmake/TBBBuild.cmake)
tbb_build(TBB_ROOT ${TBB_ROOT} MAKE_ARGS tbb_build_dir=${CMAKE_CURRENT_BINARY_DIR}/tbb_build
......@@ -127,6 +133,9 @@ if (NGRAPH_CPU_ENABLE)
add_library(cpu_backend SHARED ${SRC})
set_target_properties(cpu_backend PROPERTIES VERSION ${NGRAPH_VERSION} SOVERSION ${NGRAPH_API_VERSION})
if (NGRAPH_DEX_ONLY)
target_compile_definitions(cpu_backend PRIVATE "NGRAPH_DEX_ONLY")
endif()
if(NGRAPH_DISTRIBUTED_ENABLE)
find_package(MPI REQUIRED)
......@@ -137,7 +146,10 @@ if (NGRAPH_CPU_ENABLE)
endif()
add_dependencies(cpu_backend ext_mkldnn ext_eigen)
target_link_libraries(cpu_backend PUBLIC ngraph codegen libmkldnn libeigen libjson libtbb)
target_link_libraries(cpu_backend PUBLIC ngraph libmkldnn libeigen libjson libtbb)
if (NOT NGRAPH_DEX_ONLY)
target_link_libraries(cpu_backend PUBLIC codegen)
endif()
target_include_directories(cpu_backend SYSTEM PUBLIC libmkldnn)
set_target_properties(cpu_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${NGRAPH_BUILD_DIR})
......
......@@ -67,7 +67,9 @@ bool runtime::cpu::CPU_Backend::compile(shared_ptr<Function> func)
if (instance.m_external_function == nullptr)
{
instance.m_external_function = make_shared<CPU_ExternalFunction>(func);
#if !defined(NGRAPH_DEX_ONLY)
instance.m_external_function->m_emit_timing = instance.m_performance_counters_enabled;
#endif
auto cf = instance.m_external_function->make_call_frame();
instance.m_call_frame = dynamic_pointer_cast<CPU_CallFrame>(cf);
}
......@@ -96,6 +98,8 @@ void runtime::cpu::CPU_Backend::remove_compiled_function(shared_ptr<Function> fu
m_function_map.erase(func);
}
#if !defined(NGRAPH_DEX_ONLY)
void runtime::cpu::CPU_Backend::enable_performance_data(shared_ptr<Function> func, bool enable)
{
FunctionInstance& instance = m_function_map[func];
......@@ -139,3 +143,5 @@ vector<runtime::PerformanceCounter>
}
return rc;
}
#endif
......@@ -52,9 +52,12 @@ namespace ngraph
const std::vector<std::shared_ptr<runtime::TensorView>>& inputs) override;
void remove_compiled_function(std::shared_ptr<Function> func) override;
#if !defined(NGRAPH_DEX_ONLY)
void enable_performance_data(std::shared_ptr<Function> func, bool enable) override;
std::vector<PerformanceCounter>
get_performance_data(std::shared_ptr<Function> func) const override;
#endif
private:
class FunctionInstance
......
......@@ -33,9 +33,13 @@
#pragma clang diagnostic pop
#include <tbb/flow_graph.h>
#if !defined(NGRAPH_DEX_ONLY)
#include "ngraph/codegen/code_writer.hpp"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
#endif
#include "ngraph/descriptor/input.hpp"
#include "ngraph/descriptor/output.hpp"
#include "ngraph/descriptor/primary_tensor_view.hpp"
......@@ -160,23 +164,34 @@
using namespace std;
using namespace ngraph;
static const string s_output_dir = "cpu_codegen";
runtime::cpu::CPU_ExternalFunction::CPU_ExternalFunction(
const shared_ptr<ngraph::Function>& function, bool release_function)
: m_function(function)
, m_release_function(release_function)
, m_use_tbb(std::getenv("NGRAPH_CPU_USE_TBB") != nullptr)
, m_compiled_function(nullptr)
#if !defined(NGRAPH_DEX_ONLY)
, m_is_compiled(false)
, m_emit_timing(false)
#endif
, m_function_name(function->get_name())
, m_is_built(false)
#if !defined(NGRAPH_DEX_ONLY)
, m_direct_execution(std::getenv("NGRAPH_DEX") != nullptr)
#else
, m_direct_execution(true)
#endif
{
}
static void
generate_isnan_isinf_check(codegen::CodeWriter& writer,
std::shared_ptr<Node> node,
const std::vector<ngraph::runtime::cpu::TensorViewWrapper>& out,
const char* funcname)
runtime::cpu::CPU_ExternalFunction::~CPU_ExternalFunction()
{
auto ctype = node->get_element_type().c_type_string();
writer << "{ // A " << funcname << " for" << node->get_name() << "\n";
writer.indent++;
writer << " ngraph::check_fp_values_" << funcname << "(\"" << node->get_name() << "\", ("
<< ctype << "*)" << out[0].get_name() << ", " << out[0].get_size() << ");\n";
writer.indent--;
writer << "}\n";
}
#if !defined(NGRAPH_DEX_ONLY)
static const string s_output_dir = "cpu_codegen";
class StaticInitializers
{
public:
......@@ -322,22 +337,19 @@ static const runtime::cpu::OpMap dispatcher{
{TI(ngraph::op::LRN), &runtime::cpu::CPU_Emitter::emit<ngraph::op::LRN>},
};
runtime::cpu::CPU_ExternalFunction::CPU_ExternalFunction(
const shared_ptr<ngraph::Function>& function, bool release_function)
: m_function(function)
, m_release_function(release_function)
, m_is_compiled(false)
, m_compiled_function(nullptr)
, m_emit_timing(false)
, m_use_tbb(std::getenv("NGRAPH_CPU_USE_TBB") != nullptr)
, m_function_name(function->get_name())
, m_is_built(false)
, m_direct_execution(std::getenv("NGRAPH_DEX") != nullptr)
{
}
runtime::cpu::CPU_ExternalFunction::~CPU_ExternalFunction()
static void
generate_isnan_isinf_check(codegen::CodeWriter& writer,
std::shared_ptr<Node> node,
const std::vector<ngraph::runtime::cpu::TensorViewWrapper>& out,
const char* funcname)
{
auto ctype = node->get_element_type().c_type_string();
writer << "{ // A " << funcname << " for" << node->get_name() << "\n";
writer.indent++;
writer << " ngraph::check_fp_values<" << ctype << "," << funcname << "> (\"" << node->get_name()
<< "\", (" << ctype << "*)" << out[0].get_name() << ", " << out[0].get_size() << ");\n";
writer.indent--;
writer << "}\n";
}
void runtime::cpu::CPU_ExternalFunction::compile()
......@@ -978,6 +990,8 @@ using namespace ngraph::runtime;
}
}
#endif
bool runtime::cpu::CPU_ExternalFunction::computes_result(Node* node)
{
for (size_t i = 0; i < node->get_output_size(); i++)
......@@ -1507,10 +1521,12 @@ void*& runtime::cpu::CPU_ExternalFunction::get_tensor_data(const std::string& na
shared_ptr<ngraph::runtime::cpu::CPU_CallFrame>
runtime::cpu::CPU_ExternalFunction::make_call_frame()
{
#if !defined(NGRAPH_DEX_ONLY)
if (!m_is_compiled && !m_direct_execution)
{
compile();
}
#endif
if (!m_is_built && m_direct_execution)
{
......@@ -1533,6 +1549,8 @@ const runtime::cpu::LayoutDescriptorPtrs&
return result_layout_descriptors;
}
#if !defined(NGRAPH_DEX_ONLY)
void runtime::cpu::CPU_ExternalFunction::emit_debug_function_entry(
codegen::CodeWriter& writer,
Node* node,
......@@ -1665,3 +1683,5 @@ string runtime::cpu::CPU_ExternalFunction::strip_comments(const string& s)
}
return out.str();
}
#endif
......@@ -27,9 +27,14 @@
#include <utility>
#include <vector>
#if !defined(NGRAPH_DEX_ONLY)
#include "ngraph/codegen/code_writer.hpp"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
#endif
#include "ngraph/function.hpp"
#include "ngraph/runtime/cpu/cpu_call_frame.hpp"
#include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp"
......@@ -46,6 +51,8 @@ namespace ngraph
class CPU_Emitter;
class CPU_CallFrame;
#if !defined(NGRAPH_DEX_ONLY)
using OpFunction = std::function<void(CPU_ExternalFunction* external_function,
codegen::CodeWriter&,
const ngraph::Node*,
......@@ -53,6 +60,7 @@ namespace ngraph
const std::vector<TensorViewWrapper>& outputs)>;
using OpMap = std::unordered_map<std::type_index, OpFunction>;
#endif
struct OpAttributes
{
......@@ -123,8 +131,13 @@ namespace ngraph
bool is_direct_execution() const { return m_direct_execution; }
protected:
void build();
#if !defined(NGRAPH_DEX_ONLY)
void compile();
#endif
private:
// For non-destructive passthrough kernels, propagate function
// input buffers to internal ops
......@@ -136,9 +149,9 @@ namespace ngraph
void propagate_in_place_output(ngraph::descriptor::Output* res_src_output,
std::string output_name,
bool dex);
bool computes_result(Node* node);
#if !defined(NGRAPH_DEX_ONLY)
void emit_debug_function_entry(codegen::CodeWriter& writer,
Node* node,
const std::vector<TensorViewWrapper>& in,
......@@ -158,17 +171,24 @@ namespace ngraph
const std::unordered_map<const Node*, std::string>& node_cache);
std::string emit_op_as_function(const Node&, const std::string& function_name);
std::string strip_comments(const std::string&);
#endif
void release_function() { m_function = nullptr; }
std::shared_ptr<ngraph::Function> m_function;
bool m_release_function;
bool m_is_compiled;
bool m_use_tbb;
EntryPoint m_compiled_function;
std::unordered_map<std::string, std::string> m_variable_name_map;
#if !defined(NGRAPH_DEX_ONLY)
bool m_is_compiled;
std::unique_ptr<codegen::Compiler> m_compiler;
std::unique_ptr<codegen::ExecutionEngine> m_execution_engine;
bool m_emit_timing;
bool m_use_tbb;
std::unordered_map<std::string, std::string> m_variable_name_map;
std::map<std::string, size_t> m_name_index_map;
// Because we are directly accessing the constant data stored in the
......@@ -176,6 +196,7 @@ namespace ngraph
// so they don't get freed before we are done with them
std::vector<std::shared_ptr<Node>> m_active_constants;
#endif
std::unordered_map<std::string, CPUTensorRole> m_tensor_roles;
LayoutDescriptorPtrs parameter_layout_descriptors;
......
......@@ -14,6 +14,5 @@
# limitations under the License.
# ******************************************************************************
add_subdirectory(compile_benchmark)
add_subdirectory(nbench)
add_subdirectory(reserialize)
# ******************************************************************************
# Copyright 2017-2018 Intel Corporation
#
# 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.
# ******************************************************************************
if (NGRAPH_CPU_ENABLE)
add_executable(compile_benchmark compile_benchmark.cpp)
target_link_libraries(compile_benchmark ngraph cpu_backend)
endif()
/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* 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 <fstream>
#include <ngraph/codegen/compiler.hpp>
#include <ngraph/codegen/execution_engine.hpp>
#include <ngraph/file_util.hpp>
#include <ngraph/util.hpp>
#include <ngraph/util.hpp>
using namespace std;
using namespace ngraph;
void help()
{
cout << R"###(
DESCRIPTION
Benchmark compile process identical to ngraph JIT.
SYNOPSIS
compile_benchmark <filename>
)###" << endl;
}
int main(int argc, char** argv)
{
string source_path;
for (size_t i = 1; i < argc; i++)
{
string arg = argv[i];
if (arg == "-h" || arg == "--help")
{
help();
}
else
{
source_path = arg;
}
}
if (!file_util::exists(source_path))
{
cout << "file '" << source_path << "' not found\n";
help();
return 1;
}
else
{
stopwatch timer;
const string source_string = file_util::read_file_to_string(source_path);
codegen::Compiler compiler;
codegen::ExecutionEngine engine;
timer.start();
auto module = compiler.compile(source_string);
timer.stop();
cout << "compile took " << timer.get_milliseconds() << "ms\n";
timer.start();
engine.add_module(module);
engine.finalize();
timer.stop();
cout << "execution engine took " << timer.get_milliseconds() << "ms\n";
}
return 0;
}
......@@ -63,7 +63,7 @@ add_subdirectory(files)
add_subdirectory(util)
if(NGRAPH_CPU_ENABLE)
set(SRC ${SRC} backend_performance.cpp codegen.cpp cpu_fusion.cpp cpu_test.cpp)
set(SRC ${SRC} backend_performance.cpp cpu_fusion.cpp cpu_test.cpp)
endif()
if(NGRAPH_GPU_ENABLE)
......
/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* 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 <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/codegen/execution_engine.hpp"
using namespace std;
using namespace ngraph;
TEST(codegen, eigen_gpl_test)
{
// In order for this test to pass the in-memory compiler must define EIGEN_MPL2_ONLY
constexpr auto source = R"(
#if not defined(EIGEN_MPL2_ONLY)
#error("must define flag")
#endif
)";
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
}
TEST(DISABLED_codegen, simple_return)
{
constexpr auto source = R"(extern "C" int test() { return 2+5; })";
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
execution_engine.add_module(module);
execution_engine.finalize();
auto func = execution_engine.find_function<int()>("test");
ASSERT_NE(nullptr, func);
int result = func();
EXPECT_EQ(7, result);
}
TEST(DISABLED_codegen, pass_args)
{
constexpr auto source = R"(extern "C" int test(int a, int b) { return a+b; })";
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
execution_engine.add_module(module);
execution_engine.finalize();
auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func);
int result = func(20, 22);
EXPECT_EQ(42, result);
}
TEST(DISABLED_codegen, include)
{
constexpr auto source =
R"(
#include <cmath>
extern "C" int test(int a, int b)
{
return (int)pow((double)a,(double)b);
}
)";
codegen::Compiler compiler;
codegen::ExecutionEngine execution_engine;
auto module = compiler.compile(source);
ASSERT_NE(nullptr, module);
execution_engine.add_module(module);
execution_engine.finalize();
auto func = execution_engine.find_function<int(int, int)>("test");
ASSERT_NE(nullptr, func);
int result = func(20, 2);
EXPECT_EQ(400, result);
}
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