136 lines
3.8 KiB
C++
136 lines
3.8 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// DuckDB
|
|
//
|
|
// duckdb_benchmark.hpp
|
|
//
|
|
// Author: Mark Raasveldt
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#pragma once
|
|
|
|
#include "benchmark.hpp"
|
|
#include "duckdb.hpp"
|
|
#include "duckdb/main/client_context.hpp"
|
|
#include "test_helpers.hpp"
|
|
#include "duckdb/main/query_profiler.hpp"
|
|
#include "duckdb/common/helper.hpp"
|
|
|
|
namespace duckdb {
|
|
|
|
//! Base class for any state that has to be kept by a Benchmark
|
|
struct DuckDBBenchmarkState : public BenchmarkState {
|
|
DuckDB db;
|
|
Connection conn;
|
|
duckdb::unique_ptr<QueryResult> result;
|
|
|
|
DuckDBBenchmarkState(string path) : db(path.empty() ? nullptr : path.c_str()), conn(db) {
|
|
auto &instance = BenchmarkRunner::GetInstance();
|
|
auto res = conn.Query("PRAGMA threads=" + to_string(instance.threads));
|
|
if (!instance.memory_limit.empty()) {
|
|
res = conn.Query("PRAGMA memory_limit='" + instance.memory_limit + "'");
|
|
D_ASSERT(!res->HasError());
|
|
}
|
|
D_ASSERT(!res->HasError());
|
|
string profiling_mode;
|
|
switch (instance.configuration.profile_info) {
|
|
case BenchmarkProfileInfo::NONE:
|
|
profiling_mode = "";
|
|
break;
|
|
case BenchmarkProfileInfo::NORMAL:
|
|
profiling_mode = "standard";
|
|
break;
|
|
case BenchmarkProfileInfo::DETAILED:
|
|
profiling_mode = "detailed";
|
|
break;
|
|
default:
|
|
throw InternalException("Unknown profiling option \"%s\"", instance.configuration.profile_info);
|
|
}
|
|
if (!profiling_mode.empty()) {
|
|
res = conn.Query("PRAGMA profiling_mode=" + profiling_mode);
|
|
D_ASSERT(!res->HasError());
|
|
}
|
|
}
|
|
virtual ~DuckDBBenchmarkState() {
|
|
}
|
|
};
|
|
|
|
//! The base Benchmark class is a base class that is used to create and register
|
|
//! new benchmarks
|
|
class DuckDBBenchmark : public Benchmark {
|
|
public:
|
|
DuckDBBenchmark(bool register_benchmark, string name, string group) : Benchmark(register_benchmark, name, group) {
|
|
}
|
|
virtual ~DuckDBBenchmark() {
|
|
}
|
|
|
|
//! Load data into DuckDB
|
|
virtual void Load(DuckDBBenchmarkState *state) = 0;
|
|
//! Run a bunch of queries, only called if GetQuery() returns an empty string
|
|
virtual void RunBenchmark(DuckDBBenchmarkState *state) {
|
|
}
|
|
//! This function gets called after the GetQuery() method
|
|
virtual void Cleanup(DuckDBBenchmarkState *state) {};
|
|
//! Verify a result
|
|
virtual string VerifyResult(QueryResult *result) = 0;
|
|
//! Whether or not the benchmark is performed on an in-memory database
|
|
virtual bool InMemory() {
|
|
return true;
|
|
}
|
|
|
|
string GetDatabasePath() {
|
|
if (!InMemory()) {
|
|
string path = "duckdb_benchmark_db.db";
|
|
DeleteDatabase(path);
|
|
return path;
|
|
} else {
|
|
return string();
|
|
}
|
|
}
|
|
|
|
virtual duckdb::unique_ptr<DuckDBBenchmarkState> CreateBenchmarkState() {
|
|
return make_uniq<DuckDBBenchmarkState>(GetDatabasePath());
|
|
}
|
|
|
|
duckdb::unique_ptr<BenchmarkState> Initialize(BenchmarkConfiguration &config) override {
|
|
auto state = CreateBenchmarkState();
|
|
Load(state.get());
|
|
return std::move(state);
|
|
}
|
|
|
|
void Run(BenchmarkState *state_p) override {
|
|
auto state = (DuckDBBenchmarkState *)state_p;
|
|
string query = GetQuery();
|
|
if (query.empty()) {
|
|
RunBenchmark(state);
|
|
} else {
|
|
state->result = state->conn.Query(query);
|
|
}
|
|
}
|
|
|
|
void Cleanup(BenchmarkState *state_p) override {
|
|
auto state = (DuckDBBenchmarkState *)state_p;
|
|
Cleanup(state);
|
|
}
|
|
|
|
string Verify(BenchmarkState *state_p) override {
|
|
auto state = (DuckDBBenchmarkState *)state_p;
|
|
return VerifyResult(state->result.get());
|
|
}
|
|
|
|
string GetLogOutput(BenchmarkState *state_p) override {
|
|
auto state = (DuckDBBenchmarkState *)state_p;
|
|
auto &profiler = QueryProfiler::Get(*state->conn.context);
|
|
return profiler.ToJSON();
|
|
}
|
|
|
|
//! Interrupt the benchmark because of a timeout
|
|
void Interrupt(BenchmarkState *state_p) override {
|
|
auto state = (DuckDBBenchmarkState *)state_p;
|
|
state->conn.Interrupt();
|
|
}
|
|
};
|
|
|
|
} // namespace duckdb
|