diff options
Diffstat (limited to 'Simulator/src')
| -rw-r--r-- | Simulator/src/Simulator.cpp | 51 | ||||
| -rw-r--r-- | Simulator/src/database/Database.cpp | 286 | ||||
| -rw-r--r-- | Simulator/src/modeling/Entity.cpp | 8 | ||||
| -rw-r--r-- | Simulator/src/modeling/Rack.cpp | 21 | ||||
| -rw-r--r-- | Simulator/src/modeling/machine/CPU.cpp | 26 | ||||
| -rw-r--r-- | Simulator/src/modeling/machine/GPU.cpp | 26 | ||||
| -rw-r--r-- | Simulator/src/modeling/machine/Machine.cpp | 80 | ||||
| -rw-r--r-- | Simulator/src/simulation/workloads/Workload.cpp | 47 | ||||
| -rw-r--r-- | Simulator/src/simulation/workloads/WorkloadPool.cpp | 69 |
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; + } +} |
