summaryrefslogtreecommitdiff
path: root/Simulator/include/database
diff options
context:
space:
mode:
Diffstat (limited to 'Simulator/include/database')
-rw-r--r--Simulator/include/database/Database.h74
-rw-r--r--Simulator/include/database/Queries.h131
-rw-r--r--Simulator/include/database/Query.h124
-rw-r--r--Simulator/include/database/QueryExecuter.h155
-rw-r--r--Simulator/include/database/QueryResult.h25
5 files changed, 509 insertions, 0 deletions
diff --git a/Simulator/include/database/Database.h b/Simulator/include/database/Database.h
new file mode 100644
index 00000000..6e8bfeef
--- /dev/null
+++ b/Simulator/include/database/Database.h
@@ -0,0 +1,74 @@
+#pragma once
+#include "simulation/Section.h"
+#include "modeling/ModelingTypes.h"
+
+#include <sqlite3.h>
+#include "simulation/Experiment.h"
+
+namespace Database
+{
+ /*
+ The Database class provides a wrapper for the sqlite interface.
+ */
+ class Database
+ {
+ public:
+ /*
+ Initializes a database with the given name. If it does not yet exist is creates a $name.db file.
+ */
+ explicit Database(char* name);
+
+ /*
+ Closes the database connection.
+ */
+ ~Database();
+
+ /*
+ Starts a sqlite transaction.
+ */
+ void startTransaction() const;
+
+ /*
+ Ends a sqlite transaction.
+ */
+ void endTransaction() const;
+
+ /*
+ Writes the history of the experiment to the database.
+ */
+ void writeExperimentHistory(Simulation::Experiment& simulation) const;
+
+ /*
+ Polls the database for new simulation sections to simulate.
+ If there are no rows in the table, this returns -1.
+ */
+ int pollQueuedExperiments() const;
+
+ /*
+ Removes a row of the queued simulation sections.
+ */
+ void dequeueExperiment(int id) const;
+
+
+ /*
+ Creates a simulation object from a simulation in the database.
+ */
+ Simulation::Experiment createExperiment(uint32_t id);
+
+ private:
+ /*
+ Sets the scheduler of the datacenter
+ */
+ Simulation::Scheduler* loadScheduler(uint32_t simulationSectionId) const;
+
+ DefaultDatacenter loadDatacenter(uint32_t datacenterId) const;
+
+ /*
+ Fills the datacenter with workloads from the database.
+ */
+ Simulation::WorkloadPool loadWorkloads(uint32_t traceId) const;
+
+ // The sqlite db connection.
+ sqlite3 *db;
+ };
+}
diff --git a/Simulator/include/database/Queries.h b/Simulator/include/database/Queries.h
new file mode 100644
index 00000000..73afc1a1
--- /dev/null
+++ b/Simulator/include/database/Queries.h
@@ -0,0 +1,131 @@
+#pragma once
+#include "Query.h"
+
+namespace Database
+{
+ namespace Queries
+ {
+ Query<int> GET_QUEUED_EXPERIMENTS(std::string(R"query(
+ SELECT experiment_id FROM queued_experiments;
+ )query"));
+
+ Query<> REMOVE_QUEUED_EXPERIMENT(std::string(R"query(
+ DELETE FROM queued_experiments WHERE experiment_id = $id;
+ )query"));
+
+ Query<int, int, int, int, std::string, std::string> GET_EXPERIMENT_BY_ID(std::string(R"query(
+ SELECT id, simulation_id, path_id, trace_id, scheduler_name, name FROM experiments WHERE id = $id;
+ )query"));
+
+ Query<int, int, std::string, std::string> GET_PATH_BY_ID(std::string(R"query(
+ SELECT id, simulation_id, name, datetime_created FROM paths WHERE id = $id;
+ )query"));
+
+ Query<int, int, int, int> GET_SECTION_BY_PATH_ID(std::string(R"query(
+ SELECT id, path_id, datacenter_id, start_tick FROM sections WHERE path_id = $id;
+ )query"));
+
+
+ /*
+ Returns the type of the scheduler of the given simulation section.
+ Returns: <std::string : scheduler_name>
+ Binds: <int : id>
+ */
+ Query<std::string> GET_SCHEDULER_TYPE_OF_EXPERIMENT(std::string(R"query(
+ SELECT scheduler_name FROM experiments WHERE id = $id;
+ )query"));
+
+ /*
+ Returns the id of the trace of the given simulation section.
+ Returns: <int : trace_id>
+ Binds: <int : id>
+ */
+ Query<int> GET_TRACE_OF_EXPERIMENT(std::string(R"query(
+ SELECT trace_id FROM experiments WHERE id = $id;
+ )query"));
+
+ /*
+ Returns all columns of each room belonging to the given datacenter.
+ Returns: <int : id, std::string : name, int : datacenter_id, std::string : type>
+ Binds: <int : datacenter_id>
+ */
+ Query<int, std::string, int, std::string> GET_ROOMS_OF_DATACENTER(std::string(R"query(
+ SELECT * FROM rooms WHERE datacenter_id = $id;
+ )query"));
+
+ /*
+ Returns all columns of each rack belonging to the given room.
+ Returns: <int : id, std::string : name, int : capacity>
+ Binds: <int : tile.room_id>
+ */
+ Query<int, std::string, int> GET_RACKS_OF_ROOM(std::string(R"query(
+ SELECT racks.* FROM tiles, objects, racks
+ WHERE objects.id = tiles.object_id
+ AND objects.id = racks.id
+ AND tiles.room_id = $id;
+ )query"));
+
+ /*
+ Returns the machine in a given rack.
+ Returns: <int : id, int : position>
+ Binds: <int : rack_id>
+ */
+ Query<int, int> GET_MACHINES_OF_RACK(std::string(R"query(
+ SELECT id, position FROM machines
+ WHERE rack_id = $rid;
+ )query"));
+
+ /*
+ Returns all columns of each task belonging to the given trace.
+ Returns: <int : id, int : start_tick, inn : total_flop_count, int : trace_id, int : task_dependency_id>
+ Binds: <int : trace_id>
+ */
+ Query<int, int, int, int, int> GET_TASKS_OF_TRACE(std::string(R"query(
+ SELECT * FROM tasks WHERE trace_id = $id;
+ )query"));
+
+ /*
+ Returns the information of each cpu in the given rack, and their corresponding machine.
+ Returns: <int : slot, int : machine_speed, int : cores, int : energy_consumption, int : failure_model_id>
+ Binds: <int : machine.rack_id>
+ */
+ Query<int, int, int, int, int> GET_CPUS_IN_RACK(std::string(R"query(
+ SELECT machines.position AS slot, cpus.clock_rate_mhz AS machine_speed, cpus.number_of_cores AS cores, cpus.energy_consumption_w AS energy_consumption, cpus.failure_model_id AS failure_model_id FROM cpus, machine_cpus, machines
+ WHERE machine_cpus.cpu_id = cpus.id
+ AND machine_cpus.machine_id = machines.id
+ AND machines.rack_id = $id;
+ )query"));
+
+ /*
+ Returns the information of each gpu in the given rack, and their corresponding machine.
+ Returns: <int : slot, int : machine_speed, int : cores, int : energy_consumption, int : failure_model_id>
+ Binds: <int : machine.rack_id>
+ */
+ Query<int, int, int, int, int> GET_GPUS_IN_RACK(std::string(R"query(
+ SELECT machines.position AS slot, gpus.clock_rate_mhz AS speed, gpus.number_of_cores AS cores, gpus.energy_consumption_w AS energy_consumption, gpus.failure_model_id AS failure_model_id FROM gpus, machine_gpus, machines
+ WHERE machine_gpus.gpu_id = gpus.id
+ AND machine_gpus.machine_id = machines.id
+ AND machines.rack_id = $id;
+ )query"));
+
+ /*
+ Inserts the state of a workload into the task_state table.
+ Returns: <>
+ Binds: <int : task_id, int : experiment_id, int : tick, int : flops_left>
+ */
+ Query<> WRITE_WORKLOAD_STATE(std::string(R"query(
+ INSERT INTO task_states (task_id, experiment_id, tick, flops_left)
+ VALUES ($tid, $ssid, $tick, $flops);
+ )query"));
+
+ /*
+ Inserts the state of a machine into the machine_state table.
+ Returns: <>
+ Binds: <int : task_id, int : machine_id, int : experiment_id, int : tick, float : temperature_c, int : in_use_memory_mb, float : load_fraction>
+ */
+ Query<> WRITE_MACHINE_STATE(std::string(R"query(
+ INSERT INTO machine_states (task_id, machine_id, experiment_id, tick, temperature_c, in_use_memory_mb, load_fraction)
+ VALUES ($tid, $mid, $ssid, $tick, $temp, $mem, $load);
+ )query"));
+ }
+}
diff --git a/Simulator/include/database/Query.h b/Simulator/include/database/Query.h
new file mode 100644
index 00000000..46ce0ee2
--- /dev/null
+++ b/Simulator/include/database/Query.h
@@ -0,0 +1,124 @@
+#pragma once
+#include <assert.h>
+#include <sqlite3.h>
+
+namespace Database
+{
+
+ namespace Specializations
+ {
+ template<typename ReturnType>
+ ReturnType getResult(int location, sqlite3_stmt* statement);
+
+ template<>
+ inline int getResult<int>(int location, sqlite3_stmt* statement)
+ {
+ return sqlite3_column_int(statement, location);
+ }
+
+ template<>
+ inline std::string getResult<std::string>(int location, sqlite3_stmt* statement)
+ {
+ return std::string(reinterpret_cast<const char*>(sqlite3_column_text(statement, location)));
+ }
+
+ template<typename ValueType>
+ void bind(ValueType value, int location, sqlite3_stmt* statement);
+
+ template<>
+ inline void bind<int>(int value, int location, sqlite3_stmt* statement)
+ {
+ int rc = sqlite3_bind_int(statement, location, value);
+ assert(rc == SQLITE_OK);
+ }
+
+ template<>
+ inline void bind<float>(float value, int location, sqlite3_stmt* statement)
+ {
+ int rc = sqlite3_bind_double(statement, location, static_cast<double>(value));
+ assert(rc == SQLITE_OK);
+ }
+ }
+
+
+
+ template<typename ...ReturnTypes>
+ class Query
+ {
+ public:
+ explicit Query(std::string query) : statement(nullptr), content(query)
+ {}
+
+ /*
+ Calls sqlite3_finalize on the statement.
+ */
+ ~Query()
+ {
+ int rc = sqlite3_finalize(statement);
+ assert(rc == SQLITE_OK);
+ }
+
+ /*
+ Calls sqlite3_prepare_v2 to prepare this query.
+ */
+ void prepare(sqlite3* db)
+ {
+ // Preparation of the statement.
+ int rc = sqlite3_prepare_v2(db, content.c_str(), static_cast<int>(content.size()), &statement, NULL);
+ assert(rc == SQLITE_OK);
+ }
+
+ /*
+ Steps the execution of this query once. Returns true if the return code is SQLITE_ROW.
+ */
+ bool step() const
+ {
+ // Execution of the statement
+ int rc = sqlite3_step(statement);
+ if(rc == SQLITE_ROW)
+ return true;
+ if(rc == SQLITE_DONE)
+ return false;
+
+ assert(!"The return code of step was not SQLITE_ROW (100) or SQLITE_DONE (101)!");
+ return false;
+ }
+
+ /*
+ Resets this query back to its initial state.
+ */
+ void reset() const
+ {
+ sqlite3_reset(statement);
+ }
+
+ /*
+ A template for implementing the binding of values to parameters in the sqlite statement.
+ */
+ template<typename ValueType>
+ void bind(ValueType value, int location)
+ {
+ Specializations::bind<ValueType>(value, location, statement);
+ }
+
+ /**
+ * \brief Returns the result of ReturnType at the given location in the query result row.
+ * \tparam ReturnType The type of the entry in the row.
+ * \param location The index of the entry in the row.
+ * \return The result of the query at the given location.
+ */
+ template<typename ReturnType>
+ ReturnType getResult(int location)
+ {
+ return Specializations::getResult<ReturnType>(location, statement);
+ }
+
+ private:
+ // The sqlite3 statement that corresponds to this query.
+ sqlite3_stmt* statement;
+ // The sql string that will be executed.
+ std::string content;
+
+ };
+
+}
diff --git a/Simulator/include/database/QueryExecuter.h b/Simulator/include/database/QueryExecuter.h
new file mode 100644
index 00000000..d66f9e85
--- /dev/null
+++ b/Simulator/include/database/QueryExecuter.h
@@ -0,0 +1,155 @@
+#pragma once
+#include "Query.h"
+#include "QueryResult.h"
+
+#include <tuple>
+#include <sqlite3.h>
+#include <memory>
+#include <vector>
+
+namespace Database
+{
+ template<typename ...ReturnTypes>
+ class QueryExecuter
+ {
+ public:
+ /*
+ Creates a prepared statement and initializes the query.
+ */
+ explicit QueryExecuter(sqlite3* db) : database(db) {}
+
+ /*
+ Sets the query this executer will execute.
+ */
+ QueryExecuter<ReturnTypes...>& setQuery(Query<ReturnTypes...> query)
+ {
+ this->query = std::make_unique<Query<ReturnTypes...>>(query);
+ this->query->prepare(database);
+ return *this;
+ }
+
+ /*
+ Binds the given name-value pairs to the statement.
+ Recursive case.
+ */
+ template<typename BindType>
+ QueryExecuter<ReturnTypes...>& bindParams(BindType locationValuePair, int depth = 1)
+ {
+ query->template bind<BindType>(locationValuePair, depth);
+ return *this;
+ }
+
+ /*
+ Binds the given name-value pairs to the statement.
+ Recursive case.
+ */
+ template<typename BindType, typename ...BindTypes>
+ QueryExecuter<ReturnTypes...>& bindParams(BindType locationValuePair, BindTypes... locationValuePairs, int depth = 1)
+ {
+ query->template bind<BindType>(locationValuePair, depth);
+ bindParams<BindTypes...>(locationValuePairs..., depth + 1);
+ return *this;
+ }
+
+ /*
+ Executes the query and returns a tuple with an entry for each type. Use this to recieve only the first result.
+ Multiple calls, or calls when there are no rows in the db, can lead to exceptions.
+ This is functionally equivalent to stepping and then calling getResult
+ */
+ QueryResult<ReturnTypes...> executeOnce()
+ {
+ query->step();
+ return QueryResult<ReturnTypes...>(getResult<ReturnTypes...>());
+ }
+
+ /*
+ Steps the query.
+ */
+ bool step()
+ {
+ return query->step();
+ }
+
+ /*
+ Returns the result.
+ */
+ QueryResult<ReturnTypes...> result()
+ {
+ return QueryResult<ReturnTypes...>(getResult<ReturnTypes...>());
+ }
+
+ /*
+ Executes the query and returns a vector of tuples for each result.
+ */
+ std::vector<QueryResult<ReturnTypes...>> execute(int limit = 0)
+ {
+ std::vector<QueryResult<ReturnTypes...>> result;
+
+ // Return code
+ bool more;
+
+ int limiter = 0;
+
+ do
+ {
+ // Execution of the statement
+ more = query->step();
+
+ if (!more || (limiter >= limit && limit > 0))
+ break;
+
+ limiter++;
+ std::tuple<ReturnTypes...> row = getResult<ReturnTypes...>();
+ result.emplace_back(row);
+
+ } while (more);
+
+ return result;
+ }
+
+ /*
+ Resets the sqlite3 query object.
+ */
+ QueryExecuter<ReturnTypes...>& reset()
+ {
+ query->reset();
+ return *this;
+ }
+
+ private:
+ /*
+ Returns the results after executing the query.
+ Base case.
+ */
+ template<typename ReturnType>
+ std::tuple<ReturnType> getResult(int depth = 0)
+ {
+ return std::tuple<ReturnType>(query->template getResult<ReturnType>(depth));
+ }
+
+ /*
+ Returns the results after executing the query.
+ Recursive Case.
+ */
+ template<typename FirstReturnType, typename SecondReturnType, typename ...OtherReturnTypes>
+ std::tuple<FirstReturnType, SecondReturnType, OtherReturnTypes...> getResult(int depth = 0)
+ {
+ std::tuple<FirstReturnType> first = std::tuple<FirstReturnType>(query->template getResult<FirstReturnType>(depth));
+ std::tuple<SecondReturnType, OtherReturnTypes...> rest = getResult<SecondReturnType, OtherReturnTypes...>(depth + 1);
+ return std::tuple_cat(first, rest);
+ }
+
+ /*
+ Returns an empty tuple for when there are no return values.
+ */
+ template<typename ...NoTypes>
+ std::tuple<> getResult(int depth = 0) const
+ {
+ return std::tuple<>();
+ }
+
+ std::unique_ptr<Query<ReturnTypes...>> query;
+ sqlite3* database;
+ };
+}
+
diff --git a/Simulator/include/database/QueryResult.h b/Simulator/include/database/QueryResult.h
new file mode 100644
index 00000000..c1534be3
--- /dev/null
+++ b/Simulator/include/database/QueryResult.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <tuple>
+
+namespace Database
+{
+ template<class ...ReturnTypes>
+ class QueryResult
+ {
+ public:
+ explicit QueryResult(ReturnTypes... returnValues) : values(returnValues...) {}
+ explicit QueryResult(std::tuple<ReturnTypes...> returnValues) : values(returnValues) {}
+
+ /*
+ Returns the item at the given index.
+ ReturnType must be the same as the type of the item at position Index in the tuple.
+ */
+ template<class ReturnType, int Index>
+ ReturnType get()
+ {
+ return std::get<Index>(values);
+ }
+
+ std::tuple<ReturnTypes...> values;
+ };
+}