Skip to content

Commit

Permalink
Game of life tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lefticus committed May 21, 2024
1 parent 0013c1f commit caa3c1d
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 11 deletions.
4 changes: 4 additions & 0 deletions parallel_algorithms/game_of_life.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
85 changes: 85 additions & 0 deletions parallel_algorithms/run_performance_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

if [ $# -ne 1 ]; then
echo "Usage: $0 <source_file.cpp>"
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"

55 changes: 47 additions & 8 deletions python/conway_game_of_life/cellular_automata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -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]



Expand All @@ -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
Expand All @@ -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))
Expand Down
6 changes: 3 additions & 3 deletions python/conway_game_of_life/larger_tests/parameters.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <cstdint>

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;

0 comments on commit caa3c1d

Please sign in to comment.