Здравствуйте господа. Собственно нужно оптимизировать вот этот код: Код (Text): align 4 Long2IP proc uses ecx ebx scr:dword,scrid:dword local hIP1:dword local hIP2:dword local hIP3:dword local hIP4:dword mov hIP1,0 mov hIP2,0 mov hIP3,0 mov hIP4,0 mov eax,scr and ebx,not 255 ;---------------- movzx ebx,al push eax mov eax,ebx mov ecx,16777216 mul ecx mov hIP1,eax pop eax shr eax,8 cmp scrid,1 je @F ;---------------- movzx ebx,al push eax mov eax,ebx mov ecx,65536 mul ecx mov hIP2,eax pop eax shr eax,8 cmp scrid,2 je @F ;---------------- movzx ebx,al push eax mov eax,ebx mov ecx,256 mul ecx mov hIP3,eax pop eax shr eax,8 cmp scrid,3 je @F ;---------------- movzx ebx,al push eax mov hIP4,ebx pop eax shr eax,8 @@: mov eax,hIP4 add eax,hIP3 add eax,hIP2 add eax,hIP1 ret Long2IP endp align 4 GetCountry proc ipaddress:dword local address:dword local buffer[32]:byte local iplen:dword local ipcount:dword local ip:dword invoke inet_addr,ipaddress .if eax != -1 mov address,eax mov ipcount,4 @C: dec ipcount invoke Long2IP,address,ipcount mov ip,eax invoke wsprintfA,addr buffer,$CTA0("%u"),ip mov iplen,eax mov ecx,len mov esi,buf mov edi,esi @L1: mov al,[esi] inc esi or al,al jz @L3 cmp al,0Ah jne @L1 mov byte ptr [esi-1],0 jmp @L1 @L3: mov edx,edi @L2: repnz scasb pusha ;---------------------- strcmp inc edx xor ecx,ecx mov ebx,iplen @@: mov al,byte ptr [buffer+ecx] .if byte ptr [edx+ecx] == al inc ecx dec ebx jnz @B add edx,iplen add edx,3 mov ebx,edx @@: mov al,[ebx] inc ebx or al,al jz @F cmp al,',' jne @B mov byte ptr [ebx-1],0 add ebx,1 mov byte ptr [ebx+2],0 invoke lstrcpy,ipaddress,ebx popa xor eax,eax ret .endif @@: ;---------------------- popa repz scasb mov edx,edi dec edx test ecx,ecx jne @L2 .endif cmp ipcount,1 jne @C xor eax,eax dec eax ret GetCountry endp по скорости. Если кто не в курсе, там данные в таком виде: Код (Text): "2185625600","2185822207","US","USA","UNITED STATES" "2185822208","2185887743","DE","DEU","GERMANY" "2185887744","2185953279","US","USA","UNITED STATES" "2185953280","2186018815","DE","DEU","GERMANY" Пытался заменить wsprintfA на dwtoa, не получилось.. Кроме wsprintfA ничего сверх тормозного там не вижу. Если не прав, тыкните носом Спасибо.
быстрее всего работают операции через eax же, тогда в начале лучше Код (Text): sub eax,eax mov hIP1,eax mov hIP2,eax mov hIP3,eax mov hIP4,eax хотя это мелочи
Flasher Поясни на словах, что должен делать твой код. Тогда можно будет говорить об оптимизации. На первый взгляд не понимаю следующее: 1) Допустим invoke inet_addr,ipaddress вернул -1, тогда Код (Text): ... local ipcount:dword ;; !!! не инициализирован local ip:dword invoke inet_addr,ipaddress .if eax != -1 ... @C: ... .endif cmp ipcount,1 ;; !!! jne @C ... 2) Что содержат buf и len? Адрес и длину буфера с базой geo? Тогда зачем на _каждой_ итерации в цикле по ipcount выполнять Код (Text): ... mov ipcount,4 @C: dec ipcount ... ;; <-- begin mov ecx,len mov esi,buf mov edi,esi @L1: mov al,[esi] inc esi or al,al jz @L3 cmp al,0Ah jne @L1 mov byte ptr [esi-1],0 jmp @L1 ;; <-- end ... cmp ipcount,1 jne @C ... 3) Если я правильно понял, то имеем ip-адрес в виде строки "aaa.bbb.ccc.ddd", адрес которой передается в GetCountry в параметре ipaddress. При помощи inet_addr преобразуем его в число в виде 0xddccbbaa. Затем при помощи Long2IP переворачиваем его в 0xaabbccdd, тут непонятно назначение параметра scrid. Перед вызовом Long2IP есть dec ipcount, следовательно scrid никогда не будет больше трех и код после Код (Text): ... cmp scrid,3 je @F ... никогда не получит управления. 4) Собственно алгоритм переворачивания 0xddccbbaa в 0xaabbccdd, который реализован в Long2IP, очень неудачный. Можно использовать ws2_32.dll!ntohl, либо скопировать ее код себе, благо он тривиален. ps Если кто не в курсе, там данные в таком виде ... Например, в файле GeoIPCountryCSV.zip (1'476'084 байт) в таком виде (строки 35557 ... 35560) Код (Text): ... "130.70.0.0","130.72.255.255","2185625600","2185822207","US","United States" "130.73.0.0","130.73.255.255","2185822208","2185887743","DE","Germany" "130.74.0.0","130.74.255.255","2185887744","2185953279","US","United States" "130.75.0.0","130.75.255.255","2185953280","2186018815","DE","Germany" ...
q_q Передаю GetCountry буффер с ip адресом в байтах 130.75.123.0 Код (Text): invoke GetCountry,offset buffer построчно читаю буфер где данные из базы и проверяю совместимость, если совпадает, считываю эту строку до название страны, копирую в буфер, и с успешным возвращением выхожу из функции... По поводу проверки успешного возвращения inet_addr скосячил, там .endif ниже cmp ipcount,1 должен быть. угу Смотри, например если не найдет по 130.75.123.0, то будет проверять по 130.75.0.0, если тоже пусто, то по 130.0.0.0 Перевод ip адреса в целое число в инете показано так: Код (Text): Here we used the formula (1) to compute the IP Number based on 24.24.24.24 404232216 = 16777216*24 + 65536*24 + 256*24 + 24 Тут более подробно: http://www.maxmind.com/app/csv По поводу ntohl, да, выполняет те-же действия более оптимизировано чем моя функция. Код (Text): ; содержимое ntohl mov ecx,eax mov edx,ecx shl edx,10h and eax,0FF00h or eax,edx mov edx,ecx and edx,0FF0000h shr ecx,10h or edx,ecx shl eax,8 shr edx,8 or eax,edx Но например если "130.75.123.0" в базе не найдется как я отсюда уберу 123 ? придется написать функцию которая будет считывать точки с конца строки потом пропустить это всё через inet_addr и опять > ntohl. В аттаче полный исходный код программы. А базу можете скачать отсюда http://ip-to-country.webhosting.info/node/view/6 весит 653кб.
Flasher Но например если "130.75.123.0" в базе не найдется как я отсюда уберу 123 После inet_addr и ntohl имеем нормальный dword. Чтобы убрать 123 достаточно сделать Код (Text): and ip, 0FFFF0000h только убирать ничего не надо, см. выделенное жирным. В аттаче полный исходный код программы ... базу можете скачать отсюда В базе, на которую ты указал, есть строка ""3740270592","3740925951","CN","CHN","CHINA"", что соответствует ""222.240.0.0","222.249.255.255","3740270592","3740925951","CN","China"". Твоя версия программы не найдет страну для адреса "222.242.1.1". Т.е. искать надо не по точному совпадению, а по попаданию в диапазон. Вернемся к оптимизации. Если операция поиска разовая, то твой подход с просмотром базы сверху вниз вполне подойдет. Если предполагается многоразовый поиск, то имеет смысл предварительно преобразовать базу, чтобы сравнивать dword’ы, а не строки.
q_q Благодарю за идеи! Мне многоразовый поиск нужен. Позаимствовал метод работы с массивами у Iczelion'а. Вбиваю в массив "3740270592","3740925951", в виде dword'ов, потом смотрю чтоб наш ип был равно или больще 3740270592 и равно либо меньще 3740925951. Думаю вполне удачно получилось, но я бы хотел чтоб ты взглянул если не занят p.s. чтобы нижеприведенный код заработало, надо открыть ip-to-country.csv и добавить наверху строку [geo]
Flasher я бы хотел чтоб ты взглянул Хорошо, что ты разбил решение задачи на два этапа. Первый - приготовиться к поиску и собственно поиск. Замечания: 1) интересный способ использовать GetPrivateProfileSection чтобы прочитать файл в память и сразу расставить нуль-символы в концах строк. Imho он имеет тот недостаток, что код привязывается к конкретной ОС (а под 9x вообще существует ограничение на размер ini-файла). В AddGeoInfo происходит побайтный анализ строки, если добавить в нее пропуск "пока не конец строки", можно читать сразу из файла; 2) обрати внимание, что во всех строках, кроме пяти первых, начало ip-адресов и сигнатуры страны начинаются с одной и той же позиции, т.е. можно не сканировать в поисках двойных кавычек (хотя для полной уверенности необходимо проверить это наблюдение); 3) если не ориентироваться на подробности организации менеджера памяти той или иной ОС или той или иной rtl, то существует правило - просить память у ОС/rtl большим куском, разумеется, лучше сразу знать сколько надо. Например, для файла, содержащего 80094 диапазонов, потребуется 1281504 байт (4 ipstart + 4 ipend + 3 asciiz country + 5 dummy = 16), т.е. хватит буфера в половину размера файла; 4) организация хранения диапазонов в виде списка приводит к тому, что во время поиска просматриваются все элементы начиная с первого. Насколько я заметил, то диапазоны в файле упорядочены (тоже надо проверять), если хранить диапазоны в виде массива, то искать можно методом половинного деления, что значительно сократит количество сравнений. Итого. Если предположить, что файл ip-to-country.csv меняется редко, можно создать из него ip-to-country.bin, в котором каждая запись 16 байт и диапазоны упорядочены. Использовать последний для поиска.