From caa3c1d3e780607a58c498479d9ea1c1eed1fba6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 21 May 2024 16:33:45 -0600 Subject: [PATCH] Game of life tests --- parallel_algorithms/game_of_life.cpp | 4 + parallel_algorithms/run_performance_tests.sh | 85 +++++++++++++++++++ .../conway_game_of_life/cellular_automata.py | 55 ++++++++++-- .../larger_tests/parameters.hpp | 6 +- 4 files changed, 139 insertions(+), 11 deletions(-) create mode 100755 parallel_algorithms/run_performance_tests.sh diff --git a/parallel_algorithms/game_of_life.cpp b/parallel_algorithms/game_of_life.cpp index 0cad275..afc8ee6 100644 --- a/parallel_algorithms/game_of_life.cpp +++ b/parallel_algorithms/game_of_life.cpp @@ -199,14 +199,18 @@ constexpr void iterate_board(const BoardType &input, BoardType &output, return true; }; +#ifndef SERIAL if consteval { +#endif std::transform(indices.begin(), indices.end(), output.data.begin(), rules); +#ifndef SERIAL } else { // std::execution::par_unseq to tell the runtime that it can parallelize // this std::transform(std::execution::par_unseq, indices.begin(), indices.end(), output.data.begin(), rules); } +#endif } struct Timer { diff --git a/parallel_algorithms/run_performance_tests.sh b/parallel_algorithms/run_performance_tests.sh new file mode 100755 index 0000000..e976673 --- /dev/null +++ b/parallel_algorithms/run_performance_tests.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Check if necessary commands are available +commands=("perf" "strip" "/usr/bin/time") +for cmd in "${commands[@]}"; do + if ! command -v $cmd &> /dev/null; then + echo "$cmd could not be found. Please install $cmd and try again." + exit 1 + fi +done + +SOURCE_FILE=$1 +OUTPUT_FILE="performance_stats.csv" + +# Compiler and optimization flags +COMPILERS=("gcc" "clang" "clang-13") +OPT_FLAGS=("-O0" "-O1" "-O2" "-O3" "-Os") +ARCH_FLAGS=("-march=x86-64" "-march=x86-64-v2" "-march=x86-64-v3" "-march=x86-64-v4") + +# CSV header +echo "Compiler,Version,Optimization,Architecture,File Size (bytes),Stripped Size (bytes),Time1 (ms),Time2 (ms),Time3 (ms),Time4 (ms),Time5 (ms),RAM Usage1 (KB),RAM Usage2 (KB),RAM Usage3 (KB),RAM Usage4 (KB),RAM Usage5 (KB),Cache References,Cache Misses,Cache Miss Ratio,Instructions,Instructions Per Cycle,Branches,Branch Misses,Branch Miss Ratio" > $OUTPUT_FILE + +# Function to extract perf metrics +extract_perf_metrics() { + local perf_output=$1 + local cache_references=$(echo "$perf_output" | grep "cache-references" -A 1 | tail -n 1 | awk '{print $1}') + local cache_misses=$(echo "$perf_output" | grep "cache-misses" -A 1 | tail -n 1 | awk '{print $1}') + local cache_miss_ratio=$(echo "$perf_output" | grep "cache-misses" -A 1 | tail -n 1 | awk '{print $4}') + local instructions=$(echo "$perf_output" | grep "instructions" -A 1 | tail -n 1 | awk '{print $1}') + local instructions_per_cycle=$(echo "$perf_output" | grep "instructions" -A 1 | tail -n 1 | awk '{print $4}') + local branches=$(echo "$perf_output" | grep "branches" -A 1 | tail -n 1 | awk '{print $1}') + local branch_misses=$(echo "$perf_output" | grep "branch-misses" -A 1 | tail -n 1 | awk '{print $1}') + local branch_miss_ratio=$(echo "$perf_output" | grep "branch-misses" -A 1 | tail -n 1 | awk '{print $4}') + + echo "$cache_references,$cache_misses,$cache_miss_ratio,$instructions,$instructions_per_cycle,$branches,$branch_misses,$branch_miss_ratio" +} + +# Main loop +for compiler in "${COMPILERS[@]}"; do + compiler_version=$($compiler --version | head -n 1) + for opt in "${OPT_FLAGS[@]}"; do + for arch in "${ARCH_FLAGS[@]}"; do + echo "Compiling with $compiler $opt $arch..." + output_executable="a.out" + $compiler $opt $arch $SOURCE_FILE -o $output_executable + + if [ $? -ne 0 ]; then + echo "Compilation failed for $compiler $opt $arch" + continue + fi + + file_size=$(stat -c%s "$output_executable") + strip "$output_executable" + stripped_size=$(stat -c%s "$output_executable") + + times=() + ram_usages=() + for i in {1..5}; do + echo "Running execution $i..." + start_time=$(date +%s%N) + /usr/bin/time -v ./a.out 2> time_output.txt + end_time=$(date +%s%N) + + execution_time=$((($end_time - $start_time) / 1000000)) # in milliseconds + ram_usage=$(grep "Maximum resident set size" time_output.txt | awk '{print $6}') + + times+=($execution_time) + ram_usages+=($ram_usage) + done + + perf_output=$(perf stat -e cache-references,cache-misses,instructions,branches,branch-misses ./$output_executable 2>&1) + metrics=$(extract_perf_metrics "$perf_output") + + echo "$compiler,$compiler_version,$opt,$arch,$file_size,$stripped_size,${times[0]},${times[1]},${times[2]},${times[3]},${times[4]},${ram_usages[0]},${ram_usages[1]},${ram_usages[2]},${ram_usages[3]},${ram_usages[4]},$metrics" >> $OUTPUT_FILE + done + done +done + +echo "Performance data collected in $OUTPUT_FILE" + diff --git a/python/conway_game_of_life/cellular_automata.py b/python/conway_game_of_life/cellular_automata.py index 3d1d7f8..d1af078 100644 --- a/python/conway_game_of_life/cellular_automata.py +++ b/python/conway_game_of_life/cellular_automata.py @@ -14,6 +14,7 @@ def __add__(self, other): class Cell: rule_number: int value: int + velocity: Point class Neighborhood: def __init__(self, array, array_width, array_height, center): @@ -32,7 +33,7 @@ class Automata: def __init__(self, width, height, rules): self.width = width self.height = height - self.data = [Cell(0, 0)] * (width * height) + self.data = [Cell(0, 0, Point(0,0))] * (width * height) self.rules = rules def index(self, p: Point): @@ -61,7 +62,7 @@ def next(self, skip_borders = False): return result def randomize_values(self, value_min, value_max): - self.data = [Cell(c.rule_number, random.randint(value_min, value_max)) for c in self.data] + self.data = [Cell(c.rule_number, random.randint(value_min, value_max), Point(0,0)) for c in self.data] @@ -75,13 +76,47 @@ def gravity(cell : Cell, neighbors : Neighborhood): return cell +def towards_me(p: Point, v :Point): + if p.x < 0 and p.y < 0 and v.x >0 and v.y>0: + return True + if p.x == 0 and p.y < 0 and v.x == 0 and v.y >0: + return True + if p.x > 0 and p.y < 0 and v.x < 0 and v.y > 0: + return True + if p.x < 0 and p.y == 0 and v.x > 0 and v.y == 0: + return True + if p.x > 0 and p.y == 0 and v.x < 0 and v.y == 0: + return True + if p.x < 0 and p.y > 0 and v.x > 0 and v.y < 0: + return True + if p.x == 0 and p.y > 0 and v.x == 0 and v.y < 0: + return True + if p.x > 0 and p.y > 0 and v.x < 0 and v.y < 0: + return True + + return False + + def fire(cell : Cell, neighbors : Neighborhood): falloff = .99 - new_value = int(cell.value * (random.random()*falloff)) + int(neighbors.get(Point(0, 1)).value * (random.random()*falloff)) + new_value = int(cell.value * (random.random()*falloff)) + new_velocity = cell.velocity + + for x in [-1,0,1]: + for y in [-1,0,1]: + if not (x == 0 and y == 0): + point = Point(x,y) + neighbor = neighbors.get(point) + + if towards_me(point, neighbor.velocity): + new_value += int(neighbor.value * (random.random()*falloff)) + #new_velocity += neighbor.velocity + new_velocity += Point((neighbor.velocity.x * (random.random()*falloff)), (neighbor.velocity.y * (random.random()*falloff))) + new_value = new_value if new_value <= 255 else 255 - return Cell(cell.rule_number, new_value) + return Cell(cell.rule_number, new_value, new_velocity) width = 320 @@ -95,14 +130,18 @@ def fire(cell : Cell, neighbors : Neighborhood): obj.randomize_values(0, 255) +#Top and bottom borders for x in range(0, obj.width): - obj.set(Point(x, 0), Cell(0, 0)) - obj.set(Point(x, obj.height-1), Cell(0, 255)) + obj.set(Point(x, 0), Cell(0, 0, Point(0,0))) + obj.set(Point(x, obj.height-1), Cell(0, 255, Point(10,-10))) +# Left and right borders for y in range(0, obj.height): - obj.set(Point(0, y), Cell(0, 0)) - obj.set(Point(obj.width-1, y), Cell(0, 0)) + obj.set(Point(0, y), Cell(0, 0, Point(0,0))) + obj.set(Point(obj.width-1, y), Cell(0, 0, Point(0,0))) +for y in range(obj.height-300, obj.height): + obj.set(Point(obj.width-1, y), Cell(0, 0, Point(-10, 0))) pygame.init() screen = pygame.display.set_mode((width, height)) diff --git a/python/conway_game_of_life/larger_tests/parameters.hpp b/python/conway_game_of_life/larger_tests/parameters.hpp index 0173584..e510a3b 100644 --- a/python/conway_game_of_life/larger_tests/parameters.hpp +++ b/python/conway_game_of_life/larger_tests/parameters.hpp @@ -1,5 +1,5 @@ #include -static constexpr std::size_t WIDTH=100; -static constexpr std::size_t HEIGHT=100; -static constexpr std::size_t ITERATIONS=100'000; +static constexpr std::size_t WIDTH=10000; +static constexpr std::size_t HEIGHT=10000; +static constexpr std::size_t ITERATIONS=10;