2010-09-14 7 views
3

Для быстрой MTF (http://en.wikipedia.org/wiki/Move-to-front_transform) мне нужно быстрее версию перемещения полукокса из внутри массива в перед ним:Fast memmove для x86 и +1 сдвиг (для Move-на-перед преобразованием)

char mtfSymbol[256], front; 
char i; 

for(;;) { \\ a very big loop 
    ... 
    i=get_i(); \\ i is in 0..256 but more likely to be smaller. 

    front=mtfSymbol[i]; 
    memmove(mtfSymbol+1, mtfSymbol, i); 
    mtfSymbol[0]=front; 
} 

cachegrind показывает, что для memmove здесь много фиктивных неверных прогнозов.

Для другой версии кода (не memmove в первом примере, но этот)

do 
{ 
    mtfSymbol[i] = mtfSymbol[i-1]; 
} while (--i); 

Есть много байт чтения/записи, условные ветви и ошибочность прогнозирования ветвления

я является не очень большой, так как MTF используется для «хорошего» ввода - текстовый файл после преобразования BWT (преобразование Burrows-Wheeler)

Компилятор GCC.

+0

Есть ли основания полагать, что поставляемый «memmove» можно улучшить? Не зная, что вы подразумеваете под MTF или BWT, можете ли вы избежать этих действий? –

+1

@David Thornley, Это ограниченный случай для перемещения. Наиболее распространенным является перемещение небольшой части массива 256. Смещение фиксировано и равно +1. Кроме того, этот код является горячей точкой, так как он выполняется полностью для каждого символа в файле размером 5 ГБ. – osgx

+0

Благодарим вас за разъяснение. –

ответ

0

Если вы предварительно выделите свой буфер больше, чем вам понадобится, и поместите свой начальный массив где-нибудь посередине (или в конце, если вам никогда не придется расширять его таким образом) то вы можете добавлять элементы (до предела), изменяя адрес начала массива, а не перемещая все элементы.

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

+0

Знаете ли вы MTF? i меньше 256, поэтому есть часть массива для перемещения, i-й элемент, который будет перемещен вперёд, и длинную часть после i-го, которая должна оставаться на месте. Таким образом, вы предлагаете генерировать «дыры» – osgx

+2

@osgx: военный лечебный центр? Ручная трансмиссионная жидкость? Больше следовать? Скорее всего, это формат Microsoft Tape Format, но есть и другие возможности. По крайней мере, BWT не приводит к странице значений Википедии. –

+0

@David Thornley, извините, это преобразование «вперед-назад», используемое в архиваторах, например. bzip2 – osgx

0

Вы также можете использовать выделенную структуру данных, а не массив, чтобы ускорить форвардное преобразование. Быстрая реализация может быть построена со списком связанных списков, чтобы избежать перемещения элемента массива.

См http://code.google.com/p/kanzi/source/browse/java/src/kanzi/transform/MTFT.java

Для обратного преобразования, то получается, что массивы так быстро, как связанные списки.

+1

Это академически правильное решение, но я сомневаюсь, что это хороший исполнитель в реальном коде (возможно, на Java, но, конечно же, не на C++). Несмотря на лучшую алгоритмическую сложность, «список» в 3-4 раза медленнее, чем «вектор» (или необработанный массив), за исключением очень больших объектов. Кроме того, когда вы используете MTF, это имеет смысл только в том случае, если частые символы встречаются с кластеризацией, т. Е. Движения обычно будут очень короткими расстояниями. Таким образом, пользовательский «memmove», специализирующийся на коротких ходах, будет хорошо работать. – Damon

+0

Я согласен с общим комментарием. Однако Java, не имеющий прямого доступа к оптимизированным (низкоуровневым) инструкциям, список является самым быстрым вариантом (по крайней мере, для процессоров Intel). Я не претендую на другие языки. Так как MTF обычно используется после BWT, для большинства персонажей характерны низкие индексы. – flanglet

+0

_ "обычно используется после BWT, для большинства персонажей характерны низкие индексы". Ну да, это то, что я говорю :-) В этом контексте имеет смысл использовать MTF. Но тогда объем памяти, который нужно переместить, обязательно крошечный (обычно 3-5, редко до 8-10 байтов), поэтому специализированная 'mmove' будет очень быстрой. Накладные расходы на управление двумя указателями в списке выше, и это не включает более медленные общие последствия доступа и кеша при _using_ данных. Java VM, по общему признанию, скрывает этот факт (как в вашем примере), но вопрос OP о C. – Damon