/mobile Handheld Friendly website

 performance measurements

Each table row shows performance measurements for this C gcc program with a particular command-line input value N.

 N  CPU secs Elapsed secs Memory KB Code B ≈ CPU Load
1,0000.05?1026  
4,0000.480.13?1026  92% 92% 93% 100%
16,0007.311.8515,9721026  99% 99% 99% 99%

Read the ↓ make, command line, and program output logs to see how this program was run.

Read mandelbrot benchmark to see what this program should do.

 notes

gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu8)

"Two things are possibly cheats: (a) the code checks if a pixel is inside the largest circle or cardioid, and skip the iterations if so because it would not escape. (b) the code only calculates half of the image, then flips it about the x-axis to produce the other half.

These are valid optimizations if we are only interested in generating the image, but if comparing language features/implementations is the sole purpose of the benchmark game, then they could be considered cheats, particularly item (b), since it reduces workload by half."

 mandelbrot C gcc #5 program source code

/* The Computer Language Benchmarks Game
 * http://benchmarksgame.alioth.debian.org/
 *
 * Contributed by Mr Ledrug
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#include <stdint.h>

#define MAX_ITER 50
typedef uint8_t byte;

size_t w, h, row_bytes;
int ncpus;
byte *buf;

double xmin = -1.5, xmax = .5, ymin = -1, ymax = 1;
double dx, dy;

void calc_row(size_t row) {
   byte *pos = buf + row * row_bytes;

   double cx, cy = ymin + row * dy;

   byte mask = 1 << 7;
   size_t i, row_bits = row_bytes * 8;

   int bound = 0;
   for (i = 0; i < row_bits; i++) {
      cx = xmin + i * dx;
      double zx = cx, zy = cy;

      int iter;
      if (bound) {
         double p = cx - 1;
         if (cy * cy + p * p < 1./16)
            goto skip;

         p = cy * cy + (cx - 0.25) * (cx - 0.25);
         if ((p * (p + cx - 0.25)) * 4 < cy * cy)
            goto skip;

         for (iter = MAX_ITER - 1; iter--; ) {
            double x2 = zx * zx, y2 = zy * zy;
            zy = cy + zx * zy * 2;
            zx = cx + x2 - y2;
         }
         bound = (zx * zx + zy * zy) <= 4;

      } else {
         for (iter = MAX_ITER; iter--; ) {
            double x2 = zx * zx, y2 = zy * zy;

            if (x2 + y2 > 4) goto skip;

            zy = cy + zx * zy * 2;
            zx = cx + x2 - y2;
         }
         bound = 1;
      }

skip:
      if (bound) *pos |= mask;
      mask >>= 1;
      if (!mask) {
         mask = 1 << 7;
         pos++;
      }
   }
}

size_t next_row;
void *thread_entry(void *dummy) {
   while (1) {
      size_t r = next_row;
      if (!__sync_bool_compare_and_swap(&next_row, r, r + 1)) {
         volatile int i = 3000;
         while (i--);
         sched_yield();
         continue;
      }

      if (r >= h) return 0;
      calc_row(r);
   }
}

int get_cpus(void) {
   cpu_set_t ct;
   sched_getaffinity(0, sizeof(ct), &ct);
   int i, cnt = 0;
   for (i = 0; i < 16; i++)
      if (CPU_ISSET(i, &ct))
         cnt++;
   return cnt;
}

int main(int artc, char **argv) {
   ncpus = get_cpus();

   w = atoi(argv[1]);
   w = (w + 7) / 8 * 8;
   row_bytes = w / 8;

   dx = (xmax - xmin) / w;
   dy = (ymax - ymin) / w;

   h = w / 2 + 1;

   size_t n_bytes = h * row_bytes;
   buf = calloc(1, n_bytes);

   int i;
   pthread_t tid[16];

   for (i = 0; i < ncpus; i++)
      pthread_create(tid + i, 0, thread_entry, 0);

   for (i = 0; i < ncpus; i++)
      pthread_join(tid[i], 0);

   char header[100];
   sprintf(header, "P4\n%d %d\n", (int)w, (int)w);

   int fd = fileno(stdout);
   write(fd, header, strlen(header));
   write(fd, buf, n_bytes);

   h--;
   while (h-- > 1)
      write(fd, buf + h * row_bytes, row_bytes);

   return 0;
}

 make, command-line, and program output logs

Sat, 19 Oct 2013 18:19:07 GMT

MAKE:
/usr/bin/gcc -pipe -Wall -O3 -fomit-frame-pointer -march=native -std=c99 -mfpmath=sse -msse2 -fopenmp mandelbrot.gcc-5.c -o mandelbrot.gcc-5.gcc_run 
mandelbrot.gcc-5.c: In function ‘main’:
mandelbrot.gcc-5.c:132:9: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
    write(fd, header, strlen(header));
         ^
mandelbrot.gcc-5.c:133:9: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
    write(fd, buf, n_bytes);
         ^
mandelbrot.gcc-5.c:137:12: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
       write(fd, buf + h * row_bytes, row_bytes);
            ^
rm mandelbrot.gcc-5.c
0.14s to complete and log all make actions

COMMAND LINE:
./mandelbrot.gcc-5.gcc_run 16000

(BINARY) PROGRAM OUTPUT NOT SHOWN

Revised BSD license

  Home   Conclusions   License   Play