У меня есть 2 небольших локальных массива:
short int xpLeft [4], xpRight [4];
В тот момент, когда я делаю их глобальными (для доступа к ним другим способом, но только в пределах одного файла C (например, недоступного для других модулей)), производительность (на Motorola 68000) падает. Вместо 224 vblanks (для локальных) весь тест (рендеринг 320 кадров сцены) внезапно занимает 249 vblanks (глобальный массив)!
Что я пробовал:
Поскольку данные в массивах не использовались в этой функции, я подумал, что компилятор уловил это и не стал записывать полученное значение (из регистра) в память (чрезвычайно медленная операция на 68000 - доступ к памяти). Итак, я добавил небольшой код для использования этих значений массива в конце функции, что соответственно повысило затраты на производительность (всего 1 пустая строка).
Что могло бы помочь:
Мне нужно изучить окончательный код ASM (и сравнить обе версии), но я не знаю, как это сделать с помощью компилятора vbcc (от доктора Волкера). Я попробовал несколько переключателей из документации, и, хотя они действительно давали некоторый промежуточный результат, мне не удалось получить полный список ASM для каждого модуля (с именами функций из C).
У меня только что заработал переключатель "-k". По-видимому, порядок переключателей имеет значение, и я нашел место в командной строке, где он был распознан, и я наконец получил вывод * .ASM (не менее 300 тысяч строк), но наконец-то у меня что-то есть (ASM с символами) копаться.
Я думаю, что происходит:
- Создание глобальных массивов помещает их в разные адреса в ОЗУ, и контроллер памяти должен иметь доступ к другому банку, а переключение банка - чрезвычайно медленная операция на целевой платформе, что приводит к циклам зарядки RAS (для доступа к разным строкам адресов).
- псевдонимы указателя - возможно, компилятор генерирует другой код и может фактически получить доступ к фактической памяти для промежуточных результатов - но если бы у меня был вывод ASM для каждой функции, я мог бы легко это понять
Любые советы о том, почему это происходит, или как получить полный список вывода vbcc каждого скомпилированного модуля с соответствующим кодом ASM?
С помощью вывода ASM я создал небольшой тестовый пример:
short int tmpfn1 ()
{
short int xpLeft [4], xpRight [4];
short int i, tmp;
for (i = 0; i < 4; i++)
{
xpLeft [i] = 137 + i;
xpRight [i] = 215 + i;
}
tmp = xpLeft [0] + xpRight [0];
return tmp;
}
Вот получившийся ASM. Хотя ASM довольно понятен, я все равно добавил несколько комментариев:
public _tmpfn1
cnop 0,4
_tmpfn1
sub.w #16,a7
movem.l l4150,-(a7)
moveq #0,d1
lea (0+l4152,a7),a1 ; a1 = &xpLeft [0]
lea (8+l4152,a7),a2 ; a2 = &xpRight [0]
move.w #215,d3 ; d2/d3 = The Bulgarian constants
move.w #137,d2
l4148
move.w d1,d0
ext.l d0
lsl.l #1,d0
move.w d2,(0,a1,d0.l) ; xpLeft [i] = 137 + i;
move.w d3,(0,a2,d0.l) ; xpRight [i] = 215 + i;
addq.w #1,d1 ; d1 = Loop Counter (i++)
addq.w #1,d2
addq.w #1,d3
cmp.w #4,d1
blt l4148 ; Repeat the loop
move.w (8+l4152,a7),d0
add.w (0+l4152,a7),d0 ; tmp = xpLeft [0] + xpRight [0];
l4150 reg a2/d2/d3
movem.l (a7)+,a2/d2/d3
add.w #16,a7
l4152 equ 12
rts
; stacksize=28
opt 0
opt NQLPSMRBT
Теперь я перенесу массивы из локального в глобальный.
Вот код с глобальными переменными.
public _tmpfn1
cnop 0,4
_tmpfn1
movem.l l4150,-(a7)
moveq #0,d1
move.w #215,d2
move.w #137,d3
l4148
move.w d1,d0
ext.l d0
lsl.l #1,d0
lea _AxpLeft,a0
move.w d3,(0,a0,d0.l)
lea _AxpRight,a0
move.w d2,(0,a0,d0.l)
addq.w #1,d1
addq.w #1,d3
addq.w #1,d2
cmp.w #4,d1
blt l4148
move.w _AxpRight,d0
add.w _AxpLeft,d0
l4150 reg d2/d3
movem.l (a7)+,d2/d3
l4152 equ 8
rts
; stacksize=8
opt 0
opt NQLPSMRBT
Единственное различие - две инструкции lea, которые, если память не изменяет, имеют максимум 16 циклов.
С самой функцией должно быть что-то еще, но по какой-то причине ее код запутан в ASM (всего 6 строк в ASM, никаких переходов, никаких других меток, ничего). Я продолжу искать в ASM, где именно находится код.