Оптимизация Медленный Доступ К Трехмерному Массиву

10.01.2008
8
0
#1
Требуется перевести буфер из одного формата в другой по определенной формуле с плавающей точкой, а именно из формата yuyv в формат rgb24 (если это что-то кому то скажет).
Хотел сократить расчеты записав все значения в массив и просто беря оттуда нужные значения.
Но оказывается что каждый раз считать получается быстрее, вопрос почему?
Компилятор gcc.
Привожу тестовый код программы, непосредственный расчет ведется со скоростью 18 циклов/сек, если брать рассчитанные значения из массива - 6 циклов/сек.
Исходный буфер pbuffer заполняю случайными значения от 0 до 255. Если буфер заполнять константами, то скорость большая, но думаю это из-за оптимизации.

C++:
#include <iostream>
#include <time.h>
#include <cstdlib>

using namespace std;

#define rgb_ptr unsigned char*

static const int BPP_YUY2 = 2;
static const int BPP_YUY2_PIXEL = 4;
static const int BPP_RGB24 = 3;

unsigned char tableR[256][256][256];
unsigned char tableG[256][256][256];
unsigned char tableB[256][256][256];

inline char clip(int x){
if (x>255)
return 255;
if (x<0)
return 0;
return x;
}

void yuv2rgb(unsigned char y, unsigned char u, unsigned char v, unsigned char *r, unsigned char *g, unsigned char *b)
{
float C = y - 16;
float D = u - 128;
float E = v - 128;
*r = clip(C + ( 1.402 * E ));
*g = clip(C - ( 0.344136 * D + 0.714136 * E ));
*b = clip(C + ( 1.772 * D ));
}

void fillTables(void)
{
int i,j,k;

for (i=0;i<256;i++)
{
for (j=0;j<256;j++)
for (k=0;k<256;k++)
yuv2rgb(i,j,k,&tableR[i][j][k],&tableG[i][j][k],&tableB[i][j][k]);
}

}

void getTables(unsigned char y, unsigned char u, unsigned char v, unsigned char *r, unsigned char *g, unsigned char *b)
{
*r = tableR[y][u][v];
*g = tableG[y][u][v];
*b = tableB[y][u][v];
}

void yuyv_to_rgb(rgb_ptr buffer_yuyv, rgb_ptr buffer_rgb, int width, int height)
{
rgb_ptr pixel_16;  // for YUYV
rgb_ptr pixel_24;// for RGB
int y0, u0, v0, y1;
unsigned char r, g, b;
unsigned char r1,g1,b1;
if ( buffer_yuyv == NULL || buffer_rgb == NULL)
return;

pixel_16 = buffer_yuyv;//width * height * 2
pixel_24 = buffer_rgb;//width * height * 3

int i = 0, j = 0;
// while ((i + 2) < height * width * 2)
for (i=0;i < (height * width * 2 -2);i=i+BPP_YUY2_PIXEL)
{
y0 = pixel_16[i];
u0 = pixel_16[i+1];
y1 = pixel_16[i+2];
v0 = pixel_16[i+3];

//yuv2rgb(y0, u0, v0, &r, &g, &b);
getTables(y0, u0, v0, &r, &g, &b); // 1st pixel

pixel_24[j] = r;
pixel_24[j + 1] = g;
pixel_24[j + 2] = b;

//yuv2rgb(y1, u0, v0, &r1, &g1, &b1);
getTables(y1, u0, v0, &r1, &g1, &b1);// 2nd pixel

pixel_24[j+BPP_RGB24] = r1;
pixel_24[j + 1 + BPP_RGB24] = g1;
pixel_24[j + 2 + BPP_RGB24] = b1;

j+=BPP_RGB24;
j+=BPP_RGB24;
//i += BPP_YUY2_PIXEL;
}

}

int main()
{
timespec t1;
timespec t2;
double t;
const int ncycles=100;
unsigned char *pdata = new unsigned char[1024*768*2]; //yuv
unsigned char *data = new unsigned char[1024*768*3]; //rgb24

int i;
srand(time(NULL));

fillTables();

for (i=0;i<1024*768*2;i++)
pdata[i] = rand() % 255;

//for (i=0;i<1024*768*2;i++)
//	pdata[i] = i%255;

clock_gettime(1,&t1);

for (i=0;i<ncycles;i++)
{
yuyv_to_rgb(pdata,data,1024,768);
cout<<"#"<<i<<" ";
cout.flush();
}

clock_gettime(1,&t2);

t= (t2.tv_sec-t1.tv_sec)+(t2.tv_nsec-t1.tv_nsec)/1000000000.0; //складываем секунды и наносекунды
cout<<"\nTime: "<<t<< "secs\n";
cout<<"Cycles per sec: "<<ncycles/t<<"\n";

delete pdata;
delete data;
return 0;
}
 

Ne0N

New member
15.04.2013
1
0
#2
В данном случае у тебя размер таблицы под ону размерность цвета составляет 16мб, цвета 3, итого имеем 48 мб таблиц. Доступ к ним у тебя идет случайный, соответственно даже кэш 3го уровня не часто содержит нужных данных, что заставляет тратить несколько десятков, (а то и сотен) процессорных циклов на чтение данных из обычной RAM. Вот и получается, что время прямого расчета по указанным формулам меньше, чем время, потраченное на кэш-промахи и чтение из обычной оперативки.