Обработка строк с SSE 4.2 STTNI на практике

В рамках задачи Accelerate 2012 необходимо было найти максимизированные общие подстроки reference строки и input строк длиннее, чем некоторое minLength. Размеры строк ограничены по условиям конкурса 4 Gb и загрузка их в память и их парсинг съедает действительно много времени. Рекомендация использовать SSE 4.2 в обработке строк подтолкнула нас к её изучению.

Не секрет, что начать использовать SSE не так просто как хотелось бы. Сей пост предназначен сохранить Ваше время и силы для более приятных дел. Раз Вы читаете этот пост, наверное, вы уже знаете, зачем Вам нужно SSE 4.2, если нет, то обязательно прочитайте, например, в прошлом посте.

Дополнительные материалы по SSE 4.2:

Дополним список материалов, указанных в прошлом посте.



Устранение ошибок компиляции:

Оговоримся, что рекомендации написаны для компилятора icpc.

Для компиляции кода необходимы несколько include файлов:

#include <emmintrin.h>

#include <nmmintrin.h>



Если используются ассемблерные вставки в стиле Microsoft под Linux для успешной компиляции необходим ключ -use-msasm.

Для выровненных данных по 16 байт (16 byte memory alignment) операции должны происходить гораздо быстрее:
самый простой способ выровнить данные в памяти - дать указание компилятору сделать это за Вас

//memory alignment

__declspec( align(16) ) char * aligned_ptr = new char[100];



Поддержка процессорами:

Прежде чем использовать SSE в действии неплохо бы убедиться в его поддержке процессором, причем сделать это можно на лету (спасибо intel):
Достаточно скопировать в рабочую директорию sse41andsse42detection.cpp и sse41andsse42detection.h, подцепить их и съесть десерт:

#include 

#include "sse41andsse42detection.h"

int main() {

//int isSSE41andSSE42Supported (void)

if (isSSE41andSSE42Supported()){

     printf("You are happy owner of SSE 4 enabled processor!");

} else {

     printf("SSE 4 is not enabled... ");

}

return 0;

}



Использование mode _SIDD_UNIT_MASK:

Вместо получения битовой маски _SIDD_BIT_MASK, можно отразить 16 бит в отдельные 16 байт. Например, сравним посимвольно 2 строки (p1 и p2), предполагая, что их длина меньше либо равна 16 символам (8 для юникода) и запишем результат сравнения в массив resArray:
const int mode = _SIDD_CMP_EQUAL_EACH | _SIDD_UNIT_MASK ;

__m128i smm1;

__m128i smm2;

__m128i resMask;

__declspec( align(16) ) char * resArray = new char[16];

smm1 = _mm_loadu_si128 ((__m128i *) &p1[0]); //load p1 str to XMM register

smm2 = _mm_loadu_si128 ((__m128i *) &p2[0]); //load p1 str to XMM register

resMask = _mm_cmpistrm (smm1, smm2, mode ); //result is in XMM register resMask

_mm_maskmoveu_si128(resMask, resMask, resArray); //copy result mask to resArray in memory


Чтение флагов

Еще одно неочевидное для понимания место в руководство по SSE4 для разработчиков:
Чтение флагов CFlag, ZFlag, SFlag, OFlag, AFlag, PFlag производится с помощью соответствующих интринсиков

//Reading Flags with intrinsics

int _mm_cmpistrс(__m128i a, __m128i b, const int mode);

int _mm_cmpistrz(__m128i a, __m128i b, const int mode);

int _mm_cmpistrs(__m128i a, __m128i b, const int mode);

int _mm_cmpistro(__m128i a, __m128i b, const int mode);

int _mm_cmpistra(__m128i a, __m128i b, const int mode);

int _mm_cmpistrp(__m128i a, __m128i b, const int mode);

.

Реализация стандартных фукнций со строками с SSE 4.2:

Cуществует реализация strcmp, strlen, and strstr с помощью SSE 4.2 , но она нами не использовалась и не проверялась.

...и напоследок

К сожалению, после смены алгоритма в финальном релизе использовать SSE мы не успели, есть чем позаниматься на каникулах =).

Несколько вкусных и полезных ссылок:


Всем участникам конкурса удачной сессии!
Kategorien:
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.