From 5033ba5571f46c4295bb28377118e785006a3a6c Mon Sep 17 00:00:00 2001 From: Aman Chhaparia <64468582+amanchhaparia@users.noreply.github.com> Date: Thu, 13 Oct 2022 01:51:44 +0530 Subject: [PATCH 01/16] First draft of interface * Frontend: Graph accepting adjacency list. Added the forntend where edges are added in the adjacency list type of graph implementation. Signed-off-by: Rishikesh Donadkar * Frontend: Graph accepting adjacency list. Added the forntend where edges are added in the adjacency list type of graph implementation. Signed-off-by: Rishikesh Donadkar * added additional function to print adjList * Sarrah+Rishi final code working * Added all 4 cases of incidence matrix * clang format and adj mat * doxygen docs * removed redundancy in using memref_descriptor * Docs generated and relevant instructions added * clean up of docs * Added Graph Container * Finished formatting the code Spaces were added after the // in the comments, and incorrect formatting was fixed. * Added documentation for new code * Added documentation * Remove redundant doxygen related file * Improved Container interface. * Added Description of a constructor * Trivial changes Trivial changes Signed-off-by: Rishikesh Donadkar Co-authored-by: Rishikesh Donadkar Co-authored-by: Sarrah Bastawala Co-authored-by: Sarrah Bastawala <84874044+sarrah-basta@users.noreply.github.com> Co-authored-by: rishabh Co-authored-by: Rishabh Bali <81592570+Ris-Bali@users.noreply.github.com> Co-authored-by: meshtag --- .gitignore | 3 + CMakeLists.txt | 2 + README.md | 6 + examples/bfsExample.cpp | 47 ++- include/CMakeLists.txt | 2 +- include/Interface/Container.h | 93 +++++ include/Interface/GraphContainer.h | 78 +++++ include/Interface/graph.h | 26 +- include/Interface/memref.h | 53 --- lib/CMakeLists.txt | 1 + lib/Interface/CMakeLists.txt | 1 + lib/Interface/Container.cpp | 280 ++++++++++++++++ lib/Interface/GraphContainer.cpp | 522 +++++++++++++++++++++++++++++ 13 files changed, 1043 insertions(+), 71 deletions(-) create mode 100644 include/Interface/Container.h create mode 100644 include/Interface/GraphContainer.h delete mode 100644 include/Interface/memref.h create mode 100644 lib/Interface/CMakeLists.txt create mode 100644 lib/Interface/Container.cpp create mode 100644 lib/Interface/GraphContainer.cpp diff --git a/.gitignore b/.gitignore index e643a5f..b62b64b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ # IDEA configurations /.idea + +# Doc files +/docs* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 58ea840..5a945d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,8 +68,10 @@ include_directories(${MLIR_INCLUDE_DIRS}) # Add GraphMLIR files to the include path include_directories(${GraphMLIR_MAIN_INCLUDE_DIR}) include_directories(${GraphMLIR_INCLUDE_DIR}) +include_directories(${GraphMLIR_INCLUDE_DIR}/Interface) include_directories(${GraphMLIR_INCLUDE_DIR}/Dialect) include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/Dialect) +include_directories(${GraphMLIR_SOURCE_DIR}/lib) #------------------------------------------------------------------------------- # Directory setup diff --git a/README.md b/README.md index 6f584f5..5897208 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,9 @@ cmake -G Ninja .. \ ninja bfsExample cd bin && ./bfsExample ``` +## Instructions for generating docs +``` +Use doxywizard for generating docs automatically from relevant source directories. +``` +#### After this go to docs and open index.html in the html subdirectory with your prefered browser. + diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index ff9d068..aef235e 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -7,23 +7,46 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include #include +#include int main() { - std::cout << "Reached here !!!\n"; - float sample_graph1_array[9] = {1, 1, 1, 1, -8, 1, 1, 1, 1}; - intptr_t sample_graph_length = 3; - intptr_t sample_graph_width = 3; - float *allocation_pointer = (float *)malloc(sizeof(float)); - intptr_t sample_graph_sizes[2] = {sample_graph_width, sample_graph_length}; - intptr_t sample_graph_strides[2] = {sample_graph_width, sample_graph_length}; + // Graph + // sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, 5); - MemRef_descriptor sample_graph = - MemRef_Descriptor(allocation_pointer, sample_graph1_array, 0, - sample_graph_sizes, sample_graph_strides); + // use for unweighted graph + // sample_graph.addEdge(0,2); + // sample_graph.addEdge(2,3); + // sample_graph.addEdge(3,2); + // sample_graph.addEdge(2,2); + // sample_graph.addEdge(1,2); - graph::graph_bfs(sample_graph, sample_graph, sample_graph); + // use for weighted graph + Graph sample_graph( + graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, 5); + sample_graph.addEdge(0, 2, 1); + sample_graph.addEdge(2, 3, 3); + sample_graph.addEdge(3, 2, 3); + sample_graph.addEdge(2, 2, 6); + sample_graph.addEdge(1, 2, 2); + + // this will print the original graph. + std::cout << "Printing graph in format it was entered ( " + "GRAPH_ADJ_MARIX_DIRECTED_WEIGHTED )\n"; + sample_graph.printGraphOg(); + + auto x = sample_graph.get_Memref(); + + // this will print the linear 2d matrix in 2d form. + + std::cout + << "Printing graph in form of 2d matrix after conversion to memref\n"; + sample_graph.printGraph(); + graph::graph_bfs(x, x, x); + x.release(); + std::cout << "End of the program! \n"; } diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index e6f347c..0ca0f41 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(Dialect) \ No newline at end of file +add_subdirectory(Dialect) diff --git a/include/Interface/Container.h b/include/Interface/Container.h new file mode 100644 index 0000000..e674642 --- /dev/null +++ b/include/Interface/Container.h @@ -0,0 +1,93 @@ +//===- Container.h --------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// Container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_BUDDY_CORE_CONTAINER +#define INTERFACE_BUDDY_CORE_CONTAINER + +#include +#include +#include + +// MemRef descriptor. +// - T represents the type of the elements. +// - N represents the number of dimensions. +// - The storage order is NCHW. +template class MemRef { +public: + // Constructor from shape. + MemRef(intptr_t sizes[N], T init = T(0)); + // Constructor from data. + MemRef(const T *data, intptr_t sizes[N], intptr_t offset = 0); + // Constructor from a unique_ptr, taking over. + MemRef(std::unique_ptr &uptr, intptr_t sizes[N], intptr_t offset = 0); + // Copy constructor. + MemRef(const MemRef &other); + // Copy assignment operator. + MemRef &operator=(const MemRef &other); + // Move constructor. + MemRef(MemRef &&other) noexcept; + // Move assignment operator. + MemRef &operator=(MemRef &&other) noexcept; + // Desctrutor. + ~MemRef(); + // Get the data pointer. + T *getData(); + // Get the sizes (shape). + const intptr_t *getSizes() { return sizes; } + // Get the strides. + const intptr_t *getStrides() { return strides; } + // Get the rank of the memref. + size_t getRank() const { return N; } + // Get the size (number of elements). + size_t getSize() const { return size; } + // Get the element at index. + const T &operator[](size_t index) const; + T &operator[](size_t index); + // release the pointer + T *release(); + +protected: + // Default constructor. + MemRef(){}; + // Set the strides. + // Computes the strides of the transposed tensor for transpose=true. + void setStrides(); + // Compute the product of array elements. + size_t product(intptr_t sizes[N]) const; + + // Data. + // The `aligned` and `allocated` members point to the same address, `aligned` + // member is responsible for handling data, and `allocated` member is + // resposible for handling the memory space. + T *allocated = nullptr; + T *aligned = nullptr; + // Offset. + intptr_t offset = 0; + // Shape. + intptr_t sizes[N]; + // Strides. + intptr_t strides[N]; + // Number of elements. + size_t size; +}; + +#include "Interface/Container.cpp" + +#endif // INTERFACE_BUDDY_CORE_CONTAINER diff --git a/include/Interface/GraphContainer.h b/include/Interface/GraphContainer.h new file mode 100644 index 0000000..361fc87 --- /dev/null +++ b/include/Interface/GraphContainer.h @@ -0,0 +1,78 @@ +//===- GraphContainer.h ---------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// Graph container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_GRAPHCONTAINER_H +#define INTERFACE_GRAPHCONTAINER_H + +#include "Interface/Container.h" +#include +#include +/** + * The Graph Class ; the object of this class will be used to call functions. + * + * @tparam T represents the datatype to be used. + * @tparam N represents the number of dimensions. + */ +template class Graph { +protected: + // the graph type and representation + uint16_t graph_type; + size_t size; + intptr_t sizes[N]; + MemRef *data = nullptr; + // the count of number of edges added in the graph. + int edgeCount = 0; + + // adjacency list representation of graph. + std::vector> adjList; + + // incidence matrix representation of graph. + std::vector> incMat; + + // adjacency matrix representation of graph + std::vector> adjMat; + + // weighted adjacency list representation of graph. + std::vector>> adjList_weighted; + +public: + // Constructor + Graph(uint16_t graph_type, size_t size); + + // Function to add edges in graph. + void addEdge(T a, T b); + void addEdge(T Node1, T Node2, T EdgeWeight); + + // Function to print the linear 2d graph. + void printGraphOg(); + + // converter from graph to MemRef_descriptor + void graph_to_MemRef_descriptor(); + MemRef &get_Memref() { + graph_to_MemRef_descriptor(); + return *data; + } + + // Function to print the linear 2d graph after conversion. + void printGraph(); +}; + +#include "Interface/GraphContainer.cpp" +#endif // INTERFACE_GRAPHCONTAINER_H diff --git a/include/Interface/graph.h b/include/Interface/graph.h index fbb860c..b509ebb 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -22,21 +22,37 @@ #ifndef INCLUDE_INTERFACE_GRAPH_H #define INCLUDE_INTERFACE_GRAPH_H -#include +#include namespace graph { namespace detail { + +enum graph_type { + GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED, + GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED, + GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED, + GRAPH_ADJ_LIST_DIRECTED_WEIGHTED, + GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED, + GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, + GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED, + GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, + GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED, + GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED, + GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED, + GRAPH_INC_MATRIX_DIRECTED_WEIGHTED, +}; + // Functions present inside graph::detail are not meant to be called by users // directly. // Declare the BFS C interface. extern "C" { -void _mlir_ciface_bfs(MemRef_descriptor graph1, MemRef_descriptor graph2, - MemRef_descriptor graph3); +void _mlir_ciface_bfs(MemRef graph1, MemRef graph2, + MemRef graph3); } } // namespace detail -void graph_bfs(MemRef_descriptor graph1, MemRef_descriptor graph2, - MemRef_descriptor graph3) { +void graph_bfs(MemRef graph1, MemRef graph2, + MemRef graph3) { detail::_mlir_ciface_bfs(graph1, graph2, graph3); } } // namespace graph diff --git a/include/Interface/memref.h b/include/Interface/memref.h deleted file mode 100644 index 45ebbe6..0000000 --- a/include/Interface/memref.h +++ /dev/null @@ -1,53 +0,0 @@ -//===- memref.h -----------------------------------------------------------===// -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//===----------------------------------------------------------------------===// -// -// Header file for MemRef specific entities. -// -//===----------------------------------------------------------------------===// - -#ifndef INCLUDE_INTERFACE_MEMREF_H -#define INCLUDE_INTERFACE_MEMREF_H - -#include -#include - -// Define Memref Descriptor. -typedef struct MemRef_descriptor_ *MemRef_descriptor; -typedef struct MemRef_descriptor_ { - float *allocation_pointer; - float *aligned; - intptr_t offset; - intptr_t sizes[2]; - intptr_t strides[2]; -} Memref; - -// Constructor -MemRef_descriptor MemRef_Descriptor(float *allocation_pointer, float *aligned, - intptr_t offset, intptr_t sizes[2], - intptr_t strides[2]) { - MemRef_descriptor n = (MemRef_descriptor)malloc(sizeof(*n)); - n->allocation_pointer = allocation_pointer; - n->aligned = aligned; - n->offset = offset; - for (int i = 0; i < 2; i++) - n->sizes[i] = sizes[i]; - for (int j = 0; j < 2; j++) - n->strides[j] = strides[j]; - - return n; -} - -#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 629c08a..6965fb1 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(Conversion) add_subdirectory(Dialect) +add_subdirectory(Interface) diff --git a/lib/Interface/CMakeLists.txt b/lib/Interface/CMakeLists.txt new file mode 100644 index 0000000..381bd6a --- /dev/null +++ b/lib/Interface/CMakeLists.txt @@ -0,0 +1 @@ +add_library(Container Container.cpp) diff --git a/lib/Interface/Container.cpp b/lib/Interface/Container.cpp new file mode 100644 index 0000000..bb9d6a1 --- /dev/null +++ b/lib/Interface/Container.cpp @@ -0,0 +1,280 @@ +//===- Container.cpp ------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef CORE_CONTAINER_DEF +#define CORE_CONTAINER_DEF + +#include +#include +#include +#include +#include + +#include "Interface/Container.h" + +/** + * @brief MemRef Shape Constructor. Construct a MemRef object from the data + * shape and initial value. The default initial value is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(intptr_t sizes[N], T init) { + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + std::fill(aligned, aligned + size, init); +} + +/** + * @brief MemRef Array Constructor. Construct a MemRef object from the data + * pointer, sizes, and offset. The default offset is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(const T *data, intptr_t sizes[N], intptr_t offset) { + this->offset = offset; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + std::copy(data, data + size, aligned); +} + +/** + * @brief MemRef Array Constructor. Construct a MemRef object from a unique_ptr, + * sizes, and offset. The default offset is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(std::unique_ptr &uptr, intptr_t *sizes, + intptr_t offset) { + if (!uptr) + assert(0 && "Taking over an empty unique pointer."); + T *data = uptr.release(); + this->aligned = data; + this->allocated = data; + this->offset = offset; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); +} + +/** + * @brief Copy Constructor. This constructor is used to initialize a MemRef + object with another MemRef object. + - Copy `offset` and `size` directly. + * - Elementwise copy `sizes` array. + * - Calculate `strides`. + * - Allocate new space. + * - Deep copy the data from the original object. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(const MemRef &other) + : offset(other.offset), size(other.size) { + for (size_t i = 0; i < N; i++) { + this->sizes[i] = other.sizes[i]; + } + setStrides(); + allocated = new T[size]; + aligned = allocated; + std::copy(other.aligned, other.aligned + size, aligned); +} + +/** + * @brief Copy Assignment Operator.. + * - Check if they are the same object. + * - Copy `offset` and `size` directly. + * - Elementwise copy `sizes`. + * - Calculate the `strides`. + * - Free the data space of this object to avoid memory leaks. + * - Allocate new space and deep copy. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef &MemRef::operator=(const MemRef &other) { + this->offset = other.offset; + this->size = other.size; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = other.sizes[i]; + } + setStrides(); + // Free the original aligned and allocated space. + delete[] allocated; + // Allocate new space and deep copy. + T *ptr = new T[size]; + std::copy(other.aligned, other.aligned + size, ptr); + aligned = ptr; + allocated = ptr; + return *this; +} + +/** + * @brief Move Constructor. This constructor is used to initialize a MemRef + * object from a rvalue. The move constructor steals the resources of the + * original object. Note that the original object no longer owns the members and + * spaces. + * - Steal members from the original object. + * - Assign the NULL pointer to the original aligned and allocated members to + * avoid the double free error. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(MemRef &&other) noexcept + : allocated(other.allocated), aligned(other.aligned), offset(other.offset), + size(other.size) { + std::swap(this->sizes, other.sizes); + std::swap(this->strides, other.strides); + // Assign the NULL pointer to the original aligned and allocated members to + // avoid the double free error. + other.allocated = other.aligned = nullptr; +} + +/** + * @brief Move Assignment Operator. Note that the original object no longer owns + * the members and spaces. + * - Check if they are the same object. + * - Free the data space of this object to avoid memory leaks. + * - Steal members from the original object. + * - Assign the NULL pointer to the original aligned and allocated members to + * avoid the double free error. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef &MemRef::operator=(MemRef &&other) noexcept { + // Free the original aligned and allocated space. + delete[] allocated; + // Copy members of the original object. + MemRef::MemRef(other); + return *this; +} + +/** + * @brief MemRef Destructor. Note that the original object no longer owns the + * members and spaces. Note that the `allocated` and `aligned` point to the same + * address, so it is enough to release the space of the `allocated` pointer in + * the destructor. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template MemRef::~MemRef() { + if (allocated) + delete allocated; +} + +/** + * @brief Get the data pointer. + * Return the `aligned` pointer if the container data size is greater than zero. + * If the data size is negative or zero, which means no space is allocated for + * the container data pointer, the function does not allow to return the data + * pointer. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T *MemRef::getData() { + assert((size > 0) && "Invalid container data size."); + return aligned; +} +/** + * @brief Get the element at index. + * Return a const refrence of specific element if the container data size is + * greater than zero. If the data size is negative or zero, which means no space + * is allocated for the container data pointer, this operator does not allow to + * return the data element. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +const T &MemRef::operator[](size_t index) const { + assert((size > 0) && "Invalid container data size."); + return aligned[index + offset]; +} + +/** + * @brief Get the element at index. + * Return a non-const refrence of specific element if the container data size is + * greater than zero. If the data size is negative or zero, which means no space + * is allocated for the container data pointer, this operator does not allow to + * return the data element. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T &MemRef::operator[](size_t index) { + assert((size > 0) && "Invalid container data size."); + return aligned[index + offset]; +} + +/** + * @brief Calculate the stride values for each dimension based on the sizes. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template void MemRef::setStrides() { + assert((N > 0) && "Invalid container number of dims"); + strides[N - 1] = 1; + if (N < 2) + return; + for (int i = N - 2; i >= 0; i--) { + strides[i] = strides[i + 1] * sizes[i + 1]; + } +} + +/** + * @brief Calculate the total number of elements in the MemRef container. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +size_t MemRef::product(intptr_t sizes[N]) const { + size_t size = 1; + for (size_t i = 0; i < N; i++) + size *= sizes[i]; + return size; +} + +/** + * @brief Release the aligned and allocated field. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T *MemRef::release() { + T *temp = aligned; + aligned = nullptr; + allocated = nullptr; + return temp; +} + +#endif // CORE_CONTAINER_DEF diff --git a/lib/Interface/GraphContainer.cpp b/lib/Interface/GraphContainer.cpp new file mode 100644 index 0000000..f2d7beb --- /dev/null +++ b/lib/Interface/GraphContainer.cpp @@ -0,0 +1,522 @@ +//===- GraphContainer.cpp -------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Graph container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_GRAPH_CONTAINER_DEF +#define INTERFACE_GRAPH_CONTAINER_DEF + +#include "Interface/GraphContainer.h" +#include "Interface/Container.h" +#include "Interface/graph.h" +#include +#include + +/** + * @brief Construct a new Graph< T, N>:: Graph object + * + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + * @param graph_type represents the type of graph + * @param size represents the number of nodes in the graph + */ +template +Graph::Graph(uint16_t graph_type, size_t size) { + + // Assign the graph type. + this->graph_type = graph_type; + this->size = size; + this->sizes[0] = size; + this->sizes[1] = size; + + size_t maxEdges = ((this->size) * (this->size - 1)) / 2; + + // resize the adjacency list according to the number of nodes. + switch (graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + this->adjList.resize(this->size); + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + this->adjList.resize(this->size); + break; + + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + this->adjList_weighted.resize(this->size); + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + this->adjList_weighted.resize(this->size); + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + + default: + std::cout << "Unknown graph container" << std::endl; + } +} +/** + * @brief This function provides the functionality to add edges to the graph + * + * @tparam T represnts the datatype used. + * @tparam N represnts the number of dimensions. + * @param Node1 The first node for inserting an edge + * @param Node2 The second node for inserting an edge. + */ + +template void Graph::addEdge(T Node1, T Node2) { + + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + this->adjList[Node1].push_back(Node2); + this->adjList[Node2].push_back(Node1); + this->edgeCount++; + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + this->adjList[Node1].push_back(Node2); + this->edgeCount++; + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + this->incMat[Node1][edgeCount] = 1; + this->incMat[Node2][edgeCount] = 1; + this->edgeCount += 1; + break; + + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->incMat[Node1][edgeCount] = 2; + this->incMat[Node2][edgeCount] = 2; + this->edgeCount += 1; + } else { + this->incMat[Node1][edgeCount] = 1; + this->incMat[Node2][edgeCount] = -1; + this->edgeCount += 1; + } + break; + + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->adjMat[Node1][Node1] = 1; + this->edgeCount++; + } else { + this->adjMat[Node1][Node2] = 1; + this->adjMat[Node2][Node1] = 1; + this->edgeCount++; + } + break; + + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->adjMat[Node1][Node1] = 1; + this->edgeCount++; + } else { + this->adjMat[Node1][Node2] = 1; + this->edgeCount++; + } + break; + + default: + this->edgeCount++; + } +} + +/** + * @brief Overloading function for weighted graphs, currently assuming edges are + * of the same type as nodes + * + * @tparam T Represnts the datatype used + * @tparam N Represents the nnumber of dimensions + * @param Node1 First Node for creating an edge + * @param Node2 Second node for creating an edge + * @param EdgeWeight The edgeweight for the edge. + */ +template +void Graph::addEdge(T Node1, T Node2, T EdgeWeight) { + // Add an edge between any two nodes + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + this->adjList_weighted[Node1].push_back(std::make_pair(Node2, EdgeWeight)); + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + this->adjList_weighted[Node1].push_back(std::make_pair(Node2, EdgeWeight)); + this->adjList_weighted[Node2].push_back(std::make_pair(Node1, EdgeWeight)); + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + this->edgeCount += 1; + this->incMat[Node1][edgeCount] = EdgeWeight; + this->incMat[Node2][edgeCount] = EdgeWeight; + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + EdgeWeight = std::abs(sqrt(EdgeWeight)); + this->incMat[Node1][edgeCount] = EdgeWeight; + this->incMat[Node2][edgeCount] = -EdgeWeight; + this->edgeCount += 1; + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + this->edgeCount++; + this->adjMat[Node1][Node2] = EdgeWeight; + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + this->edgeCount++; + this->adjMat[Node1][Node2] = EdgeWeight; + this->adjMat[Node2][Node1] = EdgeWeight; + break; + } +} +/** + * @brief Prints the Graph in its original form before its conversion to a + * linear memref descriptor + * + * @tparam T represents the datatype used + * @tparam N represnts the number of dimensions. + */ +template void Graph::printGraphOg() { + std::cout << "Nodes -> Edges \n"; + for (size_t i = 0; i < this->size; i++) { + std::cout << i << " -> "; + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + for (T x : this->adjList[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + for (T x : this->adjList[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + // for (std:vector : x : this->weighted_nodes.at(i)) { + for (size_t j = 0; j < this->adjList_weighted[i].size(); j++) { + std::cout << this->adjList_weighted[i].at(j).first; + std::cout << " Weight(" << this->adjList_weighted[i].at(j).second + << ") | "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + for (size_t j = 0; j < this->adjList_weighted[i].size(); j++) { + std::cout << this->adjList_weighted[i].at(j).first; + std::cout << " Weight(" << this->adjList_weighted[i].at(j).second + << ") | "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + } + std::cout << std::endl; + } +}; +// /** +// * @brief Function to print the graph using the memref descriptor +// * +// * @tparam T Repesents the datatype used +// * @tparam N represents the number of dimensions. +// */ +template void Graph::printGraph() { + if (!this->data) { + std::cout << "Graph is not converted into memref! \n"; + return; + } + auto y = this->data->getData(); + for (int v = 0; v < this->sizes[0]; ++v) { + for (int w = 0; w < this->sizes[1]; ++w) { + std::cout << y[this->sizes[0] * v + w] << " "; + } + std::cout << "\n"; + } +} +/** + * @brief Converts the various Graph representations types to a linear memref + * descriptor + * + * @tparam T represents the datatype used + * @tparam N represents the number of dimensions. + * @return MemRef_descriptor returns a memref descriptor of the respective graph + * representation type after conversion. + */ + +template void Graph::graph_to_MemRef_descriptor() { + // Assign the memebers of MefRef. + intptr_t x = this->sizes[0]; + intptr_t y = this->sizes[1]; + T *linear = (T *)malloc(sizeof(T) * x * y); + size_t maxEdges = ((this->size) * (this->size - 1)) / 2; + T flag = -2; + + for (intptr_t i = 0; i < x; i++) { + for (intptr_t j = 0; j < y; j++) { + linear[i * x + j] = 0; + } + } + + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; i++) { + intptr_t neighbour_count = this->adjList[i].size(); + for (intptr_t j = 0; j < neighbour_count; j++) { + + T n = this->adjList[i][j]; + linear[i * x + (int)n] = 1; + linear[(int)n * x + i] = 1; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; i++) { + intptr_t neighbour_count = this->adjList[i].size(); + for (intptr_t j = 0; j < neighbour_count; j++) { + + T n = this->adjList[i][j]; + linear[i * x + (int)n] = 1; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + for (unsigned int i = 0; i < x; ++i) { + for (auto X : this->adjList_weighted[i]) { + linear[i * x + int(X.first)] = X.second; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + for (unsigned int i = 0; i < x; ++i) { + for (auto X : this->adjList_weighted[i]) { + linear[i * x + int(X.first)] = X.second; + linear[i + x * int(X.first)] = X.second; + } + } + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if (this->incMat[i][j] == 1 && flag == -2) { + flag = i; + } else if (this->incMat[i][j] == 1 && flag != -2) { + linear[int(flag) * x + i] = 1; + linear[i * x + int(flag)] = 1; + flag = -1; + } + // covering corner case of self-loop + if (i == this->incMat.size() - 1 && (flag != -1 && flag != -2)) { + linear[int(flag) * x + int(flag)] = 1; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if (this->incMat[i][j] != 0 && flag == -2) { + flag = i; + } else if (this->incMat[i][j] != 0 && flag != -2) { + linear[int(flag) * x + i] = incMat[i][j]; + linear[i * x + int(flag)] = incMat[i][j]; + flag = -1; + } + // covering corner case of self-loop + if (i == this->incMat.size() - 1 && (flag != -1 && flag != -2)) { + linear[int(flag) * x + int(flag)] = incMat[int(flag)][j]; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if ((this->incMat[i][j] == 1 || this->incMat[i][j] == -1) && + flag == -2) { + flag = i; + } else if ((this->incMat[i][j] == 1 || this->incMat[i][j] == -1) && + flag != -2) { + if (this->incMat[i][j] == -1) + linear[int(flag) * x + i] = 1; + else + linear[i * x + int(flag)] = 1; + flag = -1; + } + // case for self loops + if (this->incMat[i][j] == 2) { + linear[i * x + i] = 1; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if ((this->incMat[i][j] != 0) && flag == -2) { + flag = i; + size_t k; + for (k = flag + 1; k < this->incMat.size() && flag != -2; k++) { + if ((this->incMat[k][j] != 0) && flag != -1) { + if (this->incMat[k][j] < this->incMat[int(flag)][j]) + linear[int(flag) * x + k] = pow(incMat[k][j], 2); + else + linear[k * x + int(flag)] = pow(incMat[k][j], 2); + flag = -1; + } + } + // case of self loop + if (k == incMat.size() && flag != -1) { + linear[i * x + i] = pow(incMat[i][j], 2); + } + } + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + + default: + std::cout << "Unknown graph type" << std::endl; + break; + } + + if (data) + delete data; + std::cout << "Inside the graph to memref descriptor! \n"; + data = new MemRef(linear, this->sizes); +} + +#endif // INTERFACE_GRAPH_CONTAINER_DEF From f70e427f5f04ee87a5cfec63ac9829f90246bb44 Mon Sep 17 00:00:00 2001 From: Aman Chhaparia <64468582+amanchhaparia@users.noreply.github.com> Date: Tue, 28 Mar 2023 15:36:47 +0530 Subject: [PATCH 02/16] [Graph] [Benchmark]: Floyd Warshall Lowering pass with C++ interface and end to end example, along with benchmarking support (#22) Co-authored-by: Gautam Agrawal --- CMakeLists.txt | 44 +++++++ README.md | 14 ++ benchmarks/BoostFloydWarshall.cpp | 107 ++++++++++++++++ benchmarks/CMakeLists.txt | 55 ++++++++ benchmarks/FloydWarshall.cpp | 90 +++++++++++++ .../GraphMlirFloydWarshallBenchmark.cpp | 83 ++++++++++++ benchmarks/LemonBFS.cpp | 69 ++++++++++ benchmarks/Main.cpp | 48 +++++++ examples/CMakeLists.txt | 30 +++-- examples/bfs.mlir | 6 - examples/bfsExample.cpp | 2 +- examples/floydWarshallExample.cpp | 62 +++++++++ examples/graph.mlir | 13 ++ include/Dialect/Graph/GraphOps.td | 17 +++ include/Interface/graph.h | 14 +- include/Utility/Utils.h | 37 ++++++ lib/CMakeLists.txt | 1 + lib/Conversion/LowerGraph/LowerGraphPass.cpp | 93 ++++++++++++++ lib/Interface/CMakeLists.txt | 1 + lib/Utility/CMakeLists.txt | 1 + lib/Utility/Utils.cpp | 121 ++++++++++++++++++ tools/graph-opt/CMakeLists.txt | 4 +- tools/graph-opt/graph-opt.cpp | 17 ++- 23 files changed, 907 insertions(+), 22 deletions(-) create mode 100644 benchmarks/BoostFloydWarshall.cpp create mode 100644 benchmarks/CMakeLists.txt create mode 100644 benchmarks/FloydWarshall.cpp create mode 100644 benchmarks/GraphMlirFloydWarshallBenchmark.cpp create mode 100644 benchmarks/LemonBFS.cpp create mode 100644 benchmarks/Main.cpp delete mode 100644 examples/bfs.mlir create mode 100644 examples/floydWarshallExample.cpp create mode 100644 examples/graph.mlir create mode 100644 include/Utility/Utils.h create mode 100644 lib/Utility/CMakeLists.txt create mode 100644 lib/Utility/Utils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a945d7..89954b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GraphMLIR_BINARY_DIR}) set(GraphMLIR_EXAMPLES OFF CACHE BOOL "Build examples") +set(GraphMLIR_BENCHMARK OFF CACHE BOOL "Benchmark the Graph Algorithms") + # Add MLIR and LLVM headers to the include path include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${MLIR_INCLUDE_DIRS}) @@ -70,6 +72,7 @@ include_directories(${GraphMLIR_MAIN_INCLUDE_DIR}) include_directories(${GraphMLIR_INCLUDE_DIR}) include_directories(${GraphMLIR_INCLUDE_DIR}/Interface) include_directories(${GraphMLIR_INCLUDE_DIR}/Dialect) +include_directories(${GraphMLIR_INCLUDE_DIR}/Utility) include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/Dialect) include_directories(${GraphMLIR_SOURCE_DIR}/lib) @@ -84,3 +87,44 @@ add_subdirectory(tools) if(GraphMLIR_EXAMPLES) add_subdirectory(examples) endif() + +if(GraphMLIR_BENCHMARK) +#------------------------------------------------------------------------------- +# Deploy google/benchmark +#------------------------------------------------------------------------------- + + message(STATUS "Configuring benchmarks: google") + + include(ExternalProject) + + ExternalProject_Add(project_googlebenchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG "v1.6.0" + GIT_SHALLOW 1 + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/benchmark + TIMEOUT 10 + BUILD_BYPRODUCTS /lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX} + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/vendor/benchmark + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DBENCHMARK_ENABLE_TESTING=OFF + UPDATE_COMMAND "" + TEST_COMMAND "") + + ExternalProject_Get_Property(project_googlebenchmark INSTALL_DIR) + + file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + add_library(GoogleBenchmark STATIC IMPORTED) + target_include_directories(GoogleBenchmark INTERFACE ${INSTALL_DIR}/include) + set_property(TARGET GoogleBenchmark PROPERTY IMPORTED_LOCATION + "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX}") + + add_dependencies(GoogleBenchmark project_googlebenchmark) + + find_package(Threads) + target_link_libraries(GoogleBenchmark INTERFACE Threads::Threads) +endif() + +if(GraphMLIR_BENCHMARK) + add_subdirectory(benchmarks) +endif() \ No newline at end of file diff --git a/README.md b/README.md index 5897208..6c26372 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,20 @@ cmake -G Ninja .. \ ninja bfsExample cd bin && ./bfsExample ``` +## Benchmark project +``` +cmake -G Ninja .. \ + -DMLIR_DIR=$PWD/../llvm/build/lib/cmake/mlir \ + -DLLVM_DIR=$PWD/../llvm/build/lib/cmake/llvm \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DCMAKE_BUILD_TYPE=RELEASE \ + -DGraphMLIR_BENCHMARK=ON \ + -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE +ninja graph-processing-benchmark +cd bin && ./graph-processing-benchmark +``` +*Note* : Rename the `lemon.1.x.x` folder to `lemon`. For benchmarking install `BOOST` library in system. + ## Instructions for generating docs ``` Use doxywizard for generating docs automatically from relevant source directories. diff --git a/benchmarks/BoostFloydWarshall.cpp b/benchmarks/BoostFloydWarshall.cpp new file mode 100644 index 0000000..9562b2b --- /dev/null +++ b/benchmarks/BoostFloydWarshall.cpp @@ -0,0 +1,107 @@ +//===- BoostFloyWarshall.cpp +//-------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Boost FloydWarshall example benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { +typedef int t_weight; + +// define the graph type +typedef boost::property EdgeWeightProperty; +typedef boost::adjacency_list + Graph; + +typedef boost::property_map::type WeightMap; + +// Declare a matrix type and its corresponding property map that +// will contain the distances between each pair of vertices. +typedef boost::exterior_vertex_property DistanceProperty; +typedef DistanceProperty::matrix_type DistanceMatrix; +typedef DistanceProperty::matrix_map_type DistanceMatrixMap; +Graph g; +} // namespace + +void initializeBoostFLoydWarshall() { + + const int vertices = 100; + int num_edges = vertices * (vertices -1) / 2; + + // define edges + // int edges[] = {1, 2, 2, 3, 3, 4, 4, 1, 1, 3, 2, 4}; + + // t_weight weight[] = {4, 3, 3, 6, 2, 2}; + + std::vector edges; + std::vector weight; + + graph::generateRandomGraph(edges, weight, vertices); + + for (std::size_t k = 0; k < num_edges; ++k) + boost::add_edge(edges[k * 2] - 1, edges[k * 2 + 1] - 1, weight[k], g); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + + +} + +// Benchmarking function. +static void Boost_FloydWarshall(benchmark::State &state) { + + for (auto _ : state) { + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + for (int i = 0; i < state.range(0); ++i) { + bool valid = floyd_warshall_all_pairs_shortest_paths( + g, dm, boost::weight_map(weight_pmap)); + } + } +} + +// Register benchmarking function. +BENCHMARK(Boost_FloydWarshall)->Arg(1); + +void generateResultBoostFLoydWarshall() { + initializeBoostFLoydWarshall(); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + cout << "-------------------------------------------------------\n"; + cout << "[ BOOST FloydWarshall Result Information ]\n"; + bool valid = floyd_warshall_all_pairs_shortest_paths( + g, dm, boost::weight_map(weight_pmap)); + cout << "Boost FloydWarshall operation finished!\n"; +} diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 0000000..40d5c69 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,55 @@ +ADD_SUBDIRECTORY(${LEMON_DIR} ./lemon) +SET(LEMON_INCLUDE_DIRS + ${LEMON_DIR} + ${CMAKE_BINARY_DIR}/benchmarks/lemon +) +SET(LEMON_LIBRARIES lemon) +UNSET(LEMON_ROOT_DIR CACHE) +UNSET(LEMON_DIR CACHE) +UNSET(LEMON_INCLUDE_DIR CACHE) +UNSET(LEMON_LIBRARY CACHE) + +INCLUDE_DIRECTORIES( + ${LEMON_INCLUDE_DIRS} +) + +add_custom_command(OUTPUT graph.o +COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/graph.mlir + -lower-graph -lower-affine -convert-scf-to-cf + -test-vector-multi-reduction-lowering-patterns + -convert-vector-to-llvm + -convert-memref-to-llvm + -llvm-request-c-wrappers + -convert-func-to-llvm + -reconcile-unrealized-casts | + ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir | + ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} + --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../benchmarks/graph.o +DEPENDS graph-opt) + +add_library(graph STATIC graph.o) + +SET_TARGET_PROPERTIES( +graph +PROPERTIES +LINKER_LANGUAGE C) + +add_executable(graph-processing-benchmark + FloydWarshall.cpp + BoostFloydWarshall.cpp + GraphMlirFloydWarshallBenchmark.cpp + LemonBFS.cpp + Main.cpp + +) + + +find_package(Boost 1.40 COMPONENTS program_options REQUIRED) + +target_link_libraries(graph-processing-benchmark + PRIVATE + ${LEMON_LIBRARIES} + Boost::program_options + graph + GoogleBenchmark +) diff --git a/benchmarks/FloydWarshall.cpp b/benchmarks/FloydWarshall.cpp new file mode 100644 index 0000000..582c57c --- /dev/null +++ b/benchmarks/FloydWarshall.cpp @@ -0,0 +1,90 @@ +//===- FloydWarshall.cpp --------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +// #include + +using namespace std; + +#define V 100 + +namespace { +int input[V][V]; +int output[V][V]; +} // namespace + +void floydWarshall(int graph[][V], int dist[][V]) { + + int i, j, k; + + for (i = 0; i < V; i++) + for (j = 0; j < V; j++) + dist[i][j] = graph[i][j]; + + for (k = 0; k < V; k++) { + for (i = 0; i < V; i++) { + for (j = 0; j < V; j++) { + if (dist[i][j] > (dist[i][k] + dist[k][j])) + dist[i][j] = dist[i][k] + dist[k][j]; + } + } + } +} + +void initializeFloydWarshall() { + int data[4][4] = {{0, 4, 2, 6}, {4, 0, 3, 2}, {2, 3, 0, 3}, {5, 2, 3, 0}}; + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + input[i][j] = 100; + } + } + memset(output, 0, sizeof(output)); +} + +// Benchmarking function. +static void FloydWarshall(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + floydWarshall(input, output); + } + } +} + +// Register benchmarking function. +BENCHMARK(FloydWarshall)->Arg(1); + +void generateResultFloydWarshall() { + initializeFloydWarshall(); + cout << "-------------------------------------------------------\n"; + cout << "[Floyd Warshall Result Information ]\n"; + + floydWarshall(input, output); + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + cout << output[i][j] << " "; + } + cout << "\n"; + } + cout << "FLoyd Warshall operation finished!\n"; +} diff --git a/benchmarks/GraphMlirFloydWarshallBenchmark.cpp b/benchmarks/GraphMlirFloydWarshallBenchmark.cpp new file mode 100644 index 0000000..a4165d3 --- /dev/null +++ b/benchmarks/GraphMlirFloydWarshallBenchmark.cpp @@ -0,0 +1,83 @@ +//===- GraphMlirFloydWarshallBenchmark.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +using namespace std; + +namespace { +Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, + 100); +intptr_t size[2]; +MemRef *input; +} // namespace + +void initializeGraphMLIRFloydWarshall() { + // sample_graph.addEdge(0, 1, 4); + // sample_graph.addEdge(1, 2, 3); + // sample_graph.addEdge(2, 3, 3); + // sample_graph.addEdge(3, 0, 6); + // sample_graph.addEdge(0, 2, 2); + // sample_graph.addEdge(1, 3, 2); + + graph::generateRandomGraph(&sample_graph, 100); + + input = &sample_graph.get_Memref(); + + size[0] = 100; + size[1] = 100; + + MemRef output = MemRef(size); +} + +// Benchmarking function. +static void GraphMLIR_FloydWarshall(benchmark::State &state) { + for (auto _ : state) { + MemRef output = MemRef(size); + for (int i = 0; i < state.range(0); ++i) { + graph::floyd_warshall(input, &output); + } + } +} + +// Register benchmarking function. +BENCHMARK(GraphMLIR_FloydWarshall)->Arg(1); + +void generateResultGraphMLIRFloydWarshall() { + initializeGraphMLIRFloydWarshall(); + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR Floyd Warshall Result Information ]\n"; + MemRef generateResult(size); + graph::floyd_warshall(input, &generateResult); + + // auto y = generateResult.getData(); + + // for(int i=0; i +#include +#include + +using namespace std; +using namespace lemon; + +namespace { +ListDigraph g; +ListDigraph::Node source = g.addNode(); +} // namespace + +void initializeLemonBFS() { + ListDigraph::Node source = g.addNode(); + ListDigraph::Node y = g.addNode(); + ListDigraph::Node z = g.addNode(); + ListDigraph::Node w = g.addNode(); + + g.addArc(source, y); + g.addArc(y, z); + g.addArc(z, w); + g.addArc(w, source); + g.addArc(source, z); + g.addArc(y, w); + + Bfs bfs(g); +} + +// Benchmarking function. +static void Lemon_BFS(benchmark::State &state) { + for (auto _ : state) { + Bfs bfs(g); + for (int i = 0; i < state.range(0); ++i) { + bfs.run(source); + } + } +} + +// Register benchmarking function. +BENCHMARK(Lemon_BFS)->Arg(1); + +void generateResultLemonBFS() { + initializeLemonBFS(); + cout << "-------------------------------------------------------\n"; + cout << "[ LEMON BFS Result Information ]\n"; + Bfs output(g); + output.run(source); + cout << "Lemon bfs operation finished!\n"; +} diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp new file mode 100644 index 0000000..39cd8ed --- /dev/null +++ b/benchmarks/Main.cpp @@ -0,0 +1,48 @@ +//===- Main.cpp -----------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This is the main file of the Graph processing Algorithm benchmark. +// +//===----------------------------------------------------------------------===// + +#include + +void initializeGraphMLIRFloydWarshall(); +void initializeFloydWarshall(); +void initializeLemonBFS(); +void initializeBoostFLoydWarshall(); + +void generateResultGraphMLIRFloydWarshall(); +void generateResultFloydWarshall(); +void generateResultLemonBFS(); +void generateResultBoostFLoydWarshall(); + +int main(int argc, char **argv) { + + initializeGraphMLIRFloydWarshall(); + initializeFloydWarshall(); + initializeLemonBFS(); + initializeBoostFLoydWarshall(); + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + + generateResultGraphMLIRFloydWarshall(); + generateResultFloydWarshall(); + generateResultLemonBFS(); + generateResultBoostFLoydWarshall(); + return 0; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ec97a1d..e22b345 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,18 +1,30 @@ -add_custom_command(OUTPUT bfs.o -COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/bfs.mlir -lower-graph -lower-affine -convert-scf-to-cf -convert-vector-to-llvm -convert-memref-to-llvm -convert-func-to-llvm='emit-c-wrappers=1' -reconcile-unrealized-casts | - ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir | - ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../examples/bfs.o +add_custom_command(OUTPUT graph.o +COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/graph.mlir + -lower-graph -lower-affine -convert-scf-to-cf + -test-vector-multi-reduction-lowering-patterns + -convert-vector-to-llvm + -convert-memref-to-llvm + -llvm-request-c-wrappers + -convert-func-to-llvm + -reconcile-unrealized-casts + | + ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir + | + ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} + --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../examples/graph.o DEPENDS graph-opt) -add_library(BFS STATIC bfs.o) +add_library(GRAPH STATIC graph.o) SET_TARGET_PROPERTIES( -BFS +GRAPH PROPERTIES LINKER_LANGUAGE C) - - add_executable(bfsExample bfsExample.cpp) add_dependencies(bfsExample graph-opt) -target_link_libraries(bfsExample BFS) +target_link_libraries(bfsExample GRAPH) + +add_executable(floydWarshallExample floydWarshallExample.cpp) +add_dependencies(floydWarshallExample graph-opt) +target_link_libraries(floydWarshallExample GRAPH) diff --git a/examples/bfs.mlir b/examples/bfs.mlir deleted file mode 100644 index 294a969..0000000 --- a/examples/bfs.mlir +++ /dev/null @@ -1,6 +0,0 @@ -func @bfs(%m1 : memref, %m2 : memref, %m3 : memref) -{ - graph.bfs %m1, %m2, %m3 : memref, memref, memref - %c0 = arith.constant 0 : index - return -} diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index aef235e..7b9ca63 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -1,4 +1,4 @@ -//====- bfs.cpp - Example of graph-opt tool ========================// +//====- bfs.cpp - Example of graph-opt tool ==================================// // // The graph.bfs operation will be compiled into an object file with the // graph-opt tool. diff --git a/examples/floydWarshallExample.cpp b/examples/floydWarshallExample.cpp new file mode 100644 index 0000000..025cd39 --- /dev/null +++ b/examples/floydWarshallExample.cpp @@ -0,0 +1,62 @@ +//====- floydWarshallExample.cpp =============================================// +// +// The graph.bfs operation will be compiled into an object file with the +// graph-opt tool. +// This file will be linked with the object file to generate the executable +// file. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + + +int main() { + + int MAX_VERTICES = 20; + Graph sample_graph( + graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, MAX_VERTICES); + // sample_graph.addEdge(0, 1, 4); + // sample_graph.addEdge(1, 2, 3); + // sample_graph.addEdge(2, 3, 3); + // sample_graph.addEdge(3, 0, 6); + // sample_graph.addEdge(0, 2, 2); + // sample_graph.addEdge(1, 3, 2); + + graph::generateRandomGraph(&sample_graph, MAX_VERTICES); + + // this will print the original graph. + std::cout << "Printing graph in format it was entered ( " + "GRAPH_ADJ_MARIX_UNDIRECTED_WEIGHTED )\n"; + sample_graph.printGraphOg(); + + auto x = sample_graph.get_Memref(); + + // this will print the linear 2d matrix in 2d form. + std::cout + << "Printing graph in form of 2d matrix after conversion to memref\n"; + sample_graph.printGraph(); + int vert = MAX_VERTICES; + intptr_t size[2]; + size[0] = vert; + size[1] = vert; + MemRef output = MemRef(size); + + graph::floyd_warshall(&x, &output); + auto y = output.getData(); + + std::cout<<"Floyd Warshall Output!"<<"\n"; + + for(int i=0; i, %m2 : memref, %m3 : memref) +{ + graph.bfs %m1, %m2, %m3 : memref, memref, memref + %c0 = arith.constant 0 : index + return +} + +func.func @floyd_warshall(%input : memref, %output : memref) +{ + graph.FloydWarshall %input, %output : memref, memref + return +} + diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index 64f8170..ccf7c0f 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -42,4 +42,21 @@ def Graph_BFSOp : Graph_Op<"bfs"> }]; } +def Graph_FloydWarshallOp : Graph_Op<"FloydWarshall"> +{ + let summary = [{The Floyd Warshall Algorithm is for solving all pairs shortest path problems. + The problem is to find the shortest distances between every pair of vertices in a given + edge-weighted directed Graph. + }]; + + let arguments = (ins Arg:$memrefI, + Arg:$memrefCO); + + let assemblyFormat = [{ + $memrefI `,` $memrefCO attr-dict `:` type($memrefI) `,` type($memrefCO) + }]; +} + #endif // Graph_GraphOPS_TD diff --git a/include/Interface/graph.h b/include/Interface/graph.h index b509ebb..8d674a4 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -1,5 +1,4 @@ -//===- graph.h -//--------------------------------------------------------------===// +//===- graph.h -------------------------------------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -49,12 +48,21 @@ extern "C" { void _mlir_ciface_bfs(MemRef graph1, MemRef graph2, MemRef graph3); } + +extern "C" { +void _mlir_ciface_floyd_warshall(MemRef *graph1, MemRef *graph2); +} + } // namespace detail -void graph_bfs(MemRef graph1, MemRef graph2, +void inline bfs(MemRef graph1, MemRef graph2, MemRef graph3) { detail::_mlir_ciface_bfs(graph1, graph2, graph3); } + +void inline floyd_warshall(MemRef *input, MemRef *output) { + detail::_mlir_ciface_floyd_warshall(input, output); +} } // namespace graph #endif diff --git a/include/Utility/Utils.h b/include/Utility/Utils.h new file mode 100644 index 0000000..68d6cd2 --- /dev/null +++ b/include/Utility/Utils.h @@ -0,0 +1,37 @@ +//====- Utils.cpp ---------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements generic utility functions. +// +//===----------------------------------------------------------------------===// + +#ifndef UTILS_UTILS +#define UTILS_UTILS + +#include +#include +#include +#include + +using namespace std; + +namespace graph { +void generateRandomGraph(Graph *graph, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +void generateRandomGraph(vector &edge, vector &weight, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +} +#include + +#endif \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6965fb1..b8fbcd6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Conversion) add_subdirectory(Dialect) add_subdirectory(Interface) +add_subdirectory(Utility) diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index cd30ae8..aa9fe85 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -70,11 +70,104 @@ class GraphBFSLowering : public OpRewritePattern { private: int64_t stride; }; + +class GraphFloydWarshallLowering : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + explicit GraphFloydWarshallLowering(MLIRContext *context, int64_t strideParam) + : OpRewritePattern(context) { + stride = strideParam; + } + + LogicalResult matchAndRewrite(graph::FloydWarshallOp op, + PatternRewriter &rewriter) const override { + auto loc = op->getLoc(); + auto ctx = op->getContext(); + + // Register operand values. + Value input = op->getOperand(0); + Value output = op->getOperand(1); + + Value c0 = rewriter.create(loc, 0); + Value c1 = rewriter.create(loc, 1); + Value V = rewriter.create(loc, input, c0); + + SmallVector step{1,1}; + + buildAffineLoopNest( + rewriter, loc, ValueRange{c0, c0}, ValueRange{V, V}, step, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, input, ValueRange{ivs[0], ivs[1]}); + builder.create(loc, x, output, ValueRange{ivs[0], ivs[1]}); + }); + + SmallVector lowerBounds(3, c0); + SmallVector upperBounds(3, V); + SmallVector steps{1,1,4}; + + IntegerType i32 = IntegerType::get(ctx, 32); + FloatType f32 = FloatType::getF32(ctx); + VectorType vectorTy32 = VectorType::get({4}, f32); + VectorType vectorred = VectorType::get({2,4}, f32); + Value one = rewriter.create(loc, APFloat(float(1)), f32); + Value mx = rewriter.create(loc, APFloat(float(10000)), f32); + Value vecOne = rewriter.create(loc, vectorTy32, one); + Value vecMx = rewriter.create(loc, vectorTy32, mx); + Value temp = rewriter.create(loc, vectorred, one); + // rewriter.create(loc, vecOne); + buildAffineLoopNest( + rewriter, loc, lowerBounds, upperBounds, steps, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, output, ValueRange{ivs[1], ivs[0]}); + Value y = builder.create(loc, output, ValueRange{ivs[0], ivs[2]}); + Value z = builder.create(loc, output, ValueRange{ivs[1], ivs[2]}); + + Value temp = builder.create(loc, x, y); + + Value checkCond = builder.create(loc, CmpFPredicate::OLT, temp, z); + + builder.create( + loc, checkCond, [&](OpBuilder &builder, Location loc) { + builder.create(loc, temp, output, ValueRange{ivs[1], ivs[2]}); + builder.create(loc); + } + // [&](OpBuilder &builder, Location loc){ + // builder.create(loc); + // } + ); + // Value x = builder.create(loc, output, ValueRange{ivs[1], ivs[0]}); + // Value vecik = builder.create(loc, vectorTy32, x); + // Value vecij = builder.create(loc, vectorTy32, output, ValueRange{ivs[1], ivs[2]}); + // Value veckj = builder.create(loc, vectorTy32, output, ValueRange{ivs[0], ivs[2]}); + // Value vecikj = builder.create(loc, veckj, vecOne, vecik); + // Value y = builder.create(loc, vecij, temp, ArrayRef{0}); + // Value z = builder.create(loc, vecikj, y, ArrayRef{1}); + // Value res = builder.create(loc, z, vecMx, ArrayRef{true,false}, vector::CombiningKind::MINF); + // // builder.create(loc, vecik); + // // builder.create(loc, vecij); + // // builder.create(loc, veckj); + // // builder.create(loc, vecikj); + // // builder.create(loc, res); + // builder.create(loc, res, output, ValueRange{ivs[1], ivs[2]}); + + }); + + + rewriter.eraseOp(op); + return success(); + } + +private: + int64_t stride; +}; + } // end anonymous namespace void populateLowerGraphConversionPatterns(RewritePatternSet &patterns, int64_t stride) { patterns.add(patterns.getContext(), stride); + patterns.add(patterns.getContext(), stride); } //===----------------------------------------------------------------------===// diff --git a/lib/Interface/CMakeLists.txt b/lib/Interface/CMakeLists.txt index 381bd6a..ef9288f 100644 --- a/lib/Interface/CMakeLists.txt +++ b/lib/Interface/CMakeLists.txt @@ -1 +1,2 @@ add_library(Container Container.cpp) +add_library(GraphContainer GraphContainer.cpp) \ No newline at end of file diff --git a/lib/Utility/CMakeLists.txt b/lib/Utility/CMakeLists.txt new file mode 100644 index 0000000..c2a4c55 --- /dev/null +++ b/lib/Utility/CMakeLists.txt @@ -0,0 +1 @@ +add_library(Utils Utils.cpp) diff --git a/lib/Utility/Utils.cpp b/lib/Utility/Utils.cpp new file mode 100644 index 0000000..100e34d --- /dev/null +++ b/lib/Utility/Utils.cpp @@ -0,0 +1,121 @@ +//====- Utils.cpp ---------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements generic utility functions for the buddy compiler +// ecosystem. +// +//===----------------------------------------------------------------------===// + +#ifndef UTILS_UTILS_DEF +#define UTILS_UTILS_DEF + +#include +#include +#include +#include +#include + +using namespace std; +namespace graph{ +void inline generateRandomGraph(Graph *graph, int vertices, int maxWeight, int randomUpperLimit, int randomLowerLimit){ + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices-1) /2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j=1; j<=NUMEDGE; j++) + { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || container.find(reverse_p) != container.end()) + { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b,a); + } + + container.insert(p); + // int wt = 1 + rand() % MAXWEIGHT; + + graph->addEdge(a, b, 1 + rand() % maxWeight); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); +// return graph; + // } +} + +void inline generateRandomGraph(std::vector &edge, std::vector &weight, int vertices, int maxWeight, int randomUpperLimit, int randomLowerLimit){ + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices-1) /2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j=1; j<=NUMEDGE; j++) + { + int a = 1 + rand() % NUM; + int b = 1 + rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || container.find(reverse_p) != container.end()) + { + a = 1 + rand() % NUM; + b = 1 + rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b,a); + } + // cout<<"Inside here"<<"\n"; + container.insert(p); + int wt = 1 + rand() % maxWeight; + + edge.push_back(a); + edge.push_back(b); + weight.push_back(wt); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); +// return graph; + // } +} +} +#endif \ No newline at end of file diff --git a/tools/graph-opt/CMakeLists.txt b/tools/graph-opt/CMakeLists.txt index be54f11..b53c059 100644 --- a/tools/graph-opt/CMakeLists.txt +++ b/tools/graph-opt/CMakeLists.txt @@ -10,6 +10,8 @@ target_link_libraries(graph-opt ${dialect_libs} ${conversion_libs} MLIROptLib - + MLIRTestTransformDialect + MLIRVectorTestPasses + MLIRTestDialect LowerGraphPass ) diff --git a/tools/graph-opt/graph-opt.cpp b/tools/graph-opt/graph-opt.cpp index 006e846..6698e17 100644 --- a/tools/graph-opt/graph-opt.cpp +++ b/tools/graph-opt/graph-opt.cpp @@ -4,6 +4,7 @@ // //===----------------------------------------------------------------------===// +#include "mlir/IR/AsmState.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/MLIRContext.h" #include "mlir/InitAllDialects.h" @@ -20,21 +21,33 @@ #include "Graph/GraphDialect.h" #include "Graph/GraphOps.h" +// using namespace llvm; +// using namespace mlir; + namespace mlir { namespace graph { void registerLowerGraphPass(); } // namespace graph +namespace test { + void registerTestVectorLowerings(); +} } // namespace mlir +namespace test { +void registerTestDialect(mlir::DialectRegistry &); +void registerTestTransformDialectExtension(mlir::DialectRegistry &); +} + int main(int argc, char **argv) { // Register all MLIR passes. mlir::registerAllPasses(); - mlir::graph::registerLowerGraphPass(); - + mlir::test::registerTestVectorLowerings(); mlir::DialectRegistry registry; // Register all MLIR core dialects. registerAllDialects(registry); + ::test::registerTestDialect(registry); + ::test::registerTestTransformDialectExtension(registry); // Register dialects in graph-mlir project. // clang-format off registry.insert(); From 2af091ea21d0901abac851bb2f48803b32abff0c Mon Sep 17 00:00:00 2001 From: Tushar Date: Thu, 30 Mar 2023 10:31:07 +0530 Subject: [PATCH 03/16] BFS implementation --- examples/bfsExample.cpp | 57 +++-- examples/graph.mlir | 4 +- include/Dialect/Graph/GraphOps.td | 16 +- include/Interface/graph.h | 16 +- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 247 ++++++++++++++----- 5 files changed, 245 insertions(+), 95 deletions(-) diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index 7b9ca63..f1e8879 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -1,4 +1,4 @@ -//====- bfs.cpp - Example of graph-opt tool ==================================// +//====- bfs.cpp - Example of graph-opt tool ========================// // // The graph.bfs operation will be compiled into an object file with the // graph-opt tool. @@ -14,39 +14,50 @@ #include int main() { - - // Graph - // sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, 5); - - // use for unweighted graph - // sample_graph.addEdge(0,2); - // sample_graph.addEdge(2,3); - // sample_graph.addEdge(3,2); - // sample_graph.addEdge(2,2); - // sample_graph.addEdge(1,2); - // use for weighted graph - Graph sample_graph( - graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, 5); - sample_graph.addEdge(0, 2, 1); + Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, + 5); + + sample_graph.addEdge(0, 1, 1); + sample_graph.addEdge(1, 2, 3); sample_graph.addEdge(2, 3, 3); - sample_graph.addEdge(3, 2, 3); - sample_graph.addEdge(2, 2, 6); - sample_graph.addEdge(1, 2, 2); + sample_graph.addEdge(3, 4, 6); // this will print the original graph. std::cout << "Printing graph in format it was entered ( " "GRAPH_ADJ_MARIX_DIRECTED_WEIGHTED )\n"; sample_graph.printGraphOg(); - auto x = sample_graph.get_Memref(); + auto graph = sample_graph.get_Memref(); - // this will print the linear 2d matrix in 2d form. + // Distance and Parent vector + intptr_t size[1] = {5}; + + MemRef parent = MemRef(size); + MemRef distance = MemRef(size); + // this will print the linear 2d matrix in 2d form. std::cout << "Printing graph in form of 2d matrix after conversion to memref\n"; sample_graph.printGraph(); - graph::graph_bfs(x, x, x); - x.release(); + + graph::graph_bfs(&graph, &parent, &distance); + + std::cout << "Distance\n"; + for (int i = 0; i < 5; i++) { + std::cout << distance[i] << " "; + } + std::cout << std::endl; + + std::cout << "\nParent\n"; + for (int i = 0; i < 5; i++) { + std::cout << parent[i] << " "; + } + std::cout << std::endl; + + graph.release(); + parent.release(); + distance.release(); + std::cout << "End of the program! \n"; -} +} \ No newline at end of file diff --git a/examples/graph.mlir b/examples/graph.mlir index d3ac578..a6eead4 100644 --- a/examples/graph.mlir +++ b/examples/graph.mlir @@ -1,6 +1,6 @@ -func.func @bfs(%m1 : memref, %m2 : memref, %m3 : memref) +func.func @bfs(%graph : memref, %parent : memref, %distance : memref) { - graph.bfs %m1, %m2, %m3 : memref, memref, memref + graph.bfs %graph, %parent, %distance : memref, memref, memref %c0 = arith.constant 0 : index return } diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index ccf7c0f..22f6bd4 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -27,18 +27,18 @@ include "mlir/Interfaces/SideEffectInterfaces.td" def Graph_BFSOp : Graph_Op<"bfs"> { let summary = [{ - abcde + Breadth First Search }]; - let arguments = (ins Arg:$memrefI, - Arg:$memrefK, - Arg:$memrefCO); + let arguments = (ins Arg:$memrefG, + Arg:$memrefP, + Arg:$memrefD); let assemblyFormat = [{ - $memrefI `,` $memrefK `,` $memrefCO attr-dict `:` type($memrefI) `,` type($memrefK) `,` type($memrefCO) + $memrefG `,` $memrefP `,` $memrefD attr-dict `:` type($memrefG) `,` type($memrefP) `,` type($memrefD) }]; } diff --git a/include/Interface/graph.h b/include/Interface/graph.h index 8d674a4..6065e54 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -1,4 +1,5 @@ -//===- graph.h -------------------------------------------------------------===// +//===- graph.h +//-------------------------------------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,19 +46,20 @@ enum graph_type { // directly. // Declare the BFS C interface. extern "C" { -void _mlir_ciface_bfs(MemRef graph1, MemRef graph2, - MemRef graph3); +void _mlir_ciface_bfs(MemRef *graph, MemRef *parent, + MemRef *distance); } extern "C" { -void _mlir_ciface_floyd_warshall(MemRef *graph1, MemRef *graph2); +void _mlir_ciface_floyd_warshall(MemRef *graph1, + MemRef *graph2); } } // namespace detail -void inline bfs(MemRef graph1, MemRef graph2, - MemRef graph3) { - detail::_mlir_ciface_bfs(graph1, graph2, graph3); +void inline graph_bfs(MemRef *graph, MemRef *parent, + MemRef *distance) { + detail::_mlir_ciface_bfs(graph, parent, distance); } void inline floyd_warshall(MemRef *input, MemRef *output) { diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index aa9fe85..eb1baba 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -54,14 +54,136 @@ class GraphBFSLowering : public OpRewritePattern { auto loc = op->getLoc(); auto ctx = op->getContext(); - // Create constant indices. - Value c0 = rewriter.create(loc, 0); - Value c1 = rewriter.create(loc, 1); + // Register operands + Value graph = op->getOperand(0); + Value parent = op->getOperand(1); + Value distance = op->getOperand(2); + + // Types + IndexType idxt = IndexType::get(ctx); + IntegerType it32 = IntegerType::get(ctx, 32); + VectorType vt32 = VectorType::get({1000}, it32); + VectorType qt = VectorType::get({1000}, idxt); + + // Constants + Value idx0 = rewriter.create(loc, 0); + Value idx1 = rewriter.create(loc, 1); + + Value V = rewriter.create(loc, graph, idx0); + + Value zero = rewriter.create(loc, int(0), it32); + Value one = rewriter.create(loc, int(1), it32); + Value minusOne = rewriter.create(loc, int(-1), it32); + Value five = rewriter.create(loc, int(5), it32); + // Queue + Value queue = rewriter.create(loc, qt, idx0); + Value front = rewriter.create(loc, int(0), it32); + Value rear = rewriter.create(loc, int(1), it32); + + // Visited array + Value visited = rewriter.create(loc, vt32, zero); + + queue = rewriter.create(loc, idx0, queue, rear); + rear = rewriter.create(loc, rear, one); + + visited = rewriter.create(loc, one, visited, idx0); + + // While loop + SmallVector operands = {queue, front, rear, visited}; + SmallVector types = {qt, it32, it32, vt32}; + SmallVector locations = {loc, loc, loc, loc}; + + auto whileOp = rewriter.create(loc, types, operands); + + Block *before = + rewriter.createBlock(&whileOp.getBefore(), {}, types, locations); + Block *after = + rewriter.createBlock(&whileOp.getAfter(), {}, types, locations); + + // Before block - Condition + { + rewriter.setInsertionPointToStart(&whileOp.getBefore().front()); + + Value front = before->getArgument(1); + Value rear = before->getArgument(2); + + Value notEmpty = + rewriter.create(loc, CmpIPredicate::ne, front, rear); + + rewriter.create(loc, notEmpty, before->getArguments()); + } + + { + rewriter.setInsertionPointToStart(&whileOp.getAfter().front()); + + Value queue = after->getArgument(0); + Value front = after->getArgument(1); + Value rear = after->getArgument(2); + Value visited = after->getArgument(3); + + Value u = rewriter.create(loc, queue, front); + front = rewriter.create(loc, front, one); + + auto loop = rewriter.create( + loc, idx0, V, idx1, ValueRange{queue, front, rear, visited}, + [&](OpBuilder &builder, Location loc, Value v, ValueRange args) { + Value queue = args[0]; + Value front = args[1]; + Value rear = args[2]; + Value visited = args[3]; + + Value edge = + builder.create(loc, graph, ValueRange{u, v}); + Value vis = + builder.create(loc, visited, v); + + Value present = + builder.create(loc, CmpIPredicate::ne, edge, zero); + Value nvisited = + builder.create(loc, CmpIPredicate::eq, vis, zero); + + Value condition = builder.create(loc, present, nvisited); + + scf::IfOp ifop = builder.create( + loc, TypeRange{qt, it32, it32, vt32}, condition, true); + // Then block + { + builder.setInsertionPointToStart(ifop.thenBlock()); + + // Logic + Value dist = builder.create(loc, distance, u); + Value p = builder.create(loc, it32, u); + dist = builder.create(loc, dist, edge); + + builder.create(loc, dist, distance, v); + builder.create(loc, p, parent, v); + + Value nvisited = + builder.create(loc, one, visited, v); + Value nqueue = + builder.create(loc, v, queue, rear); + Value nrear = builder.create(loc, rear, one); - // Register operand values. - Value m1 = op->getOperand(0); - Value m2 = op->getOperand(1); - Value m3 = op->getOperand(2); + builder.create( + loc, ValueRange{nqueue, front, nrear, nvisited}); + } + // Else block + { + builder.setInsertionPointToStart(ifop.elseBlock()); + builder.create( + loc, ValueRange{queue, front, rear, visited}); + } + + builder.setInsertionPointAfter(ifop); + ValueRange results = ifop.getResults(); + + builder.create(loc, results); + }); + + ValueRange lresults = loop.getResults(); + + rewriter.create(loc, lresults); + } rewriter.eraseOp(op); return success(); @@ -71,7 +193,8 @@ class GraphBFSLowering : public OpRewritePattern { int64_t stride; }; -class GraphFloydWarshallLowering : public OpRewritePattern { +class GraphFloydWarshallLowering + : public OpRewritePattern { public: using OpRewritePattern::OpRewritePattern; @@ -92,67 +215,81 @@ class GraphFloydWarshallLowering : public OpRewritePattern(loc, 0); Value c1 = rewriter.create(loc, 1); Value V = rewriter.create(loc, input, c0); - - SmallVector step{1,1}; + + SmallVector step{1, 1}; buildAffineLoopNest( - rewriter, loc, ValueRange{c0, c0}, ValueRange{V, V}, step, - [&](OpBuilder &builder, Location loc, ValueRange ivs) { - Value x = builder.create(loc, input, ValueRange{ivs[0], ivs[1]}); - builder.create(loc, x, output, ValueRange{ivs[0], ivs[1]}); - }); - + rewriter, loc, ValueRange{c0, c0}, ValueRange{V, V}, step, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, input, + ValueRange{ivs[0], ivs[1]}); + builder.create(loc, x, output, + ValueRange{ivs[0], ivs[1]}); + }); + SmallVector lowerBounds(3, c0); SmallVector upperBounds(3, V); - SmallVector steps{1,1,4}; + SmallVector steps{1, 1, 4}; IntegerType i32 = IntegerType::get(ctx, 32); FloatType f32 = FloatType::getF32(ctx); VectorType vectorTy32 = VectorType::get({4}, f32); - VectorType vectorred = VectorType::get({2,4}, f32); + VectorType vectorred = VectorType::get({2, 4}, f32); Value one = rewriter.create(loc, APFloat(float(1)), f32); - Value mx = rewriter.create(loc, APFloat(float(10000)), f32); + Value mx = + rewriter.create(loc, APFloat(float(10000)), f32); Value vecOne = rewriter.create(loc, vectorTy32, one); Value vecMx = rewriter.create(loc, vectorTy32, mx); Value temp = rewriter.create(loc, vectorred, one); // rewriter.create(loc, vecOne); buildAffineLoopNest( - rewriter, loc, lowerBounds, upperBounds, steps, - [&](OpBuilder &builder, Location loc, ValueRange ivs) { - Value x = builder.create(loc, output, ValueRange{ivs[1], ivs[0]}); - Value y = builder.create(loc, output, ValueRange{ivs[0], ivs[2]}); - Value z = builder.create(loc, output, ValueRange{ivs[1], ivs[2]}); - - Value temp = builder.create(loc, x, y); - - Value checkCond = builder.create(loc, CmpFPredicate::OLT, temp, z); - - builder.create( - loc, checkCond, [&](OpBuilder &builder, Location loc) { - builder.create(loc, temp, output, ValueRange{ivs[1], ivs[2]}); - builder.create(loc); - } - // [&](OpBuilder &builder, Location loc){ - // builder.create(loc); - // } - ); - // Value x = builder.create(loc, output, ValueRange{ivs[1], ivs[0]}); - // Value vecik = builder.create(loc, vectorTy32, x); - // Value vecij = builder.create(loc, vectorTy32, output, ValueRange{ivs[1], ivs[2]}); - // Value veckj = builder.create(loc, vectorTy32, output, ValueRange{ivs[0], ivs[2]}); - // Value vecikj = builder.create(loc, veckj, vecOne, vecik); - // Value y = builder.create(loc, vecij, temp, ArrayRef{0}); - // Value z = builder.create(loc, vecikj, y, ArrayRef{1}); - // Value res = builder.create(loc, z, vecMx, ArrayRef{true,false}, vector::CombiningKind::MINF); - // // builder.create(loc, vecik); - // // builder.create(loc, vecij); - // // builder.create(loc, veckj); - // // builder.create(loc, vecikj); - // // builder.create(loc, res); - // builder.create(loc, res, output, ValueRange{ivs[1], ivs[2]}); - - }); - + rewriter, loc, lowerBounds, upperBounds, steps, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, output, + ValueRange{ivs[1], ivs[0]}); + Value y = builder.create(loc, output, + ValueRange{ivs[0], ivs[2]}); + Value z = builder.create(loc, output, + ValueRange{ivs[1], ivs[2]}); + + Value temp = builder.create(loc, x, y); + + Value checkCond = + builder.create(loc, CmpFPredicate::OLT, temp, z); + + builder.create( + loc, checkCond, + [&](OpBuilder &builder, Location loc) { + builder.create(loc, temp, output, + ValueRange{ivs[1], ivs[2]}); + builder.create(loc); + } + // [&](OpBuilder &builder, Location loc){ + // builder.create(loc); + // } + ); + // Value x = builder.create(loc, output, + // ValueRange{ivs[1], ivs[0]}); Value vecik = + // builder.create(loc, vectorTy32, x); Value + // vecij = builder.create(loc, vectorTy32, output, + // ValueRange{ivs[1], ivs[2]}); Value veckj = + // builder.create(loc, vectorTy32, output, + // ValueRange{ivs[0], ivs[2]}); Value vecikj = + // builder.create(loc, veckj, vecOne, vecik); Value y = + // builder.create(loc, vecij, temp, + // ArrayRef{0}); Value z = + // builder.create(loc, vecikj, y, + // ArrayRef{1}); Value res = + // builder.create(loc, z, vecMx, + // ArrayRef{true,false}, vector::CombiningKind::MINF); + // // builder.create(loc, vecik); + // // builder.create(loc, vecij); + // // builder.create(loc, veckj); + // // builder.create(loc, vecikj); + // // builder.create(loc, res); + // builder.create(loc, res, output, + // ValueRange{ivs[1], ivs[2]}); + }); rewriter.eraseOp(op); return success(); From 4823a33f1c21b586f2f3d885b826553478875f6d Mon Sep 17 00:00:00 2001 From: Tushar Date: Sat, 1 Apr 2023 18:54:09 +0530 Subject: [PATCH 04/16] BFS Benchmarking --- benchmarks/CMakeLists.txt | 2 +- benchmarks/GraphMlirBfs.cpp | 76 +++++++++++++ benchmarks/Main.cpp | 5 + include/Utility/Utils.h | 1 + lib/Utility/Utils.cpp | 212 ++++++++++++++++++++++-------------- 5 files changed, 211 insertions(+), 85 deletions(-) create mode 100644 benchmarks/GraphMlirBfs.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 40d5c69..4f3b329 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -40,7 +40,7 @@ add_executable(graph-processing-benchmark GraphMlirFloydWarshallBenchmark.cpp LemonBFS.cpp Main.cpp - + GraphMlirBfs.cpp ) diff --git a/benchmarks/GraphMlirBfs.cpp b/benchmarks/GraphMlirBfs.cpp new file mode 100644 index 0000000..a15c2b9 --- /dev/null +++ b/benchmarks/GraphMlirBfs.cpp @@ -0,0 +1,76 @@ +//===- GraphMlirBfs.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +using namespace std; + +namespace { +Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, + 100); +intptr_t size[2], opsize[1]; +MemRef *input; +} // namespace + +void initializeGraphMLIRBfs() { + graph::generateRandomGraph(&sample_graph, 100); + + input = &sample_graph.get_Memref(); + + opsize[0] = 101; + + MemRef parent = MemRef(opsize); + MemRef distance = MemRef(opsize); +} + +static void GraphMLIR_Bfs(benchmark::State &state) { + for (auto _ : state) { + MemRef parent = MemRef(opsize); + MemRef distance = MemRef(opsize); + for (int i = 0; i < state.range(0); ++i) { + graph::graph_bfs(input, &parent, &distance); + } + } +} + +BENCHMARK(GraphMLIR_Bfs)->Arg(1); + +void generateResultGraphMLIRBfs() { + initializeGraphMLIRBfs(); + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR BFS Result Information ]\n"; + MemRef parent = MemRef(opsize); + MemRef distance = MemRef(opsize); + graph::graph_bfs(input, &parent, &distance); + + // auto y = generateResult.getData(); + + // for(int i=0; i *graph, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +void generateRandomGraph(Graph *graph, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); void generateRandomGraph(vector &edge, vector &weight, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); } #include diff --git a/lib/Utility/Utils.cpp b/lib/Utility/Utils.cpp index 100e34d..cc719bb 100644 --- a/lib/Utility/Utils.cpp +++ b/lib/Utility/Utils.cpp @@ -24,98 +24,142 @@ #include #include +#include #include #include -#include using namespace std; -namespace graph{ -void inline generateRandomGraph(Graph *graph, int vertices, int maxWeight, int randomUpperLimit, int randomLowerLimit){ - // printf("Inside the function create_graph\n"); - std::set> container; - std::set>::iterator it; - // printf("Inside the function create_graph 1\n"); - srand(time(NULL)); - // printf("Inside the function create_graph 2\n"); - int NUM = vertices; // Number of Vertices - int MAX_EDGES = vertices * (vertices-1) /2; - int NUMEDGE = MAX_EDGES; // Number of Edges - - - // Then print the edges of the form (a b) - // where 'a' is connected to 'b' - for (int j=1; j<=NUMEDGE; j++) - { - int a = rand() % NUM; - int b = rand() % NUM; - std::pair p = std::make_pair(a, b); - std::pair reverse_p = std::make_pair(b, a); - - while (container.find(p) != container.end() || container.find(reverse_p) != container.end()) - { - a = rand() % NUM; - b = rand() % NUM; - p = std::make_pair(a, b); - reverse_p = std::make_pair(b,a); - } - - container.insert(p); - // int wt = 1 + rand() % MAXWEIGHT; - - graph->addEdge(a, b, 1 + rand() % maxWeight); +namespace graph { +void inline generateRandomGraph(Graph *graph, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); } - // for (it=container.begin(); it!=container.end(); ++it) - // printf("%d %d\n", it->first, it->second); - - container.clear(); - printf("\n"); -// return graph; - // } + + container.insert(p); + // int wt = 1 + rand() % MAXWEIGHT; + + graph->addEdge(a, b, 1 + rand() % maxWeight); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } } -void inline generateRandomGraph(std::vector &edge, std::vector &weight, int vertices, int maxWeight, int randomUpperLimit, int randomLowerLimit){ - // printf("Inside the function create_graph\n"); - std::set> container; - std::set>::iterator it; - // printf("Inside the function create_graph 1\n"); - srand(time(NULL)); - // printf("Inside the function create_graph 2\n"); - int NUM = vertices; // Number of Vertices - int MAX_EDGES = vertices * (vertices-1) /2; - int NUMEDGE = MAX_EDGES; // Number of Edges - - - // Then print the edges of the form (a b) - // where 'a' is connected to 'b' - for (int j=1; j<=NUMEDGE; j++) - { - int a = 1 + rand() % NUM; - int b = 1 + rand() % NUM; - std::pair p = std::make_pair(a, b); - std::pair reverse_p = std::make_pair(b, a); - - while (container.find(p) != container.end() || container.find(reverse_p) != container.end()) - { - a = 1 + rand() % NUM; - b = 1 + rand() % NUM; - p = std::make_pair(a, b); - reverse_p = std::make_pair(b,a); - } - // cout<<"Inside here"<<"\n"; - container.insert(p); - int wt = 1 + rand() % maxWeight; - - edge.push_back(a); - edge.push_back(b); - weight.push_back(wt); +void inline generateRandomGraph(Graph *graph, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); } - // for (it=container.begin(); it!=container.end(); ++it) - // printf("%d %d\n", it->first, it->second); - - container.clear(); - printf("\n"); -// return graph; - // } + + container.insert(p); + // int wt = 1 + rand() % MAXWEIGHT; + + graph->addEdge(a, b, 1 + rand() % maxWeight); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } } + +void inline generateRandomGraph(std::vector &edge, + std::vector &weight, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = 1 + rand() % NUM; + int b = 1 + rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = 1 + rand() % NUM; + b = 1 + rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + // cout<<"Inside here"<<"\n"; + container.insert(p); + int wt = 1 + rand() % maxWeight; + + edge.push_back(a); + edge.push_back(b); + weight.push_back(wt); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } } +} // namespace graph #endif \ No newline at end of file From f5cec34389e26a66a7d05fd105759efed3f87bad Mon Sep 17 00:00:00 2001 From: Tushar Date: Tue, 4 Apr 2023 12:30:15 +0530 Subject: [PATCH 05/16] Lemon BFS generate random graph --- benchmarks/LemonBFS.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/benchmarks/LemonBFS.cpp b/benchmarks/LemonBFS.cpp index a67c37e..ad3b77a 100644 --- a/benchmarks/LemonBFS.cpp +++ b/benchmarks/LemonBFS.cpp @@ -19,6 +19,7 @@ //===----------------------------------------------------------------------===// #include +#include #include #include @@ -31,17 +32,25 @@ ListDigraph::Node source = g.addNode(); } // namespace void initializeLemonBFS() { - ListDigraph::Node source = g.addNode(); - ListDigraph::Node y = g.addNode(); - ListDigraph::Node z = g.addNode(); - ListDigraph::Node w = g.addNode(); + ListDigraph::Node nodes[100]; - g.addArc(source, y); - g.addArc(y, z); - g.addArc(z, w); - g.addArc(w, source); - g.addArc(source, z); - g.addArc(y, w); + for (int i = 0; i < 100; i++) + nodes[i] = g.addNode(); + + source = nodes[0]; + + int vertices = 100; + int NUM = vertices; + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; + + for (int i = 1; i <= vertices; i++) { + ListDigraph::Node a = nodes[rand() % NUM]; + ListDigraph::Node b = nodes[rand() % NUM]; + + g.addArc(a, b); + g.addArc(b, a); + } Bfs bfs(g); } From 2f7b9bc9d47aea244599aa5d0f6181bcef09e58f Mon Sep 17 00:00:00 2001 From: Tushar Date: Tue, 4 Apr 2023 23:34:44 +0530 Subject: [PATCH 06/16] Normal BFS for benchmarking purposes --- benchmarks/Bfs.cpp | 78 +++++++++++++++++++++++++++++++++++++++ benchmarks/CMakeLists.txt | 1 + 2 files changed, 79 insertions(+) create mode 100644 benchmarks/Bfs.cpp diff --git a/benchmarks/Bfs.cpp b/benchmarks/Bfs.cpp new file mode 100644 index 0000000..b28454e --- /dev/null +++ b/benchmarks/Bfs.cpp @@ -0,0 +1,78 @@ +#include +#include + +using namespace std; + +#define V 100 + +namespace { +int graph[V][V]; +int parent[V]; +int dist[V]; +} // namespace + +void bfs(int graph[V][V], int parent[V], int dist[V]) { + bool visited[V]; + + for (int i = 0; i < V; i++) + visited[i] = false; + + queue q; + + visited[0] = true; + q.push(0); + + while (!q.empty()) { + int u = q.front(); + q.pop(); + + for (int v = 0; v < V; v++) { + if (visited[v] == false && graph[u][v] != 0) { + visited[v] = true; + + dist[v] = dist[u] + graph[u][v]; + parent[v] = u; + + q.push(v); + } + } + } +} + +void initializeBfs() { + for (int i = 0; i < (100 * 99) / 2; i++) { + int u = rand() % 100; + int v = rand() % 100; + int d = rand() % 100; + + graph[u][v] = d; + graph[v][u] = d; + } +} + +static void Bfs(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); i++) { + bfs(graph, parent, dist); + } + } +} + +BENCHMARK(Bfs)->Arg(1); + +void generateResultBfs() { + initializeBfs(); + cout << "-------------------------------------------------------\n"; + cout << "BFS Result Information ]\n"; + + bfs(graph, parent, dist); + + for (int x : parent) + cout << x << " "; + cout << endl; + + for (int x : dist) + cout << x << " "; + cout << endl; + cout << "BFS operation finished!\n"; +} \ No newline at end of file diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 4f3b329..830f11b 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(graph-processing-benchmark LemonBFS.cpp Main.cpp GraphMlirBfs.cpp + Bfs.cpp ) From 652c314b8511bd545f7f0a64a803233cbd839bc3 Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 5 Apr 2023 11:15:03 +0530 Subject: [PATCH 07/16] Create memref from vector --- include/Interface/Container.h | 2 ++ lib/Interface/Container.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/Interface/Container.h b/include/Interface/Container.h index e674642..fb1b2f1 100644 --- a/include/Interface/Container.h +++ b/include/Interface/Container.h @@ -37,6 +37,8 @@ template class MemRef { MemRef(const T *data, intptr_t sizes[N], intptr_t offset = 0); // Constructor from a unique_ptr, taking over. MemRef(std::unique_ptr &uptr, intptr_t sizes[N], intptr_t offset = 0); + // Constructor from a 1D vector + MemRef(std::vector data); // Copy constructor. MemRef(const MemRef &other); // Copy assignment operator. diff --git a/lib/Interface/Container.cpp b/lib/Interface/Container.cpp index bb9d6a1..527d88f 100644 --- a/lib/Interface/Container.cpp +++ b/lib/Interface/Container.cpp @@ -88,6 +88,20 @@ MemRef::MemRef(std::unique_ptr &uptr, intptr_t *sizes, size = product(sizes); } +/** + * @bried MemRef Array Constructor. Construct a MemRef object from a vector. + * @tparam T represents the datatype to be used + */ +template MemRef::MemRef(std::vector data) { + this->sizes[0] = data.size(); + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + for (size_t i = 0; i < size; i++) + aligned[i] = data[i]; +} + /** * @brief Copy Constructor. This constructor is used to initialize a MemRef object with another MemRef object. From 7792f946dc53ac369aec4bd3c9692a2a15c02001 Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 5 Apr 2023 20:01:22 +0530 Subject: [PATCH 08/16] BFS implementation using Compressed Sparse Matrix graph representation --- README.md | 16 ++- benchmarks/GraphMlirBfs.cpp | 62 ++++++--- benchmarks/LemonBFS.cpp | 9 +- examples/bfsExample.cpp | 88 ++++++++----- examples/graph.mlir | 5 +- include/Dialect/Graph/GraphOps.td | 12 +- include/Interface/graph.h | 8 +- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 130 +++++++++---------- 8 files changed, 198 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index 6c26372..9c87fb3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # GraphMLIR + An IR based solution for optimising graph algorithms. ## Clone repository and its dependencies + ``` git clone https://github.com/meshtag/GraphMLIR.git cd GraphMLIR @@ -9,6 +11,7 @@ git submodule update --init ``` ## Build LLVM + ``` cd llvm && mkdir build && cd build cmake -G Ninja ../llvm \ @@ -21,6 +24,7 @@ ninja check-mlir ``` ## Build project + ``` cd ../../ && mkdir build && cd build cmake -G Ninja .. \ @@ -32,7 +36,9 @@ cmake -G Ninja .. \ ninja bfsExample cd bin && ./bfsExample ``` + ## Benchmark project + ``` cmake -G Ninja .. \ -DMLIR_DIR=$PWD/../llvm/build/lib/cmake/mlir \ @@ -40,15 +46,17 @@ cmake -G Ninja .. \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DCMAKE_BUILD_TYPE=RELEASE \ -DGraphMLIR_BENCHMARK=ON \ - -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE + -DLEMON_DIR=/home/tushar/Downloads/lemon ninja graph-processing-benchmark cd bin && ./graph-processing-benchmark ``` -*Note* : Rename the `lemon.1.x.x` folder to `lemon`. For benchmarking install `BOOST` library in system. -## Instructions for generating docs +_Note_ : Rename the `lemon.1.x.x` folder to `lemon`. For benchmarking install `BOOST` library in system. + +## Instructions for generating docs + ``` Use doxywizard for generating docs automatically from relevant source directories. ``` -#### After this go to docs and open index.html in the html subdirectory with your prefered browser. +#### After this go to docs and open index.html in the html subdirectory with your prefered browser. diff --git a/benchmarks/GraphMlirBfs.cpp b/benchmarks/GraphMlirBfs.cpp index a15c2b9..f066654 100644 --- a/benchmarks/GraphMlirBfs.cpp +++ b/benchmarks/GraphMlirBfs.cpp @@ -26,20 +26,56 @@ using namespace std; +#define V 100 + namespace { -Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, - 100); -intptr_t size[2], opsize[1]; -MemRef *input; +int g[V][V]; +intptr_t opsize[1]; +std::vector a, ia, ca; +MemRef *weights, *cnz, *cidx; } // namespace +// Generate compressed sparse matrix +void generateCSR(int graph[V][V], std::vector &a, std::vector &ia, + std::vector &ca) { + int count = 0; + ia.push_back(0); + + for (int r = 0; r < V; r++) { + for (int c = 0; c < V; c++) { + if (graph[r][c] != 0) { + a.push_back(graph[r][c]); + ca.push_back(c); + + count++; + } + } + + ia.push_back(count); + } +} + void initializeGraphMLIRBfs() { - graph::generateRandomGraph(&sample_graph, 100); + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; - input = &sample_graph.get_Memref(); + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = rand() % 100 + 1; + + g[u][v] = d; + } + + std::vector a, ia, ca; + + generateCSR(g, a, ia, ca); opsize[0] = 101; + weights = new MemRef(a); + cnz = new MemRef(ia); + cidx = new MemRef(ca); MemRef parent = MemRef(opsize); MemRef distance = MemRef(opsize); } @@ -49,7 +85,7 @@ static void GraphMLIR_Bfs(benchmark::State &state) { MemRef parent = MemRef(opsize); MemRef distance = MemRef(opsize); for (int i = 0; i < state.range(0); ++i) { - graph::graph_bfs(input, &parent, &distance); + graph::graph_bfs(weights, cnz, cidx, &parent, &distance); } } } @@ -58,19 +94,13 @@ BENCHMARK(GraphMLIR_Bfs)->Arg(1); void generateResultGraphMLIRBfs() { initializeGraphMLIRBfs(); + cout << "-------------------------------------------------------\n"; cout << "[ GraphMLIR BFS Result Information ]\n"; + MemRef parent = MemRef(opsize); MemRef distance = MemRef(opsize); - graph::graph_bfs(input, &parent, &distance); - - // auto y = generateResult.getData(); - // for(int i=0; i bfs(g); diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index f1e8879..24d9a51 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -13,51 +13,73 @@ #include #include +#define V 100 + +// Generate compressed sparse matrix +void generateCSR(int graph[V][V], std::vector &a, std::vector &ia, + std::vector &ca) { + int count = 0; + ia.push_back(0); + + for (int r = 0; r < V; r++) { + for (int c = 0; c < V; c++) { + if (graph[r][c] != 0) { + a.push_back(graph[r][c]); + ca.push_back(c); + + count++; + } + } + + ia.push_back(count); + } +} + +// Print memref data +void print(MemRef data) { + auto y = data.getData(); + + for (size_t i = 0; i < data.getSize(); i++) + std::cout << y[i] << " "; + std::cout << std::endl; +} + int main() { - // use for weighted graph - Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, - 5); + int graph[V][V]; + intptr_t size[1] = {V}; + + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; - sample_graph.addEdge(0, 1, 1); - sample_graph.addEdge(1, 2, 3); - sample_graph.addEdge(2, 3, 3); - sample_graph.addEdge(3, 4, 6); + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = rand() % 100 + 1; - // this will print the original graph. - std::cout << "Printing graph in format it was entered ( " - "GRAPH_ADJ_MARIX_DIRECTED_WEIGHTED )\n"; - sample_graph.printGraphOg(); + graph[u][v] = d; + } - auto graph = sample_graph.get_Memref(); + std::vector a, ia, ca; - // Distance and Parent vector - intptr_t size[1] = {5}; + generateCSR(graph, a, ia, ca); + MemRef weights = MemRef(a); + MemRef cnz = MemRef(ia); + MemRef cidx = MemRef(ca); MemRef parent = MemRef(size); MemRef distance = MemRef(size); - // this will print the linear 2d matrix in 2d form. - std::cout - << "Printing graph in form of 2d matrix after conversion to memref\n"; - sample_graph.printGraph(); - - graph::graph_bfs(&graph, &parent, &distance); + graph::graph_bfs(&weights, &cnz, &cidx, &parent, &distance); - std::cout << "Distance\n"; - for (int i = 0; i < 5; i++) { - std::cout << distance[i] << " "; - } - std::cout << std::endl; + auto y = parent.getData(); - std::cout << "\nParent\n"; - for (int i = 0; i < 5; i++) { - std::cout << parent[i] << " "; - } + for (size_t i = 0; i < V; i++) + std::cout << y[i] << " "; std::cout << std::endl; - graph.release(); - parent.release(); - distance.release(); + y = distance.getData(); - std::cout << "End of the program! \n"; + for (size_t i = 0; i < V; i++) + std::cout << y[i] << " "; + std::cout << std::endl; } \ No newline at end of file diff --git a/examples/graph.mlir b/examples/graph.mlir index a6eead4..943396b 100644 --- a/examples/graph.mlir +++ b/examples/graph.mlir @@ -1,7 +1,6 @@ -func.func @bfs(%graph : memref, %parent : memref, %distance : memref) +func.func @bfs(%weights : memref, %cnz : memref, %cidx : memref, %parent : memref, %distance : memref) { - graph.bfs %graph, %parent, %distance : memref, memref, memref - %c0 = arith.constant 0 : index + graph.bfs %weights, %cnz, %cidx, %parent, %distance : memref, memref, memref, memref, memref return } diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index 22f6bd4..0176daf 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -27,18 +27,22 @@ include "mlir/Interfaces/SideEffectInterfaces.td" def Graph_BFSOp : Graph_Op<"bfs"> { let summary = [{ - Breadth First Search + Breadth First Search on graph represented by CSR }]; - let arguments = (ins Arg:$memrefG, + let arguments = (ins Arg:$memrefW, + Arg:$memrefCnz, + Arg:$memrefCidx, Arg:$memrefP, Arg:$memrefD); let assemblyFormat = [{ - $memrefG `,` $memrefP `,` $memrefD attr-dict `:` type($memrefG) `,` type($memrefP) `,` type($memrefD) + $memrefW `,` $memrefCnz `,` $memrefCidx `,` $memrefP `,` $memrefD attr-dict `:` type($memrefW) `,` type($memrefCnz) `,` type($memrefCidx) `,` type($memrefP) `,` type($memrefD) }]; } diff --git a/include/Interface/graph.h b/include/Interface/graph.h index 6065e54..08f37ef 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -46,7 +46,8 @@ enum graph_type { // directly. // Declare the BFS C interface. extern "C" { -void _mlir_ciface_bfs(MemRef *graph, MemRef *parent, +void _mlir_ciface_bfs(MemRef *weights, MemRef *cnz, + MemRef *cidx, MemRef *parent, MemRef *distance); } @@ -57,9 +58,10 @@ void _mlir_ciface_floyd_warshall(MemRef *graph1, } // namespace detail -void inline graph_bfs(MemRef *graph, MemRef *parent, +void inline graph_bfs(MemRef *weights, MemRef *cnz, + MemRef *cidx, MemRef *parent, MemRef *distance) { - detail::_mlir_ciface_bfs(graph, parent, distance); + detail::_mlir_ciface_bfs(weights, cnz, cidx, parent, distance); } void inline floyd_warshall(MemRef *input, MemRef *output) { diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index eb1baba..d6ec097 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -35,6 +35,24 @@ using namespace graph; using namespace vector; using namespace mlir::arith; +// Cast index to i32 +Value indexToI32(OpBuilder &builder, Location loc, Value v) { + return builder.create(loc, builder.getI32Type(), v); +} + +// Cast i32 to index +Value I32ToIndex(OpBuilder &builder, Location loc, Value v) { + return builder.create(loc, builder.getIndexType(), v); +} + +// Add to index +Value addIndex(OpBuilder &builder, Location loc, Value u, Value d) { + Value ans = indexToI32(builder, loc, u); + ans = builder.create(loc, ans, d); + + return I32ToIndex(builder, loc, ans); +} + //===----------------------------------------------------------------------===// // Rewrite Pattern //===----------------------------------------------------------------------===// @@ -54,39 +72,48 @@ class GraphBFSLowering : public OpRewritePattern { auto loc = op->getLoc(); auto ctx = op->getContext(); - // Register operands - Value graph = op->getOperand(0); - Value parent = op->getOperand(1); - Value distance = op->getOperand(2); + Value weights = op->getOperand(0); + Value cnz = op->getOperand(1); + Value cidx = op->getOperand(2); + Value parent = op->getOperand(3); + Value distance = op->getOperand(4); // Types IndexType idxt = IndexType::get(ctx); IntegerType it32 = IntegerType::get(ctx, 32); - VectorType vt32 = VectorType::get({1000}, it32); - VectorType qt = VectorType::get({1000}, idxt); + VectorType vt32 = VectorType::get({10000}, it32); + VectorType qt = VectorType::get({10000}, idxt); - // Constants Value idx0 = rewriter.create(loc, 0); Value idx1 = rewriter.create(loc, 1); - - Value V = rewriter.create(loc, graph, idx0); + Value cnzsize = rewriter.create(loc, cnz, idx0); Value zero = rewriter.create(loc, int(0), it32); Value one = rewriter.create(loc, int(1), it32); + Value two = rewriter.create(loc, int(2), it32); Value minusOne = rewriter.create(loc, int(-1), it32); - Value five = rewriter.create(loc, int(5), it32); + + // Number of vertices as index + Value V = indexToI32(rewriter, loc, cnzsize); + V = rewriter.create(loc, V, minusOne); + V = I32ToIndex(rewriter, loc, V); + // Queue Value queue = rewriter.create(loc, qt, idx0); Value front = rewriter.create(loc, int(0), it32); Value rear = rewriter.create(loc, int(1), it32); - // Visited array + // Visited + // 0 = not discovered = white + // 1 = discovered but no explored = grey + // 2 = discovered and explored = black Value visited = rewriter.create(loc, vt32, zero); queue = rewriter.create(loc, idx0, queue, rear); rear = rewriter.create(loc, rear, one); - visited = rewriter.create(loc, one, visited, idx0); + rewriter.create(loc, zero, distance, idx0); + rewriter.create(loc, minusOne, parent, idx0); // While loop SmallVector operands = {queue, front, rear, visited}; @@ -122,41 +149,40 @@ class GraphBFSLowering : public OpRewritePattern { Value visited = after->getArgument(3); Value u = rewriter.create(loc, queue, front); - front = rewriter.create(loc, front, one); + Value z = addIndex(rewriter, loc, u, one); - auto loop = rewriter.create( - loc, idx0, V, idx1, ValueRange{queue, front, rear, visited}, - [&](OpBuilder &builder, Location loc, Value v, ValueRange args) { - Value queue = args[0]; - Value front = args[1]; - Value rear = args[2]; - Value visited = args[3]; - - Value edge = - builder.create(loc, graph, ValueRange{u, v}); - Value vis = - builder.create(loc, visited, v); + front = rewriter.create(loc, front, one); + visited = rewriter.create(loc, two, visited, u); - Value present = - builder.create(loc, CmpIPredicate::ne, edge, zero); - Value nvisited = - builder.create(loc, CmpIPredicate::eq, vis, zero); + Value s = rewriter.create(loc, cnz, u); + Value e = rewriter.create(loc, cnz, z); + s = I32ToIndex(rewriter, loc, s); + e = I32ToIndex(rewriter, loc, e); - Value condition = builder.create(loc, present, nvisited); + auto loop = rewriter.create( + loc, s, e, idx1, ValueRange{queue, front, rear, visited}, + [&](OpBuilder &builder, Location loc, Value i, ValueRange args) { + Value v = rewriter.create(loc, cidx, i); + v = I32ToIndex(builder, loc, v); + Value color = + rewriter.create(loc, visited, v); + Value condition = + rewriter.create(loc, CmpIPredicate::eq, color, zero); scf::IfOp ifop = builder.create( loc, TypeRange{qt, it32, it32, vt32}, condition, true); + // Then block { builder.setInsertionPointToStart(ifop.thenBlock()); - // Logic - Value dist = builder.create(loc, distance, u); - Value p = builder.create(loc, it32, u); - dist = builder.create(loc, dist, edge); + Value d = rewriter.create(loc, distance, u); + Value e = rewriter.create(loc, weights, i); + Value f = rewriter.create(loc, d, e); + Value p = rewriter.create(loc, it32, u); - builder.create(loc, dist, distance, v); - builder.create(loc, p, parent, v); + rewriter.create(loc, f, distance, v); + rewriter.create(loc, p, parent, v); Value nvisited = builder.create(loc, one, visited, v); @@ -167,6 +193,7 @@ class GraphBFSLowering : public OpRewritePattern { builder.create( loc, ValueRange{nqueue, front, nrear, nvisited}); } + // Else block { builder.setInsertionPointToStart(ifop.elseBlock()); @@ -179,7 +206,6 @@ class GraphBFSLowering : public OpRewritePattern { builder.create(loc, results); }); - ValueRange lresults = loop.getResults(); rewriter.create(loc, lresults); @@ -258,37 +284,11 @@ class GraphFloydWarshallLowering builder.create(loc, CmpFPredicate::OLT, temp, z); builder.create( - loc, checkCond, - [&](OpBuilder &builder, Location loc) { + loc, checkCond, [&](OpBuilder &builder, Location loc) { builder.create(loc, temp, output, ValueRange{ivs[1], ivs[2]}); builder.create(loc); - } - // [&](OpBuilder &builder, Location loc){ - // builder.create(loc); - // } - ); - // Value x = builder.create(loc, output, - // ValueRange{ivs[1], ivs[0]}); Value vecik = - // builder.create(loc, vectorTy32, x); Value - // vecij = builder.create(loc, vectorTy32, output, - // ValueRange{ivs[1], ivs[2]}); Value veckj = - // builder.create(loc, vectorTy32, output, - // ValueRange{ivs[0], ivs[2]}); Value vecikj = - // builder.create(loc, veckj, vecOne, vecik); Value y = - // builder.create(loc, vecij, temp, - // ArrayRef{0}); Value z = - // builder.create(loc, vecikj, y, - // ArrayRef{1}); Value res = - // builder.create(loc, z, vecMx, - // ArrayRef{true,false}, vector::CombiningKind::MINF); - // // builder.create(loc, vecik); - // // builder.create(loc, vecij); - // // builder.create(loc, veckj); - // // builder.create(loc, vecikj); - // // builder.create(loc, res); - // builder.create(loc, res, output, - // ValueRange{ivs[1], ivs[2]}); + }); }); rewriter.eraseOp(op); From 51f9987c92ff6790fb9e2ae412a8f6174e3d871c Mon Sep 17 00:00:00 2001 From: Tushar Date: Wed, 5 Apr 2023 21:55:43 +0530 Subject: [PATCH 09/16] Changed vector type from 10000 to 100 --- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 4 ++-- llvm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index d6ec097..ef6c519 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -81,8 +81,8 @@ class GraphBFSLowering : public OpRewritePattern { // Types IndexType idxt = IndexType::get(ctx); IntegerType it32 = IntegerType::get(ctx, 32); - VectorType vt32 = VectorType::get({10000}, it32); - VectorType qt = VectorType::get({10000}, idxt); + VectorType vt32 = VectorType::get({100}, it32); + VectorType qt = VectorType::get({100}, idxt); Value idx0 = rewriter.create(loc, 0); Value idx1 = rewriter.create(loc, 1); diff --git a/llvm b/llvm index b1333f0..088f336 160000 --- a/llvm +++ b/llvm @@ -1 +1 @@ -Subproject commit b1333f03d94e4099c2bbffb19eeb6df293c61500 +Subproject commit 088f33605d8a61ff519c580a71b1dd57d16a03f8 From ea59ececcee886816ea5801b790d66454fc4e068 Mon Sep 17 00:00:00 2001 From: Tushar Date: Sat, 29 Apr 2023 11:56:17 +0530 Subject: [PATCH 10/16] Bellman ford implementation --- README.md | 3 +- examples/CMakeLists.txt | 4 + examples/bellmanFordExample.cpp | 72 +++++++++++++++++ examples/graph.mlir | 6 ++ include/Dialect/Graph/GraphOps.td | 20 +++++ include/Interface/graph.h | 11 +++ lib/Conversion/LowerGraph/LowerGraphPass.cpp | 84 ++++++++++++++++++++ 7 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 examples/bellmanFordExample.cpp diff --git a/README.md b/README.md index 9c87fb3..5a9b313 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ cmake -G Ninja .. \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DCMAKE_BUILD_TYPE=RELEASE \ -DGraphMLIR_BENCHMARK=ON \ - -DLEMON_DIR=/home/tushar/Downloads/lemon + -DLEMON_DIR=/home/tushar/Downloads/lemon \ + -DGraphMLIR_EXAMPLES=ON ninja graph-processing-benchmark cd bin && ./graph-processing-benchmark ``` diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e22b345..a1c6de5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -25,6 +25,10 @@ add_executable(bfsExample bfsExample.cpp) add_dependencies(bfsExample graph-opt) target_link_libraries(bfsExample GRAPH) +add_executable(bellmanFordExample bellmanFordExample.cpp) +add_dependencies(bellmanFordExample graph-opt) +target_link_libraries(bellmanFordExample GRAPH) + add_executable(floydWarshallExample floydWarshallExample.cpp) add_dependencies(floydWarshallExample graph-opt) target_link_libraries(floydWarshallExample GRAPH) diff --git a/examples/bellmanFordExample.cpp b/examples/bellmanFordExample.cpp new file mode 100644 index 0000000..314f241 --- /dev/null +++ b/examples/bellmanFordExample.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +#define V 100 + +// Bellman Ford basic implementation +void bellman_ford(std::vector &st, std::vector &ed, + std::vector &dist, std::vector &output1) { + int E = st.size(); + output1[0] = 0; + + for (int i = 1; i < V; i++) { + for (int j = 0; j < E; j++) { + int u = st[j]; + int v = ed[j]; + int d = dist[j]; + + if (output1[u] != INT16_MAX && output1[u] + d < output1[v]) + output1[v] = output1[u] + d; + } + } + + for (int j = 0; j < E; j++) { + int u = st[j]; + int v = ed[j]; + int d = dist[j]; + + if (output1[u] != INT16_MAX && output1[u] + d < output1[v]) + return; + } +} + +int main() { + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; + + std::vector st, ed, dist, op(V, INT16_MAX); + + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = (rand() % 100) - 50; + + st.push_back(u); + ed.push_back(v); + dist.push_back(d); + } + + std::vector output1(V, INT16_MAX); + bellman_ford(st, ed, dist, output1); + + std::cout << st[0] << " " << ed[0] << " " << dist[0] << std::endl; + + intptr_t size[1] = {V}; + + MemRef start = MemRef(st); + MemRef end = MemRef(ed); + MemRef distance = MemRef(dist); + MemRef output = MemRef(op); + + graph::bellman_ford(&start, &end, &distance, &output); + + auto y = output.getData(); + + for (int i = 0; i < V; i++) { + std::cout << (y[i] == output1[i]) << " "; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/examples/graph.mlir b/examples/graph.mlir index 943396b..fd005dd 100644 --- a/examples/graph.mlir +++ b/examples/graph.mlir @@ -4,6 +4,12 @@ func.func @bfs(%weights : memref, %cnz : memref, %cidx : memref, %end : memref, %distance : memref, %output : memref) +{ + graph.bellman_ford %start, %end, %distance, %output : memref, memref, memref, memref + return +} + func.func @floyd_warshall(%input : memref, %output : memref) { graph.FloydWarshall %input, %output : memref, memref diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index 0176daf..531b29a 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -46,6 +46,26 @@ def Graph_BFSOp : Graph_Op<"bfs"> }]; } +def Graph_BellmanFordOp : Graph_Op<"bellman_ford"> +{ + let summary = [{ + Bellman Ford algorithm + }]; + + let arguments = (ins Arg:$memrefS, + Arg:$memrefE, + Arg:$memrefD, + Arg:$memrefO); + + let assemblyFormat = [{ + $memrefS `,` $memrefE `,` $memrefD `,` $memrefO attr-dict `:` type($memrefS) `,` type($memrefE) `,` type($memrefD) `,` type($memrefO) + }]; +} + def Graph_FloydWarshallOp : Graph_Op<"FloydWarshall"> { let summary = [{The Floyd Warshall Algorithm is for solving all pairs shortest path problems. diff --git a/include/Interface/graph.h b/include/Interface/graph.h index 08f37ef..4e7d30f 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -56,6 +56,12 @@ void _mlir_ciface_floyd_warshall(MemRef *graph1, MemRef *graph2); } +extern "C" { +void _mlir_ciface_bellman_ford(MemRef *start, MemRef *end, + MemRef *distance, + MemRef *output); +} + } // namespace detail void inline graph_bfs(MemRef *weights, MemRef *cnz, @@ -64,6 +70,11 @@ void inline graph_bfs(MemRef *weights, MemRef *cnz, detail::_mlir_ciface_bfs(weights, cnz, cidx, parent, distance); } +void inline bellman_ford(MemRef *start, MemRef *end, + MemRef *distance, MemRef *output) { + detail::_mlir_ciface_bellman_ford(start, end, distance, output); +} + void inline floyd_warshall(MemRef *input, MemRef *output) { detail::_mlir_ciface_floyd_warshall(input, output); } diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index ef6c519..314b1f5 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -219,6 +219,89 @@ class GraphBFSLowering : public OpRewritePattern { int64_t stride; }; +class GraphBellmanFordLowering : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + explicit GraphBellmanFordLowering(MLIRContext *context, int64_t strideParam) + : OpRewritePattern(context) { + stride = strideParam; + } + + LogicalResult matchAndRewrite(graph::BellmanFordOp op, + PatternRewriter &rewriter) const override { + auto loc = op->getLoc(); + auto ctx = op->getContext(); + + Value start = op->getOperand(0); + Value end = op->getOperand(1); + Value distance = op->getOperand(2); + Value output = op->getOperand(3); + + // Types + IndexType idxt = IndexType::get(ctx); + IntegerType it32 = IntegerType::get(ctx, 32); + VectorType vt32 = VectorType::get({100}, it32); + VectorType qt = VectorType::get({100}, idxt); + + Value idx0 = rewriter.create(loc, 0); + Value idx1 = rewriter.create(loc, 1); + Value V = rewriter.create(loc, output, idx0); + Value E = rewriter.create(loc, start, idx0); + + Value zero = rewriter.create(loc, int(0), it32); + Value one = rewriter.create(loc, int(1), it32); + Value two = rewriter.create(loc, int(2), it32); + Value minusOne = rewriter.create(loc, int(-1), it32); + Value maxInt = rewriter.create(loc, output, idx0); + + SmallVector lowerBounds{idx1, idx0}; + SmallVector upperBounds{V, E}; + SmallVector steps{1, 1}; + + rewriter.create(loc, zero, output, idx0); + + buildAffineLoopNest( + rewriter, loc, lowerBounds, upperBounds, steps, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value u = + rewriter.create(loc, start, ValueRange{ivs[1]}); + Value v = + rewriter.create(loc, end, ValueRange{ivs[1]}); + Value d = rewriter.create(loc, distance, + ValueRange{ivs[1]}); + + Value uidx = I32ToIndex(builder, loc, u); + Value vidx = I32ToIndex(builder, loc, v); + + Value id = rewriter.create(loc, output, uidx); + // distance[u] + d + Value fd = rewriter.create(loc, id, d); + // distance[v] + Value vd = rewriter.create(loc, output, vidx); + + Value condition1 = + rewriter.create(loc, CmpIPredicate::ne, id, maxInt); + Value condition2 = + rewriter.create(loc, CmpIPredicate::slt, fd, vd); + Value condition = + rewriter.create(loc, condition1, condition2); + + builder.create( + loc, condition, [&](OpBuilder &builder, Location loc) { + builder.create(loc, fd, output, vidx); + builder.create(loc); + }); + }); + + rewriter.eraseOp(op); + return success(); + } + +private: + int64_t stride; +}; + class GraphFloydWarshallLowering : public OpRewritePattern { public: @@ -305,6 +388,7 @@ void populateLowerGraphConversionPatterns(RewritePatternSet &patterns, int64_t stride) { patterns.add(patterns.getContext(), stride); patterns.add(patterns.getContext(), stride); + patterns.add(patterns.getContext(), stride); } //===----------------------------------------------------------------------===// From 34a4eaf306550c8b5407d0c20ecb63c25856c15d Mon Sep 17 00:00:00 2001 From: Tushar Date: Sun, 30 Apr 2023 15:40:05 +0530 Subject: [PATCH 11/16] Bellman Ford implementation --- examples/bellmanFordExample.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/bellmanFordExample.cpp b/examples/bellmanFordExample.cpp index 314f241..b24d8a6 100644 --- a/examples/bellmanFordExample.cpp +++ b/examples/bellmanFordExample.cpp @@ -18,7 +18,7 @@ void bellman_ford(std::vector &st, std::vector &ed, int v = ed[j]; int d = dist[j]; - if (output1[u] != INT16_MAX && output1[u] + d < output1[v]) + if (output1[u] != INT32_MAX && output1[u] + d < output1[v]) output1[v] = output1[u] + d; } } @@ -28,7 +28,7 @@ void bellman_ford(std::vector &st, std::vector &ed, int v = ed[j]; int d = dist[j]; - if (output1[u] != INT16_MAX && output1[u] + d < output1[v]) + if (output1[u] != INT32_MAX && output1[u] + d < output1[v]) return; } } @@ -37,19 +37,21 @@ int main() { int MAX_EDGES = V * (V - 1) / 2; int NUMEDGES = MAX_EDGES; - std::vector st, ed, dist, op(V, INT16_MAX); + std::vector st, ed, dist, op(V, INT32_MAX); + + srand(time(0)); for (int i = 0; i < NUMEDGES; i++) { int u = rand() % V; int v = rand() % V; - int d = (rand() % 100) - 50; + int d = (rand() % 100); st.push_back(u); ed.push_back(v); dist.push_back(d); } - std::vector output1(V, INT16_MAX); + std::vector output1(V, INT32_MAX); bellman_ford(st, ed, dist, output1); std::cout << st[0] << " " << ed[0] << " " << dist[0] << std::endl; @@ -66,7 +68,7 @@ int main() { auto y = output.getData(); for (int i = 0; i < V; i++) { - std::cout << (y[i] == output1[i]) << " "; + std::cout << (y[i]) << " " << (output1[i]) << "\n"; } std::cout << std::endl; } \ No newline at end of file From d958a309aa66516ba9b157aefca890ca3547d54b Mon Sep 17 00:00:00 2001 From: Tushar Bauskar <75204198+tusharsb-12@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:00:28 +0530 Subject: [PATCH 12/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a9b313..073fecb 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ cmake -G Ninja .. \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DCMAKE_BUILD_TYPE=RELEASE \ -DGraphMLIR_BENCHMARK=ON \ - -DLEMON_DIR=/home/tushar/Downloads/lemon \ + -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE \ -DGraphMLIR_EXAMPLES=ON ninja graph-processing-benchmark cd bin && ./graph-processing-benchmark From f9589478265d060c202c3b3dd06bfbfb9b876042 Mon Sep 17 00:00:00 2001 From: Tushar Bauskar <75204198+tusharsb-12@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:00:59 +0530 Subject: [PATCH 13/16] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 073fecb..ed8cf60 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,7 @@ cmake -G Ninja .. \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DCMAKE_BUILD_TYPE=RELEASE \ -DGraphMLIR_BENCHMARK=ON \ - -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE \ - -DGraphMLIR_EXAMPLES=ON + -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE ninja graph-processing-benchmark cd bin && ./graph-processing-benchmark ``` From 8b3ea962ead5467342c368654264d757f5bf96ce Mon Sep 17 00:00:00 2001 From: Tushar Date: Sat, 6 May 2023 13:21:16 +0530 Subject: [PATCH 14/16] Fixes in BFS implementation and benchmarking --- benchmarks/Bfs.cpp | 22 ++++---- benchmarks/GraphMlirBfs.cpp | 12 ++-- benchmarks/LemonBFS.cpp | 10 ++-- examples/bfsExample.cpp | 41 ++++++-------- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 59 +++++++++++++++++--- 5 files changed, 93 insertions(+), 51 deletions(-) diff --git a/benchmarks/Bfs.cpp b/benchmarks/Bfs.cpp index b28454e..b3f59e4 100644 --- a/benchmarks/Bfs.cpp +++ b/benchmarks/Bfs.cpp @@ -3,7 +3,7 @@ using namespace std; -#define V 100 +#define V 1000 namespace { int graph[V][V]; @@ -11,7 +11,7 @@ int parent[V]; int dist[V]; } // namespace -void bfs(int graph[V][V], int parent[V], int dist[V]) { +void bfs(int graph[V][V], int *parent, int *dist) { bool visited[V]; for (int i = 0; i < V; i++) @@ -40,13 +40,14 @@ void bfs(int graph[V][V], int parent[V], int dist[V]) { } void initializeBfs() { - for (int i = 0; i < (100 * 99) / 2; i++) { - int u = rand() % 100; - int v = rand() % 100; + int MAX_EDGES = V * (V - 1) / 2; + + for (int i = 0; i < MAX_EDGES; i++) { + int u = rand() % V; + int v = rand() % V; int d = rand() % 100; graph[u][v] = d; - graph[v][u] = d; } } @@ -67,12 +68,13 @@ void generateResultBfs() { bfs(graph, parent, dist); - for (int x : parent) - cout << x << " "; + for (int i = 0; i < V; i++) + cout << parent[i] << " "; cout << endl; - for (int x : dist) - cout << x << " "; + for (int i = 0; i < V; i++) + cout << dist[i] << " "; cout << endl; + cout << "BFS operation finished!\n"; } \ No newline at end of file diff --git a/benchmarks/GraphMlirBfs.cpp b/benchmarks/GraphMlirBfs.cpp index f066654..739784e 100644 --- a/benchmarks/GraphMlirBfs.cpp +++ b/benchmarks/GraphMlirBfs.cpp @@ -26,7 +26,7 @@ using namespace std; -#define V 100 +#define V 1000 namespace { int g[V][V]; @@ -64,14 +64,15 @@ void initializeGraphMLIRBfs() { int v = rand() % V; int d = rand() % 100 + 1; - g[u][v] = d; + if (g[u][v] == 0) + g[u][v] = d; } std::vector a, ia, ca; generateCSR(g, a, ia, ca); - opsize[0] = 101; + opsize[0] = V + 1; weights = new MemRef(a); cnz = new MemRef(ia); @@ -98,9 +99,10 @@ void generateResultGraphMLIRBfs() { cout << "-------------------------------------------------------\n"; cout << "[ GraphMLIR BFS Result Information ]\n"; - MemRef parent = MemRef(opsize); - MemRef distance = MemRef(opsize); + MemRef parent(opsize); + MemRef distance(opsize); graph::graph_bfs(weights, cnz, cidx, &parent, &distance); + cout << "BFS operation finished!\n"; } \ No newline at end of file diff --git a/benchmarks/LemonBFS.cpp b/benchmarks/LemonBFS.cpp index cef6a06..b6c2aba 100644 --- a/benchmarks/LemonBFS.cpp +++ b/benchmarks/LemonBFS.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace lemon; -#define V 100 +#define V 1000 namespace { ListDigraph g; -ListDigraph::Node source = g.addNode(); +ListDigraph::Node source; } // namespace void initializeLemonBFS() { @@ -46,9 +46,9 @@ void initializeLemonBFS() { int MAX_EDGES = vertices * (vertices - 1) / 2; int NUMEDGE = MAX_EDGES; - for (int i = 1; i <= vertices; i++) { - ListDigraph::Node a = nodes[rand() % NUM]; - ListDigraph::Node b = nodes[rand() % NUM]; + for (int i = 1; i <= NUMEDGE; i++) { + ListDigraph::Node a = nodes[rand() % V]; + ListDigraph::Node b = nodes[rand() % V]; g.addArc(a, b); } diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index 24d9a51..5c9473f 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -13,11 +13,11 @@ #include #include -#define V 100 +#define V 5 // Generate compressed sparse matrix -void generateCSR(int graph[V][V], std::vector &a, std::vector &ia, - std::vector &ca) { +void generateCSR(std::vector> &graph, std::vector &a, + std::vector &ia, std::vector &ca) { int count = 0; ia.push_back(0); @@ -35,18 +35,8 @@ void generateCSR(int graph[V][V], std::vector &a, std::vector &ia, } } -// Print memref data -void print(MemRef data) { - auto y = data.getData(); - - for (size_t i = 0; i < data.getSize(); i++) - std::cout << y[i] << " "; - std::cout << std::endl; -} - int main() { - int graph[V][V]; - intptr_t size[1] = {V}; + std::vector> graph(V, std::vector(V, 0)); int MAX_EDGES = V * (V - 1) / 2; int NUMEDGES = MAX_EDGES; @@ -56,7 +46,8 @@ int main() { int v = rand() % V; int d = rand() % 100 + 1; - graph[u][v] = d; + if (graph[u][v] == 0) + graph[u][v] = d; } std::vector a, ia, ca; @@ -66,20 +57,24 @@ int main() { MemRef weights = MemRef(a); MemRef cnz = MemRef(ia); MemRef cidx = MemRef(ca); - MemRef parent = MemRef(size); - MemRef distance = MemRef(size); + MemRef parent = MemRef(std::vector(V, -1)); + MemRef distance = MemRef(std::vector(V, INT32_MAX)); graph::graph_bfs(&weights, &cnz, &cidx, &parent, &distance); auto y = parent.getData(); - for (size_t i = 0; i < V; i++) - std::cout << y[i] << " "; - std::cout << std::endl; + // Print parents + for (size_t i = 0; i < V; i++) { + std::cout << "parent(" << i << ")" + << " = " << parent[i] << std::endl; + } y = distance.getData(); - for (size_t i = 0; i < V; i++) - std::cout << y[i] << " "; - std::cout << std::endl; + // Print distance + for (size_t i = 0; i < V; i++) { + std::cout << "distance(" << i << ")" + << " = " << distance[i] << std::endl; + } } \ No newline at end of file diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index 314b1f5..8876ce5 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -35,6 +35,9 @@ using namespace graph; using namespace vector; using namespace mlir::arith; +// Size for visited and queue vector +#define MAXSIZE 1000 + // Cast index to i32 Value indexToI32(OpBuilder &builder, Location loc, Value v) { return builder.create(loc, builder.getI32Type(), v); @@ -81,13 +84,13 @@ class GraphBFSLowering : public OpRewritePattern { // Types IndexType idxt = IndexType::get(ctx); IntegerType it32 = IntegerType::get(ctx, 32); - VectorType vt32 = VectorType::get({100}, it32); - VectorType qt = VectorType::get({100}, idxt); + VectorType vt32 = VectorType::get({MAXSIZE}, it32); + VectorType qt = VectorType::get({MAXSIZE}, idxt); + // Constants Value idx0 = rewriter.create(loc, 0); Value idx1 = rewriter.create(loc, 1); Value cnzsize = rewriter.create(loc, cnz, idx0); - Value zero = rewriter.create(loc, int(0), it32); Value one = rewriter.create(loc, int(1), it32); Value two = rewriter.create(loc, int(2), it32); @@ -101,14 +104,21 @@ class GraphBFSLowering : public OpRewritePattern { // Queue Value queue = rewriter.create(loc, qt, idx0); Value front = rewriter.create(loc, int(0), it32); - Value rear = rewriter.create(loc, int(1), it32); + Value rear = rewriter.create(loc, int(0), it32); // Visited - // 0 = not discovered = white - // 1 = discovered but no explored = grey - // 2 = discovered and explored = black + // 0 = not discovered = white (not added to the queue) + // 1 = discovered but no explored = grey (added to the queue) + // 2 = discovered and explored = black (removed from the queue) Value visited = rewriter.create(loc, vt32, zero); + /* + queue[rear] = 0 + rear++ + visited[0] = 1 + distance[0] = 0 + parent[0] = -1 + */ queue = rewriter.create(loc, idx0, queue, rear); rear = rewriter.create(loc, rear, one); visited = rewriter.create(loc, one, visited, idx0); @@ -128,6 +138,7 @@ class GraphBFSLowering : public OpRewritePattern { rewriter.createBlock(&whileOp.getAfter(), {}, types, locations); // Before block - Condition + // while(front != rear) { rewriter.setInsertionPointToStart(&whileOp.getBefore().front()); @@ -148,6 +159,12 @@ class GraphBFSLowering : public OpRewritePattern { Value rear = after->getArgument(2); Value visited = after->getArgument(3); + /* + u = queue[front] + z = u + 1 + front++ + visited[u] = 2 + */ Value u = rewriter.create(loc, queue, front); Value z = addIndex(rewriter, loc, u, one); @@ -159,9 +176,20 @@ class GraphBFSLowering : public OpRewritePattern { s = I32ToIndex(rewriter, loc, s); e = I32ToIndex(rewriter, loc, e); + // for(i = s; i < e; i++) auto loop = rewriter.create( loc, s, e, idx1, ValueRange{queue, front, rear, visited}, [&](OpBuilder &builder, Location loc, Value i, ValueRange args) { + Value queue = args[0]; + Value front = args[1]; + Value rear = args[2]; + Value visited = args[3]; + + /* + v = cidx[i] + color = visited[v] + condition = (color == 0) + */ Value v = rewriter.create(loc, cidx, i); v = I32ToIndex(builder, loc, v); Value color = @@ -175,15 +203,29 @@ class GraphBFSLowering : public OpRewritePattern { // Then block { builder.setInsertionPointToStart(ifop.thenBlock()); - + /* + d = distance[u] + e = weights[i] + f = d + e + p = u + */ Value d = rewriter.create(loc, distance, u); Value e = rewriter.create(loc, weights, i); Value f = rewriter.create(loc, d, e); Value p = rewriter.create(loc, it32, u); + /* + distance[v] = f + parent[v] = u + */ rewriter.create(loc, f, distance, v); rewriter.create(loc, p, parent, v); + /* + visited[v] = 1 + queue[rear] = v + rear++ + */ Value nvisited = builder.create(loc, one, visited, v); Value nqueue = @@ -206,6 +248,7 @@ class GraphBFSLowering : public OpRewritePattern { builder.create(loc, results); }); + ValueRange lresults = loop.getResults(); rewriter.create(loc, lresults); From 0d35c143933d051304ee5e135de442fc1463d41a Mon Sep 17 00:00:00 2001 From: Gautam Agrawal Date: Fri, 26 May 2023 04:39:39 +0530 Subject: [PATCH 15/16] Add benchmarking for Bellman Ford algorithm * Add benchmarking for GraphMLIR based bellman ford algorithm * Add benchmarking for Lemon based bellman ford algorithm (Note: Number of vertices has been taken as 100 in both the benchmarking) --- benchmarks/CMakeLists.txt | 2 + benchmarks/GraphMlirBellmanFordBenchmark.cpp | 101 +++++++++++++++++++ benchmarks/LemonBellmanFord.cpp | 91 +++++++++++++++++ benchmarks/Main.cpp | 9 +- 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 benchmarks/GraphMlirBellmanFordBenchmark.cpp create mode 100644 benchmarks/LemonBellmanFord.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 830f11b..61cff9f 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -38,7 +38,9 @@ add_executable(graph-processing-benchmark FloydWarshall.cpp BoostFloydWarshall.cpp GraphMlirFloydWarshallBenchmark.cpp + GraphMlirBellmanFordBenchmark.cpp LemonBFS.cpp + LemonBellmanFord.cpp Main.cpp GraphMlirBfs.cpp Bfs.cpp diff --git a/benchmarks/GraphMlirBellmanFordBenchmark.cpp b/benchmarks/GraphMlirBellmanFordBenchmark.cpp new file mode 100644 index 0000000..33c6f02 --- /dev/null +++ b/benchmarks/GraphMlirBellmanFordBenchmark.cpp @@ -0,0 +1,101 @@ +//===- GraphMlirBellmanFordBenchmark.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Bellman Ford Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#define V 100 +#define NUM_EDGE V *(V - 1) / 2 + +using namespace std; + +namespace { +// Graph +// sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, +// 100); +intptr_t size[1]; +// // MemRef *input; +MemRef *start; +MemRef *e; +MemRef *dist; +} // namespace + +void initializeGraphMLIRBellmanFord() { + + // graph::generateRandomGraph(&sample_graph, V); + + // input = &sample_graph.get_Memref(); + + // size = 100; + + // MemRef output = MemRef(size); + + std::vector st, ed, distance(V, INT32_MAX); + + srand(time(0)); + + for (int i = 0; i < NUM_EDGE; i++) { + int u = rand() % V; + int v = rand() % V; + int d = (rand() % 100); + + st.push_back(u); + ed.push_back(v); + distance.push_back(d); + } + size[0] = V; + + MemRef temp1 = MemRef(st); + start = &temp1; + MemRef temp2 = MemRef(ed); + e = &temp2; + MemRef temp3 = MemRef(distance); + dist = &temp3; + // start = MemRef(st); + // e = MemRef(ed); + // dist = MemRef(distance); +} + +// Benchmarking function. +static void GraphMLIR_BellmanFord(benchmark::State &state) { + for (auto _ : state) { + std::vector op(V, INT32_MAX); + MemRef output = MemRef(op); + for (int i = 0; i < state.range(0); ++i) { + graph::bellman_ford(start, e, dist, &output); + } + } +} + +// Register benchmarking function. +BENCHMARK(GraphMLIR_BellmanFord)->Arg(1); + +void generateResultGraphMLIRBellmanFord() { + initializeGraphMLIRBellmanFord(); + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR Bellman Ford Result Information ]\n"; + MemRef output(size); + // graph::bellman_ford(&start, &end, &dist, &output); + + cout << "Bellman Ford operation finished!\n"; +} diff --git a/benchmarks/LemonBellmanFord.cpp b/benchmarks/LemonBellmanFord.cpp new file mode 100644 index 0000000..4b56712 --- /dev/null +++ b/benchmarks/LemonBellmanFord.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +using namespace std; +using namespace lemon; + +#define V 100 +#define MaxWeight 900 +#define UpperLimit 100 +#define LowerLimit 2 + +typedef ListDigraph::ArcMap LengthMap; + +namespace { +ListDigraph g; +ListDigraph::Node source; +LengthMap length(g); +ListDigraph::Node nodes[V]; +} // namespace + +void initializeLemonBellmanFord() { + + // LengthMap length(g); + + for (int i = 0; i < V; i++) { + nodes[i] = g.addNode(); + } + + source = nodes[0]; + + // length[g.addArc(nodes[0], nodes[1])] = 4; + // length[g.addArc(nodes[1], nodes[2])] = 3; + // length[g.addArc(nodes[2], nodes[3])] = 3; + // length[g.addArc(nodes[3], nodes[0])] = 6; + // length[g.addArc(nodes[0], nodes[2])] = 2; + // length[g.addArc(nodes[1], nodes[3])] = 2; + + std::set> container; + std::set>::iterator it; + srand(time(NULL)); + + int NUM = V; // Number of Vertices + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + + container.insert(p); + length[g.addArc(nodes[a], nodes[b])] = 1 + rand() % MaxWeight; + } + BellmanFord bf(g, length); +} + +// Benchmarking function. +static void Lemon_BellmanFord(benchmark::State &state) { + for (auto _ : state) { + BellmanFord bf(g, length); + for (int i = 0; i < state.range(0); ++i) { + bf.run(source); + } + } +} + +BENCHMARK(Lemon_BellmanFord)->Arg(1); + +void generateResultLemonBellmanFord() { + initializeLemonBellmanFord(); + cout << "-------------------------------------------------------\n"; + cout << "[ LEMON Bellman Ford Result Information ]\n"; + BellmanFord output(g, length); + output.run(source); + + LengthMap::Value value = output.dist(nodes[2]); + std::cout << "The distance of node t from node s: " + << output.dist(nodes[3]) << std::endl; + + cout << "Lemon Bellman Ford Operation Completed!\n"; +} \ No newline at end of file diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp index b060f7d..3149c5f 100644 --- a/benchmarks/Main.cpp +++ b/benchmarks/Main.cpp @@ -25,12 +25,16 @@ void initializeFloydWarshall(); void initializeLemonBFS(); void initializeBoostFLoydWarshall(); void initializeGraphMLIRBfs(); +void initializeGraphMLIRBellmanFord(); +void initializeLemonBellmanFord(); void generateResultGraphMLIRFloydWarshall(); void generateResultFloydWarshall(); void generateResultLemonBFS(); void generateResultBoostFLoydWarshall(); void generateResultGraphMLIRBfs(); +void generateResultGraphMLIRBellmanFord(); +void generateResultLemonBellmanFord(); int main(int argc, char **argv) { @@ -39,6 +43,8 @@ int main(int argc, char **argv) { initializeLemonBFS(); initializeBoostFLoydWarshall(); initializeGraphMLIRBfs(); + initializeGraphMLIRBellmanFord(); + initializeLemonBellmanFord(); ::benchmark::Initialize(&argc, argv); ::benchmark::RunSpecifiedBenchmarks(); @@ -48,6 +54,7 @@ int main(int argc, char **argv) { generateResultLemonBFS(); generateResultBoostFLoydWarshall(); generateResultGraphMLIRBfs(); - + generateResultGraphMLIRBellmanFord(); + generateResultLemonBellmanFord(); return 0; } From 22e94e19b5d314eaff0f8d17f5de664cba956279 Mon Sep 17 00:00:00 2001 From: Aman Chhaparia Date: Fri, 26 May 2023 05:01:29 +0530 Subject: [PATCH 16/16] Add Boost benchmarking support for Bellman Ford --- benchmarks/BoostBellmanFordBenchmarking.cpp | 112 ++++++++++++++++++++ benchmarks/CMakeLists.txt | 1 + benchmarks/Main.cpp | 5 + 3 files changed, 118 insertions(+) create mode 100644 benchmarks/BoostBellmanFordBenchmarking.cpp diff --git a/benchmarks/BoostBellmanFordBenchmarking.cpp b/benchmarks/BoostBellmanFordBenchmarking.cpp new file mode 100644 index 0000000..4615b87 --- /dev/null +++ b/benchmarks/BoostBellmanFordBenchmarking.cpp @@ -0,0 +1,112 @@ +//===- BoostBellmanforBenchmarking.cpp -----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Boost Bellmanford example benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define SIZE 100 + +namespace { +typedef int t_weight; + +// define the graph type +typedef boost::property EdgeWeightProperty; +typedef boost::adjacency_list + Graph; + +typedef boost::property_map::type WeightMap; + + +Graph g; + +std::vector distnce(SIZE, (std::numeric_limits::max)()); +int source_node_index = 0; +std::vector parent(SIZE); + +} // namespace + +void initializeBoostBellmanFord() { + + const int vertices = SIZE; + int num_edges = vertices * (vertices -1) / 2; + + // define edges + // int edges[] = {1, 2, 2, 3, 3, 4, 4, 1, 1, 3, 2, 4}; + + // t_weight weight[] = {4, 3, 3, 6, 2, 2}; + + std::vector edges; + std::vector weight; + + graph::generateRandomGraph(edges, weight, vertices); + + for (std::size_t k = 0; k < num_edges; ++k) + boost::add_edge(edges[k * 2] - 1, edges[k * 2 + 1] - 1, weight[k], g); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + + for (int i = 0; i < num_vertices(g); ++i) + parent[i] = i; + distnce[source_node_index] = 0; + + +} + +// Benchmarking function. +static void Boost_BellmanFord(benchmark::State &state) { + + for (auto _ : state) { + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + for (int i = 0; i < state.range(0); ++i) { + bool r = bellman_ford_shortest_paths(g, num_vertices(g), weight_pmap, &parent[0], + &distnce[0], boost::closed_plus< int >(), std::less< int >(), + boost::default_bellman_visitor()); + } + } +} + +// Register benchmarking function. +BENCHMARK(Boost_BellmanFord)->Arg(1); + +void generateResultBoostBellmanFord() { + initializeBoostBellmanFord(); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + for (int i = 0; i < num_vertices(g); ++i) + parent[i] = i; + distnce[source_node_index] = 0; + + cout << "-------------------------------------------------------\n"; + cout << "[ BOOST FloydWarshall Result Information ]\n"; + bool r = bellman_ford_shortest_paths(g, num_vertices(g), weight_pmap, &parent[0], + &distnce[0], boost::closed_plus< int >(), std::less< int >(), + boost::default_bellman_visitor()); + cout << "Boost FloydWarshall operation finished!\n"; +} \ No newline at end of file diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 61cff9f..565a057 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -37,6 +37,7 @@ LINKER_LANGUAGE C) add_executable(graph-processing-benchmark FloydWarshall.cpp BoostFloydWarshall.cpp + BoostBellmanFordBenchmarking.cpp GraphMlirFloydWarshallBenchmark.cpp GraphMlirBellmanFordBenchmark.cpp LemonBFS.cpp diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp index 3149c5f..6f504ae 100644 --- a/benchmarks/Main.cpp +++ b/benchmarks/Main.cpp @@ -27,6 +27,7 @@ void initializeBoostFLoydWarshall(); void initializeGraphMLIRBfs(); void initializeGraphMLIRBellmanFord(); void initializeLemonBellmanFord(); +void initializeBoostBellmanFord(); void generateResultGraphMLIRFloydWarshall(); void generateResultFloydWarshall(); @@ -35,6 +36,7 @@ void generateResultBoostFLoydWarshall(); void generateResultGraphMLIRBfs(); void generateResultGraphMLIRBellmanFord(); void generateResultLemonBellmanFord(); +void generateResultBoostBellmanFord(); int main(int argc, char **argv) { @@ -45,6 +47,7 @@ int main(int argc, char **argv) { initializeGraphMLIRBfs(); initializeGraphMLIRBellmanFord(); initializeLemonBellmanFord(); + initializeBoostBellmanFord(); ::benchmark::Initialize(&argc, argv); ::benchmark::RunSpecifiedBenchmarks(); @@ -56,5 +59,7 @@ int main(int argc, char **argv) { generateResultGraphMLIRBfs(); generateResultGraphMLIRBellmanFord(); generateResultLemonBellmanFord(); + generateResultBoostBellmanFord(); + return 0; }