Untitled
unknown
plain_text
9 months ago
3.7 kB
15
Indexable
#include "conv2d.h"
// Define constants for the padded image dimensions.
#define PADDING (KERNEL_SIZE / 2)
#define PADDED_SIZE (IMAGE_SIZE + 2 * PADDING)
/*
* OPTIMIZE THIS FUNCTION
*/
void conv2d_optimised(
int input[IMAGE_SIZE][IMAGE_SIZE],
int output[IMAGE_SIZE][IMAGE_SIZE],
int kernel[KERNEL_SIZE][KERNEL_SIZE]
) {
// A static array avoids stack overflow and is auto-initialized to zero.
static int padded_input[PADDED_SIZE][PADDED_SIZE];
// ==================================================================
// OPTIMIZATION: PADDING LOOP UNROLLED 8x WITH POINTERS
// ==================================================================
for (int y = 0; y < IMAGE_SIZE; y++) {
// Pointers to the start of the source and destination rows.
int *p_in = &input[y][0];
int *p_pad = &padded_input[y + PADDING][PADDING];
int x = 0;
// Process 8 elements at a time using pointers.
for (; x <= IMAGE_SIZE - 8; x += 8) {
p_pad[x] = p_in[x];
p_pad[x + 1] = p_in[x + 1];
p_pad[x + 2] = p_in[x + 2];
p_pad[x + 3] = p_in[x + 3];
p_pad[x + 4] = p_in[x + 4];
p_pad[x + 5] = p_in[x + 5];
p_pad[x + 6] = p_in[x + 6];
p_pad[x + 7] = p_in[x + 7];
}
// Cleanup for remaining elements.
for (; x < IMAGE_SIZE; x++) {
p_pad[x] = p_in[x];
}
}
#if KERNEL_SIZE == 3
// Kernel Caching: Load kernel into local variables.
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 for the three input rows.
int *p_row0 = &padded_input[y][0];
int *p_row1 = &padded_input[y + 1][0];
int *p_row2 = &padded_input[y + 2][0];
// ==================================================================
// OPTIMIZATION: X-LOOP UNROLLED 2x WITH MULTIPLE SUMS (PIPELINING)
// ==================================================================
for (int x = 0; x < IMAGE_SIZE; x += 2) {
// Independent accumulators to reduce data dependency and enable pipelining.
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;
if (x + 1 < IMAGE_SIZE) {
output[y][x + 1] = (sum2 > 0) ? sum2 : 0;
}
}
}
#else
// Fallback for other kernel sizes.
for (int y = 0; y < IMAGE_SIZE; y++) {
for (int x = 0; x < IMAGE_SIZE; x++) {
int sum = 0;
for (int ky = 0; ky < KERNEL_SIZE; ky++) {
for (int kx = 0; kx < KERNEL_SIZE; kx++) {
sum += padded_input[y + ky][x + kx] * kernel[ky][kx];
}
}
output[y][x] = (sum > 0) ? sum : 0;
}
}
#endif
}Editor is loading...
Leave a Comment