Заранее извиняюсь если тема немного не туда, но вроде под вынь32. Я из сети получаю пакет данных(обычный массив типа char*) и в нём надо найти кодовую последовательность.(например 55АА=) ). Причём код очень кретичен к скорости. (Сам знаю асм(но не очень хорошо), но надо писать на С++, поэтому наверно асмовская вставка). можно конечно банальным for'ом, но может есть решение поэлегантнее? Заранее спасибо
под вынь не знаю под Dos что то вроде при условии что конец масива обозначается нулём - если иначе то придётся указывать размер масива - и прогонять через цикл Код (Text): massiv db 'asdsadktw452984523945orgj mm cas;',55h,0AAh db 'fkhg dfmcssadax;sldk ma;dkadl; a;sdkfsa ' ... ... lea si,massiv ;si на указатель масива NexSymbol:lodsb ;получаем в al символ or al,al ;Код ноль? jz ExitFind ;угу - сваливаем cmp al,55h ;Первый символ нашей ;последовательности? jnz NexSymbol ;неа - идём смотреть следующий lodsb ;да наш - получаем следующий cmp al,0AAh ;следующий наш? jz Found ;ага - нашли dec si ;нет - уменьшаем указатель jmp NexSymbol ;дальше ExitFind: ... ... ... found: .... .... ....
или так Код (Text): massiv db 'asdsadktw452984523945orgj mm cas;',55h,0AAh db 'fkhg dfmcssadax;sldk ma;dkadl; a;sdkfsa ' ... ... lea si,massiv ;si на указатель масива NexSymbol:lodsw ;получаем в ax пару символов or al,al ;У поледнего код ноль? jz ExitFind ;угу - сваливаем cmp ax,0AA55h ;Это оно? jz Found ;Да - сваливаем dec si ;нет - уменьшаем указатель jmp NexSymbol ;продолжить поиск ExitFind: ... ... ... found: .... .... ....
Спасибо!=) последний вариант мне особенно понравился!=)) Интересно, а за сколько он успеет просмотреть 20000 байт? (вопрос конечно глупый, но число тактов наверно приблезительно оценить можно)
eXod Если искомая последовательность наверняка есть в массиве, то можно сделать короче и быстрее исключив проверку на окончание массива: Код (Text): lea esi,massiv ;esi на указатель масива NexSymbol:lodsw ;получаем в ax пару символов dec esi cmp ax,0AA55h ;Это оно? jne short NexSymbol ;Нет - продолжаем ExitFind: ;Здесь окажемся когда найдено. ....
=) жаль вот только последовательности там может и не оказаться... Может кто подскажет как можно замерить время выполнения программы? хочу стравнить разные варианты на асм вставках и на чистом с++=) может если скорость будет выше то в итоге вообще оставлю только описание функций/классов, а всё тело буду реализовывать на асме.(полностью к сожалению не получиться, другим надо класс встраивать в свою программку на с++)
Просили же вроде не тупой перебор в цикле. Для поиска подстрок в строке нормальные люди используют Боуера-Мура и его производные адаптированные для конкретного случая. Особенно заметен выигрышь на длинных подстроках. http://algolist.manual.ru/search/esearch/index.php
Как испытать на время ? - Делаеш тестовую прогу с большим циклом этой продседуры. Запускаеш в Soft-ice и там показывается время исполнения.Получается что строчные инструкции и смена адресации тормозные (не испльзуй lodsb и word адресацию). Код (Text): start: mov dword ptr [esi],eax inc esi cmp eax, '55AA' ; char je p1:1 inc esi inc esi inc esi jmp start p1: mov byte ptr [esi],al cmp al,'=' jne start
2Dr.Golova огромное спасибо за ссылку!!!! 2zzzyab дык софтайс ещё поставить надо... но помниться после перехода с 9х на НТ(2000) у меня так и не получилось его нормально поставить=( (в смясле не софтайс для 9х, а для НТ... на 2000 не хотел вставать). Может можно как-то программно(то бишь кодом в самой программе)?
Dr.Golova Получается тот, кто не использует алгоритм Боуера-Мура ненормальный? Для данного случая тогда может Алгоритм Сдвига-Или предпочтительней? Как раз для маленьких искомых последовательностей. По сравнению с Боуера-Мура он требует меньше времени как в худшем случае, так и в усредненном варианте.
Между прочим, поиск в строке реализован аппаратно - и по идее должен выполняться быстрее такой код: Код (Text): _asm { mov eax, 0AA55h mov ecx, length ; в вордах! mov edi, pArray cld repne scasw setz al mov fFound, al }
Можно два раза прогнать зачем? просто нужно scasb использовать... Можно попробовать распараллелить процесс: Код (Text): in_str proc ;вход: ;edi - адрес строки ;ecx - длина строки ;выход: ;не найдено - ecx==FALSE ;найдено - ecx!=FALSE, edi указывает на 0xAA55 mov ax,0AA55h lea ecx,[edi+(ecx-1)-3] cmp edi,ecx jae eo_long @@: cmp [edi],ax je at0 cmp [edi+1],ax je at1 cmp [edi+2],ax je at2 cmp [edi+3],ax je at3 add edi,4 cmp edi,ecx jc @B ;достаточно больших циклов eo_long: add ecx,3 sub ecx,edi je eo_short @@: cmp [edi+ecx-1],ax ;не факт, что мы найдем первое! je atECX dec ecx jne @B eo_short: ret atECX: lea edi,[edi+ecx-1] ret at3: inc edi at2: inc edi at1: inc edi at0: ret in_str endp должно быть быстрее в разы,.. хотя не знаю как там scasb работает...
Если размер строки большой (мегабайты) нужно оптимизировать под кеш - сначала читать блок, скажем 128Кб, потом уже искать в нём каким нибудь хитрым способом. А тут же маленький пакет, просто тупо искать: Код (Text): mov esi, pointer_to_string mov edx, 0AA55h align 16 loop: movzx eax, word[esi] ; именно так inc esi cmp eax, edx jz found test al, al jnz loop zzzyab Оригинальный способ заполнения области памяти .
Скорее байт - линейка обычно 64 байта. Пока просматриваем одну нужно делать prefetch на следующую, и т.д. Наверно так... ...Да и ecx на ноль после scasbа все-таки можно не проверять, если в конец строки записать например 0
boozook > IMHO не будет оно быстрее, там куча 16-битных операций над невыровненными данными ( cmp [edi],ax ) Параллелить, это как-нибудь так (без учёта длины!): Код (Text): .1: mov eax, [esi] .2: add esi, 4 xor eax, 55555555h lea edx, [eax-01010101h] not eax and edx, 80808080h and edx, eax jz .1 lea ebx, [eax-01010101h] not eax and ebx, 80808080h and ebx, eax jnz доп_проверка ; DWORD содержит одновременно 55h и 0AAh ; нужно отдельно проверить, что это именно 55h[b],[/b]AAh, но мне лень :) ; вариант пересечения DWORD test edx, edx mov eax [esi] jns .2 cmp al, 0AAh jz .2 found: