Jump to content

    

C6x GCC - что скажете? Лучше или хуже чем TI CC 8.3.5 ?

@__inline__ а с GCC всё-таки не стали сравнивать?)

Наверное, для честного сравнения нужно самому собрать тулчейн GCC C6x версии 9. Версия 4.y уже устарела.

Share this post


Link to post
Share on other sites
3 часа назад, __inline__ сказал:

Внял рекомендациям jcxz (за что ему громное спасибо! :sun_bespectacled:).  Удалось увеличить производительность на 30...50% (в зависимости от случая).  Оказывается, индексная адресация лучше ложится на конвеер, чем инкременты с указателями.  И однотипные операции лучше дублировать 2 , 4 или 8 раз.  Перестановка действий также может влиять.   И ещё можно не присваивать переменным промежуточный результат - компилятор это видит и оптимизирует сам.

Конечно индексная лучше! Почему? Ведь когда пишете например:

*ptr = x1; ptr++; *ptr = x2; ptr++; *ptr = x3; ptr++; *ptr = x4; ...

то это означает, что для того чтоб можно было выполнить операцию *ptr=x4 нужно до этого выполнить ptr++ перед ней (так как она вычислит исполнительный адрес для *ptr=x4). А чтобы выполнить *ptr=x3 надо также сделать ptr++ до неё. То есть - все операции в этой цепочке оказываются последовательно-зависимыми. Их нельзя выполнять одновременно-параллельно. Конечно умный компилятор может догадаться и превратить все эти ptr++; *ptr=x.. в индексные, посчитав индексы. Но не факт что он так сделает.

А вот индексные обращения к памяти - они будут независимы одна от другой и могут быть легко распараллелены. И не нужно бояться индексов - для них в системе команд процессоров (тем более DSP) есть индексная адресация. Тем более если индексы - const.

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

И дублирование - тоже по этой же причине лучше.

Цитата

 _nassert((int)SROMOffset0%32==0);

Вижу - наконец-то стали использовать _nassert(), а я ещё в самом начале, когда Вы только начинали работать с этим ядром, его советовал. :wink:

 

3 часа назад, __inline__ сказал:

Особо радует вот это (несколько инструкций впараллель):

Да, видно что Вы уже очень плотно загрузили ядро  :good:

Share this post


Link to post
Share on other sites

Потестировал этот GCC, получил листинг.  Параллельность есть, но она слабенькая в отличие от TI CC.

Команда:

c6x-uclinux-g++ -S  -fsel-sched-pipelining -fsel-sched-pipelining-outer-loops -march=c674x -O3 -fomit-frame-pointer -ffast-math -fno-rtti -fno-exceptions -Dc6745 -DNDEBUG -c PPU16.cpp

Код:

#include <stdlib.h>

#include "PPU16.h"

#define VRAM_BUFFER 0xC0800000 /* Bank1 SDRAM            */

#define VIDEO_CACHE 0x11800000 /* 240 x 400 pixel buffer */

#define PRUSS_VideoBuffer (*(IO u32*)(PRU1_Data+0x0000))

#define SROM16 (*(u16*)SROMOffset)
#define VRAM16 (*(u16*)VRAMOffset)

u8 *VRAMBuffer=(u8*)VRAM_BUFFER;

const u8 *SROMBuffer; //SROM Buffer - Pointer

u32 SPRITE_PITCH=2048; //Default Sprite Width: 1024 pixel

#define _amem8(x) (*(x))
#define _mem8(x) (*(x))

void PPU16_ClearVRAM(u16 Color)
{
 u64 c=Color|(Color<<16);
 c|=(c<<32);
 u64 * __restrict vb=(u64*)VRAMBuffer;
// #pragma UNROLL(4)
 for(int i=0;i<(SCREEN_WIDTH*SCREEN_HEIGHT)>>2;i++)_amem8(&vb[i])=c;
}

void PPU16_OutOLED(void)
{
 for(int y=0;y<(SCREEN_HEIGHT<<1);y+=8)
 {
  u64 * __restrict vc=(u64*)(VIDEO_CACHE+y);
  u64 * __restrict vb0=(u64*)&VRAMBuffer[((SCREEN_WIDTH-4)<<1)+(SCREEN_WIDTH*y)];
  u64 * __restrict vb1=vb0+(SCREEN_WIDTH>>2);
  u64 * __restrict vb2=vb1+(SCREEN_WIDTH>>2);
  u64 * __restrict vb3=vb2+(SCREEN_WIDTH>>2); 

  for(int x=0;x<(SCREEN_WIDTH>>2);x++)
  {
   _amem8(&vc[(3*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16) _amem8(&vb0[-x])     ))|((u64)((u16) _amem8(&vb1[-x])     )<<16)|((u64)((u16) _amem8(&vb2[-x])     )<<32)|((u64)((u16) _amem8(&vb3[-x])     )<<48);
   _amem8(&vc[(2*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>16)))|((u64)((u16)(_amem8(&vb1[-x])>>16))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>16))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>16))<<48);
   _amem8(&vc[(1*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>32)))|((u64)((u16)(_amem8(&vb1[-x])>>32))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>32))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>32))<<48);
   _amem8(&vc[(0*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>48)))|((u64)((u16)(_amem8(&vb1[-x])>>48))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>48))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>48))<<48);
  }
 }
}

 

Даёт такой листинг:

Spoiler

	.file	"PPU16.cpp"
	.c6xabi_attribute Tag_ABI_array_object_alignment, 0
	.c6xabi_attribute Tag_ABI_array_object_align_expected, 0
	.c6xabi_attribute Tag_ABI_stack_align_needed, 0
	.c6xabi_attribute Tag_ABI_stack_align_preserved, 0
	.c6xabi_attribute Tag_ABI_conformance, "1.0"
.text;
	.align	2
	.global	PPU16_ClearVRAM
	.type	PPU16_ClearVRAM, @function
PPU16_ClearVRAM:
		sub	.d2	B15, 8, B15
		stw	.d2t2	B14, *+B15(8)
		ldw	.d2t2	*+B14($DSBT_index(__c6xabi_DSBT_BASE)), B14
	||	extu	.s1	A4, 16, 16, A6
		mvk	.s1	24000, A0
		shl	.s1	A6, 16, A7
		mvc	.s2x	A0, ILC
	||	or	.d1	A6, A7, A4
		shr	.s1	A4, 31, A8
		ldw	.d2t1	*+B14(VRAMBuffer), A3
	||	or	.d1	A8, A4, A5
		nop	4
		sploop	2
.L2:
		stw	.d1t1	A4, *A3
		stw	.d1t1	A5, *+A3(4)
	||	add	.s1	8, A3, A3
		spkernel	1, 0
		ret	.s2	B3
	||	ldw	.d2t2	*+B15(8), B14
	||	add	.l2	8, B15, B15
		nop	5
	;; return occurs
	.size	PPU16_ClearVRAM, .-PPU16_ClearVRAM
	.align	2
	.global	PPU16_OutOLED
	.type	PPU16_OutOLED, @function
PPU16_OutOLED:
		sub	.d2	B15, 8, B15
		stw	.d2t2	B14, *+B15(8)
		ldw	.d2t2	*+B14($DSBT_index(__c6xabi_DSBT_BASE)), B14
	||	mvk	.s1	1440, A24
	||	mvk	.d1	0, A21
	||	mvk	.l1	0, A26
		mvk	.s1	960, A23
		mvk	.s1	480, A22
		mvklh	.s1	4480, A24
		mvklh	.s1	4480, A23
		ldw	.d2t1	*+B14(VRAMBuffer), A25
	||	mvklh	.s1	4480, A22
		mvklh	.s1	4480, A21
		mvk	.s1	60, A2
		nop	2
		addk	.s1	792, A25
.L8:
		mvk	.s1	800, A7
	||	sub	.d1	A2, 1, A2
	||	mv	.l1	A26, A5
		mvk	.s1	1600, A8
	||	add	.d1	A25, A7, A4
	||	mv	.l1	A25, A0
		mvk	.s1	2400, A9
	||	add	.d1	A25, A8, A3
		add	.d1	A25, A9, A6
	||	mvk	.s1	100, A1
.L7:
		ldhu	.d1t1	*A4, A19
	||	add	.l1	A5, A24, A16
	||	add	.s1	A5, A23, A27
		ldhu	.d1t1	*A6, A17
	||	add	.l1	A5, A22, A28
	||	add	.s1	-1, A1, A1
		ldhu	.d1t1	*A3, A18
	||	add	.l1	A5, A21, A29
	||	addk	.s1	1920, A5
		ldhu	.d1t1	*A0, A20
		nop	1
		shl	.s1	A19, 16, A30
		shl	.s1	A17, 16, A7
		or	.d1	A7, A18, A8
		or	.s1	A20, A30, A31
	||	stw	.d1t1	A8, *+A16(4)
		stw	.d1t1	A31, *A16
		ldw	.d1t1	*A4, A9
		ldw	.d1t1	*A3, A20
		ldw	.d1t1	*A0, A18
		ldw	.d1t1	*A6, A16
		nop	1
		clr	.s1	A9, 0, 15, A19
		shru	.s1	A20, 16, A17
		shru	.s1	A18, 16, A30
		clr	.s1	A16, 0, 15, A7
	||	or	.d1	A30, A19, A31
		or	.s1	A7, A17, A8
	||	stw	.d1t1	A31, *A27
		stw	.d1t1	A8, *+A27(4)
		ldhu	.d1t1	*+A4(4), A27
		ldhu	.d1t1	*+A6(4), A9
		ldhu	.d1t1	*+A3(4), A20
		ldhu	.d1t1	*+A0(4), A18
		nop	1
		shl	.s1	A27, 16, A16
		shl	.s1	A9, 16, A17
		or	.d1	A17, A20, A30
		or	.s1	A18, A16, A19
	||	stw	.d1t1	A30, *+A28(4)
		stw	.d1t1	A19, *A28
		ldhu	.d1t1	*+A4(6), A28
	||	add	.s1	-8, A4, A4
		ldhu	.d1t1	*+A6(6), A8
	||	add	.s1	-8, A6, A6
		ldhu	.d1t1	*+A3(6), A31
	||	add	.s1	-8, A3, A3
		ldhu	.d1t1	*+A0(6), A7
	||	add	.s1	-8, A0, A0
	[A1]	b	.s1	.L7
		shl	.s1	A28, 16, A27
		shl	.s1	A8, 16, A18
		or	.d1	A18, A31, A9
		stw	.d1t1	A9, *+A29(4)
	||	or	.s1	A7, A27, A20
		stw	.d1t1	A20, *A29
	;; condjump to .L7 occurs
	[A2]	b	.s1	.L8
	||	add	.d1	A26, 8, A26
		addk	.s1	3200, A25
		nop	4
	;; condjump to .L8 occurs
		ret	.s2	B3
	||	ldw	.d2t2	*+B15(8), B14
	||	add	.l2	8, B15, B15
		nop	5
	;; return occurs
	.size	PPU16_OutOLED, .-PPU16_OutOLED
	.global	VRAMBuffer
	.section	.neardata,"aw",@progbits
	.align	2
	.type	VRAMBuffer, @object
	.size	VRAMBuffer, 4
VRAMBuffer:
	.long	-1065353216
	.global	SROMBuffer
	.section	.bss,"aw",@nobits
	.align	2
	.type	SROMBuffer, @object
	.size	SROMBuffer, 4
SROMBuffer:
	.zero	4
	.global	SPRITE_PITCH
	.section	.neardata
	.align	2
	.type	SPRITE_PITCH, @object
	.size	SPRITE_PITCH, 4
SPRITE_PITCH:
	.long	2048
	.ident	"GCC: (Sourcery CodeBench Lite 4.5-124) 4.5.1"

 

 

Слабовато.   И _mem8, _amem8 не знает, пришлось задефайнить разыменовыванием указателей, что не совсем верно.

Share this post


Link to post
Share on other sites
6 минут назад, __inline__ сказал:

Потестировал этот GCC

Он уже старенький :) Собрать бы GCC 9 или даже из транка GCC 10 на праздниках под TI и посмотреть. Вряд ли кто-то ещё выкладывает нынче бинарные сборки тулчейна. Но, думаю, ситуация не сильно изменится по сравнению исо старыми версиями.

9 минут назад, __inline__ сказал:

Даёт такой листинг:

Класс! Спасибо за исследование. Очень интересно.

Share this post


Link to post
Share on other sites
1 hour ago, Grizzly said:

Класс! Спасибо за исследование. Очень интересно.

Да не за что )) Вы можете это проделать сами очень легко - ничего сложного !

Edited by __inline__

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now