Untitled
unknown
plain_text
9 months ago
3.3 kB
11
Indexable
/*
* ===========================================================================
* OPTIMISATION 3: LOOP UNROLLING & REGISTER CACHING
* ===========================================================================
* This code reverts to baseline and implements the third strategy:
* - Kernel Caching: Loads kernel values into local variables to avoid
* repeated memory fetches inside the loops[cite: 42, 43].
* - Loop Unrolling: The inner x-loop is unrolled by a factor of 2,
* processing two output pixels per iteration to reduce loop overhead
* and increase instruction-level parallelism[cite: 44, 46].
* - NOTE: Retains original 'double' math and boundary checks to isolate
* the effect of these specific techniques.
* ===========================================================================
*/
void conv2d_optimised(
int input[IMAGE_SIZE][IMAGE_SIZE],
int output[IMAGE_SIZE][IMAGE_SIZE],
int kernel[KERNEL_SIZE][KERNEL_SIZE]
) {
int offset = KERNEL_SIZE / 2;
// Kernel Caching: Load kernel into local variables (simulating registers).
// This example is hardcoded for a 3x3 kernel as discussed in the report[cite: 41, 42].
// Note: This path would ideally be taken only if KERNEL_SIZE == 3.
const int k00 = kernel[0][0]; const int k01 = kernel[0][1]; const int k02 = kernel[0][2];
const int k10 = kernel[1][0]; const int k11 = kernel[1][1]; const int k12 = kernel[1][2];
const int k20 = kernel[2][0]; const int k21 = kernel[2][1]; const int k22 = kernel[2][2];
for (int y = 0; y < IMAGE_SIZE; y++) {
// Loop Unrolling: process two pixels per iteration (x and x+1).
for (int x = 0; x < IMAGE_SIZE; x += 2) {
// Accumulators for the two pixels being calculated.
double sum1 = 0.0;
double sum2 = 0.0;
// Manual 3x3 kernel loop for both pixels.
for (int ky = 0; ky < 3; ky++) {
int img_y = y + ky - offset;
// Check row validity once.
if (img_y >= 0 && img_y < IMAGE_SIZE) {
for (int kx = 0; kx < 3; kx++) {
int img_x1 = x + kx - offset;
int img_x2 = (x + 1) + kx - offset;
int k_val = kernel[ky][kx];
// Process pixel 1 (output[y][x])
if (img_x1 >= 0 && img_x1 < IMAGE_SIZE) {
sum1 += (double)input[img_y][img_x1] * k_val;
}
// Process pixel 2 (output[y][x+1])
if ((x + 1) < IMAGE_SIZE && img_x2 >= 0 && img_x2 < IMAGE_SIZE) {
sum2 += (double)input[img_y][img_x2] * k_val;
}
}
}
}
// Store result for the first pixel.
short temp1 = (short)sum1;
int final_val1 = (int)temp1;
output[y][x] = (final_val1 > 0) ? final_val1 : 0;
// Store result for the second pixel, ensuring we don't write out of bounds.
if ((x + 1) < IMAGE_SIZE) {
short temp2 = (short)sum2;
int final_val2 = (int)temp2;
output[y][x+1] = (final_val2 > 0) ? final_val2 : 0;
}
}
}
}Editor is loading...
Leave a Comment