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

View File

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

View File

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

View File

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

View File

@ -3,31 +3,48 @@
#include "utils/string/file.hpp"
#include "template_engine/engine.hpp"
#include "config/config.hpp"
#include "utils/log/logger.hpp"
#include "traverser/query_traverser.hpp"
using std::string;
class CodeGenerator
{
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 =
config::Config::instance()[config::TEMPLATE_CPU_PATH];
string template_path = CONFIG(config::TEMPLATE_CPU_HPP_PATH);
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(
template_file,
{
{"class_name", "Code"},
{"query", "\"" + query + "\""},
{"code", "cout << \"test code\" << endl;"}
{"stripped_hash", std::to_string(stripped_hash)},
{"data_type", "int"}
}
);
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);
}
private:
template_engine::TemplateEngine template_engine;
Logger log;
QueryTraverser traverser;
};

View File

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

View File

@ -1,8 +1,8 @@
#!/bin/bash
# TODO: create Makefile or cmake script
cd compiled/cpu
clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC
cd ../..
# cd compiled/cpu
# clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC
# 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../ 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
#include <string>
#include "query_engine/query_result.hpp"
#include "database/db.hpp"
class ICodeCPU
{
public:
virtual std::string query() const = 0;
virtual void run(Db& db) const = 0;
virtual QueryResult::sptr run(Db& db) = 0;
virtual ~ICodeCPU() {}
};
typedef ICodeCPU* (*produce_t)();
typedef void (*destruct_t)(ICodeCPU*);
using produce_t = ICodeCPU*(*)();
using destruct_t = void (*)(ICodeCPU*);

View File

@ -1,9 +1,15 @@
#pragma once
#include <string>
#include <memory>
class QueryResult
{
public:
using sptr = std::shared_ptr<QueryResult>;
QueryResult(std::string result) :
result(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"
// TODO generate with the template engine
// #include "storage/model/properties/jsonwriter.hpp"
using std::cout;
using std::endl;
// query: {{query}}
class {{class_name}} : public ICodeCPU
{
public:
std::string query() const override
QueryResult::sptr run(Db& db) override
{
return {{query}};
}
void run(Db& db) const override
{
{{code}}
}
{{code}} }
~{{class_name}}() {}
};
extern "C" ICodeCPU* produce()
{
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
#include <iostream>
#include <typeinfo>
#include <map>
#include "cypher/visitor/traverser.hpp"
#include "storage/model/properties/properties.hpp"
using std::cout;
using std::endl;
class NodeTraverser : public Traverser
struct NodeTraverser : public Traverser
{
struct PropertiesTraverser : public Traverser
Properties traverse(ast::Node& node)
{
PropertiesTraverser(NodeTraverser* node_traverser)
: node_traverser(node_traverser) {}
Traverser::visit(node);
return properties;
}
// friend NodeTraverser;
void visit(ast::Property& property) override
{
name = property.idn->name;
Traverser::visit(property);
json[name] = value;
}
void visit(ast::String& string) override
{
value = string.value;
}
void visit(ast::Integer& integer) override
{
value = std::to_string(integer.value);
}
void visit(ast::Node& node) override
{
Traverser::visit(node);
node_traverser->json = json;
}
private:
std::string name;
std::string value;
std::map<std::string, std::string> json;
NodeTraverser* node_traverser;
};
public:
// TODO: replace with generic value
std::map<std::string, std::string> json;
void visit(ast::Create& create) override
void visit(ast::Property& property) override
{
auto create_nodes = PropertiesTraverser(this);
create.accept(create_nodes);
};
key = property.idn->name;
Traverser::visit(property);
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
{
flag = Property::Flags::String;
string_value = std::make_shared<String>(string.value);
}
void visit(ast::Integer& integer) override
{
flag = Property::Flags::Int32;
int_value = std::make_shared<Int32>(integer.value);
}
void visit(ast::Node& node) override
{
Traverser::visit(node);
}
private:
std::string key;
Property::Flags flag;
std::shared_ptr<Int32> int_value;
std::shared_ptr<String> string_value;
Properties properties;
};

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)
first = false;
}
handler.finish();
}
private:

View File

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

View File

@ -8,6 +8,10 @@
class Logger
{
public:
Logger(Logger& other) = delete;
Logger(Logger&& other) = delete;
private:
Logger() = default;
// TODO logger name support
@ -16,13 +20,17 @@ public:
// TODO handlers 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);
}
@ -35,3 +43,11 @@ private:
<< text << std::endl;
}
};
#ifdef NOT_LOG_INFO
# define LOG_INFO(_)
#else
# define LOG_INFO(_MESSAGE_) Logger::instance().info(_MESSAGE_);
#endif