diff options
| author | MDBijman <matthijs@bijman.org> | 2017-01-24 12:15:26 +0100 |
|---|---|---|
| committer | MDBijman <matthijs@bijman.org> | 2017-01-24 12:15:26 +0100 |
| commit | 070ce923574dcc57435cb3fb2dfe86b6a38cd249 (patch) | |
| tree | ffd69a842ac4ad22aaf7161f923b9f0b47c7147a /Simulator/include/simulation | |
Initial code commit with organized dependencies
Diffstat (limited to 'Simulator/include/simulation')
| -rw-r--r-- | Simulator/include/simulation/Experiment.h | 179 | ||||
| -rw-r--r-- | Simulator/include/simulation/Path.h | 63 | ||||
| -rw-r--r-- | Simulator/include/simulation/Section.h | 76 | ||||
| -rw-r--r-- | Simulator/include/simulation/history/History.h | 43 | ||||
| -rw-r--r-- | Simulator/include/simulation/history/MachineSnapshot.h | 17 | ||||
| -rw-r--r-- | Simulator/include/simulation/history/SimulationHistory.h | 81 | ||||
| -rw-r--r-- | Simulator/include/simulation/history/WorkloadSnapshot.h | 13 | ||||
| -rw-r--r-- | Simulator/include/simulation/schedulers/FirstInFirstOutScheduler.h | 37 | ||||
| -rw-r--r-- | Simulator/include/simulation/schedulers/Scheduler.h | 25 | ||||
| -rw-r--r-- | Simulator/include/simulation/schedulers/ShortestRemainingTimeScheduler.h | 46 | ||||
| -rw-r--r-- | Simulator/include/simulation/workloads/Workload.h | 80 | ||||
| -rw-r--r-- | Simulator/include/simulation/workloads/WorkloadPool.h | 43 |
12 files changed, 703 insertions, 0 deletions
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; + }; +} |
