diff --git a/Makefile b/Makefile index 36fda09..b414954 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ CXX = g++ -CXXFLAGS = -Wall +CXXFLAGS = -Wall -O3 -gol: main.o - $(CXX) $(CXXFLAGS) -o gol main.o +gol: main.o Timing.o + $(CXX) $(CXXFLAGS) -o gol main.o Timing.o -main.o: main.cpp +main.o: main.cpp Timing.h $(CXX) $(CXXFLAGS) -c main.cpp +Timing.o: Timing.h + clean : -rm *.o gol diff --git a/Timing.cpp b/Timing.cpp new file mode 100644 index 0000000..a2f11b8 --- /dev/null +++ b/Timing.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include "Timing.h" + +Timing* Timing::mInstance = 0; + +/** + * Singleton: Get instance. + */ +Timing* Timing::getInstance() { + if (mInstance == 0) { + mInstance = new Timing(); + } + + return mInstance; +} + +/** + * Start recording time with any name. + */ +void Timing::startRecord(const std::string& name) { + auto start = std::chrono::high_resolution_clock::now(); + + auto it = mRecordings.find(name); + if (it != mRecordings.end()) { + it->second = start; + } else { + mRecordings.insert(std::pair(name, start)); + } + +} + +/** + * Stop recording time with any name. + */ +void Timing::stopRecord(const std::string& name) { + auto end = std::chrono::high_resolution_clock::now(); + + auto it = mRecordings.find(name); + if (it != mRecordings.end()) { + auto start = it->second; + auto result = end - start; + + mResults.insert(std::pair >(name, result)); + } + +} + +/** + * Print measured results human-readable. + * Set prettyPrint to true to display mm:ss.ms instead of ms. + */ +void Timing::print(const bool prettyPrint) const { + std::cout << "-----" << std::endl << "Results: " << std::endl << "-----" << std::endl; + + auto it = mResults.begin(); + while(it != mResults.end()) { + if (prettyPrint) { + std::cout << it->first << ": " << parseDate((int) it->second.count()) << std::endl; + } else { + std::cout << it->first << ": " << it->second.count() << "ms" << std::endl; + } + it++; + } + + std::cout << "-----" << std::endl; +} + +/** + * Parse date from ms to mm:ss.ms. + */ +std::string Timing::parseDate(const int ms) const { + int minutes = (int) (ms / 1000 / 60); + int seconds = (int) ((ms % (1000 * 60)) / 1000); + int milliseconds = (int) (ms % 1000); + + std::ostringstream stringStream; + if (seconds == 60) { + stringStream << minutes + 1 << ":00" << seconds << "."; + } else { + stringStream << minutes << ":" << (seconds < 10 ? "0" : "") << seconds << "."; + } + + if (milliseconds < 100) { + if (milliseconds < 10) { + stringStream << "00" << milliseconds; + } else { + stringStream << "0" << milliseconds; + } + } else { + stringStream << milliseconds; + } + + return stringStream.str(); +} + +/** + * Get results of setup, computation and finalization in form: + * mm:ss.ms;mm:ss.ms;mm.ss.ms + */ +std::string Timing::getResults() const { + std::ostringstream stringStream; + + auto start = mResults.find("setup"); + if (start != mResults.end()) { + stringStream << parseDate((int) start->second.count()) << ";"; + } + + auto computation = mResults.find("computation"); + if (computation != mResults.end()) { + stringStream << parseDate((int) computation->second.count()) << ";"; + } + + auto finalization = mResults.find("finalization"); + if (start != mResults.end()) { + stringStream << parseDate((int) finalization->second.count()); + } + + return stringStream.str(); +} + +/** + * Start recording the setup time. + */ +void Timing::startSetup() { + this->startRecord("setup"); +} + +/** + * Stop recording the setup time. + */ +void Timing::stopSetup() { + this->stopRecord("setup"); +} + +/** + * Start recording the computation time. + */ +void Timing::startComputation() { + this->startRecord("computation"); +} + +/** + * Stop recording the computation time. + */ +void Timing::stopComputation() { + this->stopRecord("computation"); +} + +/** + * Start recording the finalization time. + */ +void Timing::startFinalization() { + this->startRecord("finalization"); +} + +/** + * Stop recording the finalization time. + */ +void Timing::stopFinalization() { + this->stopRecord("finalization"); +} \ No newline at end of file diff --git a/Timing.h b/Timing.h new file mode 100644 index 0000000..a05ac78 --- /dev/null +++ b/Timing.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include + +/** + * Measure high precision time intervals (using std::chrono). + * Author: Karl Hofer + */ +class Timing { +public: + static Timing* getInstance(); + + void startSetup(); + void stopSetup(); + void startComputation(); + void stopComputation(); + void startFinalization(); + void stopFinalization(); + + void startRecord(const std::string& name); + void stopRecord(const std::string& name); + void print(const bool prettyPrint = false) const; + std::string getResults() const; + +private: + Timing() {}; + std::map mRecordings; + std::map > mResults; + std::string parseDate(const int ms) const; + + static Timing* mInstance; +}; diff --git a/main.cpp b/main.cpp index d3ae571..cd6d443 100644 --- a/main.cpp +++ b/main.cpp @@ -5,6 +5,8 @@ #include #include +#include "Timing.h" + #define LIVE_CELL 'x' #define DEAD_CELL '.' @@ -28,6 +30,7 @@ struct World { char **data; char get_value(int x, int y) { + // TODO: Way too much work to do all the time. Move this to special cases if (x < 0) x += size_x; if (y < 0) y += size_y; if (x >= size_x) x -= size_x; @@ -51,30 +54,27 @@ struct World { int size_y; }; -void generation(World &world) { - // Set neighbor counts - int **neighbor_counts = new int*[world.size_y]; - for (int y = 0; y < world.size_y; y++) { - neighbor_counts[y] = new int[world.size_x]; - } +void generation(World &world, int *neighbor_counts) { + int size_x = world.size_x; + // Set neighbor counts for (int y = 0; y < world.size_y; y++) { for (int x = 0; x < world.size_x; x++) { // Get number of living neighbors int neighbors = 0; - for (int local_y = -1; local_y < 2; local_y++) { - for (int local_x = -1; local_x < 2; local_x++) { - // Ignore self - if (local_x == 0 && local_y == 0) continue; + if (world.get_value(x - 1, y - 1) == LIVE_CELL) neighbors++; + if (world.get_value(x, y - 1) == LIVE_CELL) neighbors++; + if (world.get_value(x + 1, y - 1) == LIVE_CELL) neighbors++; - if (world.get_value(x + local_x, y + local_y) == LIVE_CELL) { - neighbors++; - } - } - } + if (world.get_value(x - 1, y) == LIVE_CELL) neighbors++; + if (world.get_value(x + 1, y) == LIVE_CELL) neighbors++; - neighbor_counts[y][x] = neighbors; + if (world.get_value(x - 1, y + 1) == LIVE_CELL) neighbors++; + if (world.get_value(x, y + 1) == LIVE_CELL) neighbors++; + if (world.get_value(x + 1, y + 1) == LIVE_CELL) neighbors++; + + neighbor_counts[y * size_x + x] = neighbors; } } @@ -82,7 +82,7 @@ void generation(World &world) { for (int y = 0; y < world.size_y; y++) { for (int x = 0; x < world.size_x; x++) { char this_cell = world.get_value(x, y); - int neighbors = neighbor_counts[y][x]; + int neighbors = neighbor_counts[y * size_x + x]; if (this_cell == DEAD_CELL) { if (neighbors == 3) { @@ -102,9 +102,16 @@ void generation(World &world) { } int main() { + Timing *timing = Timing::getInstance(); + + // Setup. + timing->startSetup(); + // Read in the start state + std::string file_begin = "random250"; + std::ifstream world_file; - world_file.open("random250_in.gol"); + world_file.open(file_begin + "_in.gol"); // Get x and y size std::string x_str, y_str; @@ -128,14 +135,22 @@ int main() { world_file.close(); + timing->stopSetup(); + timing->startComputation(); + + int *neighbor_counts = new int[world.size_y * world.size_x]; + // Do some generations for (int i = 0; i < 250; i++) { - generation(world); + generation(world, neighbor_counts); } + timing->stopComputation(); + timing->startFinalization(); + // Write the result std::ofstream result_file; - result_file.open("random250_out.gol"); + result_file.open(file_begin + "_out.gol"); result_file << size_x << "," << size_y << '\n'; @@ -151,6 +166,11 @@ int main() { } result_file.close(); + delete neighbor_counts; + + timing->stopFinalization(); + + timing->print(); return 0; }