Untitled
unknown
plain_text
9 months ago
5.1 kB
14
Indexable
/*
* ===========================================================================
* OPTIMISATIONS 1 & 2 COMBINED: INTEGER CONVERSION + IMAGE PADDING
* ===========================================================================
* This code combines the first two optimisation strategies:
* 1. Image Padding: A padded input array is created to eliminate the need
* for boundary-checking 'if' statements in the main loops[cite: 31].
* 2. Integer Conversion: All floating-point 'double' operations are replaced
* with 'int' to leverage native hardware speed and avoid software
* emulation. Function logic is inlined.
* ===========================================================================
*/
void conv2d_optimised(
int input[IMAGE_SIZE][IMAGE_SIZE],
int output[IMAGE_SIZE][IMAGE_SIZE],
int kernel[KERNEL_SIZE][KERNEL_SIZE]
) {
const int pad = KERNEL_SIZE / 2;
const int PADDED_SIZE = IMAGE_SIZE + 2 * pad;
int padded_input[PADDED_SIZE][PADDED_SIZE];
// Initialize the padded array with zeros.
for (int y = 0; y < PADDED_SIZE; y++) {
for (int x = 0; x < PADDED_SIZE; x++) {
padded_input[y][x] = 0;
}
}
// Copy the original image into the center of the padded array[cite: 34].
for (int y = 0; y < IMAGE_SIZE; y++) {
for (int x = 0; x < IMAGE_SIZE; x++) {
padded_input[y + pad][x + pad] = input[y][x];
}
}
// Main convolution loop is now branch-free and uses integer math.
for (int y = 0; y < IMAGE_SIZE; y++) {
for (int x = 0; x < IMAGE_SIZE; x++) {
// Use an integer accumulator.
int sum = 0;
for (int ky = 0; ky < KERNEL_SIZE; ky++) {
for (int kx = 0; kx < KERNEL_SIZE; kx++) {
// Access the padded array directly with no boundary checks[cite: 35].
sum += padded_input[y + ky][x + kx] * kernel[ky][kx];
}
}
// Apply activation function.
if (sum > 0) {
output[y][x] = sum;
} else {
output[y][x] = 0;
}
}
}
}
/*
* ===========================================================================
* OPTIMISATIONS 1, 2, & 3 COMBINED: FINAL VERSION
* ===========================================================================
* This code combines all three optimisation strategies for maximum performance:
* 1. Image Padding: Eliminates branching in the inner loops.
* 2. Integer Conversion: Uses fast, native integer arithmetic.
* 3. Micro-Optimization: Adds Kernel Caching, Loop Unrolling, and Pointer
* Sliding to increase ILP and reduce memory traffic[cite: 40, 64].
* NOTE: This implementation is specialized for KERNEL_SIZE = 3.
* ===========================================================================
*/
void conv2d_optimised(
int input[IMAGE_SIZE][IMAGE_SIZE],
int output[IMAGE_SIZE][IMAGE_SIZE],
int kernel[KERNEL_SIZE][KERNEL_SIZE]
) {
const int pad = KERNEL_SIZE / 2;
const int PADDED_SIZE = IMAGE_SIZE + 2 * pad;
int padded_input[PADDED_SIZE][PADDED_SIZE] = {{0}};
// Copy the original image into the center of the padded array.
for (int y = 0; y < IMAGE_SIZE; y++) {
for (int x = 0; x < IMAGE_SIZE; x++) {
padded_input[y + pad][x + pad] = input[y][x];
}
}
// Kernel Caching: Load 3x3 kernel into local variables (registers).
const int k00 = kernel[0][0], k01 = kernel[0][1], k02 = kernel[0][2];
const int k10 = kernel[1][0], k11 = kernel[1][1], k12 = kernel[1][2];
const int k20 = kernel[2][0], k21 = kernel[2][1], k22 = kernel[2][2];
for (int y = 0; y < IMAGE_SIZE; y++) {
// Pointer Sliding: Set pointers to the start of each relevant row.
int *p_row0 = &padded_input[y][0];
int *p_row1 = &padded_input[y + 1][0];
int *p_row2 = &padded_input[y + 2][0];
// Loop Unrolling: Process two output pixels per iteration.
for (int x = 0; x < IMAGE_SIZE; x += 2) {
// Integer accumulators for two concurrent calculations.
int sum1 = 0;
int sum2 = 0;
// --- Unrolled Kernel Calculation for Pixel 1 (x) ---
sum1 += p_row0[x] * k00 + p_row0[x + 1] * k01 + p_row0[x + 2] * k02;
sum1 += p_row1[x] * k10 + p_row1[x + 1] * k11 + p_row1[x + 2] * k12;
sum1 += p_row2[x] * k20 + p_row2[x + 1] * k21 + p_row2[x + 2] * k22;
// --- Unrolled Kernel Calculation for Pixel 2 (x+1) ---
sum2 += p_row0[x + 1] * k00 + p_row0[x + 2] * k01 + p_row0[x + 3] * k02;
sum2 += p_row1[x + 1] * k10 + p_row1[x + 2] * k11 + p_row1[x + 3] * k12;
sum2 += p_row2[x + 1] * k20 + p_row2[x + 2] * k21 + p_row2[x + 3] * k22;
// Apply activation and store results.
output[y][x] = (sum1 > 0) ? sum1 : 0;
// Ensure we don't write past the end of the row if IMAGE_SIZE is odd.
if (x + 1 < IMAGE_SIZE) {
output[y][x + 1] = (sum2 > 0) ? sum2 : 0;
}
}
}
}
Editor is loading...
Leave a Comment