/* Benchmark for http://www.tophatstuff.co.uk/?p=119 Using a Paeth pre-compression filter as described by http://www.gnupdf.org/PNG_and_TIFF_Predictors_Filter#Filter_type_4:_Paeth http://www.w3.org/TR/PNG-Filters.html gcc -O0 -Wall -Wextra -DX_FIRST paeth.c -o paeth_xfirst.elf gcc -O0 -Wall -Wextra paeth.c -o paeth_yfirst.elf ./paeth_xfirst.elf ./paeth_yfirst.elf */ #include #include #include #include #define WIDTH 2048 #define ITERATIONS 20 int PaethPredictor(int a, int b, int c) { int p, pa, pb, pc; // These apply to bytes. // a = left, b = above, c = upper left p = a + b - c; // initial estimate pa = abs(p - a); // distances to a, b, c pb = abs(p - b); pc = abs(p - c); // return nearest of a,b,c, // breaking ties in order a,b,c. if ((pa <= pb) && (pa <= pc)) { return a; } else if (pb <= pc) { return b; } else { return c; } } void TestOutput(unsigned char *data, int w, int h) { int i, x, y; #if WIDTH < 8 # error WIDTH must be at least 8 #endif printf("TestOutput:\n"); for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { i = (y * w) + x; printf("%2d ", data[i]); } printf("\n"); } printf("\n\n"); } int main(void) { int w, h, size; int i, j; int index; int x, y; int a, b, c; clock_t start, end; int seq_length, seq_randomness, seq_base; unsigned char *orig, *filter; /* --- SETUP --- */ w = h = WIDTH; size = w * h; orig = malloc(sizeof(char) * size); filter = malloc(sizeof(char) * size); assert(orig); assert(filter); /* fill with numbers typical of an image */ for (i = 0; i < size; i++) { seq_length = rand() % 80; seq_randomness = 1 + (rand() % 10); seq_base = rand() % 10; for (j = i; (j < size) && (j < (i + seq_length)); j++) { orig[j] = (unsigned char) seq_base + (rand() % seq_randomness); } i = j; } TestOutput(orig, w, h); /* --- MAIN --- */ start = clock(); /* --- Precompression filter (this is what we are timing) --- */ for (i = 0; i < ITERATIONS; i++) { /* fill x=0 and y=0 rows */ for (y = 0; y < h; y++) { index = y * w; filter[index] = orig[index]; } for (x = 0; x < w; x++) { filter[x] = orig[x]; } /* start from 1,1 */ #ifdef X_FIRST for (x = 1; x < w; x++) { for (y = 1; y < h; y++) { #else for (y = 1; y < h; y++) { for (x = 1; x < w; x++) { #endif // a = left, b = above, c = upper left index = (y * w) + x; a = index - 1; b = ((y-1) * w) + x; c = b - 1; filter[index] = orig[index] - PaethPredictor(orig[a], filter[b], filter[c]); } } } end = clock(); TestOutput(filter, w, h); /* --- Verify by undoing the filter --- */ for (i = 0; i < ITERATIONS; i++) { /* start from 1,1 */ for (y = 1; y < h; y++) { for (x = 1; x < w; x++) { // a = left, b = above, c = upper left index = (y * w) + x; a = index - 1; b = ((y-1) * w) + x; c = b - 1; orig[index] = filter[index] + PaethPredictor(orig[a], filter[b], filter[c]); } } } TestOutput(orig, w, h); printf("w=%d, wxh=%d, %f secs\n", w, (w * h), ((double)(end - start)) / ((double) CLOCKS_PER_SEC)); fflush(stdout); return 0; }