| /** |
| Pankaj Kukreja |
| github.com/proton0001 |
| Indian Institute of Technology Hyderabad |
| */ |
| #include "ImageHelper.h" |
| #include "dither.h" |
| #include <cmath> |
| #include <cstdlib> |
| #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); |
| |
| while (state.KeepRunning()) { |
| 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->ArgPair(i, 2); |
| b->ArgPair(i, 3); |
| b->ArgPair(i, 4); |
| b->ArgPair(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); |
| while (state.KeepRunning()) { |
| 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 |