В архиве - 1) подборка бинарных компараторов, работающих командной строкой с файлами >4Gb, и - 2) гуишная оболочка, которую можно вытягивать в узкую полоску вдоль левого или правого борта экрана, чтобы драгдропом бросать туда файлы "не глядя". Но это в боевом режиме, в режиме настройки окно оболочки по-обычнее: fcdd_mmf.png: https://drive.google.com/open?id=0B7M0DPHIQGRQVENRRVdsQVhHY3c Наведение курсора на любой контрол оболочки выдает инфу о его назначении и ID. А теперь - почему это здесь, в WIN32: оболочка содержит и пару собственных процедур сравнения, и вот одна из них, построеннная на сочетании вроде бы скоростных MMF и RtlCompareMemory, огорошила неожиданной (для меня) тормознутостью. Но - и это, пожалуй, главное - иногда вдруг таки начинает работать в разы быстрее. Хотелось бы разобраться. Исходник в архиве, но указанную процедуру привожу сразу, возможно кому-то хватит взгляда, чтобы въехать: Код (ASM): Proc1 proc uses ebx edi esi hWnd:HWND local hFile1:HANDLE local hFile2:HANDLE local hMapFile1:HANDLE local hMapFile2:HANDLE local lpMem1:DWORD local lpMem2:DWORD local var:DWORD local cntr:DWORD local gran:DWORD local bytes:DWORD local bu[1]:BYTE local bufA[MAX_PATH]:BYTE local buf[MAX_PATH]:TCHAR local err:DWORD invoke GetDlgItemTextA,hWnd,id+29,addr bufA,MAX_PATH invoke htodw,addr bufA mov gran,eax ; (gran = SYSTEM_INFO.dwAllocationGranularity <= GetSystemInfo,addr SYSTEM_INFO) xor eax,eax mov var,eax mov cntr,eax mov err,eax inc eax mov bytes,eax invoke GetDlgItemText,hWnd,id+10,addr buf,MAX_PATH invoke CreateFile,addr buf, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 .if eax==INVALID_HANDLE_VALUE mov err,5 .else mov hFile1,eax invoke CreateFileMapping,hFile1, 0, PAGE_READONLY, 0, ; dwMaximumSizeHigh ; L_I.HighPart 0, ; dwMaximumSizeLow ; L_I.LowPart 0 ; lpName .if eax==0 mov err,17 invoke CloseHandle,hFile1 mov hFile1,0 .else mov hMapFile1,eax .endif .endif invoke GetDlgItemText,hWnd,id+20,addr buf,MAX_PATH invoke CreateFile,addr buf, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 .if eax==INVALID_HANDLE_VALUE mov err,5 .else mov hFile2,eax invoke CreateFileMapping,hFile2, 0, PAGE_READONLY, 0, 0, 0 .if eax==0 mov err,17 invoke CloseHandle,hFile2 mov hFile2,0 .else mov hMapFile2,eax .endif .endif .if err==0 xor ebx,ebx xor edi,edi mov L_I1.HighPart,edi mov L_I1.LowPart,edi fn wsprintf,addr buf,"%8.8lX",edi invoke SetDlgItemText,hWnd,id+7,addr buf invoke SetDlgItemText,hWnd,id+8,addr buf .while TRUE mov edx,edi mov ecx,ebx mov eax,L_I.LowPart sub eax,ebx add ecx,eax jnc @f inc edx @@: .if edx==L_I.HighPart && eax<=gran mov gran,eax inc var .endif invoke MapViewOfFile,hMapFile1, FILE_MAP_READ, edi, ; dwFileOffsetHigh ebx, ; dwFileOffsetLow gran ; dwNumberOfBytesToMap .if eax==0 mov err,16 invoke CloseHandle,hMapFile1 mov hMapFile1,0 invoke CloseHandle,hFile1 mov hFile1,0 .else mov lpMem1,eax .endif invoke MapViewOfFile,hMapFile2, FILE_MAP_READ, edi, ebx, gran .if eax==0 mov err,16 invoke CloseHandle,hMapFile2 mov hMapFile2,0 invoke CloseHandle,hFile2 mov hFile2,0 .else mov lpMem2,eax .endif .break .if err!=0 invoke RtlCompareMemory,lpMem1,lpMem2,gran .if eax!=gran mov err,12 .endif push eax invoke UnmapViewOfFile,lpMem1 invoke UnmapViewOfFile,lpMem2 pop eax .if err!=0 || var!=0 add ebx,eax .break .endif add ebx,gran jnc @f inc edi @@: inc cntr .if ch39==BST_CHECKED mov L_I1.HighPart,edi fn wsprintf,addr buf,"%8.8lX",edi invoke SetDlgItemText,hWnd,id+7,addr buf mov L_I1.LowPart,ebx fn wsprintf,addr buf,"%8.8lX",ebx invoke SetDlgItemText,hWnd,id+8,addr buf invoke SetDlgItemInt,hWnd,id+15,cntr,0 .endif .endw .endif mov L_I1.HighPart,edi fn wsprintf,addr buf,"%8.8lX",edi invoke SetDlgItemText,hWnd,id+7,addr buf mov L_I1.LowPart,ebx fn wsprintf,addr buf,"%8.8lX",ebx invoke SetDlgItemText,hWnd,id+8,addr buf .if err!=0 invoke SetFilePointerEx,hFile1, ebx, edi, 0, FILE_CURRENT invoke ReadFile,hFile1, addr bu, bytes, addr bytes, 0 xor eax,eax mov al,byte ptr[bu] fn wsprintf,addr buf,"%2.2lX",eax invoke SetDlgItemText,hWnd,id+5,addr buf invoke SetFilePointerEx,hFile2, ebx, edi, 0, FILE_CURRENT invoke ReadFile,hFile2, addr bu, bytes, addr bytes, 0 xor eax,eax mov al,byte ptr[bu] fn wsprintf,addr buf,"%2.2lX",eax invoke SetDlgItemText,hWnd,id+6,addr buf .endif invoke CloseHandle,hMapFile1 mov hMapFile1,0 invoke CloseHandle,hFile1 mov hFile1,0 invoke CloseHandle,hMapFile2 mov hMapFile2,0 invoke CloseHandle,hFile2 mov hFile2,0 mov eax,err .if eax==0 mov eax,11 ; "== Equal" .endif ret Proc1 endp fcdd.zip: https://drive.google.com/open?id=0B7M0DPHIQGRQN1FyeDFkTExpNnM
UPD: уточнил и заменил fcdd (и соответственно фотку) + расширен набор компараторов (там mmfc - это выделенная из fcdd процедура MMF+RtlCompareMemory). fcdd.zip: https://drive.google.com/open?id=0B7M0DPHIQGRQLS1tTmduY0puOUU fcdd_mmf.png: https://drive.google.com/open?id=0B7M0DPHIQGRQcEFnRk45b3RtNGM
Скорость маппинга файла какбе намекает, что файл изначально никуда не читается, а страницы подгружаются с диска на лету по мере обращения к ним. Ни на какую линейность тут, очевидно, расчитывать не стоит.
Привет, rmn. Насчет "файл изначально никуда не читается": наоборот, в самом-то начале - как правило - чтение идет куда быстрее, чем любым из компараторов в подборке (mmfc не в счет). Изредка - так до самого конца, но как правило - очень скоро темп резко звмедляется. То, о чем ты сказал, - понятно, но меня занимают такие вопросы: с какой стати обращается не к оперативке, а к диску ? кто виноват (в диапазоне от моего кода до особенностей RtlCompareMemory и вообще win7-32) ? и наконец - как бы изловчиться и продлить период начального бурного темпа ? ----------- UPD: fcdd-3 (исправлена фигня с LAYERED комбобокса)
Так а к чему еще обращаться? Ведь на момент вызова RtlCompareMemory() ни одного из файлов в оперативке нет.
Задача сравнить две области памяти - есть машинная строковая инструкция cmps. Очевидно что заранее нужно отобразить файлы в память. Зачем нужны какие то винапи, comparemem() и диалоги ?? Читается файл или не читается - да без разницы(не имеет отношения к задаче), про права доступа на мсдн почитайте, там и прототипы с описанием апи найдёте. Шикарный бред да есчо и с картинками
Не просто две области, а две области размером больше, чем 232 и желательно быстрее, чем за час Т.е. перед сравнением пробежать по страницам смапленного файла и прочитать с них хотя бы один байт, чтобы гарантированно подгрузить их в оперативку?
MapViewOfFile() не копирует содержимое файла в память, а лишь изменяет свойства страниц виртуальной памяти. Я не знаю, как точно там все реализовано (может инде подскажет ), но предполагаю, что страницы проекции имеют что-то типа guard-page атрибута: при обращении к ним генерируется фолт и система подгружает содержимое страницы из файла, а затем возобновляет операцию чтения. Попробуй, как я выше говорил, сделать "touch" всем страницам, просто прочитав первый байт каждой, а затем уже вызывать функцию сравнения.
Что-то не выходит каменный цветок... Если найдется время - не дашь ли рабочий "touch" ? У меня если размер 1/4 гига это пара секунд, то выше - тормоза резко нарастают.
Как-то так (нанотехнологий не нужно ) Код (ASM): mov esi, lpMem1 mov edi, lpMem2 lea ecx, [esi+gran] touch: mov eax, [esi] mov ebx, [edi] lea esi, [esi+4096] lea edi, {edi+4096] cmp esi, ecx jl touch
rmn, привет и спасибо. Но если я правильно распорядился твоим кодом - Код (ASM): push esi push edi push ebx mov edx,gran mov esi, lpMem1 mov edi, lpMem2 lea ecx, [esi+edx] touch: mov eax, [esi] mov ebx, [edi] lea esi, [esi+4096] lea edi, [edi+4096] cmp esi, ecx jl touch pop ebx pop edi pop esi invoke RtlCompareMemory,lpMem1,lpMem2,gran - то тогда выходит, что если и есть какое-то ускорение, то не очень заметное (во всяком случае сильно медленнее, чем с исходным кодом в редкие моменты наскипидаренности). (с gran - вылетало, потому и edx)
в fcdd есть чекбокс выбора между GetTickCount и QueryPerformanceCounter, считал и тем, и тем, а кроме того - с таймингом каждого компаратора из подборки OK, и в плохие (т.е. почти всегда) моменты fcdd - их средняя скорость стабильно показывается в 4-5 раз выше.
В возникшей, т.с., паузе - об одной детали интерфейса FCDD как компаратора компараторов. Чем больше файл, тем дольше время обработки, и если задача - всего лишь проверка на идентичность, то прямо-таки напрашивается выход при первом несовпадении. Тем более что соответствующий ключ - дело плевое. И однако, к примеру, у FC, Comp и WinDiff от MS - его нет. Это меня так удивило, что даже спросил на олдскульном dostips.com, нет ли у FC недокументированного (http://www.dostips.com/forum/viewtopic.php?f=3&t=7725 - "About FC /B - for very large files"). Ответили два мексиканца: один набросал батфайл для требуемого выхода из FC, а другой удивился, что я удивился: "You do realize it was written by someone at Microsoft. That in itself should tell you something. I usually blame it on all the Peyote they smoked when the company was first located in New Mexico." А еще запросил автора FCB насчет этого недостающего и FCB ключа. Сначала он не ответил. Тогда написал баг-репорт: файлы размером 0xFFFFFFFF - FCB считает равными. Uwe исправил, поблагодарил. Тогда запросил повторно про ключ. Ответ пришел замечательный: "An option to stop after n mismatches might be handy but usually the files I compare are identical, so I did not feel the need. Regards, Uwe". Вот почему во встроенном в FCDD файл-мейкере есть ячейки первого и последнего байтов (остальные-то в тестовых файлах - нули).
UPD: fcdd v.2017-06-25 1) Проблемная процедура (MMF+RtlCompareMemory) выделена а mmfc.exe. 2) Изменен сабкласс комбобокса для ведения лога длительностей операций сравнения. Длительность измеряется через QueryPerformansCounter, измерение индицируется через GetTickCount, лог автоматом записывается в файл. 3) NB: если читатель знает (а еще лучше - если сам накодил) скоростной компаратор громадных бинарников, не учтенный в FCDD, - просьба поделиться!