From a8c1d9962baae7b57f5cb0a6ad90b4c4dbcf004a Mon Sep 17 00:00:00 2001
From: "raphael.bach" <raphael.bach@etu.hesge.ch>
Date: Mon, 18 Jul 2022 22:33:57 +0200
Subject: [PATCH] Add Game of Life example

---
 Makefile                         | 36 ++++++++++++-
 examples/game_of_life/.gitignore |  7 +++
 examples/game_of_life/Makefile   | 87 ++++++++++++++++++++++++++++++++
 examples/game_of_life/gol.fut    | 11 ++++
 examples/game_of_life/main.c     | 85 +++++++++++++++++++++++++++++++
 5 files changed, 225 insertions(+), 1 deletion(-)
 create mode 100644 examples/game_of_life/.gitignore
 create mode 100644 examples/game_of_life/Makefile
 create mode 100644 examples/game_of_life/gol.fut
 create mode 100644 examples/game_of_life/main.c

diff --git a/Makefile b/Makefile
index 1eba9c4..f65a966 100644
--- a/Makefile
+++ b/Makefile
@@ -98,7 +98,7 @@ src/futhark/fmpi_entry.h src/futhark/fmpi_entry.c &: src/futhark/fmpi_entry.fut
 # BUILD TARGETS - EXAMPLES
 ################################################################################
 .PHONY: examples
-examples: array-sum rule-110
+examples: array-sum rule-110 gol
 #-------------------------------------------------------------------------------
 # Array sum
 #-------------------------------------------------------------------------------
@@ -131,6 +131,22 @@ rule-110-pp: export BUILD_MODE := $(BUILD_MODE)
 rule-110-pp: export CFLAGS     := $(filter-out -Iinclude,$(CFLAGS)) -I../../include
 rule-110-pp:
 	$(MAKE) -C examples/rule_110 pp
+#-------------------------------------------------------------------------------
+# Game of Life
+#-------------------------------------------------------------------------------
+.PHONY: gol
+gol: export BUILD_MODE := $(BUILD_MODE)
+gol: export CFLAGS     := $(filter-out -Iinclude,$(CFLAGS)) -I../../include
+gol: export LDFLAGS    := $(LDFLAGS) -L../../build/$(BUILD_MODE)
+gol: export LDLIBS     := $(LDLIBS) -lfmpi -lm
+gol:
+	$(MAKE) -C examples/game_of_life
+
+.PHONY: gol-pp
+gol-pp: export BUILD_MODE := $(BUILD_MODE)
+gol-pp: export CFLAGS     := $(filter-out -Iinclude,$(CFLAGS)) -I../../include
+gol-pp:
+	$(MAKE) -C examples/gol pp
 ################################################################################
 # INSTALL TARGETS
 ################################################################################
@@ -206,16 +222,19 @@ clean-examples: clean-examples-$(BUILD_MODE)
 .PHONY: clean-examples-all
 clean-examples-all:
 	$(MAKE) -C examples/array_sum clean-all
+	$(MAKE) -C examples/game_of_life clean-all
 	$(MAKE) -C examples/rule_110 clean-all
 
 .PHONY: clean-examples-debug
 clean-examples-debug:
 	$(MAKE) -C examples/array_sum clean-debug
+	$(MAKE) -C examples/game_of_life clean-debug
 	$(MAKE) -C examples/rule_110 clean-debug
 
 .PHONY: clean-examples-release
 clean-examples-release:
 	$(MAKE) -C examples/array_sum clean-release
+	$(MAKE) -C examples/game_of_life clean-release
 	$(MAKE) -C examples/rule_110 clean-release
 ################################################################################
 # REBUILD TARGETS
@@ -259,6 +278,20 @@ run-r110-debug:
 .PHONY: run-r110-release
 run-r110-release:
 	$(MAKE) -C examples/rule_110 run-release
+#-------------------------------------------------------------------------------
+# Game of Life
+#-------------------------------------------------------------------------------
+.PHONY: run-gol
+run-gol:
+	$(MAKE) -C examples/game_of_life run-$(BUILD_MODE)
+
+.PHONY: run-gol-debug
+run-gol-debug:
+	$(MAKE) -C examples/game_of_life run-debug
+
+.PHONY: run-gol-release
+run-gol-release:
+	$(MAKE) -C examples/game_of_life run-release
 ################################################################################
 # MISC TARGETS
 ################################################################################
@@ -320,6 +353,7 @@ help:
 	@printf "\n"
 	@printf "RUN:\n"
 	@printf "  run-as                     : Run 'Array sum' example.\n"
+	@printf "  run-gol                    : Run 'Game of Life' example.\n"
 	@printf "  run-r110                   : Run 'Rule 110' example.\n"
 	@printf "\n"
 	@printf "UNINSTALL:\n"
diff --git a/examples/game_of_life/.gitignore b/examples/game_of_life/.gitignore
new file mode 100644
index 0000000..bfce2aa
--- /dev/null
+++ b/examples/game_of_life/.gitignore
@@ -0,0 +1,7 @@
+*.json
+*.o
+*.pp
+gol-debug
+gol-release
+gol.c
+gol.h
diff --git a/examples/game_of_life/Makefile b/examples/game_of_life/Makefile
new file mode 100644
index 0000000..a2f4c0d
--- /dev/null
+++ b/examples/game_of_life/Makefile
@@ -0,0 +1,87 @@
+################################################################################
+# BUILD TARGETS - MAIN
+################################################################################
+NAME := gol
+
+.PHONY: all
+all: $(NAME)-$(BUILD_MODE)
+
+.PHONY: all-debug
+all_debug:
+	$(MAKE) all BUILD_MODE=debug
+
+.PHONY: all-release
+all_release:
+	$(MAKE) all BUILD_MODE=release
+
+$(NAME)-$(BUILD_MODE): main-$(BUILD_MODE).o $(NAME)-$(BUILD_MODE).o
+	$(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS) $(LDLIBS)
+
+main-$(BUILD_MODE).o: main.c $(NAME).h
+	$(CC) $< -o $@ -c -fPIC $(CFLAGS)
+
+$(NAME)-$(BUILD_MODE).o: $(NAME).c $(NAME).h
+	$(CC) $< -o $@ -c -fPIC $(CFLAGS_FUTHARK)
+
+$(NAME).h $(NAME).c &: $(NAME).fut
+	futhark c --library $<
+
+.PHONY: pp
+pp: main.pp
+
+main.pp: main.c
+	$(CC) $< -o $@ $(CFLAGS) -dU -E
+################################################################################
+# CLEAN TARGETS
+################################################################################
+.PHONY: clean
+clean: clean-$(BUILD_MODE)
+
+.PHONY: clean-all
+clean-all: clean-debug clean-release clean-futhark
+
+.PHONY: clean-debug
+clean-debug:
+	rm -f $(NAME)-debug
+	rm -f $(NAME)-debug.o
+	rm -f main-debug.o
+
+.PHONY: clean-release
+clean-release:
+	rm -f $(NAME)-release
+	rm -f $(NAME)-release.o
+	rm -f main-release.o
+
+.PHONY: clean-futhark
+clean-futhark:
+	rm -f $(NAME).h
+	rm -f $(NAME).c
+	rm -f $(NAME).json
+################################################################################
+# REBUILD TARGETS
+################################################################################
+.PHONY: rebuild
+rebuild: clean all
+
+.PHONY: rebuild-debug
+rebuild_debug: clean-debug all-debug
+
+.PHONY: rebuild-release
+rebuild_release: clean-release all-release
+################################################################################
+# RUN TARGETS
+################################################################################
+.PHONY: run
+run: run-$(BUILD_MODE)
+
+.PHONY: run-debug
+run-debug: export LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH):../../build/debug
+run-debug:
+	mpirun $(NAME)-debug
+
+.PHONY: run-release
+run-release: export LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH):../../build/release
+run-release:
+	mpirun $(NAME)-release
+################################################################################
+.DELETE_ON_ERROR:
diff --git a/examples/game_of_life/gol.fut b/examples/game_of_life/gol.fut
new file mode 100644
index 0000000..281aea8
--- /dev/null
+++ b/examples/game_of_life/gol.fut
@@ -0,0 +1,11 @@
+entry gol [y][x] (xs: [y][x]u64): [][]u64 =
+    let res = tabulate_2d (y) (x) (\i j ->
+        if(i > 0 && i < (y-1) && j > 0 && j < (x-1)) then
+            let cnt =
+                xs[(i-1), (j-1)] + xs[(i-1), j] + xs[(i-1), (j+1)] +
+                xs[  i  , (j-1)] +       0      + xs[  i  , (j+1)] +
+                xs[(i+1), (j-1)] + xs[(i+1), j] + xs[(i+1), (j+1)]
+            in u64.bool ((cnt == 3) || ((xs[i, j] == 1) && (cnt == 2)))
+        else xs[i,j]
+    )
+    in res[1:(y-1), 1:(x-1)]
diff --git a/examples/game_of_life/main.c b/examples/game_of_life/main.c
new file mode 100644
index 0000000..6525451
--- /dev/null
+++ b/examples/game_of_life/main.c
@@ -0,0 +1,85 @@
+// C Standard Library
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+// fmpi
+#include <fmpi.h>
+// Internal
+#include "gol.h"
+
+#define T u64
+#define STEP_CNT 20
+#define X_LEN 8
+#define Y_LEN 8
+
+FMPI_TASK_FUTHARK(gol, 1)
+
+int main(int argc, char * argv[])
+{
+    struct fmpi_ctx * ctx = fmpi_init(&argc, &argv);
+    if(ctx == NULL) {
+        fprintf(stderr, "fmpi_init() failed!\n");
+        return EXIT_FAILURE;
+    }
+    T in[] = {
+        0,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,
+        1,1,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+    };
+    #define in_size (sizeof(in)/sizeof(T))
+    T out[in_size] = {0};
+    struct fmpi_task gol_task = FMPI_REGISTER_SYNC_TASK(
+        ctx, gol, fmpi_stencil_square(1),
+        fmpi_data_2d_out(ctx, out, X_LEN, Y_LEN),
+        fmpi_data_2d_in(ctx, in, X_LEN, Y_LEN)
+    );
+    for(size_t i = 0; i < STEP_CNT; i++) {
+        if(fmpi_run_task(ctx, &gol_task) != FMPI_SUCCESS) {
+            printf("Error rank=%d: fmpi_run_task()\n", fmpi_world_rank(ctx));
+        }
+    }
+    if(fmpi_task_finalize(ctx, &gol_task, FMPI_TASK_OP_GATHER) != FMPI_SUCCESS) {
+        printf("Error rank=%d: fmpi_task_finalize()\n", fmpi_world_rank(ctx));
+    }
+    if(fmpi_is_root(ctx)) {
+        T expected[] = {
+            0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,1,0,
+            0,0,0,0,0,0,0,1,
+            0,0,0,0,0,1,1,1,
+        };
+        printf("Expected =>\n");
+        for(size_t i = 0; i < in_size; i++) {
+            printf("%"PRIu64, expected[i]);
+            if((i+1) % X_LEN == 0) {
+                printf("\n");
+            }
+        }
+        printf("Actual =>\n");
+        size_t correct_cnt = 0;
+        for(size_t i = 0; i < in_size; i++) {
+            if(out[i] == expected[i]) {
+                correct_cnt++;
+            }
+            printf("%"PRIu64, out[i]);
+            if((i+1) % X_LEN == 0) {
+                printf("\n");
+            }
+        }
+        if(correct_cnt == in_size) {
+            printf("OK!\n");
+        }
+    }
+    fmpi_exit(&ctx);
+    return EXIT_SUCCESS;
+}
-- 
GitLab