first proposal of compile process

This commit is contained in:
Marko Budiselic 2016-02-10 23:34:49 +01:00
parent 7d8c5a7f7e
commit 6eac9a5ac5
23 changed files with 232 additions and 173 deletions

View File

@ -6,6 +6,7 @@ namespace config
{ {
constexpr const char * COMPILE_CPU_PATH = "compile_cpu_path"; constexpr const char * COMPILE_CPU_PATH = "compile_cpu_path";
constexpr const char * TEMPLATE_CPU_PATH = "template_cpu_path"; constexpr const char * TEMPLATE_CPU_CPP_PATH = "template_cpu_cpp_path";
constexpr const char * TEMPLATE_CPU_HPP_PATH = "template_cpu_hpp_path";
} }

View File

@ -8,6 +8,9 @@
#include "cypher/common.hpp" #include "cypher/common.hpp"
#include "utils/terminate_handler.hpp" #include "utils/terminate_handler.hpp"
// dumping ground for all kind of visitors
#include "query_engine/traverser/create_traverser.hpp"
using std::cout; using std::cout;
using std::endl; using std::endl;
@ -30,8 +33,10 @@ int main(int argc, char *argv[])
// traversers // traversers
auto traverser = get_argument(arguments, "-t", "code"); auto traverser = get_argument(arguments, "-t", "code");
auto print_traverser = Traverser::sptr(new PrintVisitor(cout)); auto print_traverser = Traverser::sptr(new PrintVisitor(cout));
auto create_traverser = Traverser::sptr(new CreateTraverser());
std::map<std::string, Traverser::sptr> traversers = { std::map<std::string, Traverser::sptr> traversers = {
{"print", print_traverser}, {"print", print_traverser},
{"create", create_traverser}
}; };
cypher::Compiler compiler; cypher::Compiler compiler;

View File

@ -7,9 +7,13 @@
template<typename T> template<typename T>
class DynamicLib class DynamicLib
{ {
private:
using produce_t = typename T::produce;
using destruct_t = typename T::destruct;
public: public:
typename T::produce produce_method; produce_t produce_method;
typename T::destruct destruct_method; destruct_t destruct_method;
DynamicLib(const std::string& lib_path) : DynamicLib(const std::string& lib_path) :
lib_path(lib_path) lib_path(lib_path)
@ -20,7 +24,11 @@ public:
typename T::lib_object* instance() typename T::lib_object* instance()
{ {
// TODO singleton, lazy, concurrency // TODO singleton, lazy, concurrency
// ifs are uncommented -> SEGMENTATION FAULT
// TODO debug
// if (dynamic_lib == nullptr)
this->load(); this->load();
// if (dynamic_lib == nullptr)
lib_object = this->produce_method(); lib_object = this->produce_method();
return lib_object; return lib_object;
} }
@ -55,7 +63,7 @@ private:
void load_produce_func() void load_produce_func()
{ {
produce_method = (typename T::produce) dlsym( produce_method = (produce_t) dlsym(
dynamic_lib, dynamic_lib,
T::produce_name.c_str() T::produce_name.c_str()
); );
@ -67,7 +75,7 @@ private:
void load_destruct_func() void load_destruct_func()
{ {
destruct_method = (typename T::destruct) dlsym( destruct_method = (destruct_t) dlsym(
dynamic_lib, dynamic_lib,
T::destruct_name.c_str() T::destruct_name.c_str()
); );

View File

@ -17,6 +17,8 @@ public:
"-I../", "-I../",
"-shared -fPIC" "-shared -fPIC"
); );
// synchronous call
system(compile_command.c_str()); system(compile_command.c_str());
} }
}; };

View File

@ -6,17 +6,22 @@
#include "database/db.hpp" #include "database/db.hpp"
#include "utils/log/logger.hpp" #include "utils/log/logger.hpp"
// preparations before execution
// execution
// postprocess the results
using std::cout;
using std::endl;
class CodeExecutor class CodeExecutor
{ {
public: public:
void execute(ICodeCPU *code_cpu) void execute(ICodeCPU *code_cpu)
{ {
log.info(code_cpu->query()); auto result = code_cpu->run(db);
code_cpu->run(db); cout << result->result << endl;
} }
private: private:
Db db; Db db;
Logger log;
}; };

View File

@ -3,31 +3,48 @@
#include "utils/string/file.hpp" #include "utils/string/file.hpp"
#include "template_engine/engine.hpp" #include "template_engine/engine.hpp"
#include "config/config.hpp" #include "config/config.hpp"
#include "utils/log/logger.hpp" #include "traverser/query_traverser.hpp"
using std::string; using std::string;
class CodeGenerator class CodeGenerator
{ {
public: public:
void generate(const std::string& query, const std::string& path) void generate_hpp(const uint64_t stripped_hash, const std::string& path)
{ {
string template_path = string template_path = CONFIG(config::TEMPLATE_CPU_HPP_PATH);
config::Config::instance()[config::TEMPLATE_CPU_PATH];
string template_file = utils::read_file(template_path.c_str()); string template_file = utils::read_file(template_path.c_str());
// TODO instead of code should be generated code
// use query visitor to build the code
string generated = template_engine.render( string generated = template_engine.render(
template_file, template_file,
{ {
{"class_name", "Code"}, {"stripped_hash", std::to_string(stripped_hash)},
{"query", "\"" + query + "\""}, {"data_type", "int"}
{"code", "cout << \"test code\" << endl;"} }
);
utils::write_file(generated, path);
}
void generate_cpp(const std::string& query,
const uint64_t stripped_hash,
const std::string& path)
{
string template_path = CONFIG(config::TEMPLATE_CPU_CPP_PATH);
string template_file = utils::read_file(template_path.c_str());
traverser.build_tree(query);
string code = traverser.traverse();
string generated = template_engine.render(
template_file,
{
{"class_name", "CodeCPU"},
{"stripped_hash", std::to_string(stripped_hash)},
{"query", query},
{"code", code},
{"return_type", "int"}
} }
); );
utils::write_file(generated, path); utils::write_file(generated, path);
} }
private: private:
template_engine::TemplateEngine template_engine; template_engine::TemplateEngine template_engine;
Logger log; QueryTraverser traverser;
}; };

View File

@ -4,18 +4,21 @@
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
// #define NOT_LOG_INFO
#include "memgraph_dynamic_lib.hpp" #include "memgraph_dynamic_lib.hpp"
#include "query_stripper.hpp" #include "query_stripper.hpp"
#include "code_compiler.hpp" #include "code_compiler.hpp"
#include "code_generator.hpp" #include "code_generator.hpp"
#include "utils/hashing/fnv.hpp" #include "utils/hashing/fnv.hpp"
#include "utils/log/logger.hpp"
#include "config/config.hpp" #include "config/config.hpp"
#include "utils/log/logger.hpp"
using std::string; using std::string;
using std::cout; using std::cout;
using std::endl; using std::endl;
class CodeLoader class CodeLoader
{ {
public: public:
@ -30,10 +33,10 @@ public:
ICodeCPU* load_code_cpu(const string& query) ICodeCPU* load_code_cpu(const string& query)
{ {
auto stripped = stripper.strip(query); auto stripped = stripper.strip(query);
log.info("stripped_query=" + stripped); LOG_INFO("stripped_query=" + stripped);
auto stripped_hash = fnv(stripped); auto stripped_hash = fnv(stripped);
auto hash_string = std::to_string(stripped_hash); auto hash_string = std::to_string(stripped_hash);
log.info("query_hash=" + hash_string); LOG_INFO("query_hash=" + hash_string);
auto code_lib_iter = code_libs.find(stripped_hash); auto code_lib_iter = code_libs.find(stripped_hash);
@ -47,7 +50,7 @@ public:
// TODO load output path from config // TODO load output path from config
auto base_path = config::Config::instance()[config::COMPILE_CPU_PATH]; auto base_path = config::Config::instance()[config::COMPILE_CPU_PATH];
auto path_cpp = base_path + hash_string + ".cpp"; auto path_cpp = base_path + hash_string + ".cpp";
code_generator.generate(query, path_cpp); code_generator.generate_cpp(query, stripped_hash, path_cpp);
// TODO compile generated code // TODO compile generated code
auto path_so = base_path + hash_string + ".so"; auto path_so = base_path + hash_string + ".so";
@ -71,7 +74,6 @@ private:
CodeGenerator code_generator; CodeGenerator code_generator;
CodeCompiler code_compiler; CodeCompiler code_compiler;
Logger log;
sptr_code_lib load_code_lib(const string& path) sptr_code_lib load_code_lib(const string& path)
{ {

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
# TODO: create Makefile or cmake script # TODO: create Makefile or cmake script
cd compiled/cpu # cd compiled/cpu
clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC # clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC
cd ../.. # cd ../..
# clang++ -std=c++1y -g -I../ -I ../lib/yaml-cpp/include main.cpp ../cypher/cypher.cpp -o engine -L ../lib/yaml-cpp/build -l yaml-cpp -l dl # clang++ -std=c++1y -g -I../ -I ../lib/yaml-cpp/include main.cpp ../cypher/cypher.cpp -o engine -L ../lib/yaml-cpp/build -l yaml-cpp -l dl
clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine -l dl clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine.out -l dl -pthread

View File

@ -1,34 +0,0 @@
#include <iostream>
#include <string>
#include "query_engine/i_code_cpu.hpp"
using std::cout;
using std::endl;
class CreateReturn : public ICodeCPU
{
public:
std::string query() const override
{
return "CRETE RETURN QUERY";
}
void run(Db& db) const override
{
cout << db.identifier() << endl;
}
~CreateReturn() {}
};
extern "C" ICodeCPU* produce()
{
return new CreateReturn();
}
extern "C" void destruct(ICodeCPU* p)
{
delete p;
}

View File

@ -1,3 +0,0 @@
# Memgraph test config
compile_cpu_path: ./compiled/cpu/

Binary file not shown.

View File

@ -1,16 +1,14 @@
#pragma once #pragma once
#include <string> #include "query_engine/query_result.hpp"
#include "database/db.hpp" #include "database/db.hpp"
class ICodeCPU class ICodeCPU
{ {
public: public:
virtual std::string query() const = 0; virtual QueryResult::sptr run(Db& db) = 0;
virtual void run(Db& db) const = 0;
virtual ~ICodeCPU() {} virtual ~ICodeCPU() {}
}; };
typedef ICodeCPU* (*produce_t)(); using produce_t = ICodeCPU*(*)();
typedef void (*destruct_t)(ICodeCPU*); using destruct_t = void (*)(ICodeCPU*);

View File

@ -1,9 +1,15 @@
#pragma once #pragma once
#include <string> #include <string>
#include <memory>
class QueryResult class QueryResult
{ {
public: public:
using sptr = std::shared_ptr<QueryResult>;
QueryResult(std::string result) :
result(result) {}
std::string result; std::string result;
}; };

View File

@ -1,37 +0,0 @@
#pragma once
#include "cypher/ast/ast.hpp"
#include "cypher/compiler.hpp"
#include "traverser/node_traverser.hpp"
// The purpose of this class is to find out has
// the query already been compiled into the machine code / c++ code
// in the same pass query arguments should be extracted (e.g. poperties
// or node names)
// if the query has already been comiled into the machine code
// than it shouldn't be compiled again
class QueryTraverser
{
public:
QueryTraverser() = default;
void build_tree(const std::string& query)
{
tree = compiler.syntax_tree(query);
}
void traverse()
{
tree.root->accept(traverser);
for (auto& kv : traverser.json) {
cout << "Key: " << kv.first << ", Value: " << kv.second << endl;
}
}
private:
ast::Ast tree;
cypher::Compiler compiler;
NodeTraverser traverser;
};

View File

@ -3,26 +3,26 @@
#include "query_engine/i_code_cpu.hpp" #include "query_engine/i_code_cpu.hpp"
// TODO generate with the template engine
// #include "storage/model/properties/jsonwriter.hpp"
using std::cout; using std::cout;
using std::endl; using std::endl;
// query: {{query}}
class {{class_name}} : public ICodeCPU class {{class_name}} : public ICodeCPU
{ {
public: public:
std::string query() const override QueryResult::sptr run(Db& db) override
{ {
return {{query}}; {{code}} }
}
void run(Db& db) const override
{
{{code}}
}
~{{class_name}}() {} ~{{class_name}}() {}
}; };
extern "C" ICodeCPU* produce() extern "C" ICodeCPU* produce()
{ {
return new {{class_name}}(); return new {{class_name}}();

View File

@ -0,0 +1,9 @@
#pragma once
#include "query_engine/i_code_cpu.hpp"
class ICodeCPUData : ICodeCPU
{
public:
{{data_type}} data;
};

View File

@ -0,0 +1,41 @@
#pragma once
#include <iostream>
#include <typeinfo>
#include <map>
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/jsonwriter.hpp"
#include "cypher/visitor/traverser.hpp"
#include "node_traverser.hpp"
using std::cout;
using std::endl;
class CreateTraverser : public Traverser
{
public:
std::string code;
Properties properties;
void visit(ast::Create& create) override
{
code = "\t\tauto& t = db.tx_engine.begin();\n";
code += "\t\tauto vertex_accessor = db.graph.vertices.insert(t);\n";
Traverser::visit(create);
};
void visit(ast::Node& node) override
{
Traverser::visit(node);
}
void visit(ast::Return& ret) override
{
code += "\t\tauto properties = vertex_accessor.properties();\n";
code += "\t\tStringBuffer buffer;\n";
code += "\t\tJsonWriter<StringBuffer> writer(buffer);\n";
code += "\t\tproperties.accept(writer);\n";
code += "\t\treturn std::make_shared<QueryResult>(buffer.str());\n";
}
};

View File

@ -1,59 +1,49 @@
#pragma once #pragma once
#include <iostream>
#include <typeinfo>
#include <map>
#include "cypher/visitor/traverser.hpp" #include "cypher/visitor/traverser.hpp"
#include "storage/model/properties/properties.hpp"
using std::cout; struct NodeTraverser : public Traverser
using std::endl;
class NodeTraverser : public Traverser
{ {
struct PropertiesTraverser : public Traverser Properties traverse(ast::Node& node)
{ {
PropertiesTraverser(NodeTraverser* node_traverser) Traverser::visit(node);
: node_traverser(node_traverser) {} return properties;
}
// friend NodeTraverser;
void visit(ast::Property& property) override void visit(ast::Property& property) override
{ {
name = property.idn->name; key = property.idn->name;
Traverser::visit(property); Traverser::visit(property);
json[name] = value; if (flag == Property::Flags::Int32) {
properties.set<Int32>(key, *int_value);
}
if (flag == Property::Flags::String) {
properties.set<String>(key, *string_value);
}
} }
void visit(ast::String& string) override void visit(ast::String& string) override
{ {
value = string.value; flag = Property::Flags::String;
string_value = std::make_shared<String>(string.value);
} }
void visit(ast::Integer& integer) override void visit(ast::Integer& integer) override
{ {
value = std::to_string(integer.value); flag = Property::Flags::Int32;
int_value = std::make_shared<Int32>(integer.value);
} }
void visit(ast::Node& node) override void visit(ast::Node& node) override
{ {
Traverser::visit(node); Traverser::visit(node);
node_traverser->json = json;
} }
private: private:
std::string name; std::string key;
std::string value; Property::Flags flag;
std::map<std::string, std::string> json; std::shared_ptr<Int32> int_value;
NodeTraverser* node_traverser; std::shared_ptr<String> string_value;
}; Properties properties;
public:
// TODO: replace with generic value
std::map<std::string, std::string> json;
void visit(ast::Create& create) override
{
auto create_nodes = PropertiesTraverser(this);
create.accept(create_nodes);
};
}; };

View File

@ -0,0 +1,27 @@
#pragma once
#include "cypher/ast/ast.hpp"
#include "cypher/compiler.hpp"
#include "create_traverser.hpp"
class QueryTraverser
{
public:
QueryTraverser() = default;
void build_tree(const std::string& query)
{
tree = compiler.syntax_tree(query);
}
std::string traverse()
{
tree.root->accept(traverser);
return traverser.code;
}
private:
ast::Ast tree;
cypher::Compiler compiler;
CreateTraverser traverser;
};

View File

@ -53,6 +53,7 @@ public:
if(first) if(first)
first = false; first = false;
} }
handler.finish();
} }
private: private:

View File

@ -45,9 +45,12 @@ public:
if (0 == std::strcmp(key, "compile_cpu_path")) if (0 == std::strcmp(key, "compile_cpu_path"))
return "./compiled/cpu/"; return "./compiled/cpu/";
if (std::strcmp(key, "template_cpu_path") == 0) if (std::strcmp(key, "template_cpu_cpp_path") == 0)
return "./template/template_code_cpu.cpp"; return "./template/template_code_cpu.cpp";
if (std::strcmp(key, "template_cpu_hpp_path") == 0)
return "./template/template_code_cpu.hpp";
throw std::runtime_error("implement me"); throw std::runtime_error("implement me");
// TODO optimize access // TODO optimize access
@ -56,3 +59,5 @@ public:
}; };
} }
#define CONFIG(_KEY_) config::Config::instance()[_KEY_]

View File

@ -8,6 +8,10 @@
class Logger class Logger
{ {
public: public:
Logger(Logger& other) = delete;
Logger(Logger&& other) = delete;
private:
Logger() = default; Logger() = default;
// TODO logger name support // TODO logger name support
@ -17,12 +21,16 @@ public:
// TODO handlers support: // TODO handlers support:
// * log format support // * log format support
void info(const std::string& text) // TODO merge with debug/log.hpp
public:
static Logger& instance()
{ {
stdout_log(text); static Logger logger;
return logger;
} }
void debug(const std::string& text) void info(const std::string& text)
{ {
stdout_log(text); stdout_log(text);
} }
@ -35,3 +43,11 @@ private:
<< text << std::endl; << text << std::endl;
} }
}; };
#ifdef NOT_LOG_INFO
# define LOG_INFO(_)
#else
# define LOG_INFO(_MESSAGE_) Logger::instance().info(_MESSAGE_);
#endif