Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
inputs/
pbbsbench/
bin/
164 changes: 164 additions & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
PBBS_DIR ?= pbbsbench
INPUT_DIR := inputs
BIN_DIR := bin


#=================inputs=================
RAND_PTS := $(PBBS_DIR)/testData/geometryData/randPoints
RMAT_GRAPH := $(PBBS_DIR)/testData/graphData/rMatGraph

UC_INPUTS := $(INPUT_DIR)/uniform-circle-1M $(INPUT_DIR)/uniform-circle-20M
RMAT_INPUTS := $(INPUT_DIR)/rmat-1M-symm $(INPUT_DIR)/rmat-10M-symm
RMAT_BIN_INPUTS := $(patsubst %,%-bin,$(RMAT_INPUTS))
TEXT_INPUTS := $(INPUT_DIR)/words-8 $(INPUT_DIR)/words-32
BIN_INPUTS := $(INPUT_DIR)/mangore-waltz.wav $(INPUT_DIR)/pano.ppm $(INPUT_DIR)/moon-landing.wav
ALL_INPUTS := $(UC_INPUTS) $(RMAT_INPUTS) $(RMAT_BIN_INPUTS) $(TEXT_INPUTS) $(BIN_INPUTS)

.PHONY: all clean deepclean

all: input tests

input: $(ALL_INPUTS)

$(PBBS_DIR):
git clone https://github.com/cmuparlay/pbbsbench $@
git -C $@ submodule update --init --recursive

$(RAND_PTS) $(RMAT_GRAPH): $(PBBS_DIR)
$(MAKE) -C $(@D) $(@F)

$(BIN_INPUTS):
curl -L https://raw.githubusercontent.com/MPLLang/parallel-ml-bench/refs/heads/main/inputs/$(notdir $@) -o $@

$(INPUT_DIR)/uniform-circle-%: $(RAND_PTS)
$< -s $(subst M,000000,$(*)) $@

$(INPUT_DIR)/rmat-%-symm: $(RMAT_GRAPH)
$< -s 15210 -o -j $(subst M,000000,$(*)) $@

$(INPUT_DIR)/rmat-%-symm-bin: $(BIN_DIR)/graphio.mlton $(INPUT_DIR)/rmat-%-symm $(INPUT_DIR)
$< $(word 2, $^) -outfile $@

$(INPUT_DIR)/words:
curl -L -o $@ https://raw.githubusercontent.com/dwyl/english-words/refs/heads/master/words_alpha.txt

$(INPUT_DIR)/words-%: $(INPUT_DIR)/words
# Evil shell magic:
# 1. count the lines of the original words file
# 2. multiply that by n in words-n
# 3. shuffle with repetition that many times
#
# You can technically create words-n for any n, not just 8 or 32
shuf -n $$(( $$(wc -l < $<) * $(*) )) -o $@ --repeat $<

$(ALL_INPUTS): | $(INPUT_DIR)/

#=================binaries=================
DEFAULT_FLAGS ?= -default-type int64 -default-type word64
SMLC ?= mlton

COMPILER_NAME := $(notdir $(SMLC))
TESTS_NAME := $(sort $(basename $(notdir $(wildcard bench/*/*.mlb))))
BINARIES := $(addprefix $(BIN_DIR)/,$(TESTS_NAME))

$(BIN_DIR)/%.$(COMPILER_NAME): bench/%/*.mlb $(BIN_DIR)/
$(SMLC) -output $@ -mlb-path-var 'COMPAT $(COMPILER_NAME)' $(DEFAULT_FLAGS) $<

#=================default parameters for tests=================
primes_N := 100000000
dense-matmul_N := 1024
msort_N := 20000000
suffix-array_N := 1000000
palindrome_N := 1000000
nqueens_N := 13
linefit-opt_N := 500000000
linearrec_N := 200000000
bignum-add-opt_N := 500000000
integrate-opt_N := 500000000
sparse-mxv-opt_N := 200000000
mcss-opt_N := 500000000
ocaml-lu-decomp_N := 1024
ocaml-binarytrees5_N := 19

dedup_W := $(INPUT_DIR)/words-32
grep_W := $(INPUT_DIR)/words-32
tokens_W := $(INPUT_DIR)/words-32
msort-strings_W := $(INPUT_DIR)/words-8

delaunay_C := 1M
nearest-nbrs_C := 1M
quickhull_C := 20M

dedup_PRE := --verbose --no-output
grep_PRE := EE
tokens_PRE := --verbose --no-output
bfs_PRE := --no-dir-opt

NUMERICAL_TESTS := primes dense-matmul msort suffix-array palindrome \
nqueens linefit-opt linearrec bignum-add-opt integrate-opt \
sparse-mxv-opt mcss-opt ocaml-lu-decomp ocaml-binarytrees5
WORDS_TESTS := dedup grep tokens msort-strings
CIRC_TESTS := delaunay nearest-nbrs quickhull
RMAT_TESTS := bfs centrality low-d-decomp max-indep-set triangle-count wc-opt
MISC_TESTS := tinykaboom reverb seam-carve range-tree raytracer ocaml-nbody-imm

ALL_TESTS := $(NUMERICAL_TESTS) $(WORDS_TESTS) $(CIRC_TESTS) $(RMAT_TESTS) $(MISC_TESTS)
$(ALL_TESTS): %: $(BIN_DIR)/%.$(COMPILER_NAME)

test: $(ALL_TESTS)

$(NUMERICAL_TESTS):
ifdef N
$(BIN_DIR)/$@.$(COMPILER_NAME) -n $(N)
else
$(BIN_DIR)/$@.$(COMPILER_NAME) -n $($@_N)
endif

.SECONDEXPANSION:

ifdef WORDS
$(WORDS_TESTS):
$(BIN_DIR)/$@.$(COMPILER_NAME) $($@_PRE) $(WORDS)
else
$(WORDS_TESTS): $$($$@_W)
$(BIN_DIR)/$@.$(COMPILER_NAME) $($@_PRE) $<
endif


$(CIRC_TESTS): $(INPUT_DIR)/uniform-circle-$$($$@_C)
$(BIN_DIR)/$@.$(COMPILER_NAME) -input $<

$(RMAT_TESTS): $(INPUT_DIR)/rmat-10M-symm-bin
$(BIN_DIR)/$@.$(COMPILER_NAME) $($@_PRE) $<

tinykaboom:
$(BIN_DIR)/$@.$(COMPILER_NAME) -width 100 -height 100 -frames 10 -fps 1

reverb: $(INPUT_DIR)/mangore-waltz.wav
$(BIN_DIR)/$@.$(COMPILER_NAME) $(INPUT_DIR)/mangore-waltz.wav

seam-carve: $(INPUT_DIR)/pano.ppm
$(BIN_DIR)/$@.$(COMPILER_NAME) $(INPUT_DIR)/pano.ppm -num-seams 100

range-tree:
$(BIN_DIR)/$@.$(COMPILER_NAME) -n 1000000 -q 1000000

raytracer:
$(BIN_DIR)/$@.$(COMPILER_NAME) -n 1000 -m 1000

game-of-life:
$(BIN_DIR)/$@.$(COMPILER_NAME) -n_times 100 -board_size 1024

ocaml-nbody-imm:
$(BIN_DIR)/$@.$(COMPILER_NAME) -n 500 -num_bodies 1024

clean:
rm -rf $(INPUT_DIR)
rm -rf $(BIN_DIR)

deepclean: clean
-$(MAKE) -C $(PBBS_DIR) clean 2>/dev/null || true
rm -rf $(PBBS_DIR)

$(INPUT_DIR)/ $(BIN_DIR)/:
mkdir -p $@
2 changes: 2 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The `mpllib` is a copy of the parallel utilities in `github.com/mpllang/mpllib`.
All other directories hold tests.
47 changes: 47 additions & 0 deletions tests/bench/bfs-delayed/MkBFS.sml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
functor MkBFS (Seq: SEQUENCE) =
struct

structure G = AdjacencyGraph(Int)

fun bfs graph source =
let
val N = G.numVertices graph
val M = G.numEdges graph

fun outEdges u =
Seq.map (fn v => (u, v)) (Seq.fromArraySeq (G.neighbors graph u))

val parents = ForkJoin.alloc N
val _ = ForkJoin.parfor 10000 (0, N) (fn i =>
Array.update (parents, i, ~1))

fun isVisited v =
Array.sub (parents, v) <> ~1

fun visit (u, v) =
if not (isVisited v) andalso
(~1 = Concurrency.casArray (parents, v) (~1, u))
then
SOME v
else
NONE

fun loop frontier totalVisited =
if Seq.length frontier = 0 then
totalVisited
else
let
val allNeighbors = Seq.flatten (Seq.map outEdges frontier)
val nextFrontier = Seq.mapOption visit allNeighbors
in
loop nextFrontier (totalVisited + Seq.length nextFrontier)
end

val _ = Array.update (parents, source, source)
val initFrontier = Seq.singleton source
val numVisited = loop initFrontier 1
in
ArraySlice.full parents
end

end
39 changes: 39 additions & 0 deletions tests/bench/bfs-delayed/SerialBFS.sml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
structure SerialBFS =
struct

structure Seq = ArraySequence
structure G = AdjacencyGraph(Int)

fun bfs g s =
let
fun neighbors v = G.neighbors g v
fun degree v = G.degree g v

val n = G.numVertices g
val m = G.numEdges g

val queue = ForkJoin.alloc (m+1)
val parents = Array.array (n, ~1)

fun search (lo, hi) =
if lo >= hi then lo else
let
val v = Array.sub (queue, lo)
fun visit (hi', u) =
if Array.sub (parents, u) >= 0 then hi'
else ( Array.update (parents, u, v)
; Array.update (queue, hi', u)
; hi'+1
)
in
search (lo+1, Seq.iterate visit hi (neighbors v))
end

val _ = Array.update (parents, s, s)
val _ = Array.update (queue, 0, s)
val numVisited = search (0, 1)
in
ArraySlice.full parents
end

end
4 changes: 4 additions & 0 deletions tests/bench/bfs-delayed/bfs-delayed.mlb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
../../mpllib/sources.$(COMPAT).mlb
SerialBFS.sml
MkBFS.sml
main.sml
72 changes: 72 additions & 0 deletions tests/bench/bfs-delayed/main.sml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
structure CLA = CommandLineArgs
structure Seq = ArraySequence
structure G = AdjacencyGraph(Int)

(* Set by subdirectory *)
structure BFS = MkBFS(OldDelayedSeq)

(* Generate an input
* If -infile <file> is given, then will load file.
* Otherwise, uses -n <num vertices> -d <degree> to generate a random graph. *)
val filename = CLA.parseString "infile" ""
val t0 = Time.now ()
val (graphspec, input) =
if filename <> "" then
(filename, G.parseFile filename)
else
let
val n = CLA.parseInt "n" 1000000
val d = CLA.parseInt "d" 10
in
("random(" ^ Int.toString n ^ "," ^ Int.toString d ^ ")",
G.randSymmGraph n d)
end
val t1 = Time.now ()
val _ = print ("loaded graph in " ^ Time.fmt 4 (Time.- (t1, t0)) ^ "s\n")

val n = G.numVertices input
val source = CLA.parseInt "source" 0
val doCheck = CLA.parseFlag "check"

val _ = print ("graph " ^ graphspec ^ "\n")
val _ = print ("num-verts " ^ Int.toString n ^ "\n")
val _ = print ("num-edges " ^ Int.toString (G.numEdges input) ^ "\n")
val _ = print ("source " ^ Int.toString source ^ "\n")
val _ = print ("check " ^ (if doCheck then "true" else "false") ^ "\n")

fun task () =
BFS.bfs input source

val P = Benchmark.run "running bfs" task

val numVisited =
SeqBasis.reduce 10000 op+ 0 (0, Seq.length P)
(fn i => if Seq.nth P i >= 0 then 1 else 0)
val _ = print ("visited " ^ Int.toString numVisited ^ "\n")

fun numHops P hops v =
if hops > Seq.length P then ~2
else if Seq.nth P v = ~1 then ~1
else if Seq.nth P v = v then hops
else numHops P (hops+1) (Seq.nth P v)

val maxHops =
SeqBasis.reduce 100 Int.max ~3 (0, G.numVertices input) (numHops P 0)
val _ = print ("max dist " ^ Int.toString maxHops ^ "\n")

fun check () =
let
val (P', serialTime) =
Util.getTime (fn _ => SerialBFS.bfs input source)

val correct =
Seq.length P = Seq.length P'
andalso
SeqBasis.reduce 10000 (fn (a, b) => a andalso b) true (0, Seq.length P)
(fn i => numHops P 0 i = numHops P' 0 i)
in
print ("serial finished in " ^ Time.fmt 4 serialTime ^ "s\n");
print ("correct? " ^ (if correct then "yes" else "no") ^ "\n")
end

val _ = if doCheck then check () else ()
Loading