aboutsummaryrefslogtreecommitdiff
path: root/MicroBenchmarks
diff options
context:
space:
mode:
authorPankaj Kukreja <cs15btech11029@iith.ac.in>2018-08-06 11:19:13 +0000
committerPankaj Kukreja <cs15btech11029@iith.ac.in>2018-08-06 11:19:13 +0000
commit7dedc179c7fdae056e37b542fec8827ac8032d80 (patch)
treef512479c9fabcd8cd47a6a4637c69c4374e777ba /MicroBenchmarks
parent377a8e84dd5dcee56bdd745437b1698035e1548a (diff)
Add Image dithering kernels using Benchmark Library
Contains Ordered and Floyd-Steinberg dithering algorithms Reviewers: Meinersbur Differential Revision: https://reviews.llvm.org/D49503 git-svn-id: https://llvm.org/svn/llvm-project/test-suite/trunk@339006 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'MicroBenchmarks')
-rw-r--r--MicroBenchmarks/ImageProcessing/CMakeLists.txt1
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt13
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/dither.h15
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output1
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c69
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/main.cpp156
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output1
-rw-r--r--MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c72
8 files changed, 328 insertions, 0 deletions
diff --git a/MicroBenchmarks/ImageProcessing/CMakeLists.txt b/MicroBenchmarks/ImageProcessing/CMakeLists.txt
new file mode 100644
index 00000000..806360a9
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Dither)
diff --git a/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt b/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt
new file mode 100644
index 00000000..28d57115
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(IMAGEPROC_UTILS MicroBenchmarks/ImageProcessing/utils)
+list(APPEND CPPFLAGS -I ${CMAKE_SOURCE_DIR}/${IMAGEPROC_UTILS} -std=c++11)
+
+llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh ${CMAKE_CURRENT_BINARY_DIR}/orderedOutput.txt")
+llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/orderedOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/orderedDither.reference_output")
+
+llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh ${CMAKE_CURRENT_BINARY_DIR}/floydOutput.txt")
+llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/floydOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/floydDither.reference_output")
+
+llvm_test_run(WORKDIR ${CMAKE_CURRENT_BINARY_DIR})
+llvm_test_executable(Dither main.cpp orderedDitherKernel.c floydDitherKernel.c ../utils/ImageHelper.cpp ../utils/glibc_compat_rand.c)
+
+target_link_libraries(Dither benchmark)
diff --git a/MicroBenchmarks/ImageProcessing/Dither/dither.h b/MicroBenchmarks/ImageProcessing/Dither/dither.h
new file mode 100644
index 00000000..dc0a81db
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/dither.h
@@ -0,0 +1,15 @@
+/**
+ Pankaj Kukreja
+ github.com/proton0001
+ Indian Institute of Technology Hyderabad
+*/
+#ifndef _DITHER_H_
+#define _DITHER_H_
+
+#define MaxGray 255
+#define MXGRAY 256
+
+#define HEIGHT 512
+#define WIDTH 512
+
+#endif /* _DITHER_H_ */
diff --git a/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output b/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output
new file mode 100644
index 00000000..7f7c9812
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output
@@ -0,0 +1 @@
+23473c2d34c91e33eaa3d5008ce3640e
diff --git a/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c b/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c
new file mode 100644
index 00000000..3830a43a
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c
@@ -0,0 +1,69 @@
+/**
+ Source: https://imagej.net/Dithering
+ Modified by Pankaj Kukreja (github.com/proton0001)
+ Indian Institute of Technology Hyderabad
+*/
+#include "dither.h"
+void floydDitherKernel(int height, int width, int inputImage[HEIGHT][WIDTH],
+ int outputImage[height][width]) {
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ outputImage[i][j] = inputImage[i][j];
+ }
+ }
+
+ int err;
+ int a, b, c, d;
+
+ for (int i = 1; i < height - 1; i++) {
+ for (int j = 1; j < width - 1; j++) {
+ if (outputImage[i][j] > 127) {
+ err = outputImage[i][j] - 255;
+ outputImage[i][j] = 255;
+ } else {
+ err = outputImage[i][j] - 0;
+ outputImage[i][j] = 0;
+ }
+ a = (err * 7) / 16;
+ b = (err * 1) / 16;
+ c = (err * 5) / 16;
+ d = (err * 3) / 16;
+
+ int temp1 = (outputImage[i][j + 1] + a);
+ if (temp1 > 255) {
+ outputImage[i][j + 1] = 255;
+ } else if (temp1 < 0) {
+ outputImage[i][j + 1] = 0;
+ } else {
+ outputImage[i][j + 1] = temp1;
+ }
+
+ int temp2 = (outputImage[i + 1][j + 1] + b);
+ if (temp2 > 255) {
+ outputImage[i + 1][j + 1] = 255;
+ } else if (temp2 < 0) {
+ outputImage[i + 1][j + 1] = 0;
+ } else {
+ outputImage[i + 1][j + 1] = temp2;
+ }
+
+ int temp3 = outputImage[i + 1][j + 0] + c;
+ if (temp3 > 255) {
+ outputImage[i + 1][j + 0] = 255;
+ } else if (temp3 < 0) {
+ outputImage[i + 1][j + 0] = 0;
+ } else {
+ outputImage[i + 1][j + 0] = temp3;
+ }
+
+ int temp4 = outputImage[i + 1][j - 1] + d;
+ if (temp4 > 255) {
+ outputImage[i + 1][j - 1] = 255;
+ } else if (temp4 < 0) {
+ outputImage[i + 1][j - 1] = 0;
+ } else {
+ outputImage[i + 1][j - 1] = temp4;
+ }
+ }
+ }
+}
diff --git a/MicroBenchmarks/ImageProcessing/Dither/main.cpp b/MicroBenchmarks/ImageProcessing/Dither/main.cpp
new file mode 100644
index 00000000..b6ab1d36
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/main.cpp
@@ -0,0 +1,156 @@
+/**
+ Pankaj Kukreja
+ github.com/proton0001
+ Indian Institute of Technology Hyderabad
+*/
+#include "ImageHelper.h"
+#include "dither.h"
+#include <cmath>
+#include <iostream> // std::cerr
+
+#define BENCHMARK_LIB
+#ifdef BENCHMARK_LIB
+#include "benchmark/benchmark.h"
+#endif
+
+int *inputImage;
+extern "C" {
+void orderedDitherKernel(int height, int width, int *inpImage, int *outImage,
+ int *temp, int n, int m);
+void floydDitherKernel(int height, int width, int *inpImage, int *outImage);
+}
+int main(int argc, char **argv) {
+#ifdef BENCHMARK_LIB
+ ::benchmark::Initialize(&argc, argv);
+#endif
+
+ const char *orderedOutputFilename = (char *)"./orderedOutput.txt";
+ const char *floydOutputFilename = (char *)"./floydOutput.txt";
+ inputImage = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+ if (inputImage == NULL) {
+ std::cerr << "Insufficient memory\n";
+ exit(1);
+ }
+ initializeRandomImage(inputImage, HEIGHT, WIDTH);
+
+#ifdef BENCHMARK_LIB
+ ::benchmark::RunSpecifiedBenchmarks();
+#endif
+ int *outputImage = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+ int *temp = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+ if (outputImage == NULL || temp == NULL) {
+ std::cerr << "Insufficient memory\n";
+ exit(1);
+ }
+ orderedDitherKernel(HEIGHT, WIDTH, inputImage, outputImage, temp, 16, 4);
+ saveImage(outputImage, orderedOutputFilename, HEIGHT, WIDTH);
+ floydDitherKernel(HEIGHT, WIDTH, inputImage, outputImage);
+
+ for (int i = 0; i < HEIGHT; i++) {
+ outputImage[(i)*WIDTH + 0] = 0;
+ outputImage[(i)*WIDTH + WIDTH - 1] = 0;
+ }
+
+ for (int j = 0; j < WIDTH; j++) {
+ outputImage[(0) * WIDTH + j] = 0;
+ outputImage[(HEIGHT - 1) * WIDTH + j] = 0;
+ }
+
+ saveImage(outputImage, floydOutputFilename, HEIGHT, WIDTH);
+ free(temp);
+ free(outputImage);
+ free(inputImage);
+ return EXIT_SUCCESS;
+}
+
+#ifdef BENCHMARK_LIB
+void BENCHMARK_ORDERED_DITHER(benchmark::State &state) {
+ int height = state.range(0);
+ int width = state.range(0);
+ int m = state.range(1);
+ int n = pow(m, 2);
+ int *outputImage = (int *)malloc(sizeof(int) * height * width);
+ int *temp = (int *)malloc(sizeof(int) * height * width);
+
+ if (outputImage == NULL) {
+ std::cerr << "Insufficient memory\n";
+ exit(1);
+ }
+ /* This call is to warm up the cache */
+ orderedDitherKernel(height, width, inputImage, outputImage, temp, n, m);
+
+ for (auto _ : state) {
+ orderedDitherKernel(height, width, inputImage, outputImage, temp, n, m);
+ }
+ /* Since we are not passing state.range as 20 this if case will always be
+ * false. This call is to make compiler think that outputImage may be used
+ * later so that above kernel calls will not optimize out */
+ if (state.range(0) == 20) {
+ saveImage(outputImage, (const char *)"failedCase.txt", height, width);
+ }
+ free(temp);
+ free(outputImage);
+}
+
+#if (HEIGHT < WIDTH)
+#define MINIMUM_DIM HEIGHT
+#else
+#define MINIMUM_DIM WIDTH
+#endif
+
+static void CustomArguments(benchmark::internal::Benchmark *b) {
+ int limit = MINIMUM_DIM;
+ int start = 1;
+ if (limit > 128) {
+ start = 128;
+ }
+ for (int i = start; i <= limit; i <<= 1) {
+ b->Args({i, 2});
+ b->Args({i, 3});
+ b->Args({i, 4});
+ b->Args({i, 8});
+ }
+}
+BENCHMARK(BENCHMARK_ORDERED_DITHER)
+ ->Apply(CustomArguments)
+ ->Unit(benchmark::kMicrosecond);
+
+void BENCHMARK_FLOYD_DITHER(benchmark::State &state) {
+
+ int height = state.range(0);
+ int width = state.range(0);
+
+ int *outputImage = (int *)malloc(sizeof(int) * height * width);
+
+ if (outputImage == NULL) {
+ std::cerr << "Insufficient memory\n";
+ exit(1);
+ }
+ /* This call is to warm up the cache */
+ floydDitherKernel(height, width, inputImage, outputImage);
+ for (auto _ : state) {
+ floydDitherKernel(height, width, inputImage, outputImage);
+ }
+ /* Since we are not passing state.range as 20 this if case will always be
+ * false. This call is to make compiler think that outputImage may be used
+ * later so that above kernel calls will not optimize out */
+ if (state.range(0) == 20) {
+ saveImage(outputImage, (const char *)"failedCase.txt", height, width);
+ }
+
+ free(outputImage);
+}
+
+#if MINIMUM_DIM > 128
+BENCHMARK(BENCHMARK_FLOYD_DITHER)
+ ->RangeMultiplier(2)
+ ->Range(128, MINIMUM_DIM)
+ ->Unit(benchmark::kMicrosecond);
+#else
+BENCHMARK(BENCHMARK_FLOYD_DITHER)
+ ->RangeMultiplier(2)
+ ->Range(1, MINIMUM_DIM)
+ ->Unit(benchmark::kMicrosecond);
+#endif
+
+#endif
diff --git a/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output b/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output
new file mode 100644
index 00000000..85c29e0e
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output
@@ -0,0 +1 @@
+7b339ccc04bbaebf30f44f4f3129756f
diff --git a/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c b/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c
new file mode 100644
index 00000000..b4be8cfb
--- /dev/null
+++ b/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c
@@ -0,0 +1,72 @@
+/**
+ Source: github -> https://github.com/brianwu02/ImageProcessing.git
+ Modified by Pankaj Kukreja (github.com/proton0001)
+ Indian Institute of Technology Hyderabad
+*/
+#include "dither.h"
+#include <math.h> // pow
+
+#define GAMMA 0.5
+
+void orderedDitherKernel(int height, int width, int inputImage[HEIGHT][WIDTH],
+ int outputImage[height][width],
+ int temp[height][width], int n, int m) {
+ int scale;
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ temp[i][j] =
+ (int)(pow((double)inputImage[i][j] / 255.0, (1.0 / GAMMA)) * 255.0);
+ }
+ }
+
+ scale = 256 / n;
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ outputImage[i][j] = (int)(scale * (temp[i][j] / scale)) / scale;
+ }
+ }
+
+ if (m == 2) {
+ int dither[2][2] = {{0, 2}, {3, 1}};
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int i = x % m;
+ int j = y % m;
+ outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+ }
+ }
+ } else if (m == 3) {
+ int dither[3][3] = {{6, 8, 4}, {1, 0, 3}, {5, 2, 7}};
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int i = x % m;
+ int j = y % m;
+ outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+ }
+ }
+ } else if (m == 4) {
+ int dither[4][4] = {
+ {0, 8, 2, 10}, {12, 4, 14, 6}, {3, 11, 1, 9}, {15, 7, 13, 5}};
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int i = x % m;
+ int j = y % m;
+ outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+ }
+ }
+ } else if (m == 8) {
+ int dither[8][8] = {
+ {0, 48, 12, 60, 3, 51, 15, 63}, {32, 16, 44, 28, 35, 19, 47, 31},
+ {8, 56, 4, 52, 11, 59, 7, 55}, {40, 24, 36, 20, 43, 27, 39, 23},
+ {2, 50, 14, 62, 1, 49, 13, 61}, {34, 18, 46, 30, 33, 17, 45, 29},
+ {10, 58, 6, 54, 9, 57, 5, 53}, {42, 26, 38, 22, 41, 25, 37, 21}};
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int i = x % m;
+ int j = y % m;
+ outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+ }
+ }
+ }
+}