Commit 5b75fd3a authored by Robert Kimball's avatar Robert Kimball

compiler update to search for header files and option to cache them

parent aa385dad
...@@ -49,9 +49,14 @@ ...@@ -49,9 +49,14 @@
#include <llvm/ExecutionEngine/SectionMemoryManager.h> #include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include "ngraph/codegen/compiler.hpp" #include "ngraph/codegen/compiler.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/util.hpp"
// TODO: Fix leaks // TODO: Fix leaks
// #define USE_CACHE
using namespace clang; using namespace clang;
using namespace llvm; using namespace llvm;
using namespace llvm::opt; using namespace llvm::opt;
...@@ -59,6 +64,8 @@ using namespace std; ...@@ -59,6 +64,8 @@ using namespace std;
using namespace ngraph::codegen; using namespace ngraph::codegen;
static HeaderCache s_header_cache;
static std::string GetExecutablePath(const char* Argv0) static std::string GetExecutablePath(const char* Argv0)
{ {
// This just needs to be some symbol in the binary; C++ doesn't // This just needs to be some symbol in the binary; C++ doesn't
...@@ -78,6 +85,70 @@ execution_state::~execution_state() ...@@ -78,6 +85,70 @@ execution_state::~execution_state()
{ {
} }
bool execution_state::is_version_number(const string& path)
{
bool rc = true;
vector<string> tokens = ngraph::split(path, '.');
for (string s : tokens)
{
for (char c : s)
{
if (!isdigit(c))
{
rc = false;
}
}
}
return rc;
}
void execution_state::add_header_search_path(HeaderSearchOptions& hso, const string& path)
{
static vector<string> valid_ext = {".h", ".hpp", ".tcc", ""};
#ifdef USE_CACHE
string mapped_path = file_util::path_join("/$BUILTIN", path);
mapped_path = path;
s_header_cache.add_path(mapped_path);
auto func = [&](const std::string& file, bool is_dir) {
if (!is_dir)
{
string ext = file_util::get_file_ext(file);
if (contains(valid_ext, ext))
{
// This is a header file
string relative_name = file.substr(path.size() + 1);
string mapped_name = file_util::path_join(mapped_path, relative_name);
ErrorOr<unique_ptr<MemoryBuffer>> code = MemoryBuffer::getFile(file);
if (error_code ec = code.getError())
{
// throw up
}
s_header_cache.add_file(mapped_name, code.get());
}
}
};
file_util::iterate_files(path, func, true);
#else
hso.AddPath(path, clang::frontend::System, false, false);
#endif
}
void execution_state::use_cached_files(std::unique_ptr<CompilerInstance>& Clang)
{
HeaderSearchOptions& hso = Clang->getInvocation().getHeaderSearchOpts();
for (const string& path : s_header_cache.get_include_paths())
{
hso.AddPath(path, clang::frontend::System, false, false);
}
for (auto& header : s_header_cache.get_header_map())
{
Clang->getPreprocessorOpts().addRemappedFile(header.first, header.second.get());
}
}
std::unique_ptr<llvm::Module> execution_state::compile(const string& source, const string& name) std::unique_ptr<llvm::Module> execution_state::compile(const string& source, const string& name)
{ {
llvm::InitializeAllTargets(); llvm::InitializeAllTargets();
...@@ -113,24 +184,56 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con ...@@ -113,24 +184,56 @@ std::unique_ptr<llvm::Module> execution_state::compile(const string& source, con
Clang->getHeaderSearchOpts().ResourceDir = path; Clang->getHeaderSearchOpts().ResourceDir = path;
} }
auto& HSO = Clang->getInvocation().getHeaderSearchOpts(); HeaderSearchOptions& hso = Clang->getInvocation().getHeaderSearchOpts();
// Add base toolchain-supplied header paths if (s_header_cache.is_valid() == false)
// Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h {
// But that's a private header and isn't part of the public libclang API // Add base toolchain-supplied header paths
// Instead of re-implementing all of that functionality in a custom toolchain // Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h
// just hardcode the paths relevant to frequently used build/test machines for now // But that's a private header and isn't part of the public libclang API
HSO.AddPath(CLANG_BUILTIN_HEADERS_PATH, clang::frontend::System, false, false); // Instead of re-implementing all of that functionality in a custom toolchain
HSO.AddPath("/usr/include/x86_64-linux-gnu", clang::frontend::System, false, false); // just hardcode the paths relevant to frequently used build/test machines for now
HSO.AddPath("/usr/include", clang::frontend::System, false, false); add_header_search_path(hso, CLANG_BUILTIN_HEADERS_PATH);
// Add C++ standard library headers add_header_search_path(hso, "/usr/include/x86_64-linux-gnu");
// Debian-like + GCC 4.8 libstdc++ add_header_search_path(hso, "/usr/include");
HSO.AddPath("/usr/include/x86_64-linux-gnu/c++/4.8", clang::frontend::System, false, false);
HSO.AddPath("/usr/include/c++/4.8", clang::frontend::System, false, false); // Search for headers in
// Debian-like + GCC 5 libstdc++ // /usr/include/x86_64-linux-gnu/c++/N.N
HSO.AddPath("/usr/include/x86_64-linux-gnu/c++/5", clang::frontend::System, false, false); // /usr/include/c++/N.N
HSO.AddPath("/usr/include/c++/5", clang::frontend::System, false, false); // and add them to the header search path
HSO.AddPath(EIGEN_HEADERS_PATH, clang::frontend::System, false, false);
HSO.AddPath(NGRAPH_HEADERS_PATH, clang::frontend::System, false, false); file_util::iterate_files("/usr/include/x86_64-linux-gnu/c++/",
[&](const std::string& file, bool is_dir) {
if (is_dir)
{
string dir_name = file_util::get_file_name(file);
if (is_version_number(dir_name))
{
add_header_search_path(hso, file);
}
}
});
file_util::iterate_files("/usr/include/c++/", [&](const std::string& file, bool is_dir) {
if (is_dir)
{
string dir_name = file_util::get_file_name(file);
if (is_version_number(dir_name))
{
add_header_search_path(hso, file);
}
}
});
add_header_search_path(hso, EIGEN_HEADERS_PATH);
add_header_search_path(hso, NGRAPH_HEADERS_PATH);
#ifdef USE_CACHE
s_header_cache.set_valid();
#endif
}
#ifdef USE_CACHE
use_cached_files(Clang);
#endif
// Language options // Language options
// These are the C++ features needed to compile ngraph headers // These are the C++ features needed to compile ngraph headers
......
...@@ -28,9 +28,16 @@ namespace ngraph ...@@ -28,9 +28,16 @@ namespace ngraph
{ {
class module; class module;
class execution_state; class execution_state;
class HeaderCache;
} }
} }
namespace clang
{
class HeaderSearchOptions;
class CompilerInstance;
}
class ngraph::codegen::module class ngraph::codegen::module
{ {
public: public:
...@@ -73,4 +80,28 @@ private: ...@@ -73,4 +80,28 @@ private:
{ {
return static_cast<signature*>(reinterpret_cast<signature*>(f)); return static_cast<signature*>(reinterpret_cast<signature*>(f));
} }
bool is_version_number(const std::string& path);
void add_header_search_path(clang::HeaderSearchOptions& hso, const std::string& path);
void use_cached_files(std::unique_ptr<clang::CompilerInstance>& Clang);
};
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 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 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)
...@@ -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_AEON_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)
...@@ -159,9 +187,9 @@ vector<char> ngraph::file_util::read_file_contents(const string& path) ...@@ -159,9 +187,9 @@ vector<char> ngraph::file_util::read_file_contents(const string& path)
if (f) if (f)
{ {
char* p = data.data(); char* p = data.data();
size_t remainder = file_size; int remainder = static_cast<int>(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);
......
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