Я написал некоторый последовательный код, который хотел бы максимально оптимизировать, прежде чем я распараллелю его с помощью OpenMP.Программа читает файл PPM, просматривая данные пикселей в ячейках 4x4 (переменная c
), затем находит среднее значение RGB для каждой из этих ячеек 4x4 и, наконец, записывает в новый файл, выводя средний цветзначение, опять же каждой из 4х4 ячеек.Это создает своего рода эффект мозаики / пикселизации.
После определения производительности моего кода основными узкими местами являются fscanf
и fprintf
.Я игнорирую время выполнения для чтения / записи на диск, поэтому эти две функции не имеют значения.
Мои попытки оптимизировать до сих пор:
Замыкание цикла: в коде есть два вложенных цикла FOR, которые имеют точно такие же условия цикла.Однако второй набор вложенных циклов FOR требует, чтобы функции, необходимые для вычисления среднего значения RGB, оставались за пределами этого конкретного набора.Затем необходимы вычисления среднего значения RGB для использования в третьем наборе вложенных циклов FOR (которые имеют те же условия цикла, что и второй набор).Из-за этого я изо всех сил пытался объединить второй и третий наборы вложенных циклов FOR, несмотря на их сходство.
Вычисления, инвариантные к циклу: я пытался переместить некоторые операции за пределы цикла, где это возможно, но это оказалось трудным.
Подводя итог: Как я могу оптимизировать эту программу, чтобы максимально сократить время выполнения?
Мой код:
typedef struct { //struct holding RGB type int
int r, g, b; //12 bytes
} pixelInt;
typedef struct { //struct holding RGB type unsigned char
unsigned char r, g, b; //3 bytes
} pixel;
int c = 4; // Variable of 4x4 grids
int width, height; //image variable declarations
//Raw 1 dimensional store of pixel data - will contain all the data for each pixel in the image
pixel *data = (pixel *)calloc(width * height, sizeof(pixelInt));
//Loop through entire input image
for (int yy = 0; yy < height; yy += c)
{
for (int xx = 0; xx < width; xx += c)
{
//the total colour of cell of size 'c'
pixelInt cell_tot = { 0, 0, 0 }; //zero initialize struct containing mosaic cell pixel totals.
unsigned int counter = 0; //the counter for how many pixels are in a 4x4 cell
int bx = xx + c; //used in loop conditions
int by = yy + c;
// Store each color from the cell into cell_tot struct
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
unsigned char r, g, b; //maximum vales are 255, i.e. unsigned char data type
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b); //%hhu is unsigned char specifier
//store the pixel value into data array
data[index_1d].r = r;
data[index_1d].g = g;
data[index_1d].b = b;
counter++; //increment counter
//average pixel color of cell
cell_tot.r += r;
cell_tot.g += g;
cell_tot.b += b;
}
}
//average colour of cell found by dividing cell total by loop counter
pixel cell_average;
cell_average.r = cell_tot.r / counter;
cell_average.g = cell_tot.g / counter;
cell_average.b = cell_tot.b / counter;
//Loop through the new image in cells of size c
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
//Assign average cell value to the pixels in the cell
data[index_1d].r = cell_average.r;
data[index_1d].g = cell_average.g;
data[index_1d].b = cell_average.b;
//Output the average colour value for the image
fprintf(f_output, "%hhu %hhu %hhu \t", data[index_1d].r, data[index_1d].g, data[index_1d].b);
}
fprintf(f_output, "\n"); //Prints new line
}
}
}