LINUX.ORG.RU

Как можно затюнинговать этот участок кода?

 , , ,


4

13

Я не програмист и С знаю достаточно плохо, но вот тут хочеться разобраться и попытаться оптимизировать этот участок. Это код из gstreamer, который участвует в перегоне RGB в UYV http://cgit.freedesktop.org/gstreamer/gst-plugins-base/tree/gst/videoconvert/...

#define SCALE    (8)
#define SCALE_F  ((float) (1 << SCALE))

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer pixels)
{
  int i;
  int r, g, b;
  int y, u, v;
  guint8 *p = pixels;

  for (i = 0; i < convert->width; i++) {
    r = p[i * 4 + 1];
    g = p[i * 4 + 2];
    b = p[i * 4 + 3];

    y = (convert->cmatrix[0][0] * r + convert->cmatrix[0][1] * g +
        convert->cmatrix[0][2] * b + convert->cmatrix[0][3]) >> SCALE;
    u = (convert->cmatrix[1][0] * r + convert->cmatrix[1][1] * g +
        convert->cmatrix[1][2] * b + convert->cmatrix[1][3]) >> SCALE;
    v = (convert->cmatrix[2][0] * r + convert->cmatrix[2][1] * g +
        convert->cmatrix[2][2] * b + convert->cmatrix[2][3]) >> SCALE;

    p[i * 4 + 1] = CLAMP (y, 0, 255);
    p[i * 4 + 2] = CLAMP (u, 0, 255);
    p[i * 4 + 3] = CLAMP (v, 0, 255);
  }
}

При записи скринкаста в фуллхд videoconvert_convert_matrix8 жрет нереально много времени. Может чей-то опытый глаз поможет, хоть напрвит в сторону чего тут можно оптимизировать. например i * 4 повторяеться 6 раз, хотя понимаю что оно то почти и не дает нагрузку.

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 3)

Ответ на: комментарий от Carb_blog2

Что-то ты не то говоришь. Количество потоков определяешь ты сам. Скажем, если у тебя 4 ядра, то уже где-то 4-6 потоков значительно ускорят вычисления. Критических участков у тебя нет, не нужно будет блокировки использовать.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Что-то ты не то говоришь.

Маловероятно.

Количество потоков определяешь ты сам.

Не имеет значения.

Скажем, если у тебя 4 ядра, то уже где-то 4-6 потоков значительно ускорят вычисления.

Какой жопой?

Критических участков у тебя нет, не нужно будет блокировки использовать.

Какая нахрен разница?

Ещё раз, оно спавнит треды. Допустим у тебя 4ведра:

#pragma govno_paralel
for(0 ... 4k){}
//это переделывается в:
work1() { for(0 ... 1k) {} }
work2() { for(1k ... 2k) {} }
work3() { for(2k ... 3k) {} }
work4() { for(3k ... 4k) {} }
run_thread(work1);//вот это стоит много
run_thread(work2);//и это
run_thread(work3);//и это
run_thread(work4);//и это
wait_thread(work1);//это синхронизация
wait_thread(work2);//и это
wait_thread(work3);//и это
wait_thread(work4);//и это

Т.е. ведро должно создать 4нитки, запустить их и твоя мэйн нить будет в локе до последнего вайта.

Если бы эта функция вызывалась на каждый кадр - надо было создать всего 24*4 треда, но она юзается на каждую строку кадра - т.е. в фуллхд - это 1080вызовов на кадр * 24.

Посчитать сколько можно заспавнить треджоинов(т.е. заспавнил 4нитки, поджал 4нитки и так в цикле) ты можешь сам - напиши бенч.

Carb_blog2
()
Ответ на: комментарий от anonymous

Я добавил sse и gstreamer методы https://github.com/pontostroy/rgb2yuv-bench

rgb2yuv_wiki: 0.629 sec
rgb2yuv_novell_ch: 0.398 sec
rgb2yuv_tables: 0.340 sec
rgb2yuv_gstreamer: 0.356 sec
rgb2yuv_sse: 0.096 sec

0: 0 0 0 0 0
1: 161 154 154 155 155
2: 79 79 79 80 80
3: 159 150 150 147 147
4: 0 0 0 0 0
5: 122 121 121 112 112
6: 100 101 101 105 105
7: 205 183 183 182 182
8: 0 0 0 0 0
9: 69 76 76 74 74
10: 131 132 132 131 131
11: 131 131 131 131 131
12: 0 0 0 0 0
13: 179 170 170 188 188
14: 82 83 83 74 74
15: 40 66 66 60 60

Разброс между ними конечно суровый, но главное что у sse и gsteamer результат один, а разница в скорости почти 4-кратная

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

Пробовал с openmp, загрузка была еще выше

А-а, эта функция обрабатывает только одну строку? Ну тогда Carb_blog2 прав, накладные расходы будут слишком большие. Вы можете эту OpenMP-прагму воткнуть перед циклом который проходит по строкам

Deleted
()
Ответ на: комментарий от Novell-ch

Я добавил ещё один «кроссплатформенный» вариант - rgb2yuv_tables64. На 32-битной ОС он быстрее на 15% относительно rgb2yuv_tables. Интересно посмотреть на 64-битной.

Твой rgb2yuv_gstreamer.c - нечестный, в оригинале там не константы, а переменные, которые компилятор оптимизировать не может.

anonymous
()
Ответ на: комментарий от Novell-ch

Накати - тут более приближенный к реальности тест, а так же ещё одна функция с шафлом вместо сдвигов - она поидее должна быть побыстрее, ибо на твоём ивике 2порта с шафлом и 1 с шифтом: http://pastebin.com/u08GPu1M

Твой тест:

rgb2yuv_wiki: 0.325 sec
rgb2yuv_novell_ch: 0.229 sec
rgb2yuv_tables: 0.208 sec
rgb2yuv_gstreamer: 0.180 sec
rgb2yuv_sse: 0.068 sec

После патча:

rgb2yuv_wiki: (1048576)4KB: total 4GB: 1.147320GB/s
rgb2yuv_novell_ch: (1048576)4KB: total 4GB: 1.633184GB/s
rgb2yuv_tables: (1048576)4KB: total 4GB: 1.813355GB/s
rgb2yuv_gstreamer: (1048576)4KB: total 4GB: 2.063535GB/s
rgb2yuv_sse: (1048576)4KB: total 4GB: 5.547196GB/s
rgb2yuv_sse2: (1048576)4KB: total 4GB: 6.473663GB/s

Даже у меня быстрее, вроде она правильно считает - я не проверял особо - мне лень. Там ещё раскомментируй анрольчик.

Carb_blog2
()
Ответ на: комментарий от anonymous

Уменьшил PIXELS_COUNT (85 * 1000 * 1000) а то уже не компилиться. Но прирост внушает.

rgb2yuv_wiki: 0.536 sec
rgb2yuv_novell_ch: 0.339 sec
rgb2yuv_tables: 0.290 sec
rgb2yuv_tables64: 0.154 sec
rgb2yuv_gstreamer: 0.302 sec
rgb2yuv_sse: 0.082 sec
0: 0 0 0 0 0 0
1: 83 88 88 88 85 85
2: 167 168 168 168 167 167
3: 114 118 118 118 121 121
4: 0 0 0 0 0 0
5: 179 170 170 170 176 176
6: 165 165 165 165 159 159
7: 53 75 75 75 76 76
8: 0 0 0 0 0 0
9: 74 80 80 80 77 77
10: 136 137 137 137 137 137
11: 136 134 134 134 134 134
12: 0 0 0 0 0 0
13: 83 87 87 87 89 89
14: 131 131 131 131 129 129
15: 110 115 115 115 115 115

Так ведь можно взять перменные из матрицы и сохранить их при первом запуске функции, как я и делал а дальше еще можно построить таблицу для того же алгоритма что в gstreamer и пользоваться таблицей.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от anonymous

i7-4770K@4.5

rgb2yuv_tables: 0.216 sec
rgb2yuv_tables64: 0.119 sec
//вытащил инит
rgb2yuv_tables: 0.207 sec
rgb2yuv_tables64: 0.113 sec

Твой rgb2yuv_gstreamer.c - нечестный, в оригинале там не константы, а переменные, которые компилятор оптимизировать не может.

У тебя тоже. И что же ему помешает? Не запишет их в код?

Carb_blog2
()
Ответ на: комментарий от Carb_blog2
rgb2yuv_wiki: (1048576)4KB: total 4GB: 0.557117GB/s
rgb2yuv_novell_ch: (1048576)4KB: total 4GB: 0.880680GB/s
rgb2yuv_tables: (1048576)4KB: total 4GB: 0.977739GB/s
rgb2yuv_gstreamer: (1048576)4KB: total 4GB: 0.982648GB/s
rgb2yuv_sse: (1048576)4KB: total 4GB: 3.830584GB/s
rgb2yuv_sse2: (1048576)4KB: total 4GB: 4.511046GB/s

считает вроде верно, только числа везде одинаковые, проверю вскоре боем.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

Но прирост внушает.

Ага, я так и ожидал, что в пару раз быстрее на x64.

Так ведь можно взять перменные из матрицы и сохранить их при первом запуске функции, как я и делал а дальше еще можно построить таблицу для того же алгоритма что в gstreamer и пользоваться таблицей.

Ага, я к тому, что мы сейчас меряем не то. Я свои реализации писал на основе твоей, потому что не охота было запариваться с выдергиванием коэффициентов из gstreamer. Сейчас лучше все переделать на получение коэффициентов из-вне.

anonymous
()
Ответ на: комментарий от Carb_blog2

Ага, спасибо за тесты.

У тебя тоже. И что же ему помешает? Не запишет их в код?

Да и у меня тоже, надо все тесты переделывать. Пути компилятора неисповедимы...

anonymous
()
Ответ на: комментарий от Novell-ch
rgb2yuv_wiki: (1048576)4KB: total 4GB: 0.556727GB/s
rgb2yuv_novell_ch: (1048576)4KB: total 4GB: 0.880667GB/s
rgb2yuv_tables: (1048576)4KB: total 4GB: 0.973720GB/s
rgb2yuv_tables64: (1048576)4KB: total 4GB: 1.842803GB/s
rgb2yuv_gstreamer: (1048576)4KB: total 4GB: 0.986475GB/s
rgb2yuv_sse: (1048576)4KB: total 4GB: 3.694469GB/s
rgb2yuv_sse2: (1048576)4KB: total 4GB: 4.471938GB/s
0: 0 0 0 0 0 0 0
1: 127 125 16 15 125 125 125
2: 128 128 128 228 127 127 127
3: 126 127 128 125 125 125 125
4: 0 0 0 0 0 0 0
5: 127 125 16 239 124 124 124
6: 127 128 128 106 127 127 127
7: 127 127 128 102 126 126 126
8: 0 0 0 0 0 0 0
9: 127 125 16 225 124 124 124
10: 127 128 128 90 127 127 127
11: 127 127 128 77 126 126 126
12: 0 0 0 0 0 0 0
13: 127 125 16 236 124 124 124
14: 128 128 128 158 127 127 127

Буду пробовать sse2 и табличный64,

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от anonymous

я этим и занимаюсь сейчас я получаю из матрицы

int k_r[] = { p00, p01, p02 };
	int k_g[] = { p04, p05, p06 };
	int k_b[] = { p08, p09, p10 };
заполняю таблицу этими данными до дальше пошла такая магия что я не понимаю
int64_t c1 = (128LL << 32) + (128 << 16) + 128 +
			(16LL << 40) + (128 << 24) + (128 << 8);

нужно

#define RGB2Y(R, G, B) CLIP(( (  66 * (R) + 129 * (G) +  25 * (B) + 128) >> 8) +  16)
#define RGB2U(R, G, B) CLIP(( ( -38 * (R) -  74 * (G) + 112 * (B) + 128) >> 8) + 128)
#define RGB2V(R, G, B) CLIP(( ( 112 * (R) -  94 * (G) -  18 * (B) + 128) >> 8) + 128)
привети в
#define RGB2Y(R, G, B) ((  p00 * (R) + p01 * (G) +  p02 * (B) + p04) >> SCALE
#define RGB2U(R, G, B) ((  p04 * (R) +  p05 * (G) + p06 * (B) + p07) >> SCALE
#define RGB2V(R, G, B) ((  p08 * (R) +  p09 * (G) +  p10 * (B) + p11) >> SCALE

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

главное что у sse и gsteamer результат один, а разница в скорости почти 4-кратная

Вопрос на засыпку - почему тормозит софт?)

devl547 ★★★★★
()
Ответ на: комментарий от Novell-ch
#define RGB2Y(R, G, B) ((  p00 * (R) + p01 * (G) +  p02 * (B) + p03) >> SCALE
#define RGB2U(R, G, B) ((  p04 * (R) +  p05 * (G) + p06 * (B) + p07) >> SCALE
#define RGB2V(R, G, B) ((  p08 * (R) +  p09 * (G) +  p10 * (B) + p11) >> SCALE

int k_r[] = { p00, p04, p08 };
int k_g[] = { p01, p05, p09 };
int k_b[] = { p02, p06, p10 };
int64_t c1 = ((uint64_t) p03 << 32) + (p07 << 16) + p11

Это векторизация для бедных - внутри одного int64 хранятся YUV компоненты каждая по 16 бит. И всё ускорения за счет одновременного вычисления всех компонент.

Но по твоим результатам видно, что где-то есть ошибочка в этой реализации.

anonymous
()
Ответ на: комментарий от anonymous

Но по твоим результатам видно, что где-то есть ошибочка в этой реализации.

Исправил у себя. Там знаковый сдвинутый int32 не должен расширятся до int64.

@@ -37,7 +37,7 @@ void rgb2yuv_tables64(uint8_t *pixels, int count)
 	int t;
 	uint8_t r, g, b;
 	int64_t c1 = (128LL << 32) + (128 << 16) + 128 +
-			(16LL << 40) + (128 << 24) + (128 << 8);
+			(16LL << 40) + (128LL << 24) + (128 << 8);
 
 	for (t = 0; t < count * 4; t += 4)
 	{
anonymous
()
Ответ на: комментарий от anonymous

да оно показывало и так и так нормально из вашего, в моем же при изменении через тот патч табличные перестают показвать нормальные результаты.

У меня проблема в другом, попытка адаптировать sse2 и tabl64 ни к чему не приводит, все собирается, но он перестает использовать videoconvert_convert_matrix8, и нет в логах ничего внятного что ему не нравиться.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

я был не прав, просто videoconvert_convert_matrix8 начинаем потреблять сотые процента, так что его сложно найти в perf top, только результат видео розово зеленый получаеться. Но в общем кадры идут, текст виден. быдло код таков.

static int p00,p01,p02,p03;
static int p04,p05,p06,p07;
static int p08,p09,p10,p11;
static int op=0;

static int64_t t_r3[256], t_g3[256], t_b3[256];

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p)
{
 while (op<2) {
  p00=convert->cmatrix[0][0];
  p01=convert->cmatrix[0][1];
  p02=convert->cmatrix[0][2];
  p03=convert->cmatrix[0][3];
  p04=convert->cmatrix[1][0];
  p05=convert->cmatrix[1][1];
  p06=convert->cmatrix[1][2];
  p07=convert->cmatrix[1][3];
  p08=convert->cmatrix[2][0];
  p09=convert->cmatrix[2][1];
  p10=convert->cmatrix[2][2];
  p11=convert->cmatrix[2][3];
   
int i, j;
int k_r[] = { p00, p04, p08 };
int k_g[] = { p01, p05, p09 };
int k_b[] = { p02, p06, p10 };


	for (i = 0; i <= 255; i++)
	{
		int64_t r = 0, g = 0, b = 0;
		for (j = 0; j <= 2; j++)
		{
			r = (r << 16) + k_r[j] * i;
			g = (g << 16) + k_g[j] * i;
			b = (b << 16) + k_b[j] * i;
		}
		t_r3[i] = r;
		t_g3[i] = g;
		t_b3[i] = b; 
  op=2;
  }
	int t;
	uint8_t r, g, b;
	int64_t c1 = ((uint64_t) p03 << 32) + (p07 << 16) + p11;
       guint8 *pixels = p;
	for (t = 0; t < convert->width * 4; t += 4)
	{
		r = pixels[t + 1];
		g = pixels[t + 2];
		b = pixels[t + 3];

		int64_t x3 = t_r3[r] + t_g3[g] + t_b3[b] + c1;

		pixels[t + 1] = x3 >> 40;
		pixels[t + 2] = x3 >> 24;
		pixels[t + 3] = x3 >> 8;
	}
 }
}
Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

Проблема скорее всего в значениях коэффициентов - они ограничены. p03, p07, p11 - 16 бит, остальные - 8 бит.

Покажи значения всех коэффициентов.

anonymous
()
Ответ на: комментарий от anonymous

они такие

#define RGB2Y(R, G, B) (( (  47 * (R) + 157 * (G) +  16 * (B) + 4096) >> SCALE)
#define RGB2U(R, G, B) ((( ( -26 * (R) +  -87 * (G) + 112 * (B) + 32768) >> SCALE)
#define RGB2V(R, G, B) ((( ( 112 * (R) +  -102 * (G) +  -10 * (B) + 32768) >> SCALE)
и не меняются, сейчас вот проверил с «моим» алгоритмом, все работает

static int64_t t_r3[256], t_g3[256], t_b3[256];
static int op=0;

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p)
{
 while (op<2) {   
int i, j;
	int k_r[] = {  66, -38, 112 };
	int k_g[] = { 129, -74, -94 };
	int k_b[] = {  25, 112, -18 };


	for (i = 0; i <= 255; i++)
	{
		int64_t r = 0, g = 0, b = 0;
		for (j = 0; j <= 2; j++)
		{
			r = (r << 16) + k_r[j] * i;
			g = (g << 16) + k_g[j] * i;
			b = (b << 16) + k_b[j] * i;
		}
		t_r3[i] = r;
		t_g3[i] = g;
		t_b3[i] = b;
		op=2;
	}
 }
  int t;
	uint8_t r, g, b;
	guint8 *pixels = p;
	int64_t c1 = (128LL << 32) + (128 << 16) + 128 +
			(16LL << 40) + (128LL << 24) + (128 << 8);

	for (t = 0; t < convert->width * 4; t += 4)
	{
		r = pixels[t + 1];
		g = pixels[t + 2];
		b = pixels[t + 3];

		int64_t x3 = t_r3[r] + t_g3[g] + t_b3[b] + c1;

		pixels[t + 1] = x3 >> 40;
		pixels[t + 2] = x3 >> 24;
		pixels[t + 3] = x3 >> 8;
	}
}

и при этом

 Performance counter stats for process id '25765':

      16838.452312 task-clock                #    0.260 CPUs utilized          
            25,274 context-switches          #    0.002 M/sec                  
             2,386 cpu-migrations            #    0.142 K/sec                  
             1,774 page-faults               #    0.105 K/sec                  
    51,113,181,950 cycles                    #    3.036 GHz                    
    11,444,873,761 stalled-cycles-frontend   #   22.39% frontend cycles idle   
   <not supported> stalled-cycles-backend  
   137,791,947,677 instructions              #    2.70  insns per cycle        
                                             #    0.08  stalled cycles per insn
     7,999,685,222 branches                  #  475.084 M/sec                  
        29,238,725 branch-misses             #    0.37% of all branches        
   <not supported> L1-dcache-loads:HG      
       820,831,013 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       343,732,325 LLC-loads:HG              #   20.414 M/sec                  
   <not supported> LLC-load-misses:HG      

      64.883041228 seconds time elapsed
рельаный успех, с sse 20% получатеться,а тут с 38% до 26 без всяких sse, мозг у вас то надо, а если учесть первоначальные 48% вообще отвал башки. Осталось перевести tabl64 на алогоритм gstreamer и кинуть им в разработчиков. int k_r[] = { convert->cmatrix[0][0], ..., ..... }; можно так заполнить, без лишних p00, но вот эта магия со смещениями, я ее не заборю.

Novell-ch ★★★★★
() автор топика
Последнее исправление: Novell-ch (всего исправлений: 1)
Ответ на: комментарий от Novell-ch

Да запилите уже тривиальной (исчерпывающей) табличкой. :) 64M — не так и много для задач преобразования видео.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

64M — не так и много для задач преобразования видео.

Самоубейся, а? А мы еще думаем, что это всё тормозит.

devl547 ★★★★★
()
Ответ на: комментарий от intelfx

not u!

Во-первых, такие вещи нельзя делать без возможности выбора опции.
Во-вторых, это вообще можно делать на GPU.

devl547 ★★★★★
()
Ответ на: комментарий от devl547

Во-первых, такие вещи нельзя делать без возможности выбора опции.

Согласен. Или табличкой, или пусть тормозит.

Во-вторых, это вообще можно делать на GPU.

Как мы уже выяснили, кодовая база gstreamer является независимой от оборудования. Иначе можно было бы просто сделать на интринсиках (и вообще, выше уже сделали).

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

кодовая база gstreamer является независимой от оборудования.

Блеск и нищета опенсорса.

Иначе можно было бы просто сделать на интринсиках

Видимо они не умеют в ifdef.

devl547 ★★★★★
()
Последнее исправление: devl547 (всего исправлений: 1)
Ответ на: комментарий от intelfx

кодовая база gstreamer является независимой от оборудования

База конечно, но это не мешает производителям железа предоставлять свои аппаратно-зависимые расширения - http://processors.wiki.ti.com/index.php/GStreamer.

anonymous
()
Ответ на: комментарий от Novell-ch

с sse 20% получатеться,а тут с 38% до 26 без всяких sse

Реализация table64 всё-таки заточена под 64-бита, под 32-бита она незначительно лучше простого table.

но вот эта магия со смещениями, я ее не заборю

Я изменил у себя интерфейс вызовов тестов на GStreamer-подобный. Теперь их перенести не сложно.

anonymous
()
Ответ на: комментарий от anonymous
static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p)
{
 while (op<2) {   
int i, j;
	int k_r[] = { convert->cmatrix[0][0], convert->cmatrix[1][0], convert->cmatrix[2][0] };
	int k_g[] = { convert->cmatrix[0][1], convert->cmatrix[1][1], convert->cmatrix[2][1] };
	int k_b[] = { convert->cmatrix[0][2], convert->cmatrix[1][2], convert->cmatrix[2][2] };


	for (i = 0; i <= 255; i++)
	{
		int64_t r = 0, g = 0, b = 0;
		for (j = 0; j <= 2; j++)
		{
			r = (r << 16) + k_r[j] * i;
			g = (g << 16) + k_g[j] * i;
			b = (b << 16) + k_b[j] * i;
		}
		t_r3[i] = r;
		t_g3[i] = g;
		t_b3[i] = b;
		op=2;
	}
 }
  int t;
	uint8_t r, g, b;
	guint8 *pixels = p;
	int64_t c1 = ((uint64_t) convert->cmatrix[0][3] << 32) + (convert->cmatrix[1][3] << 16) + (convert->cmatrix[2][3]);

	for (t = 0; t < convert->width * 4; t += 4)
	{
		r = pixels[t + 1];
		g = pixels[t + 2];
		b = pixels[t + 3];

		int64_t x3 = t_r3[r] + t_g3[g] + t_b3[b] + c1;

		pixels[t + 1] = x3 >> 40;
		pixels[t + 2] = x3 >> 24;
		pixels[t + 3] = x3 >> 8;
	}
}

дает желтизну и ничего не поделать, вот патч на твой гит http://pastebin.com/bHTL3xqu там вики заменен на гстреамер(которы отлично работает без желтого), и табл64 использует алгоритм гстреамера, они выдают один и тот же результат, но в самом гстреамере табличный64 не хочет верно работать.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch
int64_t c1 = ((int64_t) convert->cmatrix[0][3] << 32) + ((int64_t) convert->cmatrix[1][3] << 16) + (convert->cmatrix[2][3]);
anonymous
()
Ответ на: комментарий от anonymous

помогло

int64_t c = ((int64_t) convert->cmatrix[0][3] << 32)
			+ ((int64_t) convert->cmatrix[1][3] << 16)
			+ ((int64_t) convert->cmatrix[2][3] << 0);

Performance counter stats for process id '17523':

      18862.102342 task-clock                #    0.272 CPUs utilized          
            30,875 context-switches          #    0.002 M/sec                  
             4,253 cpu-migrations            #    0.225 K/sec                  
             1,858 page-faults               #    0.099 K/sec                  
    56,563,008,115 cycles                    #    2.999 GHz                    
    13,637,059,458 stalled-cycles-frontend   #   24.11% frontend cycles idle   
   <not supported> stalled-cycles-backend  
   149,019,018,585 instructions              #    2.63  insns per cycle        
                                             #    0.09  stalled cycles per insn
     8,822,857,677 branches                  #  467.756 M/sec                  
        32,225,169 branch-misses             #    0.37% of all branches        
   <not supported> L1-dcache-loads:HG      
       860,977,224 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       368,779,426 LLC-loads:HG              #   19.551 M/sec                  
   <not supported> LLC-load-misses:HG      

      69.386963059 seconds time elapsed

финальный результат такой, может примут в апстим, завтра потестю на 32 битах.

static int op=0;
static int64_t t_r3[256], t_g3[256], t_b3[256];

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p)
{
 while (op<2) {   
int i, j;
	int k_r[] = { convert->cmatrix[0][0], convert->cmatrix[1][0], convert->cmatrix[2][0] };
	int k_g[] = { convert->cmatrix[0][1], convert->cmatrix[1][1], convert->cmatrix[2][1] };
	int k_b[] = { convert->cmatrix[0][2], convert->cmatrix[1][2], convert->cmatrix[2][2] };


	for (i = 0; i <= 255; i++)
	{
		int64_t r = 0, g = 0, b = 0;
		for (j = 0; j <= 2; j++)
		{
			r = (r << 16) + k_r[j] * i;
			g = (g << 16) + k_g[j] * i;
			b = (b << 16) + k_b[j] * i;
		}
		t_r3[i] = r;
		t_g3[i] = g;
		t_b3[i] = b;
		op=2;
	}
 }
  int t;
	uint8_t r, g, b;
	guint8 *pixels = p;
	int64_t c = ((int64_t) convert->cmatrix[0][3] << 32)
			+ ((int64_t) convert->cmatrix[1][3] << 16)
			+ ((int64_t) convert->cmatrix[2][3] << 0);

	for (t = 0; t < convert->width * 4; t += 4)
	{
		r = pixels[t + 1];
		g = pixels[t + 2];
		b = pixels[t + 3];

		int64_t x3 = t_r3[r] + t_g3[g] + t_b3[b] + c;

		pixels[t + 1] = x3 >> 40;
		pixels[t + 2] = x3 >> 24;
		pixels[t + 3] = x3 >> 8;
	}
}

Novell-ch ★★★★★
() автор топика
Последнее исправление: Novell-ch (всего исправлений: 1)
Ответ на: комментарий от Novell-ch

итого x86 stock\table64

Performance counter stats for process id '2427':

      24441.388683 task-clock                #    0.555 CPUs utilized          
            16,117 context-switches          #    0.659 K/sec                  
               219 cpu-migrations            #    0.009 K/sec                  
             5,233 page-faults               #    0.214 K/sec                  
    77,409,381,175 cycles                    #    3.167 GHz                    
    26,292,718,337 stalled-cycles-frontend   #   33.97% frontend cycles idle   
   <not supported> stalled-cycles-backend  
   197,607,036,204 instructions              #    2.55  insns per cycle        
                                             #    0.13  stalled cycles per insn
    12,292,242,916 branches                  #  502.927 M/sec                  
        21,693,862 branch-misses             #    0.18% of all branches        
   <not supported> L1-dcache-loads:HG      
       481,143,745 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       239,777,528 LLC-loads:HG              #    9.810 M/sec                  
   <not supported> LLC-load-misses:HG      

      44.023759316 seconds time elapsed



Performance counter stats for process id '2822':

      16221.909026 task-clock                #    0.339 CPUs utilized          
            15,932 context-switches          #    0.982 K/sec                  
             1,189 cpu-migrations            #    0.073 K/sec                  
             3,315 page-faults               #    0.204 K/sec                  
    51,320,206,381 cycles                    #    3.164 GHz                    
    13,246,360,560 stalled-cycles-frontend   #   25.81% frontend cycles idle   
   <not supported> stalled-cycles-backend  
   127,814,464,535 instructions              #    2.49  insns per cycle        
                                             #    0.10  stalled cycles per insn
     5,902,096,929 branches                  #  363.835 M/sec                  
        21,703,222 branch-misses             #    0.37% of all branches        
   <not supported> L1-dcache-loads:HG      
       608,012,138 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       250,741,676 LLC-loads:HG              #   15.457 M/sec                  
   <not supported> LLC-load-misses:HG      

      47.831511910 seconds time elapsed

x86_64 stock\table64

Performance counter stats for process id '3506':

      23258.800974 task-clock                #    0.455 CPUs utilized          
            18,130 context-switches          #    0.779 K/sec                  
             2,288 cpu-migrations            #    0.098 K/sec                  
             1,331 page-faults               #    0.057 K/sec                  
    73,692,193,376 cycles                    #    3.168 GHz                    
    21,218,974,690 stalled-cycles-frontend   #   28.79% frontend cycles idle   
   <not supported> stalled-cycles-backend  
   198,710,985,363 instructions              #    2.70  insns per cycle        
                                             #    0.11  stalled cycles per insn
    14,252,859,241 branches                  #  612.794 M/sec                  
        22,748,214 branch-misses             #    0.16% of all branches        
   <not supported> L1-dcache-loads:HG      
       566,065,245 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       267,280,364 LLC-loads:HG              #   11.492 M/sec                  
   <not supported> LLC-load-misses:HG      

      51.148678220 seconds time elapsed
      
Performance counter stats for process id '3379':                                                                                                                                   
                                                                                                                                                                                    
      12461.157685 task-clock                #    0.250 CPUs utilized  
             5,485 context-switches          #    0.001 M/sec       
               238 cpu-migrations            #    0.019 K/sec                                                                
             8,634 page-faults               #    0.693 K/sec                                                                                                  
    39,284,950,355 cycles                    #    3.153 GHz                                                                                     
     8,891,423,340 stalled-cycles-frontend   #   22.63% frontend cycles idle                                                                                
   <not supported> stalled-cycles-backend                                                                                                         
   105,668,751,265 instructions              #    2.69  insns per cycle                                                                                                
                                             #    0.08  stalled cycles per insn
     6,123,961,551 branches                  #  491.444 M/sec                   
        20,472,272 branch-misses             #    0.33% of all branches         
   <not supported> L1-dcache-loads:HG      
       608,576,686 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits
       259,895,252 LLC-loads:HG              #   20.856 M/sec          
   <not supported> LLC-load-misses:HG      

      49.792876350 seconds time elapsed
Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Carb_blog2

жаль вас забанили, но для истории вот с вашей реализацией, таки она самая быстрая.

Performance counter stats for process id '27204':

       9777.550138 task-clock                #    0.195 CPUs utilized          
            19,092 context-switches          #    0.002 M/sec                  
             1,280 cpu-migrations            #    0.131 K/sec                  
             1,435 page-faults               #    0.147 K/sec                  
    29,367,586,023 cycles                    #    3.004 GHz                    
     8,859,854,822 stalled-cycles-frontend   #   30.17% frontend cycles idle   
   <not supported> stalled-cycles-backend  
    72,486,278,151 instructions              #    2.47  insns per cycle        
                                             #    0.12  stalled cycles per insn
     4,075,076,085 branches                  #  416.779 M/sec                  
        24,830,637 branch-misses             #    0.61% of all branches        
   <not supported> L1-dcache-loads:HG      
       566,831,645 L1-dcache-load-misses:HG  #    0.00% of all L1-dcache hits  
       258,258,258 LLC-loads:HG              #   26.413 M/sec                  
   <not supported> LLC-load-misses:HG      

      50.240305926 seconds time elapsed

typedef struct {
  __m128i r, g, b;
} r8g8b8_t;

typedef struct {
  __m128i y, u, v;
} y8u8v8_t;

typedef struct {
  __m128i r_coef, g_coef, b_coef, x_coef;
} rgb_to_yuv_mat_v8_t;

static inline rgb_to_yuv_mat_v8_t create_vecm(int32_t r_coef, int32_t g_coef, int32_t b_coef, int32_t x_coef) {
  return (rgb_to_yuv_mat_v8_t) {
    _mm_set1_epi16(r_coef),
    _mm_set1_epi16(g_coef),
    _mm_set1_epi16(b_coef),
    _mm_set1_epi16(x_coef)
  };
}

static inline __m128i op(r8g8b8_t v, rgb_to_yuv_mat_v8_t m) {
  __m128i a = _mm_mullo_epi16(v.r, m.r_coef);
  __m128i b = _mm_mullo_epi16(v.g, m.g_coef);
  __m128i c = _mm_mullo_epi16(v.b, m.b_coef);
  __m128i ret = _mm_add_epi16(_mm_add_epi16(a, b), _mm_add_epi16(c, m.x_coef));
  return _mm_srai_epi16(ret, 8);
}

static inline __m128i r8g8b8_to_y8(r8g8b8_t v) {
  return op(v, create_vecm(47, 157, 16, 4096));
}
static inline __m128i r8g8b8_to_u8(r8g8b8_t v) {
  return op(v, create_vecm(-26, -87, 112, 32768));
}
static inline __m128i r8g8b8_to_v8(r8g8b8_t v) {
  return op(v, create_vecm(112, -102, -10, 32768));
}

static inline y8u8v8_t r8g8b8_to_y8u8v8(r8g8b8_t v) {
  return (y8u8v8_t) {r8g8b8_to_y8(v), r8g8b8_to_u8(v), r8g8b8_to_v8(v)};
}


static inline r8g8b8_t p16x2_to_r8g8b8(__m128i a, __m128i b) {
  __m128i shuff_ra  = _mm_setr_epi8(1, 255, 255, 255, 5, 255, 255, 255, 9, 255, 255, 255, 13, 255, 255, 255);
  __m128i shuff_ga  = _mm_setr_epi8(2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255, 255);
  __m128i shuff_ba  = _mm_setr_epi8(3, 255, 255, 255, 7, 255, 255, 255, 11, 255, 255, 255, 15, 255, 255, 255);
  __m128i shuff_rb  = _mm_setr_epi8(255, 255, 1, 255, 255, 255, 5, 255, 255, 255, 9, 255, 255, 255, 13, 255);
  __m128i shuff_gb  = _mm_setr_epi8(255, 255, 2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255);
  __m128i shuff_bb  = _mm_setr_epi8(255, 255, 3, 255, 255, 255, 7, 255, 255, 255, 11, 255, 255, 255, 15, 255);
  __m128i r8 = _mm_or_si128(_mm_shuffle_epi8(a, shuff_ra), _mm_shuffle_epi8(b, shuff_rb));
  __m128i g8 = _mm_or_si128(_mm_shuffle_epi8(a, shuff_ga), _mm_shuffle_epi8(b, shuff_gb));
  __m128i b8 = _mm_or_si128(_mm_shuffle_epi8(a, shuff_ba), _mm_shuffle_epi8(b, shuff_bb));
  return (r8g8b8_t) {r8, g8, b8};
}

static inline __m128i y8u8v8_to_p16a(y8u8v8_t v) {
  __m128i shuff_ya  = _mm_setr_epi8(255, 0, 255, 255, 255, 4, 255, 255, 255, 8, 255, 255, 255, 12, 255, 255);
  __m128i shuff_ua  = _mm_setr_epi8(255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 8, 255, 255, 255, 12, 255);
  __m128i shuff_va  = _mm_setr_epi8(255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 8, 255, 255, 255, 12);
  return _mm_or_si128(_mm_or_si128(_mm_shuffle_epi8(v.y, shuff_ya), _mm_shuffle_epi8(v.u, shuff_ua)), _mm_shuffle_epi8(v.v, shuff_va));
}

static inline __m128i y8u8v8_to_p16b(y8u8v8_t v) {
  __m128i shuff_yb  = _mm_setr_epi8(255, 2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255);
  __m128i shuff_ub  = _mm_setr_epi8(255, 255, 2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255);
  __m128i shuff_vb  = _mm_setr_epi8(255, 255, 255, 2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14);
  return _mm_or_si128(_mm_or_si128(_mm_shuffle_epi8(v.y, shuff_yb), _mm_shuffle_epi8(v.u, shuff_ub)), _mm_shuffle_epi8(v.v, shuff_vb));
}

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p) {
  guint8 *pixels = p;
  __m128i * it = pixels, * end = (__m128i *)((int32_t *)pixels + convert->width);
  do {
    {
    __m128i a = *(it + 0), b = *(it + 1);
    y8u8v8_t v = r8g8b8_to_y8u8v8(p16x2_to_r8g8b8(a, b));
    a = y8u8v8_to_p16a(v), b = y8u8v8_to_p16b(v);
    *(it + 0) = a, *(it + 1) = b;
    it += 2;
    }
    
  } while(it < end);
}
Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

Не впервой. Я никуда не ухожу.

static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer p) {
  guint8 *pixels = p;
  __m128i * it = pixels, * end = (__m128i *)((int32_t *)pixels + convert->width);
  do {
    {
    __m128i a = *(it + 0), b = *(it + 1);
    y8u8v8_t v = r8g8b8_to_y8u8v8(p16x2_to_r8g8b8(a, b));
    a = y8u8v8_to_p16a(v), b = y8u8v8_to_p16b(v);
    *(it + 0) = a, *(it + 1) = b;
    it += 2;
    }    
    {
    __m128i a = *(it + 0), b = *(it + 1);
    y8u8v8_t v = r8g8b8_to_y8u8v8(p16x2_to_r8g8b8(a, b));
    a = y8u8v8_to_p16a(v), b = y8u8v8_to_p16b(v);
    *(it + 0) = a, *(it + 1) = b;
    it += 2;
    }
    {
    __m128i a = *(it + 0), b = *(it + 1);
    y8u8v8_t v = r8g8b8_to_y8u8v8(p16x2_to_r8g8b8(a, b));
    a = y8u8v8_to_p16a(v), b = y8u8v8_to_p16b(v);
    *(it + 0) = a, *(it + 1) = b;
    it += 2;
    }
    {
    __m128i a = *(it + 0), b = *(it + 1);
    y8u8v8_t v = r8g8b8_to_y8u8v8(p16x2_to_r8g8b8(a, b));
    a = y8u8v8_to_p16a(v), b = y8u8v8_to_p16b(v);
    *(it + 0) = a, *(it + 1) = b;
    it += 2;
    }
  } while(it < end);
}

Так должна быть ещё быстрее. Там слишком много зависимостей - без анролла оно не раскачает нормально. Поидее должно быть заметно быстрее. Или не даёт профита?

Всё же про orc интересно - можно запилить её на орке, если примут в апстрим.

anonymous
()
Ответ на: комментарий от Novell-ch

Новелл-ч (сорри, не знаю по имени), я вижу, мозги у тебя в этом плане весьма и весьма.

А не собраться-ли как-нибудь энтузиастам ЛОРа (например на твоём бложике) и понабегать на разный софт ради оптимизации?

devl547 ★★★★★
()
Ответ на: комментарий от anonymous

вроде так же, 0.19%, там уже другие функции гстреамера начинают грузить сильно, там что не думаю что он архитектурно может жрать в этом случае меньше 15-20%. Надо будет эти 3 алгоритма потестить при 60 кадрах. Вот этот что сейчас справляется хорошо, загрузка 0.407 CPUs utilized , и значительно большую часть выжирает не videoconvert_convert_matrix8 а __memcpy_sse2_unaligned.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от devl547

Та он не рачситан на такое и не удобно там, на лоре приятнее, создать тег определеннный( например разум улья). Этот топик показал что в общем то реально решить небольшую задачу вместе, сколько вариантов было предложенно, даж написаны полностью алгоритмы, люди не пожалели время, и это приятно. Я не расчитывал на такое, думал будет как в начале кинут ссылкой на стаковерфлоу и на этом все. Жаль конечно что врятли это уйдет в апстирм, но эти алгоритмы я уже поскинул им в рассылку, мож кому и пригодится.

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

при 60 кадрах
sse2 - 40
sse 42
tabl64 -48
родной - 64

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Кстати, я запустил на ARM926EJ-S @ 456MHz с 10^6 пикселей:

rgb2yuv_tables: 0.170 sec
rgb2yuv_tables64: 0.110 sec
rgb2yuv_gstreamer: 0.160 sec

Так, что для ARM такая оптимизация тоже прокатывает.

anonymous
()
Ответ на: комментарий от anonymous

говорит что мало аргументов для videoconvert_convert_init_tables () но если ему подсунуть VideoConvert * convert тож нехочет.
videoconvert.c:267:39: error: expected expression before 'VideoConvert'
[ 31s] videoconvert_convert_init_tables (VideoConvert * convert);

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от anonymous

немного подрихтовал и собралось, хочет только через указатель, но в итоге показывает только зеленый цвет.
[code]
static void
videoconvert_convert_matrix8 (VideoConvert * convert, gpointer pixels)
{
int t;
guint8 r, g, b;
gint64 c = convert->t_c;
guint8 *p = pixels;

for (t = 0; t < convert->width * 4; t += 4)
{
r = p[t + 1];
g = p[t + 2];
b = p[t + 3];

gint64 x = convert->t_r[r] + convert->t_g[g] + convert->t_b + c;

p[t + 1] = x >> (32 + SCALE);
p[t + 2] = x >> (16 + SCALE);
p[t + 3] = x >> ( 0 + SCALE);
}
}
[/code]

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от Novell-ch

Я тут слегка выпил. Появился вопрос.
А на кой фиг мы конвертируем каждый пиксель из rgb в yuv?
Не быстрее будет хранить старый кадр и делать конвертацию только изменившихся пикселей?

devl547 ★★★★★
()
Ответ на: комментарий от devl547

Не быстрее будет хранить старый кадр и делать конвертацию только изменившихся пикселей?

Тотальный даунизм не имеющий смысла. «конвертация» ничего не стоит.

anonymous
()
Ответ на: комментарий от Carb_blog2

так он и используется
140s] make -C videoconvert
[ 140s] make[3]: Entering directory `/home/abuild/rpmbuild/BUILD/gst-plugins-base-1.2.4/gst/videoconvert'
[ 140s] ORCC tmp-orc.c
[ 140s] ORCC gstvideoconvertorc.h
[ 140s] make all-am
только профит не видет, или может без него еше медленее

Novell-ch ★★★★★
() автор топика
Ответ на: комментарий от devl547

Причем тут разработчики гстримера, как они оправдывают ту херню, что сказал ты?

Эти детсадовские «считаем то, что изменилось» так умиляют. Ради интереса - иди напиши побайтовое мемкопи, авось дойдёт.

anonymous
()
Ответ на: комментарий от devl547

Как будто в подавляющем большинстве юзкейсов на кадре изменяется меньше 100% пикселей. Если б так, видеокодеки были бы куда проще... А то, понимаете ли, motion estimation там всякие пишут.

intelfx ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.