Commit 8c3be9bd authored by fstuehlinger's avatar fstuehlinger
Browse files

Solution for problem 7-2

parent a07595cd
cmake_minimum_required(VERSION 3.11)
project (containers LANGUAGES CXX)
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED TRUE)
set (CMAKE_CXX_EXTENSIONS FALSE)
if (
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"
)
set (CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic")
endif ()
add_subdirectory (timer)
add_executable (containers containers.cpp)
target_link_libraries (containers timer)
add_custom_command (
OUTPUT containers.dat
COMMAND containers > containers.dat
DEPENDS containers
)
add_custom_command (
OUTPUT containers.png
COMMAND ${CMAKE_SOURCE_DIR}/plot.py containers.dat containers.png
DEPENDS ${CMAKE_SOURCE_DIR}/plot.py containers.dat
)
add_custom_target (
plots ALL
DEPENDS containers.png
)
# Programming Techniques for Scientific Simulations I
# HS 2020
# Exercise 7.2
# 2020-10-29
# Michal Sudwoj <msudwoj@student.ethz.ch>
# Define our tools and parameters, preferably using the implicit variable names.
CXX = g++
CXXFLAGS = -O3 -std=c++11 -march=native -DNDEBUG
LDFLAGS = -Ltimer
LDLIBS = -ltimer
# Export all variables into the environment. This will come handy further below.
export
# The first target is called 'all' by convention and used to delegate.
.PHONY: all
all: containers.png
# Compile our code and generate an executable binary together with the library.
containers: containers.cpp timer/libtimer.a
$(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
# Libraries often know how to build themselves (provide their own build system).
# Exported variables will also be visible in a sub-make.
timer/libtimer.a:
$(MAKE) -C timer
# Rerun the file if either our program or the input parameter changes.
containers.dat: containers
./containers | tee containers.dat # "tee" just prints to the terminal and to the file
# Regenerate the plot if the data or plotting configuration changes.
containers.png: containers.dat containers.gnuplot
gnuplot containers.gnuplot
# Always offer a way to clean up!
.PHONY: clean
clean:
rm -f containers containers.dat containers.png
$(MAKE) -C timer clean
#include <iomanip> // for std::setw, std::setprecision
#include <ios> // for std::right
#include <iostream> // for std::cout
#include <vector> // for std::vector
#include <list> // for std::list
#include <set> // for std::set
#include "timer/timer.hpp"
#include <cmath>
using test_type = unsigned long;
template <class C>
void fill_container(const size_t & num_ops, C & container) {
}
template<typename C>
double measure_container(const size_t & num_ops,
const std::vector<test_type> & input) {
C cont (input.begin(), input.end());
double ti = 0.;
for (unsigned j = 0; j < num_ops; ++j) {
Timer t;
t.start();
cont.insert(cont.begin(), 0lu);
cont.erase(cont.begin());
t.stop();
ti += t.duration();
}
return std::log(ti / (double)num_ops);
}
int main() {
const size_t num_ops = 4e06;
std::cout
<< std::right << "# "
<< std::setw(4) << "N" << ' '
<< std::setw(13) << "Vector[ns/op]" << ' '
<< std::setw(13) << "List[ns/op]" << ' '
<< std::setw(13) << "Set[ns/op]" << '\n'
;
for(unsigned i = 4; i < 14; ++i){
const size_t size = 1ul << i; // == std::pow(2, i)
std::vector<test_type> input(size);
for(size_t i=0; i < input.size(); ++i) {
input[i] = i+1;
}
std::cout
<< std::right << std::fixed << std::setprecision(6) << " "
<< std::setw(4) << size << ' '
<< std::setw(13)
<< measure_container<std::vector<test_type>>(num_ops, input) << ' '
<< std::setw(13)
<< measure_container<std::list<test_type>>(num_ops, input) << ' '
<< std::setw(13)
<< measure_container<std::set<test_type>>(num_ops, input) << '\n'
;
}
return 0;
}
set title 'containers benchmarks'
set xlabel 'n'
set ylabel 'time [ns]'
set log xy
set grid
set key top left
set terminal png
set output 'containers.png'
plot 'containers.dat' u 1:2 w lp ti 'vector', 'containers.dat' u 1:3 w lp ti 'list', 'containers.dat' u 1:4 w lp ti 'set'
#!/usr/bin/env python
from argparse import ArgumentParser
import numpy as np
import matplotlib.pyplot as plt
def main():
parser = ArgumentParser()
parser.add_argument("input_file")
parser.add_argument("output_file", nargs="?")
args = parser.parse_args()
data = np.loadtxt(args.input_file)
fig = plt.figure()
fig.gca().set_xscale("log", base=2)
fig.gca().set_yscale("log", base=10)
plt.plot(data[:, 0], data[:, 1], label="Vector")
plt.plot(data[:, 0], data[:, 2], label="List")
plt.plot(data[:, 0], data[:, 3], label="Set")
plt.legend()
plt.title("Standard container comparison")
plt.xlabel("Size in elements")
plt.ylabel("Time in ns / op")
if args.output_file:
plt.savefig(args.output_file)
else:
plt.show()
if __name__ == "__main__":
main()
cmake_minimum_required(VERSION 3.1)
project(timer)
set(CMAKE_CXX_STANDARD 11)
add_library(timer STATIC timer.cpp)
install(TARGETS timer DESTINATION lib)
install(FILES timer.hpp DESTINATION include)
# Create a library from the object code.
libtimer.a: timer.o
ar rvs $@ $^
# Object code depending on header and implementation.
timer.o: timer.cpp timer.hpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
# Always offer a way to clean up!
.PHONY: clean
clean:
rm -f *.o *.a
# Note: in the target timer.o we could rely on implicit integration (leave the
# body empty). It is shown for verbosity: CXXFLAGS is inherited.
#include "timer.hpp"
Timer::Timer() {
tstart_ = std::chrono::high_resolution_clock::now();
}
void Timer::start() {
tstart_ = std::chrono::high_resolution_clock::now();
}
void Timer::stop() {
tend_ = std::chrono::high_resolution_clock::now();
}
double Timer::duration() const {
return std::chrono::duration< double >(tend_ - tstart_).count();
}
#ifndef TIMER_HPP
#define TIMER_HPP
#include <chrono>
class Timer {
public:
Timer();
void start();
void stop();
double duration() const;
private:
using time_point_t = std::chrono::high_resolution_clock::time_point;
time_point_t tstart_;
time_point_t tend_;
};
#endif // !defined TIMER_HPP
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment