benchmark folder has been removed from the root dir, README update, measure_time.hpp comments
This commit is contained in:
parent
d4e3c4cd10
commit
0198b37f21
86
README.md
86
README.md
@ -14,82 +14,10 @@ Some code contains linux-specific libraries and the build is only supported
|
||||
on a 64 bit linux kernel.
|
||||
|
||||
* linux
|
||||
* clang 3.5 or Gcc 4.8 (good c++11 support, especially lock free atomics)
|
||||
* boost 1.55 (or something, probably works with almost anything)
|
||||
* lexertl (2015-07-14)
|
||||
* lemon (parser generator)
|
||||
* catch (for compiling tests)
|
||||
|
||||
### Bolt
|
||||
|
||||
sudo apt-get install libssl-dev
|
||||
|
||||
## build
|
||||
```
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DRUNTIME_ASSERT=OFF -DTHROW_EXCEPTION_ON_ERROR=OFF -DNDEBUG=OFF ..
|
||||
|
||||
# Flags:
|
||||
# -DCMAKE_C_COMPILER=clang
|
||||
# -DCMAKE_CXX_COMPILER=clang++
|
||||
# -DRUNTIME_ASSERT=OFF
|
||||
# -DTHROW_EXCEPTION_ON_ERROR=OFF
|
||||
# -DNDEBUG=ON
|
||||
# -DCMAKE_BUILD_TYPE:STRING=debug
|
||||
# -DCMAKE_BUILD_TYPE:STRING=release
|
||||
|
||||
make
|
||||
ctest
|
||||
ctest -V
|
||||
ctest -R test_name
|
||||
ctest -R unit
|
||||
ctest -R concurrent
|
||||
ctest -R concurrent --parallel 4
|
||||
```
|
||||
|
||||
## Proof of concept
|
||||
|
||||
### Dressipi
|
||||
|
||||
Run command:
|
||||
```
|
||||
cd build/poc
|
||||
MEMGRAPH_CONFIG=/path/to/config/memgraph.yaml ./poc_astar -v "dressipi/graph_nodes_export.csv" -e "dressipi/graph_edges_export.csv"
|
||||
```
|
||||
|
||||
### Powerlinx
|
||||
|
||||
Run command:
|
||||
```
|
||||
cd build/poc
|
||||
MEMGRAPH_CONFIG=/path/to/config/memgraph.yaml ./profile -d ";" -v "node_account.csv" -v "node_company.csv" -v "node_opportunity.csv" -v "node_personnel.csv" -e "rel_created.csv" -e "rel_has_match.csv" -e "rel_interested_in.csv" -e "rel_is_employee.csv" -e "rel_partnered_with.csv" -e "rel_reached_to.csv" -e "rel_searched_and_clicked.csv" -e "rel_viewed.csv" -e "rel_works_in.csv"
|
||||
```
|
||||
|
||||
# Custom test build example
|
||||
clang++ -std=c++1y -o concurrent_skiplist ../tests/concurrent/skiplist.cpp -pg -I../src/ -I../libs/fmt -Lfmt-prefix/src/fmt-build/fmt -lfmt -lpthread
|
||||
|
||||
# TODO
|
||||
* implement basic subset of queries:
|
||||
* create node
|
||||
* create edge
|
||||
* find node
|
||||
* find edge
|
||||
* update node
|
||||
* update edge
|
||||
* delete node
|
||||
* delete edge
|
||||
|
||||
* implement index
|
||||
* label index
|
||||
* type index
|
||||
* property index
|
||||
|
||||
* from header only approach to .hpp + .cpp
|
||||
* query engine has to be statically linked with the rest of the code
|
||||
|
||||
* unit test of queries that are manually implemented
|
||||
* src/query_engine/main_queries.cpp -> tests/unit/manual_queries
|
||||
|
||||
* unit test of query_engine
|
||||
|
||||
* console with history
|
||||
* clang 3.8 (good c++11 support, especially lock free atomics)
|
||||
* antlr (compiler frontend)
|
||||
* cppitertools
|
||||
* fmt format
|
||||
* google benchmark
|
||||
* google test
|
||||
* yaml-cpp
|
||||
|
1
benchmark/.gitignore
vendored
1
benchmark/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.out
|
@ -1,58 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include "utils/memory/allocator.hpp"
|
||||
#include "utils/memory/maker.hpp"
|
||||
|
||||
struct TestStruct
|
||||
{
|
||||
TestStruct(int a, int b, int c, int d)
|
||||
: a(a), b(b), c(c), d(d) {}
|
||||
|
||||
int a, b, c, d;
|
||||
};
|
||||
|
||||
void test_classic(int N)
|
||||
{
|
||||
TestStruct** xs = new TestStruct*[N];
|
||||
|
||||
for(int i = 0; i < N; ++i)
|
||||
xs[i] = new TestStruct(i, i, i, i);
|
||||
|
||||
for(int i = 0; i < N; ++i)
|
||||
delete xs[i];
|
||||
|
||||
delete[] xs;
|
||||
}
|
||||
|
||||
void test_fast(int N)
|
||||
{
|
||||
TestStruct** xs = new TestStruct*[N];
|
||||
|
||||
for(int i = 0; i < N; ++i)
|
||||
xs[i] = makeme<TestStruct>(i, i, i, i);
|
||||
|
||||
for(int i = 0; i < N; ++i)
|
||||
delete xs[i];
|
||||
|
||||
delete[] xs;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
constexpr int n_threads = 256;
|
||||
constexpr int N = 80000000 / n_threads;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for(int i = 0; i < n_threads; ++i)
|
||||
threads.push_back(std::thread(test_fast, N));
|
||||
|
||||
for(auto& thread : threads){
|
||||
thread.join();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
neo4j-driver==1.0.2
|
@ -1,2 +0,0 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
@ -1,17 +0,0 @@
|
||||
#include "data_structures/bitset/dynamic_bitset.hpp"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("Dynamic bitset basic functionality") {
|
||||
DynamicBitset<> db;
|
||||
db.set(222555, 1);
|
||||
bool value = db.at(222555, 1);
|
||||
REQUIRE(value == true);
|
||||
|
||||
db.set(32, 1);
|
||||
value = db.at(32, 1);
|
||||
REQUIRE(value == true);
|
||||
|
||||
db.clear(32, 1);
|
||||
value = db.at(32, 1);
|
||||
REQUIRE(value == false);
|
||||
}
|
95
src/utils/measure_time.hpp
Normal file
95
src/utils/measure_time.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
#include <utility>
|
||||
|
||||
namespace utils {
|
||||
|
||||
using ms = std::chrono::milliseconds;
|
||||
|
||||
/**
|
||||
* Casts the time difference into DurationUnit (default values is
|
||||
* std::chrono::nanoseconds).
|
||||
*
|
||||
* @tparam DurationUnit type of return value
|
||||
* @param delta time difference
|
||||
* @return time difference in DurationUnit
|
||||
*/
|
||||
template <typename DurationUnit = std::chrono::nanoseconds>
|
||||
auto to_duration(const std::chrono::duration<long, std::nano> &delta) {
|
||||
return std::chrono::duration_cast<DurationUnit>(delta).count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures time for the function call.
|
||||
*
|
||||
* @tparam DurationUnit unit of returned value
|
||||
* @param func function to execute
|
||||
* @param args function arguments
|
||||
* @return duration of a function call
|
||||
*/
|
||||
template <typename DurationUnit, typename F, typename... Args>
|
||||
auto measure_time(F func, Args &&... args) {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
func(std::forward<Args>(args)...);
|
||||
return to_duration<DurationUnit>(std::chrono::high_resolution_clock::now() -
|
||||
start_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stopwatch
|
||||
*
|
||||
* idea from Optimized C++ Kurt Guntheroth 2016
|
||||
*
|
||||
* The instance of this class can return delta time from a single start point.
|
||||
* The start point in time is stored within the object.
|
||||
*/
|
||||
class Stopwatch {
|
||||
public:
|
||||
/**
|
||||
* Initializes start point to system clock min.
|
||||
*/
|
||||
Stopwatch() : start_(std::chrono::system_clock::time_point::min()) {}
|
||||
|
||||
/**
|
||||
* Set start point to system clock min.
|
||||
*/
|
||||
void Clear() { start_ = std::chrono::system_clock::time_point::min(); }
|
||||
|
||||
/**
|
||||
* If start isn't system clock min than the Stopwatch has been started.
|
||||
*
|
||||
* @return bool is the Stopwatch started.
|
||||
*/
|
||||
auto IsStarted() const {
|
||||
return (start_ != std::chrono::system_clock::time_point::min());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set start point to the current time.
|
||||
*/
|
||||
void Start() { start_ = std::chrono::system_clock::now(); }
|
||||
|
||||
/**
|
||||
* @return elapsed time in milliseconds
|
||||
* if the Stopwatch isn't active returns 0
|
||||
*/
|
||||
auto GetMs() {
|
||||
if (IsStarted()) {
|
||||
std::chrono::system_clock::duration diff;
|
||||
diff = std::chrono::system_clock::now() - start_;
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(diff);
|
||||
}
|
||||
return std::chrono::milliseconds(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty destructor.
|
||||
*/
|
||||
~Stopwatch() {}
|
||||
|
||||
private:
|
||||
std::chrono::system_clock::time_point start_;
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using ms = std::chrono::milliseconds;
|
@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <ratio>
|
||||
#include <utility>
|
||||
|
||||
#include "utils/time/time.hpp"
|
||||
|
||||
#define time_now() std::chrono::high_resolution_clock::now()
|
||||
|
||||
template <typename DurationUnit = std::chrono::nanoseconds>
|
||||
auto to_duration(const std::chrono::duration<long, std::nano> &delta) {
|
||||
return std::chrono::duration_cast<DurationUnit>(delta).count();
|
||||
}
|
||||
|
||||
template <typename DurationUnit, typename F, typename... Args>
|
||||
auto timer(F func, Args &&... args) {
|
||||
auto start_time = time_now();
|
||||
func(std::forward<Args>(args)...);
|
||||
return to_duration<DurationUnit>(time_now() - start_time);
|
||||
}
|
||||
|
||||
// idea from Optimized C++ Kurt Guntheroth 2016
|
||||
// TODO: make more modular and easier to use
|
||||
class Stopwatch {
|
||||
public:
|
||||
Stopwatch() : start(std::chrono::system_clock::time_point::min()) {}
|
||||
|
||||
void Clear() { start = std::chrono::system_clock::time_point::min(); }
|
||||
|
||||
bool IsStarted() const {
|
||||
return (start != std::chrono::system_clock::time_point::min());
|
||||
}
|
||||
|
||||
void Start() { start = std::chrono::system_clock::now(); }
|
||||
|
||||
unsigned long GetMs() {
|
||||
if (IsStarted()) {
|
||||
std::chrono::system_clock::duration diff;
|
||||
diff = std::chrono::system_clock::now() - start;
|
||||
return (unsigned)(std::chrono::duration_cast<ms>(diff).count());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
~Stopwatch() { std::cout << "Time: " << GetMs() << "ms" << std::endl; }
|
||||
|
||||
private:
|
||||
std::chrono::system_clock::time_point start;
|
||||
};
|
@ -8,12 +8,15 @@
|
||||
|
||||
#include "logging/default.hpp"
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* @class Timer
|
||||
*
|
||||
* @brief The timer contains counter and handler.
|
||||
* @brief The timer contains counter and handler which is executed when the time
|
||||
* exceedes.
|
||||
*
|
||||
* With every clock interval the counter should be decresed for
|
||||
* With every clock interval the counter should be decreased for
|
||||
* delta count. Delta count is one for now but it should be a variable in the
|
||||
* near future. The handler is function that will be called when counter
|
||||
* becomes zero or smaller than zero.
|
||||
@ -151,3 +154,4 @@ class TimerScheduler {
|
||||
std::thread run_thread;
|
||||
std::atomic<bool> is_running;
|
||||
};
|
||||
}
|
||||
|
58
tests/benchmark/allocator.cpp
Normal file
58
tests/benchmark/allocator.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/measure_time.hpp"
|
||||
#include "utils/memory/allocator.hpp"
|
||||
#include "utils/memory/maker.hpp"
|
||||
|
||||
struct TestStructure {
|
||||
TestStructure(int a, int b, int c, int d) : a(a), b(b), c(c), d(d) {}
|
||||
int a, b, c, d;
|
||||
};
|
||||
|
||||
void test_classic(int N) {
|
||||
TestStructure** xs = new TestStructure*[N];
|
||||
for (int i = 0; i < N; ++i) xs[i] = new TestStructure(i, i, i, i);
|
||||
for (int i = 0; i < N; ++i) delete xs[i];
|
||||
delete[] xs;
|
||||
}
|
||||
|
||||
void test_fast(int N) {
|
||||
TestStructure** xs = new TestStructure*[N];
|
||||
for (int i = 0; i < N; ++i) xs[i] = makeme<TestStructure>(i, i, i, i);
|
||||
for (int i = 0; i < N; ++i) delete xs[i];
|
||||
delete[] xs;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
constexpr int n_threads = 32;
|
||||
constexpr int N = 80000000 / n_threads;
|
||||
|
||||
auto elapsed_classic = utils::measure_time<std::chrono::milliseconds>([&]() {
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < n_threads; ++i)
|
||||
threads.push_back(std::thread(test_classic, N));
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
});
|
||||
std::cout << "Classic (new): " << elapsed_classic << "ms" << std::endl;
|
||||
|
||||
auto elapsed_fast = utils::measure_time<std::chrono::milliseconds>([&]() {
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < n_threads; ++i)
|
||||
threads.push_back(std::thread(test_fast, N));
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
});
|
||||
std::cout << "Fast (fast allocator): " << elapsed_fast << "ms" << std::endl;
|
||||
permanent_assert(elapsed_fast < elapsed_classic,
|
||||
"Custom fast allocator "
|
||||
"has to perform faster on simple array allocation");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
#define LOG_NO_INFO 1
|
||||
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "query/preprocessor.hpp"
|
||||
#include "utils/time/timer.hpp"
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "utils/timer/timer.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace utils;
|
||||
|
||||
/**
|
||||
* Creates a test timer which will log timeout message at the timeout event.
|
Loading…
Reference in New Issue
Block a user