Grizzly 0 21 декабря, 2019 Опубликовано 21 декабря, 2019 · Жалоба @__inline__ а с GCC всё-таки не стали сравнивать?) Наверное, для честного сравнения нужно самому собрать тулчейн GCC C6x версии 9. Версия 4.y уже устарела. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 21 декабря, 2019 Опубликовано 21 декабря, 2019 · Жалоба 3 часа назад, __inline__ сказал: Внял рекомендациям jcxz (за что ему громное спасибо! ). Удалось увеличить производительность на 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(), а я ещё в самом начале, когда Вы только начинали работать с этим ядром, его советовал. 3 часа назад, __inline__ сказал: Особо радует вот это (несколько инструкций впараллель): Да, видно что Вы уже очень плотно загрузили ядро Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 3 января, 2020 Опубликовано 3 января, 2020 · Жалоба Потестировал этот 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 не знает, пришлось задефайнить разыменовыванием указателей, что не совсем верно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Grizzly 0 3 января, 2020 Опубликовано 3 января, 2020 · Жалоба 6 минут назад, __inline__ сказал: Потестировал этот GCC Он уже старенький :) Собрать бы GCC 9 или даже из транка GCC 10 на праздниках под TI и посмотреть. Вряд ли кто-то ещё выкладывает нынче бинарные сборки тулчейна. Но, думаю, ситуация не сильно изменится по сравнению исо старыми версиями. 9 минут назад, __inline__ сказал: Даёт такой листинг: Класс! Спасибо за исследование. Очень интересно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 3 января, 2020 Опубликовано 3 января, 2020 (изменено) · Жалоба 1 hour ago, Grizzly said: Класс! Спасибо за исследование. Очень интересно. Да не за что )) Вы можете это проделать сами очень легко - ничего сложного ! Изменено 3 января, 2020 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Niyaz 0 14 апреля, 2021 Опубликовано 14 апреля, 2021 · Жалоба On 1/3/2020 at 2:36 PM, __inline__ said: Да не за что )) Вы можете это проделать сами очень легко - ничего сложного ! Здравствуйте! Можете порекомендовать dsp процессоры от TI для видеообработки(как минимум фильтрация двумерная, обработка гистограммы, fft,wavelet и т.д.)? И еще, matlab/simulink может генерировать c/c++ коды из своих кодов/блоков. Можно ли этот код скормить (не вдаваясь в подробности этих dsp) для code composer studio? у матлаба был "Embedded Coder Support Package for Texas Instruments C6000 DSPs" до 2016, а сейчас у них нет поддержки этих c6000. я с этими сигнальниками не имел дела, code composer studio сам может оптимизировать код? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 14 апреля, 2021 Опубликовано 14 апреля, 2021 · Жалоба 1 час назад, Niyaz сказал: я с этими сигнальниками не имел дела, code composer studio сам может оптимизировать код? Уже древний CCS3.3 для 6000-го семейства создавал вполне оптимальный код из си-исходника. Программировать на ассемблере, для оптимизации по скорости, уже тогда не было необходимости. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться