From 4f78d5110e5d6b0c69737e03dd247356ba4a8677 Mon Sep 17 00:00:00 2001
From: meshtag <prathameshtagore@gmail.com>
Date: Wed, 8 Sep 2021 00:16:37 +0530
Subject: [PATCH] Add opencv benchmark

Edit Doc

Edit readme and comments

Refactor code

Use benchmark arhuments to reduce repetitiveness

Change file structure

Add comments in Benchmarks folder and update README.md with compilation instruction
---
 README.md                                     |   4 +-
 .../Benchmarks/BenchmarkFiles/CMakeLists.txt  |   1 +
 .../ImageProcessing/BuddyBenchmark.cpp        |  82 ++++++++++++++
 .../ImageProcessing/CMakeLists.txt            |  47 ++++++++
 .../ImageProcessing/CompareBuddyOpencv.cpp    | 100 ++++++++++++++++++
 .../ImageProcessing/OpenCVBenchmark.cpp       |  36 +++++++
 buddy-mlir/Benchmarks/CMakeLists.txt          |   1 +
 .../ImageProcessing/BuddyContainer.hpp        |  39 +++++++
 8 files changed, 309 insertions(+), 1 deletion(-)
 create mode 100644 buddy-mlir/Benchmarks/BenchmarkFiles/CMakeLists.txt
 create mode 100644 buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/BuddyBenchmark.cpp
 create mode 100644 buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CMakeLists.txt
 create mode 100644 buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CompareBuddyOpencv.cpp
 create mode 100644 buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/OpenCVBenchmark.cpp
 create mode 100644 buddy-mlir/Benchmarks/CMakeLists.txt
 create mode 100644 buddy-mlir/Benchmarks/include/ImageProcessing/BuddyContainer.hpp

diff --git a/README.md b/README.md
index bc03ddc..1b81ccf 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,4 @@
 # buddy-benchmark
-Benchmark Framework for Buddy Projects
+In order to produce benchmarking results, copy and paste the `benchmarks` folder in `examples/conv-opt/` directory. Also add `add_subdirectory(Benchmarks)` in `examples/conv-opt/CMakeLists.txt`.
+
+Note : The convolution implementation in buddy mlir is not feature complete at the moment and it may produce output which differs to some extent from the frameworks used in comparison. 
diff --git a/buddy-mlir/Benchmarks/BenchmarkFiles/CMakeLists.txt b/buddy-mlir/Benchmarks/BenchmarkFiles/CMakeLists.txt
new file mode 100644
index 0000000..6071631
--- /dev/null
+++ b/buddy-mlir/Benchmarks/BenchmarkFiles/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(ImageProcessing)
diff --git a/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/BuddyBenchmark.cpp b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/BuddyBenchmark.cpp
new file mode 100644
index 0000000..b98cabd
--- /dev/null
+++ b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/BuddyBenchmark.cpp
@@ -0,0 +1,82 @@
+#include <benchmark/benchmark.h>
+#include <opencv2/opencv.hpp>
+#include "../../../kernels.h"
+#include "../../include/ImageProcessing/BuddyContainer.hpp"
+
+using namespace cv;
+using namespace std;
+
+// Read input image
+Mat inputImage = imread("../../examples/conv-opt/images/YuTu.png", IMREAD_GRAYSCALE);
+
+// Define the kernel.
+float *kernelAlign = laplacianKernelAlign;
+int kernelRows = laplacianKernelRows;
+int kernelCols = laplacianKernelCols;
+
+// Define output for buddy mlir implementation.
+int outputRows = inputImage.rows - kernelRows + 1;
+int outputCols = inputImage.cols - kernelCols + 1;
+float *outputAlign = (float *)malloc(outputRows * outputCols * sizeof(float));
+
+// Define allocated, sizes, and strides.
+float *allocated = (float *)malloc(1 * sizeof(float));
+intptr_t sizesInput[2] = {inputImage.rows, inputImage.cols};
+intptr_t sizesKernel[2] = {kernelRows, kernelCols};
+intptr_t sizesOutput[2] = {outputRows, outputCols};
+intptr_t stridesInput[2] = {inputImage.rows, inputImage.cols};
+intptr_t stridesKernel[2] = {kernelRows, kernelCols};
+intptr_t stridesOutput[2] = {outputRows, outputCols};
+
+float* fill_align(Mat image)
+{
+  int k = 0;
+  float *inputAlign = (float *)malloc(image.rows * image.cols * sizeof(float));
+  for (int i = 0; i < image.rows; i++) {
+    for (int j = 0; j < image.cols; j++) {
+      float pixelValue = (float)image.at<uchar>(i, j);
+      inputAlign[k] = pixelValue;
+      k++;
+    }
+  }
+  return inputAlign;
+}
+
+float *inputAlign = fill_align(inputImage);
+
+// Define memref descriptors.
+MemRef_descriptor input =
+    MemRef_Descriptor(allocated, inputAlign, 0, sizesInput, stridesInput);
+MemRef_descriptor kernel =
+    MemRef_Descriptor(allocated, kernelAlign, 0, sizesKernel, stridesKernel);
+MemRef_descriptor output =
+    MemRef_Descriptor(allocated, outputAlign, 0, sizesOutput, stridesOutput);
+
+static void BM_Buddy(benchmark::State &state) {
+  for (auto _ : state) {
+    for (int i = 0; i < state.range(0); ++i) {
+      _mlir_ciface_conv_2d(input, kernel, output);
+    }
+  }
+}
+
+// Register benchmarking function with different arguments
+BENCHMARK(BM_Buddy)->Arg(1);
+BENCHMARK(BM_Buddy)->Arg(2);
+BENCHMARK(BM_Buddy)->Arg(4);
+BENCHMARK(BM_Buddy)->Arg(8);
+BENCHMARK(BM_Buddy)->Arg(16);
+
+// Run benchmarks
+int main(int argc, char** argv)
+{
+  ::benchmark::Initialize(&argc, argv);
+  ::benchmark::RunSpecifiedBenchmarks();
+
+  free(inputAlign);
+  free(outputAlign);
+  free(input);
+  free(kernel);
+  free(output);
+  free(allocated);
+}
diff --git a/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CMakeLists.txt b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CMakeLists.txt
new file mode 100644
index 0000000..032f255
--- /dev/null
+++ b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CMakeLists.txt
@@ -0,0 +1,47 @@
+find_package(OpenCV REQUIRED CONFIG)
+include_directories(${OpenCV_INCLUDE_DIRS})
+
+message(STATUS "Configuring benchmarks: google")
+
+#-----------------------------------------------------------------------------
+# Deploy google/benchmark
+#-----------------------------------------------------------------------------
+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 <INSTALL_DIR>/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(buddy_googlebenchmark STATIC IMPORTED)
+target_include_directories(buddy_googlebenchmark INTERFACE ${INSTALL_DIR}/include)
+set_property(TARGET buddy_googlebenchmark PROPERTY IMPORTED_LOCATION
+  "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX}")
+
+add_dependencies(buddy_googlebenchmark project_googlebenchmark)
+
+find_package(Threads)
+target_link_libraries(buddy_googlebenchmark INTERFACE Threads::Threads)
+
+add_executable(OpenCVBenchmark OpenCVBenchmark.cpp)
+target_link_libraries(OpenCVBenchmark ${OpenCV_LIBS} buddy_googlebenchmark)
+
+add_executable(BuddyBenchmark BuddyBenchmark.cpp)
+add_dependencies(BuddyBenchmark conv-opt)
+target_link_libraries(BuddyBenchmark ${OpenCV_LIBS} Conv2D buddy_googlebenchmark)
+
+add_executable(CompareBuddyOpencv CompareBuddyOpencv.cpp)
+add_dependencies(CompareBuddyOpencv conv-opt)
+target_link_libraries(CompareBuddyOpencv ${OpenCV_LIBS} Conv2D buddy_googlebenchmark)
diff --git a/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CompareBuddyOpencv.cpp b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CompareBuddyOpencv.cpp
new file mode 100644
index 0000000..a3b565d
--- /dev/null
+++ b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/CompareBuddyOpencv.cpp
@@ -0,0 +1,100 @@
+#include <benchmark/benchmark.h>
+#include <opencv2/opencv.hpp>
+#include "../../../kernels.h"
+#include "../../include/ImageProcessing/BuddyContainer.hpp"
+
+using namespace cv;
+using namespace std;
+
+// Read input image and specify kernel
+Mat inputImage = imread("../../examples/conv-opt/images/YuTu.png", IMREAD_GRAYSCALE);
+Mat kernel_opencv = Mat(3, 3, CV_32FC1, laplacianKernelAlign);
+Mat output_opencv;
+
+// Define the kernel.
+float *kernelAlign = laplacianKernelAlign;
+int kernelRows = laplacianKernelRows;
+int kernelCols = laplacianKernelCols;
+
+// Define output for buddy mlir implementation.
+int outputRows = inputImage.rows - kernelRows + 1;
+int outputCols = inputImage.cols - kernelCols + 1;
+float *outputAlign = (float *)malloc(outputRows * outputCols * sizeof(float));
+
+// Define allocated, sizes, and strides.
+float *allocated = (float *)malloc(1 * sizeof(float));
+intptr_t sizesInput[2] = {inputImage.rows, inputImage.cols};
+intptr_t sizesKernel[2] = {kernelRows, kernelCols};
+intptr_t sizesOutput[2] = {outputRows, outputCols};
+intptr_t stridesInput[2] = {inputImage.rows, inputImage.cols};
+intptr_t stridesKernel[2] = {kernelRows, kernelCols};
+intptr_t stridesOutput[2] = {outputRows, outputCols};
+
+float* fill_align(Mat image)
+{
+  int k = 0;
+  float *inputAlign = (float *)malloc(image.rows * image.cols * sizeof(float));
+  for (int i = 0; i < image.rows; i++) {
+    for (int j = 0; j < image.cols; j++) {
+      float pixelValue = (float)image.at<uchar>(i, j);
+      inputAlign[k] = pixelValue;
+      k++;
+    }
+  }
+  return inputAlign;
+}
+
+float *inputAlign = fill_align(inputImage);
+
+// Define memref descriptors.
+MemRef_descriptor input =
+    MemRef_Descriptor(allocated, inputAlign, 0, sizesInput, stridesInput);
+MemRef_descriptor kernel =
+    MemRef_Descriptor(allocated, kernelAlign, 0, sizesKernel, stridesKernel);
+MemRef_descriptor output =
+    MemRef_Descriptor(allocated, outputAlign, 0, sizesOutput, stridesOutput);
+
+// Benchmarking function
+static void BM_OpenCV(benchmark::State &state) {
+  for (auto _ : state) {
+    for (int i = 0; i < state.range(0); ++i) {
+      filter2D(inputImage, output_opencv, CV_32FC1, kernel_opencv);
+    }
+  }
+}
+
+// Benchmarking function
+static void BM_Buddy(benchmark::State &state) {
+  for (auto _ : state) {
+    for (int i = 0; i < state.range(0); ++i) {
+      _mlir_ciface_conv_2d(input, kernel, output);
+    }
+  }
+}
+
+// Register above functions as benchmarks with different arguments
+BENCHMARK(BM_OpenCV)->Arg(1);
+BENCHMARK(BM_OpenCV)->Arg(2);
+BENCHMARK(BM_OpenCV)->Arg(4);
+BENCHMARK(BM_OpenCV)->Arg(8);
+BENCHMARK(BM_OpenCV)->Arg(16);
+
+BENCHMARK(BM_Buddy)->Arg(1);
+BENCHMARK(BM_Buddy)->Arg(2);
+BENCHMARK(BM_Buddy)->Arg(4);
+BENCHMARK(BM_Buddy)->Arg(8);
+BENCHMARK(BM_Buddy)->Arg(16);
+
+// Run benchmarks
+int main(int argc, char** argv)
+{
+  ::benchmark::Initialize(&argc, argv);
+  ::benchmark::RunSpecifiedBenchmarks();
+
+  free(inputAlign);
+  free(outputAlign);
+  free(input);
+  free(kernel);
+  free(output);
+  free(allocated);
+}
diff --git a/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/OpenCVBenchmark.cpp b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/OpenCVBenchmark.cpp
new file mode 100644
index 0000000..188bfa6
--- /dev/null
+++ b/buddy-mlir/Benchmarks/BenchmarkFiles/ImageProcessing/OpenCVBenchmark.cpp
@@ -0,0 +1,36 @@
+#include <benchmark/benchmark.h>
+#include <opencv2/opencv.hpp>
+#include "../../../kernels.h"
+
+using namespace cv;
+using namespace std;
+
+// Read input image and specify kernel
+Mat inputImage = imread("../../examples/conv-opt/images/YuTu.png", IMREAD_GRAYSCALE);
+Mat kernel_opencv = Mat(3, 3, CV_32FC1, laplacianKernelAlign);
+
+// Declare output image
+Mat output_opencv;
+
+// Benchmarking function
+static void BM_OpenCV(benchmark::State &state) {
+  for (auto _ : state) {
+    for (int i = 0; i < state.range(0); ++i) {
+      filter2D(inputImage, output_opencv, CV_32FC1, kernel_opencv);
+    }
+  }
+}
+
+// Register benchmarking function with different arguments
+BENCHMARK(BM_OpenCV)->Arg(1);
+BENCHMARK(BM_OpenCV)->Arg(2);
+BENCHMARK(BM_OpenCV)->Arg(4);
+BENCHMARK(BM_OpenCV)->Arg(8);
+BENCHMARK(BM_OpenCV)->Arg(16);
+
+// Run benchmarks
+int main(int argc, char** argv)
+{
+  ::benchmark::Initialize(&argc, argv);
+  ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/buddy-mlir/Benchmarks/CMakeLists.txt b/buddy-mlir/Benchmarks/CMakeLists.txt
new file mode 100644
index 0000000..de15c01
--- /dev/null
+++ b/buddy-mlir/Benchmarks/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(BenchmarkFiles)
diff --git a/buddy-mlir/Benchmarks/include/ImageProcessing/BuddyContainer.hpp b/buddy-mlir/Benchmarks/include/ImageProcessing/BuddyContainer.hpp
new file mode 100644
index 0000000..180ff5e
--- /dev/null
+++ b/buddy-mlir/Benchmarks/include/ImageProcessing/BuddyContainer.hpp
@@ -0,0 +1,39 @@
+#ifndef BUDDY_CONTAINER
+#define BUDDY_CONTAINER
+
+#include <stdint.h>
+#include <stdlib.h>
+
+// Define Memref Descriptor.
+typedef struct MemRef_descriptor_ *MemRef_descriptor;
+typedef struct MemRef_descriptor_ {
+  float *allocated;
+  float *aligned;
+  intptr_t offset;
+  intptr_t sizes[2];
+  intptr_t strides[2];
+} Memref;
+
+// Constructor
+MemRef_descriptor MemRef_Descriptor(float *allocated, float *aligned,
+                                    intptr_t offset, intptr_t sizes[2],
+                                    intptr_t strides[2]) {
+  MemRef_descriptor n = (MemRef_descriptor)malloc(sizeof(*n));
+  n->allocated = allocated;
+  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;
+}
+
+// Declare the conv2d C interface.
+extern "C" {
+void _mlir_ciface_conv_2d(MemRef_descriptor input, MemRef_descriptor kernel,
+                          MemRef_descriptor output);
+}
+
+#endif
-- 
GitLab