summaryrefslogtreecommitdiff
path: root/Simulator/src
diff options
context:
space:
mode:
Diffstat (limited to 'Simulator/src')
-rw-r--r--Simulator/src/Simulator.cpp51
-rw-r--r--Simulator/src/database/Database.cpp286
-rw-r--r--Simulator/src/modeling/Entity.cpp8
-rw-r--r--Simulator/src/modeling/Rack.cpp21
-rw-r--r--Simulator/src/modeling/machine/CPU.cpp26
-rw-r--r--Simulator/src/modeling/machine/GPU.cpp26
-rw-r--r--Simulator/src/modeling/machine/Machine.cpp80
-rw-r--r--Simulator/src/simulation/workloads/Workload.cpp47
-rw-r--r--Simulator/src/simulation/workloads/WorkloadPool.cpp69
9 files changed, 614 insertions, 0 deletions
diff --git a/Simulator/src/Simulator.cpp b/Simulator/src/Simulator.cpp
new file mode 100644
index 00000000..fe963e0c
--- /dev/null
+++ b/Simulator/src/Simulator.cpp
@@ -0,0 +1,51 @@
+#include "Simulator.h"
+#include "modeling/ModelingTypes.h"
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+#include <cassert>
+
+int main(int argc, char* argv[])
+{
+ assert(argc == 2);
+
+ // The main simulator, responsible for updating and writing away each simulation.
+ Simulation::Simulator<DefaultSection> simulator(argv[1]);
+
+ // Timer used for polling only once every 5 seconds
+ auto pollTimer = std::chrono::high_resolution_clock::now() - std::chrono::seconds(5);
+
+ while (true)
+ {
+ auto now = std::chrono::high_resolution_clock::now();
+
+ // Calculate the time since the last polling
+ std::chrono::duration<double> diff = now - pollTimer;
+ if (diff.count() > 5) // Every five seconds, poll and load
+ {
+ // Poll and load all experiments queued in the database
+ simulator.pollAndLoadAll();
+ // Reset the timer for polling
+ pollTimer = std::chrono::high_resolution_clock::now();
+ }
+
+ if (simulator.hasSimulations())
+ {
+ // Update each simulation
+ simulator.tickAll();
+ // Save the state of each simulation
+ simulator.saveStateAll();
+ // Write the history of each simulation when 500 states have been saved
+ simulator.writeHistoryAll();
+ }
+ else // Wait for polling
+ {
+ std::chrono::duration<double> timeToSleep = std::chrono::seconds(5) - diff;
+ std::this_thread::sleep_for(diff);
+ }
+ }
+
+ // Terminal pause, press key to exit
+ std::cin.get();
+}
diff --git a/Simulator/src/database/Database.cpp b/Simulator/src/database/Database.cpp
new file mode 100644
index 00000000..bb76abda
--- /dev/null
+++ b/Simulator/src/database/Database.cpp
@@ -0,0 +1,286 @@
+#include "database/Database.h"
+#include "database/Queries.h"
+#include "database/QueryExecuter.h"
+
+#include "modeling/ModelingTypes.h"
+#include "modeling/machine/CPU.h"
+
+#include "simulation/schedulers/ShortestRemainingTimeScheduler.h"
+
+#include <sqlite3.h>
+#include <assert.h>
+#include "simulation/Experiment.h"
+#include "simulation/schedulers/FirstInFirstOutScheduler.h"
+
+namespace Database
+{
+ Database::Database(char* name)
+ {
+ int rc = sqlite3_open_v2(name, &db, SQLITE_OPEN_READWRITE, NULL);
+ assert(rc == SQLITE_OK);
+ }
+
+ Database::~Database()
+ {
+ int rc = sqlite3_close_v2(db);
+ assert(rc == SQLITE_OK);
+ }
+
+ void Database::startTransaction() const
+ {
+ sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
+ }
+
+ void Database::endTransaction() const
+ {
+ sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, NULL);
+ }
+
+ void Database::writeExperimentHistory(Simulation::Experiment& experiment) const
+ {
+ auto history = experiment.getHistory();
+
+ auto workloadHistory = std::get<0>(history.getHistory());
+
+ QueryExecuter<> writeWorkloadStateQuery(db);
+ writeWorkloadStateQuery.setQuery(Queries::WRITE_WORKLOAD_STATE);
+ std::for_each(workloadHistory.get().begin(), workloadHistory.get().end(), [&](const auto& pair) {
+ uint32_t tick = pair.first;
+ Simulation::WorkloadSnapshot snapshot = pair.second;
+
+ uint32_t id = snapshot.id;
+ uint32_t flopsDone = snapshot.flopsDone;
+ writeWorkloadStateQuery.reset()
+ .bindParams<int, int, int, int>(id, experiment.getId(), tick, flopsDone)
+ .executeOnce();
+ });
+
+ auto machineHistory = std::get<1>(history.getHistory());
+
+ QueryExecuter<> writeMachineStateQuery(db);
+ writeMachineStateQuery.setQuery(Queries::WRITE_MACHINE_STATE);
+
+ std::for_each(machineHistory.get().begin(), machineHistory.get().end(), [&](const auto& pair) {
+ uint32_t tick = pair.first;
+ Simulation::MachineSnapshot snapshot = pair.second;
+
+ uint32_t id = snapshot.id;
+ uint32_t workloadId = snapshot.currentWorkload;
+ float temp = snapshot.temperature;
+ float load = snapshot.loadFraction;
+
+ uint32_t mem = snapshot.usedMemory;
+ writeMachineStateQuery.reset()
+ .bindParams<int, int, int, int, float, int, float>(workloadId, id, experiment.getId(), tick, temp, mem, load)
+ .executeOnce();
+ });
+
+ history.clearHistory();
+ }
+
+ int Database::pollQueuedExperiments() const
+ {
+ QueryExecuter<int> q(db);
+ q.setQuery(Queries::GET_QUEUED_EXPERIMENTS);
+ bool hasRow = q.step();
+ if(hasRow)
+ return q.result().get<int, 0>();
+ return -1;
+ }
+
+ void Database::dequeueExperiment(int experimentId) const
+ {
+ QueryExecuter<> q(db);
+ q.setQuery(Queries::REMOVE_QUEUED_EXPERIMENT)
+ .bindParams<int>(experimentId)
+ .executeOnce();
+ }
+
+ Simulation::Experiment Database::createExperiment(uint32_t experimentId)
+ {
+ // Retrieves the experiment data by ID
+ QueryExecuter<int, int, int, int, std::string, std::string> q(db);
+ QueryResult<int, int, int, int, std::string, std::string> qres = q
+ .setQuery(Queries::GET_EXPERIMENT_BY_ID)
+ .bindParams<int>(experimentId)
+ .executeOnce();
+
+ // Sets the scheduler of the datacenter
+ Simulation::Scheduler* scheduler = loadScheduler(experimentId);
+
+ int pathId = qres.get<int, 2>();
+ Simulation::Path path = Simulation::Path(pathId);
+
+ QueryExecuter<int, int, int, int> q2(db);
+ std::vector<QueryResult<int, int, int, int>> q2res = q2
+ .setQuery(Queries::GET_SECTION_BY_PATH_ID)
+ .bindParams<int>(pathId)
+ .execute();
+
+ // Retrieve workloads of trace
+ Simulation::WorkloadPool pool = loadWorkloads(experimentId);
+
+ std::for_each(q2res.begin(), q2res.end(), [&](QueryResult<int, int, int, int> r) {
+ int datacenterId = r.get<int, 2>();
+ int startTick = r.get<int, 3>();
+ DefaultDatacenter datacenter = loadDatacenter(datacenterId);
+ DefaultSection section(datacenter, startTick);
+
+ path.addSection(section);
+ });
+
+ Simulation::Experiment experiment(path, scheduler, pool, experimentId);
+
+ return experiment;
+ }
+
+ Simulation::Scheduler* Database::loadScheduler(uint32_t experimentId) const
+ {
+ std::string name = QueryExecuter<std::string>(db)
+ .setQuery(Queries::GET_SCHEDULER_TYPE_OF_EXPERIMENT)
+ .bindParams<int>(experimentId)
+ .executeOnce()
+ .get<std::string, 0>();
+
+ // Retrieve scheduler
+ Simulation::Scheduler* scheduler = nullptr;
+ if(name == "DEFAULT")
+ scheduler = new Simulation::FirstInFirstOutScheduler();
+ else if(name == "SRTF") // Shortest remaining time first
+ scheduler = new Simulation::ShortestRemainingTimeScheduler();
+ else if(name == "FIFO")
+ scheduler = new Simulation::FirstInFirstOutScheduler();
+
+ assert(scheduler != nullptr);
+ return scheduler;
+ }
+
+ DefaultDatacenter Database::loadDatacenter(uint32_t datacenterId) const
+ {
+ DefaultDatacenter datacenter;
+
+ // Retrieves a vector of rooms of the datacenter
+ std::vector<QueryResult<int, std::string, int, std::string>> rooms = QueryExecuter<int, std::string, int, std::string>(db)
+ .setQuery(Queries::GET_ROOMS_OF_DATACENTER)
+ .bindParams<int>(datacenterId)
+ .execute();
+
+ // Get machines of rooms
+ for(auto& room : rooms)
+ {
+ int id = room.get<int, 0>();
+ Modeling::ServerRoom serverRoom(id);
+
+ // Retrieves the racks in the room
+ auto racks = QueryExecuter<int, std::string, int>(db)
+ .setQuery(Queries::GET_RACKS_OF_ROOM)
+ .bindParams<int>(id)
+ .execute();
+
+ for(auto& queryResult : racks)
+ {
+ int rackId = queryResult.get<int, 0>();
+
+ // Retrieves the machines in the rack
+ auto machinesResult = QueryExecuter<int, int>(db)
+ .setQuery(Queries::GET_MACHINES_OF_RACK)
+ .bindParams<int>(rackId)
+ .execute();
+
+ std::unordered_map<uint32_t, Modeling::Machine> machines;
+ for(auto& qr : machinesResult)
+ {
+ int position = qr.get<int, 1>();
+ int machineId = qr.get<int, 0>();
+ machines.emplace(position, Modeling::Machine(machineId));
+ }
+
+ Modeling::Rack rack(rackId, machines);
+
+ // Retrieves the cpus in the rack
+ auto cpus = QueryExecuter<int, int, int, int, int>(db)
+ .setQuery(Queries::GET_CPUS_IN_RACK)
+ .bindParams<int>(rackId)
+ .execute();
+
+ for(auto& cpu : cpus)
+ {
+ int slot = cpu.get<int, 0>();
+ int speed = cpu.get<int, 1>();
+ int cores = cpu.get<int, 2>();
+ int energyConsumption = cpu.get<int, 3>();
+ int failureModelId = cpu.get<int, 4>();
+
+ rack.getMachineAtSlot(slot).addCPU(Modeling::CPU(speed, cores, energyConsumption, failureModelId));
+ }
+
+ // Retrieves the gpus in the rack
+ auto gpus = QueryExecuter<int, int, int, int, int>(db)
+ .setQuery(Queries::GET_GPUS_IN_RACK)
+ .bindParams<int>(rackId)
+ .execute();
+
+ for(auto& gpu : gpus)
+ {
+ int machineSlot = gpu.get<int, 0>();
+ int speed = gpu.get<int, 1>();
+ int cores = gpu.get<int, 2>();
+ int energyConsumption = gpu.get<int, 3>();
+ int failureModelId = gpu.get<int, 4>();
+
+ rack.getMachineAtSlot(machineSlot).addGPU(Modeling::GPU(speed, cores, energyConsumption, failureModelId));
+ }
+
+ serverRoom.addEntity<Modeling::Rack>(rack);
+ }
+
+ datacenter.addRoomOfType<Modeling::ServerRoom>(serverRoom);
+ }
+
+ return datacenter;
+ }
+
+ Simulation::WorkloadPool Database::loadWorkloads(uint32_t simulationSectionId) const
+ {
+ Simulation::WorkloadPool pool;
+
+ std::vector<QueryResult<int, int, int, int, int>> tasks;
+ // Fetch tasks from database
+ {
+ // Retrieves the traceId corresponding to the simulation section
+ QueryExecuter<int> q(db);
+ int traceId = q
+ .setQuery(Queries::GET_TRACE_OF_EXPERIMENT)
+ .bindParams<int>(simulationSectionId)
+ .executeOnce()
+ .get<int, 0>();
+
+ // Retrieves the tasks that belong to the traceId
+ QueryExecuter<int, int, int, int, int> q2(db);
+ tasks = q2
+ .setQuery(Queries::GET_TASKS_OF_TRACE)
+ .bindParams<int>(traceId)
+ .execute();
+ }
+
+ // Create workloads from tasks
+ for(auto& row : tasks)
+ {
+ int id = row.get<int, 0>();
+ int startTick = row.get<int, 1>();
+ int totalFlopCount = row.get<int, 2>();
+ int traceId = row.get<int, 3>();
+ int dependency = row.get<int, 4>();
+
+ // TODO possibly wait and batch?
+ Simulation::Workload workload(totalFlopCount, startTick, id, traceId, dependency);
+ if(dependency == 0)
+ workload.dependencyFinished = true;
+
+ pool.addWorkload(workload);
+ }
+
+ return pool;
+ }
+}
+
diff --git a/Simulator/src/modeling/Entity.cpp b/Simulator/src/modeling/Entity.cpp
new file mode 100644
index 00000000..eb39222b
--- /dev/null
+++ b/Simulator/src/modeling/Entity.cpp
@@ -0,0 +1,8 @@
+#include "modeling/Entity.h"
+
+namespace Modeling
+{
+ Entity::Entity(int id) : id(id)
+ {
+ }
+}
diff --git a/Simulator/src/modeling/Rack.cpp b/Simulator/src/modeling/Rack.cpp
new file mode 100644
index 00000000..2b330abd
--- /dev/null
+++ b/Simulator/src/modeling/Rack.cpp
@@ -0,0 +1,21 @@
+#include "modeling/Rack.h"
+
+#include <assert.h>
+#include <iterator>
+
+namespace Modeling
+{
+ Rack::Rack(int id, std::unordered_map<uint32_t, Machine> machines) : Entity(id), machines(machines) {}
+
+ std::unordered_map<uint32_t, Machine>& Rack::getMachines()
+ {
+ return machines;
+ }
+
+ Machine& Rack::getMachineAtSlot(int slot)
+ {
+ assert(machines.find(slot) != machines.end());
+
+ return machines.at(slot);
+ }
+}
diff --git a/Simulator/src/modeling/machine/CPU.cpp b/Simulator/src/modeling/machine/CPU.cpp
new file mode 100644
index 00000000..6167b133
--- /dev/null
+++ b/Simulator/src/modeling/machine/CPU.cpp
@@ -0,0 +1,26 @@
+#include "modeling/machine/CPU.h"
+
+namespace Modeling
+{
+ CPU::CPU(int speed, int cores, int energyConsumption, int failureModelId) : speed(speed), cores(cores), energyConsumption(energyConsumption), failureModelId(failureModelId) {}
+
+ int CPU::getCores()
+ {
+ return this->cores;
+ }
+
+ int CPU::getEnergyConsumption()
+ {
+ return this->energyConsumption;
+ }
+
+ int CPU::getFailureModelId()
+ {
+ return this->failureModelId;
+ }
+
+ int CPU::getSpeed()
+ {
+ return this->speed;
+ }
+}
diff --git a/Simulator/src/modeling/machine/GPU.cpp b/Simulator/src/modeling/machine/GPU.cpp
new file mode 100644
index 00000000..8458925b
--- /dev/null
+++ b/Simulator/src/modeling/machine/GPU.cpp
@@ -0,0 +1,26 @@
+#include "modeling/machine/GPU.h"
+
+namespace Modeling
+{
+ GPU::GPU(int speed, int cores, int energyConsumption, int failureModelId) : speed(speed), cores(cores), energyConsumption(energyConsumption), failureModelId(failureModelId) {}
+
+ int GPU::getCores()
+ {
+ return this->cores;
+ }
+
+ int GPU::getEnergyConsumption()
+ {
+ return this->energyConsumption;
+ }
+
+ int GPU::getFailureModelId()
+ {
+ return this->failureModelId;
+ }
+
+ int GPU::getSpeed()
+ {
+ return this->speed;
+ }
+}
diff --git a/Simulator/src/modeling/machine/Machine.cpp b/Simulator/src/modeling/machine/Machine.cpp
new file mode 100644
index 00000000..d7d4fac7
--- /dev/null
+++ b/Simulator/src/modeling/machine/Machine.cpp
@@ -0,0 +1,80 @@
+#include "modeling/machine/Machine.h"
+
+namespace Modeling
+{
+ Machine::Machine(int id) : busy(false), currentWorkload(), id(id)
+ {}
+
+ void Machine::addCPU(CPU c)
+ {
+ cpus.push_back(c);
+ }
+
+ void Machine::addGPU(GPU g)
+ {
+ gpus.push_back(g);
+ }
+
+ void Machine::giveTask(Simulation::Workload* workload)
+ {
+ busy = true;
+ currentWorkload = workload;
+ }
+
+ bool Machine::isBusy() const
+ {
+ return this->busy;
+ }
+
+ uint32_t Machine::getSpeed()
+ {
+ int speed = 0;
+ for(auto cpu : cpus)
+ {
+ speed += cpu.getSpeed() * cpu.getCores();
+ }
+ return speed;
+ }
+
+ void Machine::work()
+ {
+ if(!currentWorkload)
+ return;
+
+ currentWorkload->doOperations(static_cast<int>(getSpeed() * load));
+
+ temperature += load * temperatureIncrease;
+ //load = temperature < 70.0f ? 1.0f : 1.0f / (temperature - 69.0f);
+ load = 1.0f;
+ temperature = temperature > maxTemperature ? maxTemperature
+ : temperature < minTemperature ? minTemperature
+ : temperature;
+ }
+
+ int Machine::getWorkloadId() const
+ {
+ if(currentWorkload)
+ return currentWorkload->getId();
+ return 0;
+ }
+
+ int Machine::getId() const
+ {
+ return this->id;
+ }
+
+ float Machine::getTemperature() const
+ {
+ return this->temperature;
+ }
+
+ int Machine::getMemory() const
+ {
+ return this->memory;
+ }
+
+ float Machine::getLoad() const
+ {
+ return this->load;
+ }
+}
diff --git a/Simulator/src/simulation/workloads/Workload.cpp b/Simulator/src/simulation/workloads/Workload.cpp
new file mode 100644
index 00000000..b6a3b2d0
--- /dev/null
+++ b/Simulator/src/simulation/workloads/Workload.cpp
@@ -0,0 +1,47 @@
+#include "simulation/workloads/Workload.h"
+
+#include <iostream>
+
+namespace Simulation
+{
+ Workload::Workload(int size, int startTick, int dbId, int traceId, int dependency) : dependencyId(dependency), remainingFlops(size), TOTAL_FLOPS(size), START_TICK(startTick), ID(dbId), TRACE_ID(traceId) {}
+
+ void Workload::doOperations(uint32_t opCount)
+ {
+ if (opCount < 0 || finished) return;
+
+ if (remainingFlops <= opCount)
+ {
+ remainingFlops = 0;
+ finished = true;
+ }
+ else
+ {
+ remainingFlops -= opCount;
+ }
+ }
+
+ uint32_t Workload::getRemainingOperations() const
+ {
+ return remainingFlops;
+ }
+
+ uint32_t Workload::getTotalOperations() const
+ {
+ return TOTAL_FLOPS;
+ }
+
+ bool Workload::isFinished() const
+ {
+ return this->finished;
+ }
+ uint32_t Workload::getId() const
+ {
+ return ID;
+ }
+
+ int Workload::getDependencyId() const
+ {
+ return this->dependencyId;
+ }
+}
diff --git a/Simulator/src/simulation/workloads/WorkloadPool.cpp b/Simulator/src/simulation/workloads/WorkloadPool.cpp
new file mode 100644
index 00000000..c4910c7f
--- /dev/null
+++ b/Simulator/src/simulation/workloads/WorkloadPool.cpp
@@ -0,0 +1,69 @@
+#include "simulation/workloads/WorkloadPool.h"
+
+#include <iostream>
+#include <algorithm>
+
+namespace Simulation
+{
+ void WorkloadPool::addWorkload(Workload w)
+ {
+ workloads.push_back(w);
+ }
+
+ std::vector<Workload*> WorkloadPool::getWorkloads(uint32_t currentTick)
+ {
+ std::vector<Workload*> filteredOnStarted;
+ for(Workload& w : workloads)
+ {
+ if(w.getStartTick() < currentTick)
+ filteredOnStarted.push_back(&w);
+ }
+
+ return filteredOnStarted;
+ }
+
+ Workload& WorkloadPool::getWorkload(int id)
+ {
+ auto it = std::find_if(workloads.begin(), workloads.end(), [id](Workload& w) {
+ return (id == w.getId());
+ });
+
+ return *it;
+ }
+
+ void WorkloadPool::clearFinishedWorkloads()
+ {
+ auto it = workloads.begin();
+ while(it != workloads.end())
+ {
+ if(it->isFinished())
+ {
+ std::cout << "Finished workload " << it->getId() << std::endl;
+ int id = it->getId();
+ setDependenciesFinished(id);
+ it = workloads.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ }
+
+ void WorkloadPool::setDependenciesFinished(int id)
+ {
+ for(auto& workload : workloads)
+ {
+ if(workload.getDependencyId() == id)
+ {
+ workload.dependencyFinished = true;
+ std::cout << "Finished dependency of " << workload.getId() << std::endl;
+ }
+ }
+ }
+
+ bool WorkloadPool::isEmpty()
+ {
+ return this->workloads.size() == 0;
+ }
+}