diff --git a/lab_2/11/Makefile b/lab_2/11/Makefile new file mode 100644 index 0000000..0ef13b8 --- /dev/null +++ b/lab_2/11/Makefile @@ -0,0 +1,18 @@ +binary = memleak +folder = memleak +objects = $(patsubst %.cpp,%.o,$(wildcard *.cpp)) + +run: $(binary) + ./$(binary) 7 100000000 + +$(binary): $(objects) + g++ -o $@ $^ + +clean: + rm -f *.o + +clear: clean + rm -f *.zip $(binary) + +zip: clean + zip $(folder) Makefile *.cpp *.h diff --git a/lab_2/11/chain-random-walk.cpp b/lab_2/11/chain-random-walk.cpp new file mode 100644 index 0000000..780b048 --- /dev/null +++ b/lab_2/11/chain-random-walk.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +#include "chain-random-walk.h" + +using namespace crw; + +namespace { + // set each element forward or backward by 1, at random + void stochastic_unit_step(long size, float config[]) + { + for(long i = 0; i < size; i++) + if(std::rand() % 2 == 0) config[i]++; + else config[i]--; + } + + void shift_centre_to_origin(long size, float config[]) + { + double sum = 0.0; + for(long i = 0; i < size; i++) sum += config[i]; + for(long i = 0; i < size; i++) config[i] -= sum/size; + } + + const int el_out_max = 9; // show at most the first nine elements +} + +float crw::elongation(long size, float config[]) +{ + float min = config[0]; + float max = config[0]; + + for(long i = 1; i < size; i++) + if(config[i] > max) max = config[i]; + else if(config[i] < min) min = config[i]; + + return max - min; +} + +float* crw::step(long size, float previous[]) +{ + // allocate the next configuration + float* config = new float[size](); + + // first, let the chain contract: each element is attracted by its neighbours + for(long i = 0; i < size; i++) + config[i] = 0.5*previous[i] + 0.25*previous[(i-1) % size] + + 0.25*previous[(i+1) % size]; + + stochastic_unit_step(size, config); // actual random walk step + shift_centre_to_origin(size, config); // shift such that the average remains zero + + return config; +} + +void crw::output(long no, long size, float present[], float extreme[], double avg_el) +{ + /* output statistics over the run so far + */ + std::cout << std::setw(12) << no << "\t" << std::setprecision(3) << std::fixed + << std::setw(6) << elongation(size, present) << " " + << std::setprecision(7) << std::setw(10) << avg_el << " " << std::setprecision(5) + << std::setw(9) << elongation(size, extreme) << std::setprecision(3) << "\t\t"; + + /* display the present configuration, showing up to element coordinates */ + for(long i = 0; (i < size) && (i < el_out_max); i++) + std::cout << std::setw(7) << present[i] << " "; + if(size > el_out_max) std::cout << "..."; + std::cout << "\t\t"; + + /* display the most extreme configuration so far, + * showing up to element coordinates + */ + for(long i = 0; (i < size) && (i < el_out_max); i++) + std::cout << std::setw(7) << extreme[i] << " "; + if(size > el_out_max) std::cout << "..."; + std::cout << "\n"; +} diff --git a/lab_2/11/chain-random-walk.h b/lab_2/11/chain-random-walk.h new file mode 100644 index 0000000..9ad3d0e --- /dev/null +++ b/lab_2/11/chain-random-walk.h @@ -0,0 +1,11 @@ +#ifndef CHAIN_RANDOM_WALK_H +#define CHAIN_RANDOM_WALK_H + +namespace crw +{ + float elongation(long size, float config[]); + float* step(long size, float previous[]); + void output(long no, long size, float present[], float extreme[], double avg_el); +} + +#endif diff --git a/lab_2/11/const_Nm_timings.csv b/lab_2/11/const_Nm_timings.csv new file mode 100644 index 0000000..9380c34 --- /dev/null +++ b/lab_2/11/const_Nm_timings.csv @@ -0,0 +1,10 @@ +1024, 40.45 +512, 41.08 +256, 41.65 +128, 43.26 +64, 43.98 +32, 46.27 +16, 49.63 +8, 51.05 +4, 48.74 +2, 55.97 diff --git a/lab_2/11/const_m_timings.csv b/lab_2/11/const_m_timings.csv new file mode 100644 index 0000000..621bc60 --- /dev/null +++ b/lab_2/11/const_m_timings.csv @@ -0,0 +1,10 @@ +1024, 40.51 +512, 20.54 +256, 10.54 +128, 5.35 +64, 2.78 +32, 1.47 +16, 0.79 +8, 0.41 +4, 0.20 +2, 0.11 diff --git a/lab_2/11/log.csv b/lab_2/11/log.csv new file mode 100644 index 0000000..ec7ad70 --- /dev/null +++ b/lab_2/11/log.csv @@ -0,0 +1,10 @@ +1024, 42.77 +512, 21.70 +256, 10.86 +128, 5.67 +64, 2.88 +32, 1.53 +16, 0.84 +8, 0.45 +4, 0.21 +2, 0.11 \ No newline at end of file diff --git a/lab_2/11/memleak.cpp b/lab_2/11/memleak.cpp new file mode 100644 index 0000000..5833225 --- /dev/null +++ b/lab_2/11/memleak.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "chain-random-walk.h" + +namespace { + constexpr int default_size = 7; + constexpr int default_steps = 100000000; + constexpr int outlines = 25; +} + +/* first argument: array size + * second argument: number of steps + */ +int main(int argc, char** argv) +{ + long size = default_size; + if(argc > 1) size = std::atol(argv[1]); + assert(size > 0); + + long steps = default_steps; + if(argc > 2) steps = std::atol(argv[2]); + assert(steps > 0); + + long outfreq = steps / outlines; + if(outfreq < 1) outfreq = 1; + + /* the configuration is given by an array of float numbers */ + float* present_configuration = new float[size](); + + /* store the one with greatest deviation between min and max element */ + float* extreme_configuration = present_configuration; + float extreme_elongation = 0.0; + double el_sum = 0.0; + double el_avg = 0.0; + + std::srand(std::time(nullptr)); // initialize the random number generator + + for(long i = 0; i < steps; i++) + { + if(i % outfreq == 0) + crw::output(i, size, present_configuration, extreme_configuration, el_avg); + + /* here we are calling the random walk step; + * this returns a new configuration (float array) on the heap + */ + + // Simple fix to memleak: + float* old_configuration = present_configuration; + present_configuration = crw::step(size, present_configuration); + delete old_configuration; + float present_elongation = crw::elongation(size, present_configuration); + + if(present_elongation > extreme_elongation) + { + extreme_configuration = present_configuration; + extreme_elongation = present_elongation; + } + el_sum += present_elongation; + el_avg = el_sum / (i + 1.0); + } + crw::output(steps, size, present_configuration, extreme_configuration, el_avg); + + delete[] present_configuration; +} diff --git a/lab_2/11/plot_speedup.py b/lab_2/11/plot_speedup.py new file mode 100644 index 0000000..4417be1 --- /dev/null +++ b/lab_2/11/plot_speedup.py @@ -0,0 +1,38 @@ +import matplotlib.pyplot as plt +import matplotlib.cbook as cbook + +import numpy as np +import pandas as pd + +f1 = open('const_m_timings.csv', 'r') +f2 = open('../10_memleak/const_m_timings.csv', 'r') +x1 = [] +y1 = [] +for l,p in zip(f1.readlines(), f2.readlines()): + l = l.split(',') + p = p.split(',') + x1.append(p[0]) + y1.append(float(p[1])/float(l[1])) + +f1 = open('const_Nm_timings.csv', 'r') +f2 = open('../10_memleak/const_Nm_timings.csv', 'r') +x2 = [] +y2 = [] +for l,p in zip(f1.readlines(), f2.readlines()): + l = l.split(',') + p = p.split(',') + x2.append(p[0]) + y2.append(float(p[1])/float(l[1])) + +plt.plot(x1, y1, label = 'constant m') +plt.plot(x2, y2, label = 'constant Nm') +for i in range(len(x1)): + plt.text(i,y1[i],f'{y1[i]:.2f}', color="blue") +for i in range(len(x2)): + plt.text(i,y2[i],f'{y2[i]:.2f}', color="orange") +plt.title('Speedup after fixing leak') +plt.xlabel('N') +plt.ylabel('xspeedup') +plt.grid() +plt.legend() +plt.show() diff --git a/lab_2/11/time_N.nu b/lab_2/11/time_N.nu new file mode 100644 index 0000000..cfa51f1 --- /dev/null +++ b/lab_2/11/time_N.nu @@ -0,0 +1,7 @@ +for x in [1024 512 256 128 64 32 16 8 4 2] { +let filename = 'const_m_timings.csv'; +$x | into string | save --append $filename; +", " | save --append $filename; +let m = 2000000; +time -f %e -a -o $filename ./memleak $x $m; +}; \ No newline at end of file diff --git a/lab_2/11/time_Nm.nu b/lab_2/11/time_Nm.nu new file mode 100644 index 0000000..7298b2c --- /dev/null +++ b/lab_2/11/time_Nm.nu @@ -0,0 +1,7 @@ +for x in [1024 512 256 128 64 32 16 8 4 2] { +let filename = 'const_Nm_timings.csv'; +$x | into string | save --append $filename; +", " | save --append $filename; +let m = 2048000000 / $x; +time -f %e -a -o $filename ./memleak $x $m; +}; \ No newline at end of file diff --git a/lab_2/11_answer.md b/lab_2/11_answer.md new file mode 100644 index 0000000..42d9d56 --- /dev/null +++ b/lab_2/11_answer.md @@ -0,0 +1,10 @@ +# What approach did you decide to follow? +I saved the adress in present_configuration to a new pointer old_configuration so i could delete it after running the step function: + // Simple fix to memleak: + float* old_configuration = present_configuration; + present_configuration = crw::step(size, present_configuration); + delete old_configuration; + float present_elongation = crw::elongation(size, present_configuration); + +# determine the speedup +See 11_speedup.png diff --git a/lab_2/11_speedup.png b/lab_2/11_speedup.png new file mode 100644 index 0000000..c2f422d Binary files /dev/null and b/lab_2/11_speedup.png differ