Pull to refresh

Comments 3

Не очень понятно всё-таки как это работает. Они просмо пометили в компиляторе, что вот у этих двух библиотек у конкретно этих функций есть ассемблерные реализации, которые надо использовать вместо кода на го и лежат при этом эти ассемблерные инструкции не в .s файлах а где-то еще?
Вот просто есть у меня одна библиотека на го, которую используют в высоконагруженном коде и там очень важна производительность. И есть там очень много делений на константу дважды: один раз для получения результата деления и один раз для остатка. github.com/mr-tron/base58/blob/master/base58.go#L49
Давно была мысль заменить это на ассемблерную инструкцию, которая возвращает сразу и результат деления и остаток.
Ну я вот счас попробовал заменить
tmp[j] = byte(carry % 58)
carry /= 58


на
carry, t = bits.Div32(0, carry, 58)
tmp[j] = byte(t)

и получил сильное падение скорости.

Стало интересно:
Цикл на go
for i = zcount; i < binsz; i++ {
	j = size - 1
	for carry = uint32(bin[i]); j > high || carry != 0; j-- {
		carry = carry + 256*uint32(tmp[j])
		tmp[j] = byte(carry % 58)
		carry /= 58
	}
	high = j
}
Как он компилируется напрямую:
movzx   r14d, byte ptr [r11+rsi]
shl     r14d, 8
add     r12d, r14d
mov     r14d, 8D3DCB09h
imul    r14, r12
shr     r14, 25h
imul    r15d, r14d, 3Ah
sub     r12d, r15d
mov     [rsi+r11], r12b
dec     r11
mov     r12, r14
Как он компилируется с использованием bits.Div32:
movzx   r14d, byte ptr [r11+rsi]
shl     r14d, 8
add     r14d, r12d
nop
mov     r15d, r14d
shr     r14, 1
mov     r12, rax
mov     rax, 8D3DCB08D3DCB08Eh
mul     r14
shr     rdx, 4
imul    r14, rdx, 3Ah
sub     r15, r14
mov     [rsi+r11], r15b
dec     r11
mov     rax, r12
mov     r12, rdx
mov     rdx, [rsp+60h+var_20]
Количество вспомогательных mov инструкций стало больше, а количество умножений не уменьшилось. Но и пространства для оптимизации особо нет: 10 инструкций в нагруженном цикле.
Sign up to leave a comment.

Articles