Forums » Программное обеспечение »
Программирование на ассемблере. Пара вопросов о производительности
Added by qewerty over 12 years ago
Вот допустим есть функция перемножения матриц 4 на 4 (указатели на стек и фрейм не меняются, т.к. локальные переменные на стеке не нужны). Матрицы хранятся по столбцам (как в OpenGL).
.global qf_mat44_mul
qf_mat44_mul:
.alias qf_mat44_mul.a #SP,4
.alias qf_mat44_mul.b #SP,8
.alias qf_mat44_mul.c #SP,12
jmp qf_mat44_mul.P0
; сохранение адресов аргументов в регистрах
rdl qf_mat44_mul.a
setl #32, @1
rdl qf_mat44_mul.b
setl #33, @1
rdl qf_mat44_mul.c
setl #34, @1
complete
.local qf_mat44_mul.P0
qf_mat44_mul.P0:
rdl #SP
jmp @1
; чтение матрицы b
va01 := rdq #32
va23 := rdq #32,8
va45 := rdq #32,16
va67 := rdq #32,24
va89 := rdq #32,32
vaAB := rdq #32,40
vaCD := rdq #32,48
vaEF := rdq #32,56
; вспомогательные значения, для упаковки матрицы a в строки
va54 := pack @va45, @va45
vaDC := pack @vaCD, @vaCD
va76 := pack @va67, @va67
vaFE := pack @vaEF, @vaEF
; упаковка строк матрицы a
va04 := patch @va45, @va01
va8C := patch @vaCD, @va89
va15 := pack @va54, @va01
va9D := pack @vaDC, @va89
va26 := patch @va67, @va23
vaAE := patch @vaEF, @vaAB
va37 := pack @va76, @va23
vaBF := pack @vaFE, @vaAB
; чтение матрицы b
vb01 := rdq #33
vb23 := rdq #33,8
vb45 := rdq #33,16
vb67 := rdq #33,24
vb89 := rdq #33,32
vbAB := rdq #33,40
vbCD := rdq #33,48
vbEF := rdq #33,56
; скалярные произведения строк матрицы a со стобцами матрицы b
madd @va04, @vb01
madd @va8C, @vb23
vc_0 := addf @1, @2
madd @va15, @vb01
madd @va9D, @vb23
vc_1 := addf @1, @2
madd @va26, @vb01
madd @vaAE, @vb23
vc_2 := addf @1, @2
madd @va37, @vb01
madd @vaBF, @vb23
vc_3 := addf @1, @2
; --
madd @va04, @vb45
madd @va8C, @vb67
vc_4 := addf @1, @2
madd @va15, @vb45
madd @va9D, @vb67
vc_5 := addf @1, @2
madd @va26, @vb45
madd @vaAE, @vb67
vc_6 := addf @1, @2
madd @va37, @vb45
madd @vaBF, @vb67
vc_7 := addf @1, @2
; --
madd @va04, @vb89
madd @va8C, @vbAB
vc_8 := addf @1, @2
madd @va15, @vb89
madd @va9D, @vbAB
vc_9 := addf @1, @2
madd @va26, @vb89
madd @vaAE, @vbAB
vc_A := addf @1, @2
madd @va37, @vb89
madd @vaBF, @vbAB
vc_B := addf @1, @2
; --
madd @va04, @vbCD
madd @va8C, @vbEF
vc_C := addf @1, @2
madd @va15, @vbCD
madd @va9D, @vbEF
vc_D := addf @1, @2
madd @va26, @vbCD
madd @vaAE, @vbEF
vc_E := addf @1, @2
madd @va37, @vbCD
madd @vaBF, @vbEF
vc_F := addf @1, @2
; упаковка результатов
vc01 := patch @vc_1, @vc_0
vc23 := patch @vc_3, @vc_2
vc45 := patch @vc_5, @vc_4
vc67 := patch @vc_7, @vc_6
vc89 := patch @vc_9, @vc_8
vcAB := patch @vc_B, @vc_A
vcCD := patch @vc_D, @vc_C
vcEF := patch @vc_F, @vc_E
; запись результатов
wrq @vc01, #34
wrq @vc23, #34,8
wrq @vc45, #34,16
wrq @vc67, #34,24
wrq @vc89, #34,32
wrq @vcAB, #34,40
wrq @vcCD, #34,48
wrq @vcEF, #34,56
complete
Есть кой-какие вопросы о том, как сделать её максимально быстрой:
1.) Имеет ли смысл сохранять адреса аргументов в индексных регистрах для дальнейшего использования?
Т.е. сделав:
rdl qf_mat44_mul.a
setl #32, @1
Далее можно загрузить матрицу так:
va01 := rdq #32
va23 := rdq #32,8
va45 := rdq #32,16
va67 := rdq #32,24
va89 := rdq #32,32
vaAB := rdq #32,40
vaCD := rdq #32,48
vaEF := rdq #32,56
Вместо того, чтобы читать адрес в коммутатор и вычислять адреса вот так:
pa01 := rdl qf_mat44_mul.a
pa23 := addl @pa01, 8
pa45 := addl @pa01, 16
pa67 := addl @pa01, 24
pa89 := addl @pa01, 32
paAB := addl @pa01, 40
paCD := addl @pa01, 48
paEF := addl @pa01, 56
va01 := rdq @pa01
va23 := rdq @pa23
va45 := rdq @pa45
va67 := rdq @pa67
va89 := rdq @pa89
vaAB := rdq @paAB
vaCD := rdq @paCD
vaEF := rdq @paEF
Но последнее позволяет реализовать функцию одним параграфом. Т.е. меня интересует есть ли смысл избегать переключения параграфов, а также скорость выполнения чтения из адреса в регистре со смещением и из вычисленного адреса в коммутаторе. Возможно есть какие-то подводные камни.
2.) Имеет ли смысл минимизировать кол-во операций записи в память?
Например, тут у меня сделано так:
; упаковка результатов
vc01 := patch @vc_1, @vc_0
vc23 := patch @vc_3, @vc_2
vc45 := patch @vc_5, @vc_4
vc67 := patch @vc_7, @vc_6
vc89 := patch @vc_9, @vc_8
vcAB := patch @vc_B, @vc_A
vcCD := patch @vc_D, @vc_C
vcEF := patch @vc_F, @vc_E
; запись результатов
wrq @vc01, #34
wrq @vc23, #34,8
wrq @vc45, #34,16
wrq @vc67, #34,24
wrq @vc89, #34,32
wrq @vcAB, #34,40
wrq @vcCD, #34,48
wrq @vcEF, #34,56
Но можно сделать и так:
wrl @vc_0, #34
wrl @vc_1, #34,4
wrl @vc_2, #34,8
...
wrl @vc_E, #34,56
wrl @vc_F, #34,60
Что делает 16 операций записи в память, а не 8, но все 16 операций независимы, тогда как в первом случае операции записи зависят от упаковки значений.
Replies (82)
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by krufter_multiclet about 12 years ago
Поправим SDK в ближайшее время. Как только будет доступна бета версия новой модели выложим и её с отладчиком, а также описание нового удобного функционала.
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by sprin about 12 years ago
mouse wrote:
Файл t.c не используется в сборке — это эталон на Си под gcc. (в коде встречается множественный printf и наколенный ROL вместо одной ассемблерной инструкции).
Понятно.
mouse wrote:
gost_enc.epilogue - несколько условий перехода, которые могут одновременно быть истинными (? уточнить) (в модели возможно переход будет по последнему обработанному, а на железе неизвестно)
gost_dec.epilogue - несколько условий перехода, которые могут одновременно быть истинными (? уточнить) (в модели возможно переход будет по последнему обработанному, а на железе неизвестно)Данные условия мы пилили совместно с krufter_multiclet. Это единственный дешёвый способ перейти по нескольким условиям, не прибегая к ещё одному параграфу и повторной перепроверке условий. Условия построены таким образом, чтобы осуществить единственное возможное ветвление.
Соглашусь, что для "gost_enc.epilogue" следующий вариант вроде работает нормально:
gost_enc.epilogue¶
Show Hide
gost_enc.epilogue:
r1 := getl #IDX
r2 := addl @r1, 1
setl #IDX, @r2
r3 := subl @r2, 24
r4 := subl @r2, 32
r5 := and @r3, 0x80000000
jne @r5, gost.load_key1_24
r6 := and @r4, 0x80000000
r7 := xor @r5, @r6
jne @r7, gost.load_key25_32
r8 := or @r5, @r7
je @r8, gost.save_results ; Готово, далее сохраняем и берём следующие значения из буфера
complete
А вот для "gost_dec.epilogue" немного неправильно сделано, его надо немного модифицировать:
gost_dec.epilogue полный вариант¶
Show Hide
gost_dec.epilogue:
r1 := getl #IDX
r2 := subl @r1, 1
setl #IDX, @r2
je @r1, gost.save_results ; Готово, далее сохраняем и берём следующие значения из буфера
jne @r1, gost_dec.epilogue.2
complete
gost_dec.epilogue.2:
r1 := getl #IDX
r2 := subl @r1, 24
r3 := subl @r1, 32
r4 := and @r2, 0x80000000
jne @r4, gost.load_key1_24
r5 := and @r3, 0x80000000
r6 := xor @r5, @r4
jne @r6, gost.load_key25_32
or @r4, @r6 ; Возможно это лишнее
je gost.round ; Возможно это лишнее
complete
или укороченный вариант (если последние 2 команды не нужны):
gost_dec.epilogue укороченный вариант¶
Show Hide
gost_dec.epilogue:
r1 := getl #IDX
r2 := subl @r1, 1
setl #IDX, @r2
je @r1, gost.save_results ; Готово, далее сохраняем и берём следующие значения из буфера
jne @r1, gost_dec.epilogue.2
complete
gost_dec.epilogue.2: ; Убрали лишнее
r1 := getl #IDX
r2 := subl @r1, 24
r4 := and @r2, 0x80000000
jne @r4, gost.load_key1_24
je @r4, gost.load_key25_32
complete
Суть в том, что "gost_dec.epilogue" нельзя сделать одним параграфом. Затык был именно в том, что одновременно выполняются 2 условия. На последнем шаге (в модели): (idx < 0) и (j != 0), отсюда и получаются лишние циклы, вместо того, чтобы выйти на "save_results".
| gost_2_1.asm (12.4 KB) gost_2_1.asm |
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by krufter_multiclet about 12 years ago
Да, gost_dec.epilogue необходимо поправить. Если немного подумать, то можно и одним параграфом сделать, просто чтобы переходы не перекрывали друг друга(т.е. 2 перехода не должно сработать в одном параграфе). Для удобства пользователей в следующих реализациях процессора подумаем над новыми командами, позволяющими упростить формирование множественных переходов в одном параграфе. Хотя и сейчас не запрещено использовать несколько переходов, которые срабатывают в разное время.
Поправить параграф предлагаю следующим образом:
gost_dec.epilogue:
getl #IDX
subl @1, 1
setl #IDX, @1
subl @2, 24
subl @3, 32
and @4, 0x80000000
jne @1, gost.save_results
and @4, 0x80000000
subl @3, @1
js @1, gost.load_key1_24
and @6, 0x80000000
xor @1, @4
jne @1, gost.load_key25_32
complete
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by krufter_multiclet about 12 years ago
Переписал гост полностью на ассемблере, всё работает. Возможно ошибка в Си коде.
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by krufter_multiclet about 12 years ago
sprin вы в числе главных претендентов на отладочную плату по конкурсу. У пользователя trott отладочная плата, насколько мне известно, имеется(хотя я могу ошибаться).
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by trott about 12 years ago
пользователь trott в отпуске до понедельника. И платы у пользователя trott нет в наличии, а нужна... асинхронным электродвигателем управлять.
RE: Программирование на ассемблере. Пара вопросов о производительности - Added by krufter_multiclet about 12 years ago
Хорошо, значит нужны две платы.
- « Previous
- 1
- 2
- 3
- 4
- Next »