Skip to content

Image Softening Benchmark

Hüseyin Tuğrul BÜYÜKIŞIK edited this page Oct 20, 2021 · 13 revisions
#include <iostream>
#include <fstream>
#include <mutex>
#include <map>
#include <time.h>
#include <math.h>
#include "LruClockCache.h"

// Mandelbrot set from stackoverflow
int findMandelbrot(double cr, double ci, int max_iterations) {
  int i = 0;
  double zr = 0.0, zi = 0.0;
  while (i < max_iterations && zr * zr + zi * zi < 4.0) {
    double temp = zr * zr - zi * zi + cr;
    zi = 2.0 * zr * zi + ci;
    zr = temp;
    ++i;
  }
  return i;
}

double mapToReal(int x, int imageWidth, double minR, double maxR) {
  double range = maxR - minR;
  return x * (range / imageWidth) + minR;
}

double mapToImaginary(int y, int imageHeight, double minI, double maxI) {
  double range = maxI - minI;
  return y * (range / imageHeight) + minI;
}

int main() {
  // mandelbrot generation + (softening X10) using a cache

  using namespace std;

  std::map < int, int > map;

  int imageWidth, imageHeight, maxN;
  double minR, maxR, minI, maxI;

  imageWidth = 1024;
  imageHeight = 1024;
  maxN = 512;
  minR = -1.5;
  maxR = 0.7;
  minI = -1.0;
  maxI = 1.0;

  size_t readmiss = 0;
  size_t writemiss = 0;
  size_t read = 0;
  size_t write = 0;
  LruClockCache < int, int > cache(1024 * 1024,
    [ & ](int key) {
      readmiss++;
      return map[key];
    },
    [ & ](int key, int value) {
      writemiss++;
      map[key] = value;
    });

  ofstream g("output_image.ppm",ios::binary);
  g << "P6" << endl;
  g << imageWidth << " " << imageHeight << endl;
  g << "255" << endl;

  double start = clock();
  double t = 0;

  for (int i = 0; i < imageHeight; i++) {
    for (int j = 0; j < imageWidth; j++) {
      double cr = mapToReal(j, imageWidth, minR, maxR);
      double ci = mapToImaginary(i, imageHeight, minI, maxI);

      cache.set(i + j * imageWidth, findMandelbrot(cr, ci, maxN));

      read++;
    }
  }

  // image softening (may not be accurate)
  for (int k = 0; k < 10; k++) {
    for (int i = 1; i < imageHeight - 1; i++) {
      for (int j = 1; j < imageWidth - 1; j++) {
        double cr = mapToReal(j, imageWidth, minR, maxR);
        double ci = mapToImaginary(i, imageHeight, minI, maxI);

        int n0 = cache.get(i + j * imageWidth);
        int n1 = cache.get(i + 1 + j * imageWidth);
        int n2 = cache.get(i - 1 + j * imageWidth);
        int n3 = cache.get(i + (j + 1) * imageWidth);
        int n4 = cache.get(i + (j - 1) * imageWidth);
        int n = (n0 + n1 + n2 + n3 + n4) / 5.0;
        cache.set(i + j * imageWidth, n);

        read += 5;
        write++;
      }
    }

  }

  for (int i = 0; i < imageHeight; i++) {
    for (int j = 0; j < imageWidth; j++) {

      int n = cache.get(i + j * imageWidth);

      int r = ((int) sqrt(n) % 256);
      int gr = (2 * n % 256);
      int b = (n % 256);
      write++;
      g << (char) r << (char) gr << (char) b;
    }

  }
  cout << "Finished!" << endl;

  double stop = clock();

  cout << (stop - start) / CLOCKS_PER_SEC;

  cache.flush();

  g.flush();

  cout << endl << t << endl;
  std::cout << (read - readmiss) / (double) read << std::endl;
  std::cout << (write - writemiss) / (double) write << std::endl;
  return 0;
}

FX8150: 2.2 seconds (~28 million pixels per second)

https://www.codechef.com/ide: 2.3 seconds (~27.5 million pixels per second) (old version)

http://cpp.sh: 2.2 seconds (28 million pixels per second)(old version)

https://www.tutorialspoint.com/compile_cpp_online.php: 8.8 seconds(old version)

https://www.programiz.com/cpp-programming/online-compiler: 17 seconds(old version)