summaryrefslogtreecommitdiff
path: root/Simulator/include
diff options
context:
space:
mode:
Diffstat (limited to 'Simulator/include')
-rw-r--r--Simulator/include/Simulator.h139
-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
-rw-r--r--Simulator/include/modeling/Datacenter.h40
-rw-r--r--Simulator/include/modeling/Entity.h12
-rw-r--r--Simulator/include/modeling/ModelingTypes.h7
-rw-r--r--Simulator/include/modeling/Rack.h33
-rw-r--r--Simulator/include/modeling/Room.h52
-rw-r--r--Simulator/include/modeling/TypeIndex.h9
-rw-r--r--Simulator/include/modeling/machine/CPU.h34
-rw-r--r--Simulator/include/modeling/machine/GPU.h33
-rw-r--r--Simulator/include/modeling/machine/Machine.h112
-rw-r--r--Simulator/include/simulation/Experiment.h179
-rw-r--r--Simulator/include/simulation/Path.h63
-rw-r--r--Simulator/include/simulation/Section.h76
-rw-r--r--Simulator/include/simulation/history/History.h43
-rw-r--r--Simulator/include/simulation/history/MachineSnapshot.h17
-rw-r--r--Simulator/include/simulation/history/SimulationHistory.h81
-rw-r--r--Simulator/include/simulation/history/WorkloadSnapshot.h13
-rw-r--r--Simulator/include/simulation/schedulers/FirstInFirstOutScheduler.h37
-rw-r--r--Simulator/include/simulation/schedulers/Scheduler.h25
-rw-r--r--Simulator/include/simulation/schedulers/ShortestRemainingTimeScheduler.h46
-rw-r--r--Simulator/include/simulation/workloads/Workload.h80
-rw-r--r--Simulator/include/simulation/workloads/WorkloadPool.h43
27 files changed, 1683 insertions, 0 deletions
diff --git a/Simulator/include/Simulator.h b/Simulator/include/Simulator.h
new file mode 100644
index 00000000..381639af
--- /dev/null
+++ b/Simulator/include/Simulator.h
@@ -0,0 +1,139 @@
+#pragma once
+#include "simulation/Section.h"
+#include "database/Database.h"
+
+#include <iostream>
+#include <unordered_map>
+
+namespace Simulation
+{
+ /*
+ The Simulator class controls (the creation of) all experiments, and providing access to the database.
+ */
+ template<typename SimulationType>
+ class Simulator
+ {
+ public:
+ /*
+ Initializes the simulator with an empty list of experiments, and with a reference to the database.
+ */
+ explicit Simulator(char* databaseName) : database(databaseName) {}
+
+ /*
+ Adds a simulation to the list of experiments from the database, removing it from the queue
+ of experiments in the database.
+ */
+ void load(int experimentId)
+ {
+ Experiment experiment = database.createExperiment(experimentId);
+ experiments.insert(std::make_pair(experimentId, experiment));
+ database.dequeueExperiment(experimentId);
+ }
+
+ /*
+ Polls the database for new jobs and simulates every queued simulation it finds.
+ */
+ void pollAndLoadAll()
+ {
+ int rc = pollAndLoad();
+ if (rc != -1)
+ pollAndLoadAll();
+ }
+
+ /*
+ Polls the database for new jobs and simulates the first it finds.
+ */
+ int pollAndLoad()
+ {
+ int id = database.pollQueuedExperiments();
+ if (id != -1)
+ {
+ std::cout << "Loaded simulation section " << id << std::endl;
+ load(id);
+ }
+ return id;
+ }
+
+ /*
+ Writes the state of all experiments if their history is size 3000 or larger.
+ */
+ void writeHistoryAll()
+ {
+ if (experiments.size() == 0)
+ return;
+
+ auto it = experiments.begin();
+ while(it != experiments.end())
+ {
+ auto history = (*it).second.getHistory();
+ if (history.historySize() > 3000 || (*it).second.isFinished())
+ write((*it).first);
+
+ if ((*it).second.isFinished())
+ {
+ std::cout << "Finished simulation." << std::endl;
+ it = experiments.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ }
+
+ /*
+ Writes the state of the given simulation to the database.
+ */
+ void write(int id)
+ {
+ std::cout << "Writing batch." << std::endl;
+ database.startTransaction();
+ database.writeExperimentHistory(experiments.at(id));
+ database.endTransaction();
+ auto history = experiments.at(id).getHistory();
+ history.clearHistory();
+ std::cout << "Finished writing batch." << std::endl;
+ }
+
+ /*
+ Ticks each simulation once.
+ */
+ void tickAll()
+ {
+ for (std::pair<const int, Experiment>& s : experiments)
+ s.second.tick();
+ }
+
+ /*
+ Ticks the given simulation once.
+ */
+ void tick(int simulationId)
+ {
+ experiments.at(simulationId).tick();
+ }
+
+ /*
+ Returns true if all experiments are finished.
+ */
+ bool hasSimulations() const
+ {
+ return experiments.size() != 0;
+ }
+
+ /*
+ Saves the state of all workloads to the history.
+ */
+ void saveStateAll()
+ {
+ for (auto& pair : experiments)
+ pair.second.saveState();
+ }
+
+ private:
+ // The database to write results to.
+ Database::Database database;
+
+ // The list of experiments.
+ std::unordered_map<int, Experiment> experiments;
+ };
+}
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;
+ };
+}
diff --git a/Simulator/include/modeling/Datacenter.h b/Simulator/include/modeling/Datacenter.h
new file mode 100644
index 00000000..a9558f0a
--- /dev/null
+++ b/Simulator/include/modeling/Datacenter.h
@@ -0,0 +1,40 @@
+#pragma once
+#include "modeling/Room.h"
+#include "simulation/schedulers/Scheduler.h"
+#include "modeling/TypeIndex.h"
+
+#include <vector>
+
+namespace Modeling
+{
+ /*
+ The Datacenter class models a datacenter with rooms/entities.
+ */
+ template<typename ...RoomTypes>
+ class Datacenter
+ {
+ public:
+ /*
+ Returns a reference to the vector of rooms in this datacenter.
+ */
+ template<typename RoomType>
+ std::vector<RoomType>& getRoomsOfType()
+ {
+ return std::get<indexOfType<RoomType, RoomTypes...>::value>(rooms);
+ }
+
+ /*
+ Adds a room to this datacenter.
+ */
+ template<typename RoomType>
+ void addRoomOfType(RoomType& room)
+ {
+ std::get<indexOfType<RoomType, RoomTypes...>::value>(rooms).push_back(std::move(room));
+ }
+
+
+ private:
+ // A vector of rooms that are part of this datacenter.
+ std::tuple<std::vector<RoomTypes>...> rooms;
+ };
+}
diff --git a/Simulator/include/modeling/Entity.h b/Simulator/include/modeling/Entity.h
new file mode 100644
index 00000000..c8c5a7cd
--- /dev/null
+++ b/Simulator/include/modeling/Entity.h
@@ -0,0 +1,12 @@
+#pragma once
+namespace Modeling
+{
+ class Entity
+ {
+ public:
+ explicit Entity(int id);
+
+ // The id of this entity in the database
+ int id;
+ };
+}
diff --git a/Simulator/include/modeling/ModelingTypes.h b/Simulator/include/modeling/ModelingTypes.h
new file mode 100644
index 00000000..611a3653
--- /dev/null
+++ b/Simulator/include/modeling/ModelingTypes.h
@@ -0,0 +1,7 @@
+#pragma once
+
+// Define a DefaultDC type, capable of holding server rooms.
+using DefaultDatacenter = Modeling::Datacenter<Modeling::ServerRoom, Modeling::Hallway, Modeling::PowerRoom>;
+
+// Define a type of simulation, capable of simulating the DefaultDC.
+using DefaultSection = Simulation::Section<DefaultDatacenter>; \ No newline at end of file
diff --git a/Simulator/include/modeling/Rack.h b/Simulator/include/modeling/Rack.h
new file mode 100644
index 00000000..7e5638ef
--- /dev/null
+++ b/Simulator/include/modeling/Rack.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "modeling/Entity.h"
+#include "modeling/machine/Machine.h"
+
+#include <unordered_map>
+
+namespace Modeling
+{
+ /*
+ The Rack class models a physical rack. It holds a vector of machines.
+ */
+ class Rack : public Entity
+ {
+ public:
+ /*
+ Initializes the rack with the given machines.
+ */
+ Rack(int id, std::unordered_map<uint32_t, Machine> machines);
+
+ /*
+ Returns all machines in this rack.
+ */
+ std::unordered_map<uint32_t, Machine>& getMachines();
+
+ /*
+ Returns the machine at the given slot.
+ */
+ Machine& getMachineAtSlot(int slot);
+
+ private:
+ std::unordered_map<uint32_t, Machine> machines;
+ };
+}
diff --git a/Simulator/include/modeling/Room.h b/Simulator/include/modeling/Room.h
new file mode 100644
index 00000000..a57b045e
--- /dev/null
+++ b/Simulator/include/modeling/Room.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "modeling/Rack.h"
+#include "modeling/TypeIndex.h"
+
+#include <vector>
+
+namespace Modeling
+{
+ /*
+ The Room class models the rooms that can be created in the simulation. It contains a list of all entities in the room.
+ */
+ template<typename ...EntityTypes>
+ class Room
+ {
+ //static_assert(std::is_base_of<Entity, EntityTypes>..., "Each type must be derived from Entity!");
+ public:
+ /*
+ Initializes the room with the given name.
+ */
+ explicit Room(int id) : id(id) {}
+
+ /*
+ Adds the entity to the list of entities in this room.
+ */
+ template<typename EntityType>
+ void addEntity(EntityType& e)
+ {
+ std::get<indexOfType<EntityType, EntityTypes...>::value>(entities).push_back(e);
+ }
+
+ /*
+ Returns all entities of the given type.
+ */
+ template<typename EntityType>
+ std::vector<EntityType>& getEntitiesOfType()
+ {
+ return std::get<indexOfType<EntityType, EntityTypes...>::value>(entities);
+ }
+
+ // The id of this room corresponding to its id in the database.
+ const int id;
+
+ private:
+ // A vector for each type of entity
+ std::tuple<std::vector<EntityTypes>...> entities;
+ };
+
+ using ServerRoom = Room<Modeling::Rack>;
+ using Hallway = Room<>;
+ using PowerRoom = Room<>;
+
+}
diff --git a/Simulator/include/modeling/TypeIndex.h b/Simulator/include/modeling/TypeIndex.h
new file mode 100644
index 00000000..6fcda550
--- /dev/null
+++ b/Simulator/include/modeling/TypeIndex.h
@@ -0,0 +1,9 @@
+#pragma once
+template<typename T, typename... Ts> struct indexOfType;
+
+template <typename T, typename... Ts>
+struct indexOfType<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
+
+template <typename T, typename Tail, typename... Ts>
+struct indexOfType<T, Tail, Ts...> : std::integral_constant<std::size_t, 1 + indexOfType<T, Ts...>::value> {};
+
diff --git a/Simulator/include/modeling/machine/CPU.h b/Simulator/include/modeling/machine/CPU.h
new file mode 100644
index 00000000..dce4d2c5
--- /dev/null
+++ b/Simulator/include/modeling/machine/CPU.h
@@ -0,0 +1,34 @@
+#pragma once
+
+namespace Modeling
+{
+ class CPU
+ {
+ public:
+ CPU(int speed, int cores, int energyConsumption, int failureModelId);
+
+ /*
+ Returns the speed of this CPU.
+ */
+ int getSpeed();
+
+ /*
+ Returns the nr of cores of this CPU.
+ */
+ int getCores();
+
+ /*
+ Returns the energy consumed by this CPU.
+ */
+ int getEnergyConsumption();
+
+ /*
+ Returns the failure model id of this CPU.
+ */
+ int getFailureModelId();
+
+
+ private:
+ int speed, cores, energyConsumption, failureModelId;
+ };
+}
diff --git a/Simulator/include/modeling/machine/GPU.h b/Simulator/include/modeling/machine/GPU.h
new file mode 100644
index 00000000..049b928e
--- /dev/null
+++ b/Simulator/include/modeling/machine/GPU.h
@@ -0,0 +1,33 @@
+#pragma once
+
+namespace Modeling
+{
+ class GPU
+ {
+ public:
+ GPU(int speed, int cores, int energyConsumption, int failureModelId);
+
+ /*
+ Returns the speed of this CPU.
+ */
+ int getSpeed();
+
+ /*
+ Returns the nr of cores of this CPU.
+ */
+ int getCores();
+
+ /*
+ Returns the energy consumed by this CPU.
+ */
+ int getEnergyConsumption();
+
+ /*
+ Returns the failure model id of this CPU.
+ */
+ int getFailureModelId();
+
+ private:
+ int speed, cores, energyConsumption, failureModelId;
+ };
+}
diff --git a/Simulator/include/modeling/machine/Machine.h b/Simulator/include/modeling/machine/Machine.h
new file mode 100644
index 00000000..c89d32d1
--- /dev/null
+++ b/Simulator/include/modeling/machine/Machine.h
@@ -0,0 +1,112 @@
+#pragma once
+#include "simulation/workloads/Workload.h"
+#include "modeling/machine/CPU.h"
+#include "modeling/machine/GPU.h"
+
+#include <stdint.h>
+#include <vector>
+#include <memory>
+
+namespace Modeling
+{
+ // Defines the initial temperature of machine
+ constexpr float ROOM_TEMPERATURE_CELCIUS = 23.0f;
+
+ // Defines the usage of memory by the kernel
+ constexpr uint32_t KERNEL_MEMORY_USAGE_MB = 50;
+
+ /*
+ The Machine class models a physical machine in a rack. It has a speed, and can be given a workload on which it will work until finished or interrupted.
+ */
+ class Machine
+ {
+ public:
+ /*
+ Initializes the machine as idle with the given speed.
+ */
+ Machine(int id);
+
+ /*
+ Adds a cpu to the list of this machine.
+ */
+ void addCPU(CPU cpu);
+
+ /*
+ Adds a cpu to the list of this machine.
+ */
+ void addGPU(GPU gpu);
+
+ /*
+ Gives the task to this machine. If the machine is already busy this does nothing.
+ */
+ void giveTask(Simulation::Workload* workload);
+
+ /*
+ Returns true if the machine is busy.
+ */
+ bool isBusy() const;
+
+ /*
+ Does work on the given task and updates temperature and load appropriately.
+ */
+ void work();
+
+ /*
+ Returns the id of the current workload of this machine.
+ */
+ int getWorkloadId() const;
+
+ /*
+ Returns the id of this machine.
+ */
+ int getId() const;
+
+ /*
+ Returns the temperature of this machine.
+ */
+ float getTemperature() const;
+
+ /*
+ Returns the memory used by this machine.
+ */
+ int getMemory() const;
+
+ /*
+ Returns the load fraction on this machine.
+ */
+ float getLoad() const;
+
+ private:
+ // A list of cpus in this machine.
+ std::vector<CPU> cpus;
+
+ // A list of gpus in this machine.
+ std::vector<GPU> gpus;
+
+ // True if the machine is working on a task.
+ bool busy = false;
+
+ // The current workload the machine is working on.
+ Simulation::Workload* currentWorkload;
+
+ // Db id of this machine.
+ int id;
+
+ // Temperature of this machine.
+ float temperature = ROOM_TEMPERATURE_CELCIUS;
+ float maxTemperature = 80.0f;
+ float minTemperature = 0.0f;
+ float temperatureIncrease = 10.f;
+
+ // Memory used by this machine.
+ int memory = KERNEL_MEMORY_USAGE_MB;
+
+ // The fraction of load on this machine.
+ float load = 0.0f;
+
+ /*
+ Returns the speed of the machine.
+ */
+ uint32_t getSpeed();
+ };
+}
diff --git a/Simulator/include/simulation/Experiment.h b/Simulator/include/simulation/Experiment.h
new file mode 100644
index 00000000..69c192fa
--- /dev/null
+++ b/Simulator/include/simulation/Experiment.h
@@ -0,0 +1,179 @@
+#pragma once
+#include "Path.h"
+#include <algorithm>
+#include "workloads/WorkloadPool.h"
+
+namespace Simulation
+{
+ /**
+ * \brief Holds a Path, Scheduler, and WorkloadPool together to form a single unit that can be simulated.
+ */
+ class Experiment
+ {
+ public:
+ /**
+ * \brief Instantiates a new, complete, experiment that starts at tick 0 and can be simulated.
+ * \param path The path this experiment should simulate.
+ * \param scheduler The scheduler this experiment should use for workload balancing.
+ * \param pool The workloadPool that contains the workloads of this experiment.
+ * \param id The id of this experiment as it is in the database.
+ */
+ Experiment(Path path, Scheduler* scheduler, WorkloadPool pool, uint32_t id) : path(path), scheduler(scheduler), id(id), currentTick(0), workloadPool(pool)
+ {}
+
+ /**
+ * \brief Simulates a single tick of this experiment.
+ */
+ void tick()
+ {
+ if(finished) return;
+
+ workloadPool.clearFinishedWorkloads();
+
+ auto machineAccumulator = path.getCurrentSection(currentTick).getMachines();
+
+ // Schedule the workload over each machine
+ scheduler->schedule(machineAccumulator, workloadPool.getWorkloads(currentTick));
+
+ // Update each machine
+ std::for_each(
+ machineAccumulator.begin(),
+ machineAccumulator.end(),
+ [this](const std::reference_wrapper<Modeling::Machine>& machineWrapper) {
+ machineWrapper.get().work();
+ }
+ );
+
+ currentTick++;
+
+ if(workloadPool.isEmpty()) finished = true;
+ }
+
+ /**
+ * \brief Saves the state of the simulation, adding it to the history.
+ */
+ void saveState()
+ {
+ for(Workload* workload : workloadPool.getWorkloads(currentTick))
+ {
+ history.addSnapshot(
+ currentTick,
+ WorkloadSnapshot(
+ workload->getId(),
+ workload->getRemainingOperations()
+ )
+ );
+ }
+
+ for(std::reference_wrapper<Modeling::Machine> machineref : path.getCurrentSection(currentTick).getMachines())
+ {
+ auto machine = machineref.get();
+ history.addSnapshot(
+ currentTick,
+ MachineSnapshot(
+ machine.getId(),
+ machine.getWorkloadId(),
+ machine.getTemperature(),
+ machine.getLoad(),
+ machine.getMemory()
+ )
+ );
+ }
+ }
+
+ /**
+ * \brief Adds the given workload to the pool of workloads of this simulation.
+ * \param wl The workload to add to the simulator of this experiment.
+ */
+ void addWorkload(Workload& wl)
+ {
+ workloadPool.addWorkload(wl);
+ }
+
+ /**
+ * \return A reference to the workloads of this simulation.
+ */
+ WorkloadPool& getWorkloadPool()
+ {
+ return workloadPool;
+ }
+
+ /**
+ * \return The current tick which is being simulated, i.e. the number of ticks that have passed.
+ */
+ uint32_t getCurrentTick() const
+ {
+ return currentTick;
+ }
+
+ /**
+ * \return The history of this experiment that has no yet been written to the database.
+ */
+ SimulationHistory getHistory() const
+ {
+ return history;
+ }
+
+ /**
+ * \return The id of this experiment as it is in the database.
+ */
+ uint32_t getId() const
+ {
+ return id;
+ }
+
+ /**
+ * \brief Sets this experiment to finished. After calling this method,
+ * the tick() method will have no effect.
+ */
+ void end()
+ {
+ this->finished = true;
+ }
+
+ /**
+ * \return True if the experiment is finished, i.e. when all workloads have been completed.
+ */
+ bool isFinished() const
+ {
+ return this->finished;
+ }
+
+ private:
+ /**
+ * \brief The path of this experiment which contains the sections and when they should be used.
+ */
+ Path path;
+
+ /**
+ * \brief The scheduler that this used for workload balancing.
+ */
+ std::shared_ptr<Scheduler> scheduler;
+
+ /**
+ * \brief The id of this experiment as it is in the database.
+ */
+ uint32_t id;
+
+ /**
+ * \brief The number of ticks that have passed.
+ */
+ uint32_t currentTick;
+
+ /**
+ * \brief The pool of workloads in this simulation, to be distributed by the scheduler.
+ */
+ WorkloadPool workloadPool;
+
+ /**
+ * \brief The part of the history of this simulation which has not been written to the database.
+ */
+ SimulationHistory history;
+
+ /**
+ * \brief If this is true, then tick will not do anything. This indicates that the simulation is finished,
+ * and that its history should be written to disk.
+ */
+ bool finished = false;
+ };
+}
diff --git a/Simulator/include/simulation/Path.h b/Simulator/include/simulation/Path.h
new file mode 100644
index 00000000..d35d49fc
--- /dev/null
+++ b/Simulator/include/simulation/Path.h
@@ -0,0 +1,63 @@
+#pragma once
+#include "Section.h"
+#include "modeling/ModelingTypes.h"
+
+namespace Simulation
+{
+ /**
+ * \brief Holds all sections of the parent experiment, and returns the correct one
+ * based on the current tick.
+ */
+ class Path
+ {
+ public:
+ explicit Path(int id) : id(id)
+ {}
+
+
+ /**
+ * \brief Adds the given section to this path. The begin tick of this section
+ * should not already be in use by one of the other sections in this path.
+ * \param section The section to add to this path.
+ */
+ void addSection(DefaultSection section)
+ {
+ sections.push_back(section);
+ }
+
+ /**
+ * \brief Returns the section that is currently in use by taking the section
+ * that has the greatest begin tick smaller than the current tick
+ * \param currentTick The tick the simulator is simulating right now.
+ * \return The section that is currently in use.
+ */
+ DefaultSection& getCurrentSection(uint32_t currentTick)
+ {
+ size_t currentSection = 0;
+
+ uint32_t currentStartTick = 0;
+ for(int i = 0; i < sections.size(); ++i)
+ {
+ uint32_t tempStartTick = sections.at(i).getStartTick();
+ if(tempStartTick > currentStartTick && tempStartTick < currentTick)
+ currentSection = i;
+ }
+
+ return sections.at(currentSection);
+ }
+
+ private:
+
+ /**
+ * \brief The unordered vector of sections in this path. No pair of sections
+ * should share the same begin tick.
+ */
+ std::vector<DefaultSection> sections;
+
+
+ /**
+ * \brief The id of this path as it is in the database.
+ */
+ int id;
+ };
+}
diff --git a/Simulator/include/simulation/Section.h b/Simulator/include/simulation/Section.h
new file mode 100644
index 00000000..3c11b073
--- /dev/null
+++ b/Simulator/include/simulation/Section.h
@@ -0,0 +1,76 @@
+#pragma once
+#include "modeling/Datacenter.h"
+#include "modeling/Room.h"
+#include "simulation/history/SimulationHistory.h"
+
+#include <vector>
+#include <iterator>
+
+namespace Simulation
+{
+ /**
+ * \brief Holds a datacenter and the tick on which the parent experiment should switch to this section.
+ * \tparam DatacenterType The type of datacenter to be used.
+ */
+ template<typename DatacenterType>
+ class Section
+ {
+ public:
+ /**
+ * \brief Initializes the datacenter in the simulation. Sets paused to false and finished to false.
+ * \param dc The topology of this section.
+ * \param startTick The tick on which the experiment should start using the topology of this section.
+ */
+ Section(DatacenterType& dc, uint32_t startTick) : datacenter(dc), startTick(startTick)
+ {}
+
+ /**
+ * \return A reference to the datacenter of this section.
+ */
+ DatacenterType& getDatacenter()
+ {
+ return datacenter;
+ }
+
+ /**
+ * \return All machines in the datacenter of section.
+ */
+ std::vector<std::reference_wrapper<Modeling::Machine>> getMachines()
+ {
+ using namespace std;
+
+ vector<reference_wrapper<Modeling::Machine>> machineAccumulator;
+
+ // For each serverroom, we get the racks in the room
+ vector<Modeling::ServerRoom>& rooms = datacenter.template getRoomsOfType<Modeling::ServerRoom>();
+ for(auto& room : rooms)
+ // For each rack get the machines inside that rack
+ for(auto& rack : room.getEntitiesOfType<Modeling::Rack>())
+ // Add each machine to the accumulator
+ for(auto& machine : rack.getMachines())
+ machineAccumulator.push_back(ref(machine.second));
+
+ return machineAccumulator;
+ }
+
+ /**
+ * \return The tick on which the experiment should start using the topology of this section.
+ */
+ uint32_t getStartTick() const
+ {
+ return startTick;
+ }
+
+ private:
+ /**
+ * \brief The datacenter that is used for experiments.
+ */
+ DatacenterType datacenter;
+
+ /**
+ * \brief The tick when the next sections starts. This is -1 if this is the last section.
+ */
+ uint32_t startTick;
+ };
+
+}
diff --git a/Simulator/include/simulation/history/History.h b/Simulator/include/simulation/history/History.h
new file mode 100644
index 00000000..f1d826eb
--- /dev/null
+++ b/Simulator/include/simulation/history/History.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <stdint.h>
+#include <map>
+
+namespace Simulation {
+ template<typename Type>
+ class History {
+ public:
+ void addSnapshotAtTick(uint32_t tick, Type snapshot)
+ {
+ history.insert(std::make_pair(tick, snapshot));
+ }
+
+ const auto& snapshotsAtTick(uint32_t tick)
+ {
+ return history.equal_range(tick);
+ }
+
+ typename std::unordered_map<uint32_t, Type>::const_iterator begin()
+ {
+ return history.begin();
+ }
+
+ typename std::unordered_map<uint32_t, Type>::const_iterator end()
+ {
+ return history.end();
+ }
+
+ void clear()
+ {
+ history.clear();
+ }
+
+ size_t size()
+ {
+ return history.size();
+ }
+
+ private:
+ // Maps ticks to histories of workloads
+ std::unordered_multimap<uint32_t, Type> history;
+ };
+} \ No newline at end of file
diff --git a/Simulator/include/simulation/history/MachineSnapshot.h b/Simulator/include/simulation/history/MachineSnapshot.h
new file mode 100644
index 00000000..49ce1313
--- /dev/null
+++ b/Simulator/include/simulation/history/MachineSnapshot.h
@@ -0,0 +1,17 @@
+#pragma once
+
+namespace Simulation {
+ /*
+ POD class that represents the state of a machine.
+ */
+ class MachineSnapshot {
+ public:
+ MachineSnapshot(int id, int currentWorkload, float temp, float load, uint32_t mem) : id(id), currentWorkload(currentWorkload), temperature(temp), loadFraction(load), usedMemory(mem) {}
+
+ int id;
+ int currentWorkload;
+ float temperature;
+ float loadFraction;
+ uint32_t usedMemory;
+ };
+} \ No newline at end of file
diff --git a/Simulator/include/simulation/history/SimulationHistory.h b/Simulator/include/simulation/history/SimulationHistory.h
new file mode 100644
index 00000000..f43968b7
--- /dev/null
+++ b/Simulator/include/simulation/history/SimulationHistory.h
@@ -0,0 +1,81 @@
+#pragma once
+#include "History.h"
+#include "WorkloadSnapshot.h"
+#include "MachineSnapshot.h"
+
+#include <unordered_map>
+
+namespace Simulation
+{
+ using WorkloadHistory = History<WorkloadSnapshot>;
+ using MachineHistory = History<MachineSnapshot>;
+ using HistoryRef = std::tuple<std::reference_wrapper<WorkloadHistory>, std::reference_wrapper<MachineHistory>>;
+
+ class SimulationHistory
+ {
+ public:
+ /*
+ Adds the workload snapshot at the given tick.
+ */
+ void addSnapshot(uint32_t tick, WorkloadSnapshot snapshots)
+ {
+ workloadHistory.addSnapshotAtTick(tick, snapshots);
+ }
+
+ /*
+ Adds the machine snapshot at the given tick.
+ */
+ void addSnapshot(uint32_t tick, MachineSnapshot snapshots)
+ {
+ machineHistory.addSnapshotAtTick(tick, snapshots);
+ }
+
+ /*
+ Returns the equal_range of the workload snapshots at the given tick.
+ */
+ auto getWorkloadSnapshot(uint32_t tick)
+ {
+ return workloadHistory.snapshotsAtTick(tick);
+ }
+
+ /*
+ Returns the equal_range of the machine snapshots at the given tick.
+ */
+ auto getMachineSnapshot(uint32_t tick)
+ {
+ return machineHistory.snapshotsAtTick(tick);
+ }
+
+ /*
+ Returns a const tuple ref of the entire cached history of machines and workloads.
+ */
+ const HistoryRef getHistory()
+ {
+ return std::make_tuple(
+ std::ref(workloadHistory),
+ std::ref(machineHistory)
+ );
+ }
+
+ /*
+ Clears the cache of history.
+ */
+ void clearHistory()
+ {
+ workloadHistory.clear();
+ machineHistory.clear();
+ }
+
+ /*
+ Returns the number of snapshots that are in the history cache.
+ */
+ size_t historySize()
+ {
+ return workloadHistory.size();
+ }
+
+ private:
+ WorkloadHistory workloadHistory;
+ MachineHistory machineHistory;
+ };
+} \ No newline at end of file
diff --git a/Simulator/include/simulation/history/WorkloadSnapshot.h b/Simulator/include/simulation/history/WorkloadSnapshot.h
new file mode 100644
index 00000000..1e7e2695
--- /dev/null
+++ b/Simulator/include/simulation/history/WorkloadSnapshot.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace Simulation
+{
+ class WorkloadSnapshot
+ {
+ public:
+ WorkloadSnapshot(uint32_t id, uint32_t flopsDone) : flopsDone(flopsDone), id(id) {}
+
+ uint32_t flopsDone;
+ uint32_t id;
+ };
+} \ No newline at end of file
diff --git a/Simulator/include/simulation/schedulers/FirstInFirstOutScheduler.h b/Simulator/include/simulation/schedulers/FirstInFirstOutScheduler.h
new file mode 100644
index 00000000..0cac0dfa
--- /dev/null
+++ b/Simulator/include/simulation/schedulers/FirstInFirstOutScheduler.h
@@ -0,0 +1,37 @@
+#pragma once
+#include "Scheduler.h"
+#include <algorithm>
+
+namespace Simulation
+{
+ class FirstInFirstOutScheduler : public Scheduler
+ {
+ protected:
+ ~FirstInFirstOutScheduler()
+ {
+ }
+
+ public:
+ /*
+ Distribute workloads according to the FIFO principle
+ */
+ void schedule(std::vector<std::reference_wrapper<Modeling::Machine>>& machines, std::vector<Workload*> workloads) override
+ {
+ if (workloads.size() == 0)
+ return;
+
+ // Find the first workload with dependencies finished
+ int index = 0;
+ while(!workloads.at(index)->dependencyFinished)
+ index = (++index) % workloads.size();
+
+ std::for_each(
+ machines.begin(),
+ machines.end(),
+ [index, &workloads](std::reference_wrapper<Modeling::Machine>& machine) {
+ machine.get().giveTask(workloads.at(index));
+ }
+ );
+ }
+ };
+}
diff --git a/Simulator/include/simulation/schedulers/Scheduler.h b/Simulator/include/simulation/schedulers/Scheduler.h
new file mode 100644
index 00000000..b084e8f6
--- /dev/null
+++ b/Simulator/include/simulation/schedulers/Scheduler.h
@@ -0,0 +1,25 @@
+#pragma once
+#include "simulation/workloads/Workload.h"
+#include "modeling/machine/Machine.h"
+
+#include <vector>
+
+namespace Simulation
+{
+ /*
+ Provides a strategy for load balancing.
+ */
+ class Scheduler
+ {
+ public:
+ virtual ~Scheduler()
+ {
+
+ }
+
+ /*
+ Divides the workloads over the given machines.
+ */
+ virtual void schedule(std::vector<std::reference_wrapper<Modeling::Machine>>& machines, std::vector<Workload*> workloads) = 0;
+ };
+}
diff --git a/Simulator/include/simulation/schedulers/ShortestRemainingTimeScheduler.h b/Simulator/include/simulation/schedulers/ShortestRemainingTimeScheduler.h
new file mode 100644
index 00000000..15265985
--- /dev/null
+++ b/Simulator/include/simulation/schedulers/ShortestRemainingTimeScheduler.h
@@ -0,0 +1,46 @@
+#pragma once
+#include "Scheduler.h"
+#include <algorithm>
+
+namespace Simulation
+{
+ class ShortestRemainingTimeScheduler : public Scheduler
+ {
+ protected:
+ ~ShortestRemainingTimeScheduler()
+ {
+ }
+
+ public:
+ /*
+ Distribute workloads according to the srtf principle
+ */
+ void schedule(std::vector<std::reference_wrapper<Modeling::Machine>>& machines, std::vector<Workload*> workloads) override
+ {
+ if (workloads.size() == 0)
+ return;
+
+ std::sort(
+ workloads.begin(),
+ workloads.end(),
+ [](Workload* a, Workload* b) -> bool {
+ return a->getRemainingOperations() < b->getRemainingOperations();
+ }
+ );
+
+ int taskIndex = 0;
+
+ std::for_each(
+ machines.begin(),
+ machines.end(),
+ [&workloads, &taskIndex](Modeling::Machine& machine) {
+ while (!workloads.at(taskIndex)->dependencyFinished)
+ taskIndex = (++taskIndex) % workloads.size();
+
+ machine.giveTask(workloads.at(taskIndex));
+ taskIndex = (++taskIndex) % workloads.size();
+ }
+ );
+ }
+ };
+}
diff --git a/Simulator/include/simulation/workloads/Workload.h b/Simulator/include/simulation/workloads/Workload.h
new file mode 100644
index 00000000..9de57990
--- /dev/null
+++ b/Simulator/include/simulation/workloads/Workload.h
@@ -0,0 +1,80 @@
+#pragma once
+#include <stdint.h>
+
+namespace Simulation
+{
+ /*
+ The Workload class models a workload.
+ */
+ class Workload
+ {
+ public:
+ /*
+ Initializes the TOTAL_FLOPS and the remainingFlops to the size.
+ */
+ Workload(int size, int startTick, int dbId, int traceId, int dependency);
+
+ /*
+ Decreases the remainingFlops by the given amount.
+ */
+ void doOperations(uint32_t opCount);
+
+ /*
+ Returns the amount of operations left to do.
+ */
+ uint32_t getRemainingOperations() const;
+
+ /*
+ Returns the total amount of operations, including finished ones.
+ */
+ uint32_t getTotalOperations() const;
+
+ /*
+ Returns true if the workload has been finished.
+ */
+ bool isFinished() const;
+
+ /*
+ Returns the id of this workload.
+ */
+ uint32_t getId() const;
+
+ /*
+ Returns the dependency id of this workload.
+ */
+ int getDependencyId() const;
+
+ /**
+ * \return The start tick of this workload.
+ */
+ uint32_t getStartTick() const
+ {
+ return START_TICK;
+ }
+
+ // True if the dependency of this workload has finished.
+ bool dependencyFinished = false;
+
+ private:
+ // The id of the workload this workload depends on.
+ int dependencyId;
+
+ // Finished is true if the remainingFlops is 0.
+ bool finished = false;
+
+ // The amount of operations done.
+ uint32_t remainingFlops;
+
+ // The total amount of operations required to finish this task.
+ uint32_t TOTAL_FLOPS;
+
+ // The tick during which this workload was started.
+ uint32_t START_TICK;
+
+ // The id of this workload in the database
+ uint32_t ID;
+
+ // The id of the trace this workload belongs to in the database.
+ uint32_t TRACE_ID;
+ };
+}
diff --git a/Simulator/include/simulation/workloads/WorkloadPool.h b/Simulator/include/simulation/workloads/WorkloadPool.h
new file mode 100644
index 00000000..28a2ad04
--- /dev/null
+++ b/Simulator/include/simulation/workloads/WorkloadPool.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "simulation/workloads/Workload.h"
+#include <vector>
+
+namespace Simulation
+{
+ class WorkloadPool
+ {
+ public:
+ /*
+ Adds the given workload to this pool of workloads.
+ */
+ void addWorkload(Workload w);
+
+ /*
+ Returns a reference to the vector of workloads.
+ */
+ std::vector<Workload*> getWorkloads(uint32_t currentTick);
+
+ /*
+ Returns a reference to the workload with the given id.
+ */
+ Workload& getWorkload(int id);
+
+ /*
+ Removes all workloads that are finished.
+ */
+ void clearFinishedWorkloads();
+
+ /*
+ Returns true if the workloads vector of this pool is empty.
+ */
+ bool isEmpty();
+
+ private:
+ /*
+ Sets all dependencyFinished to true of workloads with the given id as dependency.
+ */
+ void setDependenciesFinished(int id);
+
+ std::vector<Workload> workloads;
+ };
+}