From 54d4086b0875f64a079ab44bb4a82562bb95d7d6 Mon Sep 17 00:00:00 2001 From: Moazzam Moriani Date: Fri, 26 Aug 2022 19:26:31 +0500 Subject: [PATCH 1/5] Copy work from https://github.com/moazzammoriani/graph500 --- benchmarks/graph500seq/dune | 105 ++++++++++++-- benchmarks/graph500seq/dune-project | 1 + benchmarks/graph500seq/fileHandler.ml | 10 ++ benchmarks/graph500seq/fileHandler.mli | 3 + benchmarks/graph500seq/gen.ml | 4 +- benchmarks/graph500seq/genAndKernel1.sh | 13 ++ benchmarks/graph500seq/generateSamples.ml | 3 + benchmarks/graph500seq/generateSeq.ml | 13 +- benchmarks/graph500seq/generateSeq.mli | 2 - benchmarks/graph500seq/graphTypes.mli | 3 + benchmarks/graph500seq/kernel1Old.ml | 113 --------------- benchmarks/graph500seq/kernel1_run.ml | 21 +-- benchmarks/graph500seq/kernel2.ml | 97 ------------- benchmarks/graph500seq/kernel2.sh | 3 + benchmarks/graph500seq/kernel2Par.sh | 5 + benchmarks/graph500seq/kernel2Seq.ml | 75 ++++++++++ benchmarks/graph500seq/kernel2Seq.mli | 13 ++ benchmarks/graph500seq/kernel2_run.ml | 25 ++++ .../graph500seq/kernel2_run_multicore.ml | 40 ++++++ benchmarks/graph500seq/kernel3.ml | 113 --------------- benchmarks/graph500seq/kernel3.sh | 3 + benchmarks/graph500seq/kernel3Par.sh | 5 + benchmarks/graph500seq/kernel3Seq.ml | 78 ++++++++++ benchmarks/graph500seq/kernel3_run.ml | 25 ++++ .../graph500seq/kernel3_run_multicore.ml | 40 ++++++ benchmarks/graph500seq/kronecker.ml | 136 ------------------ benchmarks/graph500seq/sampleSearchKeys.ml | 67 +++++++++ benchmarks/graph500seq/sparseGraphSeq.ml | 127 +++++++++++++++- benchmarks/graph500seq/sparseGraphSeq.mli | 26 ++++ 29 files changed, 668 insertions(+), 501 deletions(-) create mode 100644 benchmarks/graph500seq/dune-project create mode 100644 benchmarks/graph500seq/fileHandler.ml create mode 100644 benchmarks/graph500seq/fileHandler.mli create mode 100755 benchmarks/graph500seq/genAndKernel1.sh create mode 100644 benchmarks/graph500seq/generateSamples.ml create mode 100644 benchmarks/graph500seq/graphTypes.mli delete mode 100644 benchmarks/graph500seq/kernel1Old.ml delete mode 100644 benchmarks/graph500seq/kernel2.ml create mode 100755 benchmarks/graph500seq/kernel2.sh create mode 100755 benchmarks/graph500seq/kernel2Par.sh create mode 100644 benchmarks/graph500seq/kernel2Seq.ml create mode 100644 benchmarks/graph500seq/kernel2Seq.mli create mode 100644 benchmarks/graph500seq/kernel2_run.ml create mode 100644 benchmarks/graph500seq/kernel2_run_multicore.ml delete mode 100644 benchmarks/graph500seq/kernel3.ml create mode 100755 benchmarks/graph500seq/kernel3.sh create mode 100755 benchmarks/graph500seq/kernel3Par.sh create mode 100644 benchmarks/graph500seq/kernel3Seq.ml create mode 100644 benchmarks/graph500seq/kernel3_run.ml create mode 100644 benchmarks/graph500seq/kernel3_run_multicore.ml delete mode 100644 benchmarks/graph500seq/kronecker.ml create mode 100644 benchmarks/graph500seq/sampleSearchKeys.ml diff --git a/benchmarks/graph500seq/dune b/benchmarks/graph500seq/dune index 03e312f87b..67a7f6c834 100644 --- a/benchmarks/graph500seq/dune +++ b/benchmarks/graph500seq/dune @@ -1,44 +1,121 @@ -; kernel1 and kronecker have been replaced with new, more optimized -; implementations. -(executable (name kronecker) (modules kronecker)) -(library (name kernel1Old) (modules kernel1Old)) -(executable (name kernel2) (modules kernel2) (libraries kernel1Old)) -(executable (name kernel3) (modules kernel3) (libraries kernel1Old)) -;;;;; Newer implementations ;;;;; +(library + (name graphTypes) + (modules graphTypes) + (modules_without_implementation graphTypes) + (ocamlc_flags -g) +) (library (name generateSeq) (modules generateSeq) - (libraries graphTypes) + (libraries graphTypes fileHandler) + (ocamlc_flags -g) +) + +(library + (name fileHandler) + (modules fileHandler) + (ocamlc_flags -g) ) (executable (name gen) (modules gen) - (libraries unix generateSeq) + (libraries unix generateSeq fileHandler) + (ocamlc_flags -g) ) (library (name sparseGraphSeq) (modules sparseGraphSeq) (libraries graphTypes) + ;(preprocess; (pps ppx_inline_test ppx_assert)) + ;(inline_tests) + (ocamlc_flags -g) ) (library (name kernel1Seq) (modules kernel1Seq) (libraries generateSeq sparseGraphSeq unix) + (ocamlc_flags -g) +) + +(library + (name kernel2Seq) + (modules kernel2Seq) + (libraries generateSeq sparseGraphSeq unix) + ;(preprocess; (pps ppx_inline_test ppx_assert)) + ;(inline_tests) + (ocamlc_flags -g) +) + +(library + (name kernel3Seq) + (modules kernel3Seq) + (libraries graphTypes generateSeq sparseGraphSeq unix) + ;(preprocess; (pps ppx_inline_test ppx_assert)) + ;(inline_tests) + (ocamlc_flags -g) +) + +(executable + (name sampleSearchKeys) + (modules sampleSearchKeys) + (libraries graphTypes generateSeq sparseGraphSeq unix) + (ocamlc_flags -g) +) + +(executable + (name print_sparse) + (modules print_sparse) + (modes byte exe) + (libraries sparseGraphSeq graphTypes fileHandler kernel1Seq unix) + (ocamlc_flags -g) ) (executable (name kernel1_run) (modules kernel1_run) - (libraries graphTypes generateSeq kernel1Seq unix) + (libraries sparseGraphSeq graphTypes fileHandler kernel1Seq unix) + (ocamlc_flags -g) ) -(alias - (name buildbench) - (deps kronecker.exe kernel2.exe kernel3.exe - gen.exe kernel1_run.exe) +(executable + (name kernel2_run) + (modules kernel2_run) + (modes byte exe) + (libraries sparseGraphSeq graphTypes fileHandler kernel2Seq unix) + (ocamlc_flags -g) +) + +(executable + (name kernel2_run_multicore) + (modules kernel2_run_multicore) + (modes byte exe) + (libraries domainslib sparseGraphSeq graphTypes fileHandler kernel2Seq unix) + (ocamlc_flags -g) ) + +(executable + (name kernel3_run) + (modules kernel3_run) + (modes byte exe) + (libraries sparseGraphSeq graphTypes fileHandler kernel3Seq unix) + (ocamlc_flags -g) +) + +(executable + (name kernel3_run_multicore) + (modules kernel3_run_multicore) + (modes byte exe) + (libraries domainslib sparseGraphSeq graphTypes fileHandler kernel3Seq unix) + (ocamlc_flags -g) +) + +;(alias +; (name buildbench) +; (deps kronecker.exe kernel2.exe kernel3.exe +; gen.exe kernel1_run.exe) +;) diff --git a/benchmarks/graph500seq/dune-project b/benchmarks/graph500seq/dune-project new file mode 100644 index 0000000000..0c226b5b0c --- /dev/null +++ b/benchmarks/graph500seq/dune-project @@ -0,0 +1 @@ +(lang dune 3.2) diff --git a/benchmarks/graph500seq/fileHandler.ml b/benchmarks/graph500seq/fileHandler.ml new file mode 100644 index 0000000000..3939b6e351 --- /dev/null +++ b/benchmarks/graph500seq/fileHandler.ml @@ -0,0 +1,10 @@ +let to_file ~filename (data : 'a ) = + let out = open_out filename in + Marshal.to_channel out data []; + close_out out + +let from_file filename = + let in_ = open_in filename in + let res : 'a = Marshal.from_channel in_ in + close_in in_; + res diff --git a/benchmarks/graph500seq/fileHandler.mli b/benchmarks/graph500seq/fileHandler.mli new file mode 100644 index 0000000000..ac3d720e2d --- /dev/null +++ b/benchmarks/graph500seq/fileHandler.mli @@ -0,0 +1,3 @@ +val to_file : filename:string -> 'a -> unit + +val from_file : string -> 'a diff --git a/benchmarks/graph500seq/gen.ml b/benchmarks/graph500seq/gen.ml index 1f12bf5851..dd53ad45bc 100644 --- a/benchmarks/graph500seq/gen.ml +++ b/benchmarks/graph500seq/gen.ml @@ -18,9 +18,9 @@ let () = Printf.eprintf "Must provide graph file argument.\n"; exit 1 end; let scale = !scale and edge_factor = !edge_factor in - Printf.printf "Generating edge list...\n%!"; + Printf.printf "Generating edge list of scale %d...\n%!" scale; let t0 = Unix.gettimeofday () in let edges = GenerateSeq.go ~scale ~edge_factor in let t1 = Unix.gettimeofday () in Printf.printf "Generated. Time: %f s.\n" (t1 -. t0); - GenerateSeq.to_file ~filename:!filename edges; + FileHandler.to_file ~filename:!filename edges; diff --git a/benchmarks/graph500seq/genAndKernel1.sh b/benchmarks/graph500seq/genAndKernel1.sh new file mode 100755 index 0000000000..6a7846d06a --- /dev/null +++ b/benchmarks/graph500seq/genAndKernel1.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +SCALE=$1 + +gen () { ./_build/default/gen.exe -scale $SCALE edges.data; } + +kernel1 () { ./_build/default/kernel1_run.exe edges.data -o sparse.data; } + +getSamples () { ./_build/default/sampleSearchKeys.exe sparse.data -o samples.data; } + +gen && kernel1 && getSamples + + diff --git a/benchmarks/graph500seq/generateSamples.ml b/benchmarks/graph500seq/generateSamples.ml new file mode 100644 index 0000000000..e3c12fa864 --- /dev/null +++ b/benchmarks/graph500seq/generateSamples.ml @@ -0,0 +1,3 @@ +let _ = + let samples = Array.init nsamples (fun _ -> SparseGraphSeq.get_sample graph) in + FileHandler.to_file ~filename:!filename samples diff --git a/benchmarks/graph500seq/generateSeq.ml b/benchmarks/graph500seq/generateSeq.ml index b910079cfb..5b60b4990e 100644 --- a/benchmarks/graph500seq/generateSeq.ml +++ b/benchmarks/graph500seq/generateSeq.ml @@ -85,16 +85,5 @@ let kronecker ~scale ~edge_factor : (vertex * vertex * weight) array = let go ~scale ~edge_factor = kronecker ~scale ~edge_factor -let to_file ~filename (edges : edge array) = - let out = open_out filename in - Marshal.to_channel out edges []; - close_out out - -let from_file filename = - let in_ = open_in filename in - let res : edge array = Marshal.from_channel in_ in - close_in in_; - res - let generate_to_file ~scale ~edge_factor ~filename = - go ~scale ~edge_factor |> to_file ~filename + go ~scale ~edge_factor |> FileHandler.to_file ~filename diff --git a/benchmarks/graph500seq/generateSeq.mli b/benchmarks/graph500seq/generateSeq.mli index e10018e243..fdfa22e4a1 100644 --- a/benchmarks/graph500seq/generateSeq.mli +++ b/benchmarks/graph500seq/generateSeq.mli @@ -1,6 +1,4 @@ open GraphTypes val go : scale:int -> edge_factor:int -> edge array -val to_file : filename:string -> edge array -> unit -val from_file : string -> edge array val generate_to_file : scale:int -> edge_factor:int -> filename:string -> unit diff --git a/benchmarks/graph500seq/graphTypes.mli b/benchmarks/graph500seq/graphTypes.mli new file mode 100644 index 0000000000..2944204762 --- /dev/null +++ b/benchmarks/graph500seq/graphTypes.mli @@ -0,0 +1,3 @@ +type vertex = int +type weight = float +type edge = vertex * vertex * weight diff --git a/benchmarks/graph500seq/kernel1Old.ml b/benchmarks/graph500seq/kernel1Old.ml deleted file mode 100644 index 14d2ad9908..0000000000 --- a/benchmarks/graph500seq/kernel1Old.ml +++ /dev/null @@ -1,113 +0,0 @@ -(*Kernel 1 is basic construction of adjacency HashMap for undirected graphs -which is corresponding to sparse graph implementation. INPUTS : ijw and m which has been -derived from kronecker product*) - -(*(*<-------OCaml Kernel 1 inspired from https://graph500.org/?page_id=12----------> -Written by support of PRISM Lab, IIT Madras and OCaml Labs*)*) - -let scale = try int_of_string Sys.argv.(1) with _ -> 12 - -let edgefactor = try int_of_string Sys.argv.(2) with _ -> 10 - -(*This basically sorts the list in a way that (startVertex, endVertex), -startVertex > endVertex. -It removes the self loops from ijw*) -let sortVerticeList ar newAr index = - let rec sortVerticeList ar maximum newAr index = - if index = -1 then (newAr, int_of_float maximum) - else if ar.(0).(index) > ar.(1).(index) then - sortVerticeList ar - (max maximum ar.(0).(index)) - (Array.append newAr - [|[| ar.(0).(index); ar.(1).(index); ar.(2).(index) |]|]) - (index - 1) - else if ar.(0).(index) = ar.(1).(index) then - sortVerticeList ar (max maximum ar.(0).(index)) newAr (index - 1) - else - sortVerticeList ar - (max maximum ar.(1).(index)) - (Array.append newAr - [|[| ar.(1).(index); ar.(0).(index); ar.(2).(index) |]|]) - (index - 1) - in - sortVerticeList ar 0. newAr index - -(*This is basically the construction of adj matrix [row][col], -just in case dense graphs are being tested. All the kernels further though -use HashMap, and thus would require changes*) - -(*let constructionAdjMatrix list maxLabel = let matrix = Array.make_matrix -maxLabel maxLabel 0. in let rec fillMatrix matrix list = match list with [] -> -matrix | head::tail -> let _ = matrix.(int_of_float(List.nth head -0)).(int_of_float(List.nth head 1)) <- (List.nth head 2) in let _ = -matrix.(int_of_float(List.nth head 1)).(int_of_float(List.nth head 0)) <- -(List.nth head 2) in fillMatrix matrix tail in fillMatrix matrix list ;;*) - -(*Adding Edge adds the edge to HashMap for undirected graphs, where the binding -is between index and the list (endVertex, weight) *) - -let addEdge startVertex endVertex weight hashTable = - if Hashtbl.mem hashTable startVertex = false then - Hashtbl.add hashTable startVertex [ (endVertex, weight) ] - else - Hashtbl.replace hashTable startVertex - (Hashtbl.find hashTable startVertex @ [ (endVertex, weight) ]) - -(*The two functions constructionAdjHash and kernel1 are the main -functions driving all the other functions.*) -let rec constructionAdjHash ar hashTable index = - if index = -1 then hashTable - else - let startVertex = int_of_float ar.(index).(0) - and endVertex = int_of_float ar.(index).(1) - and weight = ar.(index).(2) in - addEdge startVertex endVertex weight hashTable; - addEdge endVertex startVertex weight hashTable; - constructionAdjHash ar hashTable (index - 1) - -let rec adjustForAllVertices adjMatrix size index = - if index = size then adjMatrix - else if Hashtbl.mem adjMatrix index = true then - adjustForAllVertices adjMatrix size (index + 1) - else - let _ = Hashtbl.add adjMatrix index [] in - adjustForAllVertices adjMatrix size (index + 1) - -let rec readFile file ijw = - try - match Some (input_line file) with - | None -> ijw - | Some line -> ( - match List.rev (String.split_on_char ',' line) with - | [] -> readFile file ijw - | _ :: tail -> - let list = - Array.of_list (List.map float_of_string (List.rev tail)) - in - let ijw = Array.append ijw [| list |] in - readFile file ijw ) - with End_of_file -> - let _ = close_in file in - ijw - -let computeNumber scale edgefactor = - let n = int_of_float (2. ** float_of_int scale) in - let m = edgefactor * n in - (n, m) - -let kernel1 ijw m = - let ar, maximumEdgeLabel = sortVerticeList ijw [||] (m - 1) in - let hashTable = Hashtbl.create (maximumEdgeLabel + 1) in - let adjMatrix = constructionAdjHash ar hashTable ( Array.length ar - 1) in - let adjMatrix = adjustForAllVertices adjMatrix (maximumEdgeLabel + 1) 0 in - let _ = Printf.printf "%d" maximumEdgeLabel in - (adjMatrix, maximumEdgeLabel + 1) - -let linkKronecker () = - let file = open_in "kronecker.txt" in - let ijw = readFile file [||] in - (*let _ = Array.map (Printf.printf "%f" ) ijw.(0) in*) - let adjMatrix = - kernel1 ijw (snd (computeNumber scale edgefactor)) - in - adjMatrix diff --git a/benchmarks/graph500seq/kernel1_run.ml b/benchmarks/graph500seq/kernel1_run.ml index feea46a44d..ffdbdbbbc5 100644 --- a/benchmarks/graph500seq/kernel1_run.ml +++ b/benchmarks/graph500seq/kernel1_run.ml @@ -1,18 +1,23 @@ -let filename = ref "" +let usage_msg = "kernel1Seq_run.exe -o " +let edge_list_input_filename = ref "" +let sparse_graph_output_filename = ref "" + +let speclist = [("-o", Arg.Set_string sparse_graph_output_filename, "Set output file name")] let () = Random.self_init (); - Arg.parse [] (fun s -> filename := s) - "kernel1Par.exe EDGE_LIST_FILE"; - if !filename = "" then begin - Printf.eprintf "Must provide graph file argument.\n"; exit 1 + Arg.parse speclist (fun s -> edge_list_input_filename := s) usage_msg; + if !edge_list_input_filename = "" then begin + Printf.eprintf "Must provide edge list input file argument.\n"; exit 1 end; - Printf.printf "Reading edge list from %s...\n%!" !filename; + Printf.printf "Reading edge list from %s...\n%!" !edge_list_input_filename; let t0 = Unix.gettimeofday () in - let edges = GenerateSeq.from_file !filename in + let edges = FileHandler.from_file !edge_list_input_filename in let t1 = Unix.gettimeofday () in Printf.printf "Done. Time: %f s.\nBuilding sparse representation...\n%!" (t1 -. t0); let t0 = Unix.gettimeofday () in - ignore @@ Sys.opaque_identity @@ Kernel1Seq.kernel1 edges; + let sparse_graph = Kernel1Seq.kernel1 edges in let t1 = Unix.gettimeofday () in Printf.printf "Done. Time: %f\n" (t1 -. t0); + FileHandler.to_file ~filename:!sparse_graph_output_filename sparse_graph; + diff --git a/benchmarks/graph500seq/kernel2.ml b/benchmarks/graph500seq/kernel2.ml deleted file mode 100644 index 2f32f35d73..0000000000 --- a/benchmarks/graph500seq/kernel2.ml +++ /dev/null @@ -1,97 +0,0 @@ -(*Kernel 2 aims at building a bfs tree where the bfs is maintained using a queue - and the parent Array which consists of the immediate parent of the node. The - input for this kernel is : INPUTS : adjacency HashMap(for undirected graphs) - and starting vertex which would allow you to begin the bfs*) - -(*<-------OCaml Kernel 2 inspired from https://graph500.org/?page_id=12----------> - Written by support of PRISM Lab, IIT Madras and OCaml Labs*) - -(*This function iterates over the list which are adjacent to the node. -So lets say for node n1, we have n2,n3,n4 nodes. THe list would be in -the form of (node,wght) tuple inside the list -i.e. [(n2,weight_21);(n3,weight_31);(n4,weight_41)] which is -adjacentVertice list. Parent array will be updated here. Queue is just a -list module. - Also, visited array has the nodes which have already being visited to avoid - the nodes being pushed to queue which have been visited in order to avoid redundancy.*) - -(*appendVerticesToQueue is the function doing recusrion to push desired elements -in the queue, adjacent and ~visited nodes for a node. THe queue's first element - is always the node to be computed on for adjacency. As queue pushs the node - from front, head::tail helps directly, primrily pointing out that queue - has been considered as a list.*) - -let rec appendVerticesToQueue parentVertex queue adjacentVertices - (parentArray : int array) visited = - match adjacentVertices with - | [] -> (queue, parentArray) - | head :: tail -> - if visited.(fst head) = 0 then - let _ = parentArray.(fst head) <- parentVertex in - appendVerticesToQueue parentVertex - (queue @ [ fst head ]) - tail parentArray visited - else appendVerticesToQueue parentVertex queue tail parentArray visited - -(*For debugging*) -(*let rec printList list = - match list with - [] -> Printf.printf "Empty/END" | - head::tail -> let _ = Printf.printf "%d" head in printList tail - ;;*) - -(*BFS function is a normal bfs function by building the bfs tree. -Uses adjacency HashMap, queue, parent Array, visited. -bfsTree stores the order of the nodes and - it is a list. Parent array works as : parent[node] = _parentNode_ - is the DAT being used i.e. an array*) - -let rec bfs adjMatrix queue bfsTree parentArray visited = - match queue with - | [] -> (bfsTree, parentArray) - | head :: tail -> - if visited.(head) = 0 then - let _ = visited.(head) <- 1 in - let adjacentVertices = Hashtbl.find adjMatrix head in - let queue, parentArray = - appendVerticesToQueue head tail adjacentVertices parentArray visited - in - (*let _ = printList queue in*) - (*For debugging*) - let _ = Hashtbl.remove adjMatrix head in - bfs adjMatrix queue (bfsTree @ [ head ]) parentArray visited - else bfs adjMatrix tail bfsTree parentArray visited - -(*Main function is the function where it calls bfs. -Size computation is using HashMap and the initialiszation -of all arrays and lists happen here.*) - -let rec bfsRecDisconnectedGraph adjMatrix bfsTree parentArray visited index = - if index = Array.length visited then (bfsTree, parentArray) - else if parentArray.(index) = -1 && visited.(index) = 0 then - let bfsTree, parentArray = - bfs adjMatrix [ index ] bfsTree parentArray visited - in - bfsRecDisconnectedGraph adjMatrix bfsTree parentArray visited (index + 1) - else bfsRecDisconnectedGraph adjMatrix bfsTree parentArray visited (index + 1) - -let main adjMatrixHash n = - let len = n in - let _ = Printf.printf "%d\n" len in - let parentArray = Array.make len (-1) in - let visited = Array.make len 0 in - let bfsTree, parentArray = - bfsRecDisconnectedGraph adjMatrixHash [] parentArray visited 0 - in - Printf.printf "\nBfs Tree is : "; - List.iter (fun x -> Printf.printf "%d " x) bfsTree; - Printf.printf "\n Parent Array is : "; - Array.iter (fun x -> Printf.printf "%d " x) parentArray; - Printf.printf "\n KERNEL2 OVER"; - (bfsTree, parentArray) - -let linkKernel1 () = - let ans = Kernel1Old.linkKronecker () in - main (fst ans) (snd ans) - -let _ = linkKernel1 () diff --git a/benchmarks/graph500seq/kernel2.sh b/benchmarks/graph500seq/kernel2.sh new file mode 100755 index 0000000000..1d292b87f6 --- /dev/null +++ b/benchmarks/graph500seq/kernel2.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +./_build/default/kernel2_run.exe sparse.data samples.data; diff --git a/benchmarks/graph500seq/kernel2Par.sh b/benchmarks/graph500seq/kernel2Par.sh new file mode 100755 index 0000000000..149e03d3df --- /dev/null +++ b/benchmarks/graph500seq/kernel2Par.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +NDOMAINS=$1 + +./_build/default/kernel2_run_multicore.exe sparse.data samples.data -ndomains $NDOMAINS diff --git a/benchmarks/graph500seq/kernel2Seq.ml b/benchmarks/graph500seq/kernel2Seq.ml new file mode 100644 index 0000000000..8c1f95eaea --- /dev/null +++ b/benchmarks/graph500seq/kernel2Seq.ml @@ -0,0 +1,75 @@ +let update_discovered d_arr v = + d_arr.(v) <- true + +let set_parent par_arr ~parent ~child = + par_arr.(child) <- parent + +let get_bool_vect_val_at_index d_arr v = + d_arr.(v) + +let is_discovered d_arr v = + get_bool_vect_val_at_index d_arr v + +let next_edgenode g v = SparseGraphSeq.get_vertex @@ SparseGraphSeq.get_next_edgenode g v + +let has_no_edgenodes = SparseGraphSeq.has_no_edgenodes + +let rec breadthfirstsearch (g : SparseGraphSeq.t) par_arr disc_arr (q : int Queue.t ) = + match (Queue.is_empty q) with + | true -> par_arr + | false -> + let v = Queue.peek q in + match (has_no_edgenodes g v) with + | true -> let _ = Queue.pop q in breadthfirstsearch g par_arr disc_arr q + | false -> begin + let edgenode = next_edgenode g v in (* get the edgenode of v and change the state of g *) + match (is_discovered disc_arr edgenode) with + | true -> breadthfirstsearch g par_arr disc_arr q + | false -> begin + Queue.push edgenode q; + set_parent par_arr ~parent:v ~child:edgenode; + update_discovered disc_arr edgenode; + breadthfirstsearch g par_arr disc_arr q + end + end + +let bfs g start = + let nvertices = SparseGraphSeq.num_vertices g in + let parent_arr = Array.init nvertices (fun _ -> -1) in + let discovery_arr = Array.init nvertices (fun _ -> false) in + let q = ref (Queue.create ()) in + Queue.push start !q; + update_discovered discovery_arr start; + let g_copy = SparseGraphSeq.copy_graph g in + breadthfirstsearch g_copy parent_arr discovery_arr !q + +let kernel2 = bfs + + + +(* +(* Unit tests *) +let parray = Array.init 64 (fun _ -> -1) + +open Base +let%test_unit "rev" = + [%test_eq: int list] [ 3; 2; 1 ] [ 3; 2; 1 ] + +let%test_unit "update_discovered" = + let bvect = [| false; false; false |] in + update_discovered bvect 0; + [%test_eq: bool] bvect.(0) true + + +let%test_unit "set_parent" = + set_parent parray ~parent:8 ~child:2; + [%test_eq: int] parray.(2) 8 + +let%test_unit "kernel2" = + [%test_eq: int array] (kernel2 SparseGraphSeq.graph 2) [|3;0;-1;2;2|] + +let%test_unit "kernel2_2" = + [%test_eq: int array] (kernel2 SparseGraphSeq.graph2 8) [|-1;8;1;1;1;6;8;1;-1|] + + +*) diff --git a/benchmarks/graph500seq/kernel2Seq.mli b/benchmarks/graph500seq/kernel2Seq.mli new file mode 100644 index 0000000000..16c61d4c7a --- /dev/null +++ b/benchmarks/graph500seq/kernel2Seq.mli @@ -0,0 +1,13 @@ +open GraphTypes + +val update_discovered : bool array -> vertex -> unit + +(*val set_parent : ~parent_array:vertex array -> ~parent:vertex -> ~child:vertex -> unit*) + +val get_bool_vect_val_at_index : bool array -> int -> bool + +val is_discovered: bool array -> vertex -> bool + +(*val bfs : SparseGraphSeq.t -> vertex -> vertex array -> vertex array -> vertex Queue.t -> vertex array*) + +val kernel2 : SparseGraphSeq.t -> vertex -> vertex array diff --git a/benchmarks/graph500seq/kernel2_run.ml b/benchmarks/graph500seq/kernel2_run.ml new file mode 100644 index 0000000000..4208c9d3f7 --- /dev/null +++ b/benchmarks/graph500seq/kernel2_run.ml @@ -0,0 +1,25 @@ +let usage_msg = "kernel2Seq_run.exe files := filename::!files) usage_msg; + files := List.rev !files; + let sparse_graph_input_filename = List.nth !files 0 in + let samples_input_filename = List.nth !files 1 in + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide sparse graph input file argument.\n"; exit 1 + end; + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide search keys input file argument.\n"; exit 1 + end; + Printf.printf "Reading sparse graph from %s...\n%!" sparse_graph_input_filename; + let graph = FileHandler.from_file sparse_graph_input_filename in + Printf.printf "Reading search keys from from %s...\n%!" samples_input_filename; + let samples = FileHandler.from_file samples_input_filename in + Printf.printf "Performing breadth-first searches...\n%!"; + let t0 = Unix.gettimeofday () in + ignore @@ Sys.opaque_identity @@ Array.map (fun start -> let g = graph in Kernel2Seq.kernel2 g start) samples; + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f\n" (t1 -. t0); + diff --git a/benchmarks/graph500seq/kernel2_run_multicore.ml b/benchmarks/graph500seq/kernel2_run_multicore.ml new file mode 100644 index 0000000000..0b023e12f3 --- /dev/null +++ b/benchmarks/graph500seq/kernel2_run_multicore.ml @@ -0,0 +1,40 @@ +let usage_msg = "kernel2Par_run.exe -ndomains " +let files = ref [] +let num_domains = ref 2 + +let speclist = [("-ndomains", Arg.Set_int num_domains, "Set the number of domains")] + +module T = Domainslib.Task + +let parellel_kernel2 pool graph samples res= + let len = Array.length res in + T.parallel_for pool ~start:0 ~finish:(len-1) ~body:(fun i -> + res.(i) <- (Kernel2Seq.kernel2 graph samples.(i)) + ) + + +let () = + Random.self_init (); + Arg.parse speclist (fun filename -> files := filename::!files) usage_msg; + files := List.rev !files; + let sparse_graph_input_filename = List.nth !files 0 in + let samples_input_filename = List.nth !files 1 in + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide sparse graph input file argument.\n"; exit 1 + end; + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide search keys input file argument.\n"; exit 1 + end; + Printf.printf "Reading sparse graph from %s...\n%!" sparse_graph_input_filename; + let graph = FileHandler.from_file sparse_graph_input_filename in + let g = graph in + Printf.printf "Reading search keys from from %s...\n%!" samples_input_filename; + let samples = FileHandler.from_file samples_input_filename in + Printf.printf "Performing breadth-first searches...\n%!"; + let pool = T.setup_pool ~num_additional_domains:(!num_domains-1) () in + let t0 = Unix.gettimeofday () in + let results = Array.init (Array.length samples) (fun _ -> [||]) in + ignore @@ Sys.opaque_identity @@ T.run pool (fun () -> parellel_kernel2 pool g samples results); + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f\n" (t1 -. t0); + diff --git a/benchmarks/graph500seq/kernel3.ml b/benchmarks/graph500seq/kernel3.ml deleted file mode 100644 index 186aef6126..0000000000 --- a/benchmarks/graph500seq/kernel3.ml +++ /dev/null @@ -1,113 +0,0 @@ -(*Kernel 3 works on the dijkstars algorithm which is basically the shortest path - from the node to all the nodes. As expected the main function here takes the - HashMap and the source node from where the shortest distnaces have to be - calculated.*) -(*INPUTS : Adjacency HashMap and Start Vertex*) - -(*<-------OCaml Kernel 3 inspired from https://graph500.org/?page_id=12----------> - Written by support of PRISM Lab, IIT Madras and OCaml Labs*) - -(*Minimum Distance function computes the vertex which is at the min distance from the node -which is currently under study. Only the nodes which have not been visited - are only considered. This function is not checking the visited as the - verticesInspected already takes care of it in other function (changeVerticeInspected). - E.g. N1 is under study and now the nodes N2, N3 are at 2, inf distance in distanceArray, - so N2 will be selected as the min vertex.*) - -let startVertex = try int_of_string Sys.argv.(3) with _ -> 0 - -let minimumDistance verticesInspected distanceArray = - let rec minimumDistance verticesInspected distanceArray minimumVal index - minimumVertice = - if index = Array.length verticesInspected then minimumVertice - else if minimumVal >= distanceArray.(verticesInspected.(index)) then - minimumDistance verticesInspected distanceArray - distanceArray.(verticesInspected.(index)) - (index + 1) verticesInspected.(index) - else - minimumDistance verticesInspected distanceArray minimumVal (index + 1) - minimumVertice - in - minimumDistance verticesInspected distanceArray infinity 0 0 - -(*After determining the min vertex (obtained from prev func), -we have to adjust dist such that, for all node, -if dist[node] > dist[min vertex] + weight_node_minVertex then update the distance -else continue with other nodes. Parent Array is also updated here.*) - -let rec adjustDistance vertex adjacentList distanceArray parentArray visited = - match adjacentList with - | [] -> (distanceArray, parentArray) - | head :: tail -> - if visited.(fst head) = 1 then - adjustDistance vertex tail distanceArray parentArray visited - else - let adjvertex = fst head in - if distanceArray.(adjvertex) < distanceArray.(vertex) +. snd head then - adjustDistance vertex tail distanceArray parentArray visited - else - let _ = parentArray.(adjvertex) <- vertex in - let _ = - distanceArray.(adjvertex) <- distanceArray.(vertex) +. snd head - in - adjustDistance vertex tail distanceArray parentArray visited - -(*This basically removes the nodes visited from the list verticesInspected*) - -let rec changeVerticeInspected vertex (list : int list) (newList : int list) = - match list with - | [] -> Array.of_list newList - | head :: tail -> - if head = vertex then changeVerticeInspected vertex tail newList - else changeVerticeInspected vertex tail (newList @ [ head ]) - -(*Dijkstra's algorithm which calculates the min vertex, then adjust the distance , -update the visited list and iterate till all nodes have been inspected.*) -let rec dijkstraAlgorithm adjMatrix parentArray distanceArray verticesInspected - visited = - if Array.length verticesInspected = 0 then (distanceArray, parentArray) - else - let minVerticeId = minimumDistance verticesInspected distanceArray in - let adjacentVerticeList = Hashtbl.find adjMatrix minVerticeId in - let distanceArray, parentArray = - adjustDistance minVerticeId adjacentVerticeList distanceArray parentArray - visited - in - let verticesInspected = - changeVerticeInspected minVerticeId (Array.to_list verticesInspected) [] - in - let _ = visited.(minVerticeId) <- 1 in - dijkstraAlgorithm adjMatrix parentArray distanceArray verticesInspected - visited - -let rec hashMapVerticeList adjMatrix list n index = - if index = n then Array.of_list (List.rev list) - else if Hashtbl.mem adjMatrix index = true then - hashMapVerticeList adjMatrix (index :: list) n (index + 1) - else hashMapVerticeList adjMatrix list n (index + 1) - -(*ALl intialisation done in main function. Weights are float and vertices are int*) -let main adjMatrix startVertex n = - let parentArray = Array.make n 0 in - let distanceArray = Array.make n infinity in - parentArray.(startVertex) <- startVertex; - distanceArray.(startVertex) <- 0.; - let verticesInspected = hashMapVerticeList adjMatrix [] n 0 in - let visited = Array.make n 0 in - let distanceArray, parentArray = - dijkstraAlgorithm adjMatrix parentArray distanceArray verticesInspected - visited - in - Printf.printf "\nDistance Array is : "; - Array.iter (fun x -> Printf.printf "%f, " x) distanceArray; - Printf.printf "\n Parent Array is : "; - Array.iter (fun x -> Printf.printf "%d, " x) parentArray; - Printf.printf "\n KERNEL3 OVER"; - (distanceArray, parentArray) - -let linkKernel1 () = - let ans = Kernel1Old.linkKronecker () in - main (fst ans) startVertex (snd ans) - - -let _ = linkKernel1 () diff --git a/benchmarks/graph500seq/kernel3.sh b/benchmarks/graph500seq/kernel3.sh new file mode 100755 index 0000000000..311843c165 --- /dev/null +++ b/benchmarks/graph500seq/kernel3.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +./_build/default/kernel3_run.exe sparse.data samples.data; diff --git a/benchmarks/graph500seq/kernel3Par.sh b/benchmarks/graph500seq/kernel3Par.sh new file mode 100755 index 0000000000..c7a96f8645 --- /dev/null +++ b/benchmarks/graph500seq/kernel3Par.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +NDOMAINS=$1 + +./_build/default/kernel3_run_multicore.exe sparse.data samples.data -ndomains $NDOMAINS diff --git a/benchmarks/graph500seq/kernel3Seq.ml b/benchmarks/graph500seq/kernel3Seq.ml new file mode 100644 index 0000000000..7576aa1f2a --- /dev/null +++ b/benchmarks/graph500seq/kernel3Seq.ml @@ -0,0 +1,78 @@ +let is_intree intree v = + intree.(v) + +let get_min_edgenode intree distance = + let nvertices = Array.length intree in + let d = ref Float.infinity in + let v = ref 0 in + for i = 0 to (nvertices-1) do + if ((not @@ is_intree intree i) && (!d > distance.(i))) then begin + d := distance.(i); + v := i; + end + done; + (!v , !d) + +let set_val_to_array_index arr index value = arr.(index) <- value + +let set_vertex_intree intree v = set_val_to_array_index intree v true + +let set_distance = set_val_to_array_index + +let set_parent = set_val_to_array_index + +let get_next_edgenode = SparseGraphSeq.get_next_edgenode + +let has_no_edgenodes = SparseGraphSeq.has_no_edgenodes + +let is_tree_complete intree v = is_intree intree v + +let is_shortest_dist_edge (distance : float array) src dest from_weight = + distance.(dest) > (distance.(src) +. from_weight) + +let rec run_dijkstra g v intree parents (distance : float array) = + match (is_tree_complete intree v) with + | true -> (parents, distance) + | false -> begin + match (has_no_edgenodes g v) with + | true -> begin + set_vertex_intree intree v; + let min_edge = get_min_edgenode intree distance in + let w = fst min_edge in + run_dijkstra g w intree parents distance + end + | false -> begin + let edgenode = get_next_edgenode g v in + let w = fst edgenode in + let weight = snd edgenode in + match (is_shortest_dist_edge distance v w weight) with + | false -> run_dijkstra g v intree parents distance + | true -> begin + set_distance distance w (distance.(v) +. weight); + set_parent parents w v; + run_dijkstra g v intree parents distance + end + end + end + +let dijkstra g start = + let nvertices = SparseGraphSeq.num_vertices g in + let distance = Array.init nvertices (fun _ -> Float.infinity) in + set_distance distance start 0.; + let intree = Array.init nvertices (fun _ -> false) in + let parents = Array.init nvertices (fun _ -> -1) in + set_parent parents start start; + let g_copy = SparseGraphSeq.copy_graph g in + run_dijkstra g_copy start intree parents distance + +let kernel3 g root = + dijkstra g root + +(*open Base +let%test_unit "kernel3_1" = + [%test_eq: (int array) * (float array)] (kernel3 SparseGraphSeq.graph3 2) ([|2; 0; 2; 2; 1|], [|1.;4.;0.;2.;5.|]) + +let%test_unit "kernel3_2" = + [%test_eq: (int array) * (float array)] (kernel3 SparseGraphSeq.graph4 5) ([|-1; -1; -1; -1; -1; 5; 7; 5 |], [|Float.infinity; Float.infinity; Float.infinity; Float.infinity; Float.infinity; 0.; 4.; 3.|]) +*) + diff --git a/benchmarks/graph500seq/kernel3_run.ml b/benchmarks/graph500seq/kernel3_run.ml new file mode 100644 index 0000000000..d7eee51fc1 --- /dev/null +++ b/benchmarks/graph500seq/kernel3_run.ml @@ -0,0 +1,25 @@ +let usage_msg = "kernel3Seq_run.exe files := filename::!files) usage_msg; + files := List.rev !files; + let sparse_graph_input_filename = List.nth !files 0 in + let samples_input_filename = List.nth !files 1 in + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide sparse graph input file argument.\n"; exit 1 + end; + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide search keys input file argument.\n"; exit 1 + end; + Printf.printf "Reading sparse graph from %s...\n%!" sparse_graph_input_filename; + let graph = FileHandler.from_file sparse_graph_input_filename in + Printf.printf "Reading search keys from from %s...\n%!" samples_input_filename; + let samples = FileHandler.from_file samples_input_filename in + Printf.printf "Performing single-source shortest path searches...\n%!"; + let t0 = Unix.gettimeofday () in + ignore @@ Sys.opaque_identity @@ Array.map (fun start -> let g = graph in Kernel3Seq.kernel3 g start) samples; + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f\n" (t1 -. t0); + diff --git a/benchmarks/graph500seq/kernel3_run_multicore.ml b/benchmarks/graph500seq/kernel3_run_multicore.ml new file mode 100644 index 0000000000..989f7f33ae --- /dev/null +++ b/benchmarks/graph500seq/kernel3_run_multicore.ml @@ -0,0 +1,40 @@ +let usage_msg = "kernel3Par_run.exe -ndomains " +let files = ref [] +let num_domains = ref 1 + +let speclist = [("-ndomains", Arg.Set_int num_domains, "Set the number of domains")] + +module T = Domainslib.Task + +let parellel_kernel3 pool graph samples res= + let len = Array.length res in + T.parallel_for pool ~start:0 ~finish:(len-1) ~body:(fun i -> + res.(i) <- (Kernel3Seq.kernel3 graph samples.(i)) + ) + + +let () = + Random.self_init (); + Arg.parse speclist (fun filename -> files := filename::!files) usage_msg; + files := List.rev !files; + let sparse_graph_input_filename = List.nth !files 0 in + let samples_input_filename = List.nth !files 1 in + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide sparse graph input file argument.\n"; exit 1 + end; + if sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide search keys input file argument.\n"; exit 1 + end; + Printf.printf "Reading sparse graph from %s...\n%!" sparse_graph_input_filename; + let graph = FileHandler.from_file sparse_graph_input_filename in + Printf.printf "Reading search keys from from %s...\n%!" samples_input_filename; + let samples = FileHandler.from_file samples_input_filename in + Printf.printf "Performing single-source shortest path searches...\n%!"; + let pool = T.setup_pool ~num_additional_domains:(!num_domains-1) () in + let t0 = Unix.gettimeofday () in + let results = Array.init (Array.length samples) (fun _ -> ([||],[||])) in + ignore @@ Sys.opaque_identity @@ T.run pool (fun () -> + parellel_kernel3 pool graph samples results); + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f\n" (t1 -. t0); + diff --git a/benchmarks/graph500seq/kronecker.ml b/benchmarks/graph500seq/kronecker.ml deleted file mode 100644 index 8f3a4a62d1..0000000000 --- a/benchmarks/graph500seq/kronecker.ml +++ /dev/null @@ -1,136 +0,0 @@ -(*Kronecker is using the following algorithm : - Function Kronecker generator(scale, edgefactor) : - N = 2^scale - M = edgefactor * N (No of edges) - [A,B,C] = [0.57, 0.19, 0.19] - ijw = { {1,1,1,1,1,...Mtimes}; - {1,1,1,1,1...Mtimes}; - {1,1,1,1,1...Mtimes}; - } - ab = A + B; - c_norm = C/(1 - (A + B)); - a_norm = A/(A + B); - for i in (0, scale) : - ii_bit = rand(1,M) > ab; - jj_bit = rand (1, M) > ( c_norm * ii_bit + a_norm * not (ii_bit) );(not a: a xor 0) - ijw(1:2,:) = ijw(1:2,:) + 2^(ib-1) * [ii_bit; jj_bit]; - ijw(3,:) = unifrnd(0, 1, 1, M);//produce values from 0 to 1 for 1*M array. - - p = randperm (N); - ijw(1:2,:) = p(ijw(1:2,:)); - p = randperm (M); - ijw = ijw(:, p); - ijw(1:2,:) = ijw(1:2,:) - 1; - Here, the labels are from 0 to N-1. -*) - -(*(*<-------OCaml Kronecker Kernel inspired from https://graph500.org/?page_id=12----------> -Written by support of PRISM Lab, IIT Madras and OCaml Labs*)*) - -let scale = try int_of_string Sys.argv.(1) with _ -> 2 - -let edgefactor = try int_of_string Sys.argv.(2) with _ -> 1 - -let rec randomWghtGen len ar = - if len = 0 then ar - else randomWghtGen (len - 1) (Array.append ar [| Random.float 1. |]) - -let rec generateIIBitArray ar index ab = - if index = 0 then ar - else if Random.float 1. > ab then - generateIIBitArray (Array.append ar [| 1. |]) (index - 1) ab - else generateIIBitArray (Array.append ar [| 0. |]) (index - 1) ab - -let rec generateJJBitArray ar ii_bit m a_norm c_norm index = - if index = m then ar - else - let h = ii_bit.(index) in - if - Random.float 1. - > (c_norm *. h) +. (a_norm *. float_of_int (int_of_float h lxor 1)) - then - generateJJBitArray - (Array.append ar [| 1. |]) - ii_bit m a_norm c_norm (index + 1) - else - generateJJBitArray - (Array.append ar [| 0. |]) - ii_bit m a_norm c_norm (index + 1) - -let rec modifyRowIJW kk_array index ar newAr iter m = - if iter = m then newAr - else - let element = - ar.(iter) +. ((2. ** float_of_int index) *. kk_array.(iter)) - in - modifyRowIJW kk_array index ar - (Array.append newAr [| element |]) - (iter + 1) m - -let rec compareWithPr index m n ab a_norm c_norm ijw scale = - if index = scale then ijw - else - let ii_bit = generateIIBitArray [||] m ab in - let jj_bit = generateJJBitArray [||] ii_bit m a_norm c_norm 0 in - let firstRowIJW = modifyRowIJW ii_bit index ijw.(0) [||] 0 m in - let secondRowIJW = modifyRowIJW jj_bit index ijw.(1) [||] 0 m in - let ijw = - Array.append - (Array.append [| firstRowIJW |] [| secondRowIJW |]) - [| ijw.(2) |] - in - compareWithPr (index + 1) m n ab a_norm c_norm ijw scale - -let permute list = - let list = List.map (fun x -> (Random.bits (), x)) list in - let list = List.sort compare list in - List.map (fun x -> snd x) list - -let transpose ar newAr = - for i = 0 to Array.length ar - 1 do - for j = 0 to Array.length ar.(0) - 1 do - !newAr.(j).(i) <- ar.(i).(j) - done - done; - !newAr - -let computeNumber scale edgefactor = - let n = int_of_float (2. ** float_of_int scale) in - let m = edgefactor * n in - (n, m) - -let writeFile ijw file = - let rec writeFile ijw file index = - if index = Array.length ijw then exit 0 - else - let _ = Array.iter (Printf.fprintf file "%f, ") ijw.(index) in - let _ = Printf.fprintf file "\n" in - writeFile ijw file (index + 1) - in - writeFile ijw file 0 - -let kronecker scale edgefactor = - let n, m = computeNumber scale edgefactor in - let a, b, c = (0.57, 0.19, 0.19) in - let ijw = Array.make_matrix 3 m 1. in - let ab = a +. b in - let c_norm = c /. (1. -. (a +. b)) in - let a_norm = a /. (a +. b) in - let ijw = compareWithPr 0 m n ab a_norm c_norm ijw scale in - let thirdRow = randomWghtGen m [||] in - let firstRowPermute = Array.of_list (permute (Array.to_list ijw.(0))) in - let secondRowPermute = Array.of_list (permute (Array.to_list ijw.(1))) in - let ijw = - Array.append - (Array.append [| firstRowPermute |] [| secondRowPermute |]) - [| thirdRow |] - in - let ar = Array.to_list (transpose ijw (ref (Array.make_matrix m 3 1.))) in - let ijw = transpose (Array.of_list (permute ar)) (ref ijw) in - if Sys.file_exists "kronecker.txt" then Sys.remove "kronecker.txt"; - let file = open_out "kronecker.txt" in - let _ = writeFile ijw file in - let _ = close_out file in - ijw - -let _ = kronecker scale edgefactor diff --git a/benchmarks/graph500seq/sampleSearchKeys.ml b/benchmarks/graph500seq/sampleSearchKeys.ml new file mode 100644 index 0000000000..e1df6dcc48 --- /dev/null +++ b/benchmarks/graph500seq/sampleSearchKeys.ml @@ -0,0 +1,67 @@ +(* Returns a list that contains all non-isolated vertices *) +let get_candidates g = + let glen = Array.length g in + let rec aux count xs = + match (count = glen) with + | true -> xs + | false -> begin + match g.(count) = [] with + | true -> aux (count+1) xs + | false -> aux (count+1) (count::xs) + end + in + aux 0 [] + +(* Returns a list of n random vetices from the list of candidates *) +let extract_samples n candidates = + let rec aux count cands xs = + match count with + | 0 -> xs + | _ -> begin + let sample = Random.full_int (List.length cands) in + aux (count-1) (List.filter (fun x -> if x = sample then false else true) cands) ((List.nth cands sample)::xs) + end + in + aux n candidates [] + +let get_samples n g = + let candidates = get_candidates (Array.mapi (fun i x -> if (SparseGraphSeq.has_selfloop i x) then [] else x) g) in + let samples_list = extract_samples n candidates in + Array.of_list samples_list + +let usage_msg = "sampleSearchKeys.exe -o sparse_graph_input_filename := s) usage_msg; + if !sparse_graph_input_filename = "" then begin + Printf.eprintf "Must provide sparse graph input file as an argument.\n"; exit 1 + end; + Printf.printf "Reading sparse graph from %s...\n%!" !sparse_graph_input_filename; + let t0 = Unix.gettimeofday () in + let g = FileHandler.from_file !sparse_graph_input_filename in + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f s.\nGetting 64 samples search keys...\n%!" (t1 -. t0); + let t0 = Unix.gettimeofday () in + let sample_array = get_samples 64 g in + let t1 = Unix.gettimeofday () in + Printf.printf "Done. Time: %f\n" (t1 -. t0); + FileHandler.to_file ~filename:!sample_array_output_filename sample_array; + +(*open Base +let%test_unit "get_candidates_1" = + [%test_eq: int list list] (get_candidates [| [12]; [14]; []; [16] |]) [[16]; [14]; [12]] + +let%test_unit "get_candidates_2" = + [%test_eq: int list list] (get_candidates [| []; []; []; [] |]) [] + +let%test_unit "extract_samples_1" = + [%test_eq: int ] (Array.length (extract_samples 4 [1;2;3;4;5;6;7;8])) 4 + +let%test_unit "extract_samples_2" = + [%test_eq: bool] (( (extract_samples 2 [1;2;3])= [|1;2|]) || ((extract_samples 2 [1;2;3]) = [|1;3|]) || ((extract_samples 2 [1;2;3]) = [|2;1|]) || ((extract_samples 2 [1;2;3]) = [|2;3|]) || ((extract_samples 2 [1;2;3]) = [|3;1|]) || ((extract_samples 2 [1;2;3]) = [|3;2|]) ) true +*) diff --git a/benchmarks/graph500seq/sparseGraphSeq.ml b/benchmarks/graph500seq/sparseGraphSeq.ml index 08096e1cf3..9219136047 100644 --- a/benchmarks/graph500seq/sparseGraphSeq.ml +++ b/benchmarks/graph500seq/sparseGraphSeq.ml @@ -1,5 +1,6 @@ open GraphTypes + type t = (vertex * weight) list array let create ~max_vertex_label = @@ -16,7 +17,125 @@ let add_edge (s,e,w) g = let from s g = g.(s) -let rec sample_vertex g = - let v = Random.int (Array.length g) in - let outgoing = g.(v) in - if outgoing <> [] then v else sample_vertex g +let num_vertices g = + Array.length g + +(* Takes a sparse graph g and a vertex v and returns the next edgenode + res in the edgenode list of v and changes the state of g with res removed + from the edgenode list of v. *) +let get_next_edgenode g v = + let res = List.hd g.(v) in + let rest_edgelist = List.tl g.(v) in + g.(v) <- rest_edgelist; + res + +let has_no_edgenodes g v = + g.(v) = [] + +let get_vertex edgenode = fst edgenode + +let get_weight edgenode = snd edgenode + +let rec has_selfloop v edgelist = + match (edgelist = []) with + | true -> false + | false -> begin + let edgenode = List.hd edgelist in + let rest = List.tl edgelist in + match (get_vertex @@ edgenode = v) with + | true -> true + | false -> has_selfloop v rest + end + +let copy_graph g = + Array.copy g + +let sample_vertex g = + let v = Random.int (Array.length g) in + let outgoing = g.(v) in + if (outgoing <> []) && (not @@ has_selfloop v g.(v)) then + v + else + v + +let print_edgelist el = + let rec aux str el = + match el with + | [] -> str ^ "NULL" + | _ -> aux (str ^ (List.hd el |> fst |> string_of_int) ^ "->") (List.tl el) + in + aux "" el + +let print_sparse_graph g = + for i = 0 to (Array.length g) -1 do + print_endline ((string_of_int i) ^ ": " ^ (print_edgelist g.(i))); + done + +let print_vertex v = print_int v + +let gr = [| + [1;3]; + [0]; + [3;4]; + [0;2]; + [2] +|] + +let gr2 = [| + []; + [2;3;7;4;8]; + [1;6]; + [1;7]; + [1]; + [6]; + [2;5;8]; + [1;3]; + [1;6]; +|] + +let graph = + Array.map + (fun x -> + List.map (fun y -> (y, 0.)) x + ) + gr + +let graph2 = + Array.map + (fun x -> + List.map (fun y -> (y, 0.)) x + ) + gr2 + +let graph3 = [| + [(1, 3.); (2, 1.)]; + [(0, 3.); (2, 7.); (4, 1.); (3, 5.)]; + [(1, 7.); (0, 1.); (3, 2.)]; + [(2, 2.); (1, 5.); (4, 7.)]; + [(1, 1.); (3,7.)] +|] + +let graph4 = [| + [(1, 5.); (2, 3.)]; + [(0, 5.); (2, 1.)]; + [(0, 3.); (1, 1.)]; +|] + +(*let graph5 = [| + [(0, 3.); (2, 1.)]; + [(1, 3.); (2, 7.); (4, 1.); (3, 5.)]; + [(2, 7.); (0, 1.); (3, 2.)]; + [(3, 2.); (1, 5.); (4, 7.)]; + [(4, 1.); (3, 7.)] +|]*) + + +(*open Base +let%test_unit "has_selfloop_1" = + [%test_eq: bool] (has_selfloop 2 [(1, 0.); (2, 0.)]) true + +let%test_unit "has_selfloop_2" = + [%test_eq: bool] (has_selfloop 3 [(0, 3.); (2, 7.); (4, 1.); (3, 5.)]) true + + +*) diff --git a/benchmarks/graph500seq/sparseGraphSeq.mli b/benchmarks/graph500seq/sparseGraphSeq.mli index d5814ed7dd..ee93ed2589 100644 --- a/benchmarks/graph500seq/sparseGraphSeq.mli +++ b/benchmarks/graph500seq/sparseGraphSeq.mli @@ -12,5 +12,31 @@ val from : vertex -> t -> (vertex * weight) list val max_vertex_label : t -> vertex +val num_vertices : t -> int + +val get_next_edgenode : t -> vertex -> (vertex * weight) + +val get_vertex : (vertex * weight) -> vertex + +val get_weight : (vertex * weight) -> weight + +val has_no_edgenodes : t -> vertex -> bool + +val copy_graph : t -> t + +val has_selfloop: vertex -> (vertex * weight) list -> bool + +val graph : t + +val graph2 : t + +val graph3 : t + +val graph4 : t + +val print_sparse_graph: t -> unit + +val print_vertex: vertex -> unit + (** Return a random vertex from the graph of degree at least 1. *) val sample_vertex : t -> vertex From ea8eae1c8b11733c49673ea42ec4e4b70d313b7a Mon Sep 17 00:00:00 2001 From: Moazzam Moriani Date: Fri, 26 Aug 2022 19:44:17 +0500 Subject: [PATCH 2/5] Remove dune-project --- benchmarks/graph500seq/dune-project | 1 - 1 file changed, 1 deletion(-) delete mode 100644 benchmarks/graph500seq/dune-project diff --git a/benchmarks/graph500seq/dune-project b/benchmarks/graph500seq/dune-project deleted file mode 100644 index 0c226b5b0c..0000000000 --- a/benchmarks/graph500seq/dune-project +++ /dev/null @@ -1 +0,0 @@ -(lang dune 3.2) From 8a13182cb9145983608d91302c96b56a8713a28a Mon Sep 17 00:00:00 2001 From: Moazzam Moriani Date: Thu, 1 Sep 2022 01:28:30 +0500 Subject: [PATCH 3/5] Remove GraphTypes stanza from graph500seq dune file --- benchmarks/graph500seq/dune | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/benchmarks/graph500seq/dune b/benchmarks/graph500seq/dune index 67a7f6c834..45a311d53e 100644 --- a/benchmarks/graph500seq/dune +++ b/benchmarks/graph500seq/dune @@ -1,29 +1,19 @@ -(library - (name graphTypes) - (modules graphTypes) - (modules_without_implementation graphTypes) - (ocamlc_flags -g) -) - (library (name generateSeq) (modules generateSeq) (libraries graphTypes fileHandler) - (ocamlc_flags -g) ) (library (name fileHandler) (modules fileHandler) - (ocamlc_flags -g) ) (executable (name gen) (modules gen) (libraries unix generateSeq fileHandler) - (ocamlc_flags -g) ) (library @@ -32,14 +22,12 @@ (libraries graphTypes) ;(preprocess; (pps ppx_inline_test ppx_assert)) ;(inline_tests) - (ocamlc_flags -g) ) (library (name kernel1Seq) (modules kernel1Seq) (libraries generateSeq sparseGraphSeq unix) - (ocamlc_flags -g) ) (library @@ -48,7 +36,6 @@ (libraries generateSeq sparseGraphSeq unix) ;(preprocess; (pps ppx_inline_test ppx_assert)) ;(inline_tests) - (ocamlc_flags -g) ) (library @@ -57,14 +44,12 @@ (libraries graphTypes generateSeq sparseGraphSeq unix) ;(preprocess; (pps ppx_inline_test ppx_assert)) ;(inline_tests) - (ocamlc_flags -g) ) (executable (name sampleSearchKeys) (modules sampleSearchKeys) (libraries graphTypes generateSeq sparseGraphSeq unix) - (ocamlc_flags -g) ) (executable @@ -72,14 +57,12 @@ (modules print_sparse) (modes byte exe) (libraries sparseGraphSeq graphTypes fileHandler kernel1Seq unix) - (ocamlc_flags -g) ) (executable (name kernel1_run) (modules kernel1_run) (libraries sparseGraphSeq graphTypes fileHandler kernel1Seq unix) - (ocamlc_flags -g) ) (executable @@ -87,7 +70,6 @@ (modules kernel2_run) (modes byte exe) (libraries sparseGraphSeq graphTypes fileHandler kernel2Seq unix) - (ocamlc_flags -g) ) (executable @@ -95,7 +77,6 @@ (modules kernel2_run_multicore) (modes byte exe) (libraries domainslib sparseGraphSeq graphTypes fileHandler kernel2Seq unix) - (ocamlc_flags -g) ) (executable @@ -103,7 +84,6 @@ (modules kernel3_run) (modes byte exe) (libraries sparseGraphSeq graphTypes fileHandler kernel3Seq unix) - (ocamlc_flags -g) ) (executable @@ -111,7 +91,6 @@ (modules kernel3_run_multicore) (modes byte exe) (libraries domainslib sparseGraphSeq graphTypes fileHandler kernel3Seq unix) - (ocamlc_flags -g) ) ;(alias From cae646da2ea51be8ee5b75fef2be4f8e518fc5f1 Mon Sep 17 00:00:00 2001 From: Moazzam Moriani Date: Thu, 1 Sep 2022 09:16:56 +0500 Subject: [PATCH 4/5] Remove unnecessary stanzas --- benchmarks/graph500seq/dune | 7 ------- 1 file changed, 7 deletions(-) diff --git a/benchmarks/graph500seq/dune b/benchmarks/graph500seq/dune index 45a311d53e..a2658343f0 100644 --- a/benchmarks/graph500seq/dune +++ b/benchmarks/graph500seq/dune @@ -52,13 +52,6 @@ (libraries graphTypes generateSeq sparseGraphSeq unix) ) -(executable - (name print_sparse) - (modules print_sparse) - (modes byte exe) - (libraries sparseGraphSeq graphTypes fileHandler kernel1Seq unix) -) - (executable (name kernel1_run) (modules kernel1_run) From 4ff7f33d3a29dfebfdf3319fba570e85a39ca81a Mon Sep 17 00:00:00 2001 From: Moazzam Moriani Date: Sat, 8 Oct 2022 01:19:59 +0500 Subject: [PATCH 5/5] Refactor cleanup and document --- benchmarks/graph500seq/kernel2Seq.ml | 31 ++-------- benchmarks/graph500seq/kernel3Seq.ml | 2 + benchmarks/graph500seq/sampleSearchKeys.ml | 31 ++++------ benchmarks/graph500seq/sparseGraphSeq.ml | 70 ---------------------- benchmarks/graph500seq/sparseGraphSeq.mli | 20 ++++--- 5 files changed, 28 insertions(+), 126 deletions(-) diff --git a/benchmarks/graph500seq/kernel2Seq.ml b/benchmarks/graph500seq/kernel2Seq.ml index 8c1f95eaea..a8f4143140 100644 --- a/benchmarks/graph500seq/kernel2Seq.ml +++ b/benchmarks/graph500seq/kernel2Seq.ml @@ -1,3 +1,7 @@ +(* Kernel 2 performs a breadth-first search on a sparse graph and outputs + the resulting tree in as a parent relation. + INPUTS: Sparse graph and a starting vertex *) + let update_discovered d_arr v = d_arr.(v) <- true @@ -46,30 +50,3 @@ let bfs g start = let kernel2 = bfs - -(* -(* Unit tests *) -let parray = Array.init 64 (fun _ -> -1) - -open Base -let%test_unit "rev" = - [%test_eq: int list] [ 3; 2; 1 ] [ 3; 2; 1 ] - -let%test_unit "update_discovered" = - let bvect = [| false; false; false |] in - update_discovered bvect 0; - [%test_eq: bool] bvect.(0) true - - -let%test_unit "set_parent" = - set_parent parray ~parent:8 ~child:2; - [%test_eq: int] parray.(2) 8 - -let%test_unit "kernel2" = - [%test_eq: int array] (kernel2 SparseGraphSeq.graph 2) [|3;0;-1;2;2|] - -let%test_unit "kernel2_2" = - [%test_eq: int array] (kernel2 SparseGraphSeq.graph2 8) [|-1;8;1;1;1;6;8;1;-1|] - - -*) diff --git a/benchmarks/graph500seq/kernel3Seq.ml b/benchmarks/graph500seq/kernel3Seq.ml index 7576aa1f2a..33eeeca109 100644 --- a/benchmarks/graph500seq/kernel3Seq.ml +++ b/benchmarks/graph500seq/kernel3Seq.ml @@ -1,3 +1,5 @@ +(* Kernel 3 performs a Si*) + let is_intree intree v = intree.(v) diff --git a/benchmarks/graph500seq/sampleSearchKeys.ml b/benchmarks/graph500seq/sampleSearchKeys.ml index e1df6dcc48..017feda2f2 100644 --- a/benchmarks/graph500seq/sampleSearchKeys.ml +++ b/benchmarks/graph500seq/sampleSearchKeys.ml @@ -1,5 +1,6 @@ -(* Returns a list that contains all non-isolated vertices *) -let get_candidates g = +(** Returns a list vertices of vertices that have at least one + out-going edge *) +let get_sinks g = let glen = Array.length g in let rec aux count xs = match (count = glen) with @@ -12,8 +13,8 @@ let get_candidates g = in aux 0 [] -(* Returns a list of n random vetices from the list of candidates *) -let extract_samples n candidates = +(** Returns a list of n random vetices from the list of sinks *) +let extract_samples n sinks = let rec aux count cands xs = match count with | 0 -> xs @@ -22,11 +23,13 @@ let extract_samples n candidates = aux (count-1) (List.filter (fun x -> if x = sample then false else true) cands) ((List.nth cands sample)::xs) end in - aux n candidates [] + aux n sinks [] +(** Returns an array of n samples from g that don't contain + self-loops *) let get_samples n g = - let candidates = get_candidates (Array.mapi (fun i x -> if (SparseGraphSeq.has_selfloop i x) then [] else x) g) in - let samples_list = extract_samples n candidates in + let sinks = get_sinks (Array.mapi (fun i x -> if (SparseGraphSeq.has_selfloop i x) then [] else x) g) in + let samples_list = extract_samples n sinks in Array.of_list samples_list let usage_msg = "sampleSearchKeys.exe -o - List.map (fun y -> (y, 0.)) x - ) - gr - -let graph2 = - Array.map - (fun x -> - List.map (fun y -> (y, 0.)) x - ) - gr2 - -let graph3 = [| - [(1, 3.); (2, 1.)]; - [(0, 3.); (2, 7.); (4, 1.); (3, 5.)]; - [(1, 7.); (0, 1.); (3, 2.)]; - [(2, 2.); (1, 5.); (4, 7.)]; - [(1, 1.); (3,7.)] -|] - -let graph4 = [| - [(1, 5.); (2, 3.)]; - [(0, 5.); (2, 1.)]; - [(0, 3.); (1, 1.)]; -|] - -(*let graph5 = [| - [(0, 3.); (2, 1.)]; - [(1, 3.); (2, 7.); (4, 1.); (3, 5.)]; - [(2, 7.); (0, 1.); (3, 2.)]; - [(3, 2.); (1, 5.); (4, 7.)]; - [(4, 1.); (3, 7.)] -|]*) - - -(*open Base -let%test_unit "has_selfloop_1" = - [%test_eq: bool] (has_selfloop 2 [(1, 0.); (2, 0.)]) true - -let%test_unit "has_selfloop_2" = - [%test_eq: bool] (has_selfloop 3 [(0, 3.); (2, 7.); (4, 1.); (3, 5.)]) true - - -*) diff --git a/benchmarks/graph500seq/sparseGraphSeq.mli b/benchmarks/graph500seq/sparseGraphSeq.mli index ee93ed2589..c74a190999 100644 --- a/benchmarks/graph500seq/sparseGraphSeq.mli +++ b/benchmarks/graph500seq/sparseGraphSeq.mli @@ -6,34 +6,38 @@ type t lesser than or equal to [max_vertex_label]. *) val create : max_vertex_label:int -> t +(** Add edge to the sparse graph *) val add_edge : edge -> t -> unit val from : vertex -> t -> (vertex * weight) list +(** *) val max_vertex_label : t -> vertex +(** Rerturn the number of vertices *) val num_vertices : t -> int +(** Takes a sparse graph g and a vertex v and returns the next edgenode + res in the edgenode list of v and changes the state of g with res removed + from the edgenode list of v. *) val get_next_edgenode : t -> vertex -> (vertex * weight) +(** Extract vertex from the (vertex, weight) edgenode *) val get_vertex : (vertex * weight) -> vertex +(** Extract weight from (vertex, weight) edgenode *) val get_weight : (vertex * weight) -> weight +(** Returns true if the vertex v has not out-going edges + and false otherwise *) val has_no_edgenodes : t -> vertex -> bool +(** Returns a copy of the graph *) val copy_graph : t -> t +(** Returns true if the vertex has an edge pointing to itself *) val has_selfloop: vertex -> (vertex * weight) list -> bool -val graph : t - -val graph2 : t - -val graph3 : t - -val graph4 : t - val print_sparse_graph: t -> unit val print_vertex: vertex -> unit