Функция SIMD ARM64 оказалась узким местом с помощью простой команды вычитания? - PullRequest
0 голосов
/ 12 октября 2018

У меня есть функция с сигнатурой void aggregate(const char *string, int64_t length, void *dest), цель которой - сопоставить каждый символ в string с соответствующим битом в dest, где бит равен 1, если этот символ равен '\"', и 0 в противном случае.Так что если строка "\"aaaaaa\"..., то 0b10000001... записывается в dest.Эта функция обрабатывает 32 байта из string за один раз, поэтому length должен быть кратным этому.

В любом случае, у меня есть рабочая функция, но согласно моему профилированию она тратит более 80% времени по инструкции subs.Я знаю, что вы должны быть осторожны при обработке обычных регистров наряду с SIMD, но я не могу понять, почему это такое узкое место.Я также попытался сделать cmp с указателем текущей строки и концом строки, и зацикливался, только если текущий указатель меньше конца.Однако это не помогло.Я также попытался развернуться, чтобы выполнить половину или четверть инструкций subs, но это тоже не помогло.Есть идеи?

#define vadds_raw v0
#define vadds vadds_raw##.16b
#define vrepquote v1.16b
#define vchrs0_raw v2
#define vchrs0 vchrs0_raw##.16b
#define stepmask_raw v7
#define stepmask stepmask_raw##.16b
#define halfmask_raw v8
#define adder_scratch v9

#define string x0
#define length x1
#define out x2
#define scratch_reg x3

.section    __TEXT,__text,regular,pure_instructions
.build_version ios, 12, 0
.globl    _aggregate
.p2align    2

_aggregate:
// load masks
movi vrepquote, #0x22

mov scratch_reg, 0x4080
movk scratch_reg, 0x1020, lsl 16
movk scratch_reg, 0x0408, lsl 32
movk scratch_reg, 0x0201, lsl 48
dup stepmask_raw.2d, scratch_reg

mov scratch_reg, 0xffff
movk scratch_reg, 0xffff, lsl 16
movk scratch_reg, 0xffff, lsl 32
movk scratch_reg, 0xffff, lsl 48

ins halfmask_raw.d[0], x31 // zero it out
ins halfmask_raw.d[1], scratch_reg

iter:
subs length, length, #16
ldur q2, [string]

cmeq vchrs0, vchrs0, vrepquote
and vchrs0, vchrs0, stepmask

movi.16b vadds_raw, #0
addv b0, vchrs0_raw.8b
and vchrs0, vchrs0, halfmask_raw.16b
addv b9, vchrs0
ins vadds_raw.b[1], adder_scratch.b[0]

str h0, [out]
add out, out, #2
add string, string, #16
b.hi iter
ret

1 Ответ

0 голосов
/ 12 октября 2018

Профилировщик предоставляет адрес в двоичном виде в качестве местоположения.В данном случае это метка iter.Но метка, конечно, не занимает места в самом двоичном файле, поэтому адрес - это адрес инструкции subs, которая является местом назначения ветви в конце вашего цикла.

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

Интересный эксперимент состоит в том, чтобы опробовать вашу функцию на разных длинах ввода.Значительно ли меняется профиль?

...