О сравнении бинарных файлов, бОльших 4Gb

Тема в разделе "WASM.WIN32", создана пользователем kero, 16 май 2017.

  1. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    В архиве - 1) подборка бинарных компараторов, работающих командной строкой с файлами >4Gb, и - 2) гуишная оболочка, которую можно вытягивать в узкую полоску вдоль левого или правого борта экрана, чтобы драгдропом бросать туда файлы "не глядя". Но это в боевом режиме, в режиме настройки окно оболочки по-обычнее:

    fcdd_mmf.png: https://drive.google.com/open?id=0B7M0DPHIQGRQVENRRVdsQVhHY3c
    fcdd_mmf.png

    Наведение курсора на любой контрол оболочки выдает инфу о его назначении и ID.

    А теперь - почему это здесь, в WIN32: оболочка содержит и пару собственных процедур сравнения, и вот одна из них, построеннная на сочетании вроде бы скоростных MMF и RtlCompareMemory, огорошила неожиданной (для меня) тормознутостью. Но - и это, пожалуй, главное - иногда вдруг таки начинает работать в разы быстрее. Хотелось бы разобраться. Исходник в архиве, но указанную процедуру привожу сразу, возможно кому-то хватит взгляда, чтобы въехать:
    Код (ASM):
    1.  
    2. Proc1 proc uses ebx edi esi hWnd:HWND
    3.  
    4.   local hFile1:HANDLE
    5.   local hFile2:HANDLE
    6.   local hMapFile1:HANDLE
    7.   local hMapFile2:HANDLE
    8.   local lpMem1:DWORD
    9.   local lpMem2:DWORD
    10.   local var:DWORD
    11.   local cntr:DWORD
    12.   local gran:DWORD
    13.   local bytes:DWORD
    14.   local bu[1]:BYTE
    15.   local bufA[MAX_PATH]:BYTE
    16.   local buf[MAX_PATH]:TCHAR
    17.   local err:DWORD
    18.  
    19.   invoke GetDlgItemTextA,hWnd,id+29,addr bufA,MAX_PATH
    20.   invoke htodw,addr bufA
    21.   mov gran,eax            ; (gran = SYSTEM_INFO.dwAllocationGranularity <= GetSystemInfo,addr SYSTEM_INFO)
    22.   xor eax,eax
    23.   mov var,eax
    24.   mov cntr,eax
    25.   mov err,eax
    26.   inc eax
    27.   mov bytes,eax
    28.   invoke GetDlgItemText,hWnd,id+10,addr buf,MAX_PATH
    29.   invoke CreateFile,addr buf,
    30.                     GENERIC_READ,
    31.                     FILE_SHARE_READ,
    32.                     0,
    33.                     OPEN_EXISTING,
    34.                     FILE_ATTRIBUTE_NORMAL,
    35.                     0
    36.   .if eax==INVALID_HANDLE_VALUE
    37.     mov err,5
    38.   .else
    39.     mov hFile1,eax
    40.     invoke CreateFileMapping,hFile1,
    41.                              0,
    42.                              PAGE_READONLY,
    43.                              0,                   ; dwMaximumSizeHigh ; L_I.HighPart
    44.                              0,                   ; dwMaximumSizeLow  ; L_I.LowPart
    45.                              0                    ; lpName
    46.     .if eax==0
    47.       mov err,17
    48.       invoke CloseHandle,hFile1
    49.       mov hFile1,0
    50.     .else
    51.       mov hMapFile1,eax
    52.     .endif
    53.   .endif
    54.   invoke GetDlgItemText,hWnd,id+20,addr buf,MAX_PATH
    55.   invoke CreateFile,addr buf,
    56.                     GENERIC_READ,
    57.                     FILE_SHARE_READ,
    58.                     0,
    59.                     OPEN_EXISTING,
    60.                     FILE_ATTRIBUTE_NORMAL,
    61.                     0
    62.   .if eax==INVALID_HANDLE_VALUE
    63.     mov err,5
    64.   .else
    65.     mov hFile2,eax
    66.     invoke CreateFileMapping,hFile2,
    67.                              0,
    68.                              PAGE_READONLY,
    69.                              0,
    70.                              0,
    71.                              0
    72.     .if eax==0
    73.       mov err,17
    74.       invoke CloseHandle,hFile2
    75.       mov hFile2,0
    76.     .else
    77.       mov hMapFile2,eax
    78.     .endif
    79.   .endif
    80.   .if err==0
    81.     xor ebx,ebx
    82.     xor edi,edi
    83.     mov L_I1.HighPart,edi
    84.     mov L_I1.LowPart,edi
    85.     fn wsprintf,addr buf,"%8.8lX",edi
    86.     invoke SetDlgItemText,hWnd,id+7,addr buf
    87.     invoke SetDlgItemText,hWnd,id+8,addr buf
    88.     .while TRUE
    89.       mov edx,edi
    90.       mov ecx,ebx
    91.       mov eax,L_I.LowPart
    92.       sub eax,ebx
    93.       add ecx,eax
    94.       jnc @f
    95.       inc edx
    96. @@:
    97.       .if edx==L_I.HighPart && eax<=gran
    98.         mov gran,eax
    99.         inc var
    100.       .endif
    101.       invoke MapViewOfFile,hMapFile1,
    102.                            FILE_MAP_READ,
    103.                            edi,                   ; dwFileOffsetHigh
    104.                            ebx,                   ; dwFileOffsetLow
    105.                            gran                   ; dwNumberOfBytesToMap
    106.       .if eax==0
    107.         mov err,16
    108.         invoke CloseHandle,hMapFile1
    109.         mov hMapFile1,0
    110.         invoke CloseHandle,hFile1
    111.         mov hFile1,0
    112.       .else
    113.         mov lpMem1,eax
    114.       .endif
    115.       invoke MapViewOfFile,hMapFile2,
    116.                            FILE_MAP_READ,
    117.                            edi,
    118.                            ebx,
    119.                            gran
    120.       .if eax==0
    121.         mov err,16
    122.         invoke CloseHandle,hMapFile2
    123.         mov hMapFile2,0
    124.         invoke CloseHandle,hFile2
    125.         mov hFile2,0
    126.       .else
    127.         mov lpMem2,eax
    128.       .endif
    129.     .break .if err!=0
    130.  
    131.       invoke RtlCompareMemory,lpMem1,lpMem2,gran
    132.  
    133.       .if eax!=gran
    134.         mov err,12
    135.       .endif
    136.       push eax
    137.       invoke UnmapViewOfFile,lpMem1
    138.       invoke UnmapViewOfFile,lpMem2
    139.       pop eax
    140.       .if err!=0 || var!=0
    141.         add ebx,eax
    142.     .break
    143.       .endif
    144.       add ebx,gran
    145.       jnc @f
    146.       inc edi
    147. @@:
    148.       inc cntr
    149.       .if ch39==BST_CHECKED
    150.         mov L_I1.HighPart,edi
    151.         fn wsprintf,addr buf,"%8.8lX",edi
    152.         invoke SetDlgItemText,hWnd,id+7,addr buf
    153.         mov L_I1.LowPart,ebx
    154.         fn wsprintf,addr buf,"%8.8lX",ebx
    155.         invoke SetDlgItemText,hWnd,id+8,addr buf
    156.         invoke SetDlgItemInt,hWnd,id+15,cntr,0
    157.       .endif
    158.     .endw
    159.   .endif
    160.   mov L_I1.HighPart,edi
    161.   fn wsprintf,addr buf,"%8.8lX",edi
    162.   invoke SetDlgItemText,hWnd,id+7,addr buf
    163.   mov L_I1.LowPart,ebx
    164.   fn wsprintf,addr buf,"%8.8lX",ebx
    165.   invoke SetDlgItemText,hWnd,id+8,addr buf
    166.   .if err!=0
    167.     invoke SetFilePointerEx,hFile1,
    168.                             ebx,
    169.                             edi,
    170.                             0,
    171.                             FILE_CURRENT
    172.     invoke ReadFile,hFile1,
    173.                     addr bu,
    174.                     bytes,
    175.                     addr bytes,
    176.                     0
    177.     xor eax,eax
    178.     mov al,byte ptr[bu]
    179.     fn wsprintf,addr buf,"%2.2lX",eax
    180.     invoke SetDlgItemText,hWnd,id+5,addr buf
    181.     invoke SetFilePointerEx,hFile2,
    182.                             ebx,
    183.                             edi,
    184.                             0,
    185.                             FILE_CURRENT
    186.     invoke ReadFile,hFile2,
    187.                     addr bu,
    188.                     bytes,
    189.                     addr bytes,
    190.                     0
    191.     xor eax,eax
    192.     mov al,byte ptr[bu]
    193.     fn wsprintf,addr buf,"%2.2lX",eax
    194.     invoke SetDlgItemText,hWnd,id+6,addr buf
    195.   .endif
    196.   invoke CloseHandle,hMapFile1
    197.   mov hMapFile1,0
    198.   invoke CloseHandle,hFile1
    199.   mov hFile1,0
    200.   invoke CloseHandle,hMapFile2
    201.   mov hMapFile2,0
    202.   invoke CloseHandle,hFile2
    203.   mov hFile2,0
    204.   mov eax,err
    205.   .if eax==0
    206.     mov eax,11                                    ; "== Equal"
    207.   .endif
    208.   ret
    209. Proc1 endp
    210.  
    fcdd.zip: https://drive.google.com/open?id=0B7M0DPHIQGRQN1FyeDFkTExpNnM
     
    Последнее редактирование: 16 май 2017
    Mikl___ нравится это.
  2. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва

    Вложения:

    • fcdd-2.zip
      Размер файла:
      412,8 КБ
      Просмотров:
      367
    Последнее редактирование: 9 июн 2017
    Mikl___ нравится это.
  3. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Скорость маппинга файла какбе намекает, что файл изначально никуда не читается, а страницы подгружаются с диска на лету по мере обращения к ним. Ни на какую линейность тут, очевидно, расчитывать не стоит.
     
    Mikl___ нравится это.
  4. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Привет, rmn.

    Насчет "файл изначально никуда не читается":
    наоборот, в самом-то начале - как правило - чтение идет куда быстрее, чем любым из компараторов в подборке (mmfc не в счет).
    Изредка - так до самого конца, но как правило - очень скоро темп резко звмедляется.
    То, о чем ты сказал, - понятно, но меня занимают такие вопросы:
    с какой стати обращается не к оперативке, а к диску ?
    кто виноват (в диапазоне от моего кода до особенностей RtlCompareMemory и вообще win7-32) ?
    и наконец - как бы изловчиться и продлить период начального бурного темпа ?
    -----------
    UPD: fcdd-3 (исправлена фигня с LAYERED комбобокса)
     

    Вложения:

    • fcdd-3.zip
      Размер файла:
      413 КБ
      Просмотров:
      379
    Mikl___ нравится это.
  5. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Так а к чему еще обращаться? Ведь на момент вызова RtlCompareMemory() ни одного из файлов в оперативке нет.
     
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Задача сравнить две области памяти - есть машинная строковая инструкция cmps. Очевидно что заранее нужно отобразить файлы в память. Зачем нужны какие то винапи, comparemem() и диалоги ??
    Читается файл или не читается - да без разницы(не имеет отношения к задаче), про права доступа на мсдн почитайте, там и прототипы с описанием апи найдёте.
    Шикарный бред да есчо и с картинками :crazy:
     
  7. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Не просто две области, а две области размером больше, чем 232 и желательно быстрее, чем за час :)

    Т.е. перед сравнением пробежать по страницам смапленного файла и прочитать с них хотя бы один байт, чтобы гарантированно подгрузить их в оперативку?
     
  8. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Т.е. MapViewOfFile для RtlCompareMemory мало? Разъясни, пожалуйста.
     
  9. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Единственный диалог, который не зачем, - диалог с тобой, его и не будет.
     
    Последнее редактирование: 10 июн 2017
    Полный 30h нравится это.
  10. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    MapViewOfFile() не копирует содержимое файла в память, а лишь изменяет свойства страниц виртуальной памяти. Я не знаю, как точно там все реализовано (может инде подскажет :)), но предполагаю, что страницы проекции имеют что-то типа guard-page атрибута: при обращении к ним генерируется фолт и система подгружает содержимое страницы из файла, а затем возобновляет операцию чтения.
    Попробуй, как я выше говорил, сделать "touch" всем страницам, просто прочитав первый байт каждой, а затем уже вызывать функцию сравнения.
     
  11. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    rmn,

    А какая собственно разница как это реализовано.
     
    Последнее редактирование модератором: 11 июн 2017
  12. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Что-то не выходит каменный цветок... Если найдется время - не дашь ли рабочий "touch" ?

    У меня если размер 1/4 гига это пара секунд, то выше - тормоза резко нарастают.
     
    Последнее редактирование: 12 июн 2017
  13. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
     
  14. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Как-то так (нанотехнологий не нужно :))
    Код (ASM):
    1.  
    2.     mov esi, lpMem1
    3.     mov edi, lpMem2
    4.     lea ecx, [esi+gran]
    5.  
    6. touch:
    7.     mov eax, [esi]
    8.     mov ebx, [edi]
    9.     lea esi, [esi+4096]
    10.     lea edi, {edi+4096]
    11.     cmp esi, ecx
    12.     jl  touch
    13.  
     
  15. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    rmn, привет и спасибо.

    Но если я правильно распорядился твоим кодом -

    Код (ASM):
    1.  
    2.     push esi
    3.     push edi
    4.     push ebx
    5.    
    6.     mov edx,gran
    7.    
    8.     mov esi, lpMem1  
    9.     mov edi, lpMem2  
    10.     lea ecx, [esi+edx]
    11. touch:
    12.     mov eax, [esi]    
    13.     mov ebx, [edi]    
    14.     lea esi, [esi+4096]
    15.     lea edi, [edi+4096]
    16.     cmp esi, ecx      
    17.     jl  touch          
    18.    
    19.     pop ebx
    20.     pop edi
    21.     pop esi
    22.    
    23.     invoke RtlCompareMemory,lpMem1,lpMem2,gran
    24.  
    - то тогда выходит, что если и есть какое-то ускорение, то не очень заметное
    (во всяком случае сильно медленнее, чем с исходным кодом в редкие моменты наскипидаренности).

    (с gran - вылетало, потому и edx)
     
  16. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Так ты точно посчитай тайминги. Может там уже просто в скорость чтения памяти уперлись.
     
  17. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    в fcdd есть чекбокс выбора между GetTickCount и QueryPerformanceCounter, считал и тем, и тем, а кроме того - с таймингом каждого компаратора из подборки OK, и в плохие (т.е. почти всегда) моменты fcdd - их средняя скорость стабильно показывается в 4-5 раз выше.
     
  18. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    В возникшей, т.с., паузе - об одной детали интерфейса 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 файл-мейкере есть ячейки первого и последнего байтов (остальные-то в тестовых файлах - нули).
     
  19. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    UPD: fcdd v.2017-06-25

    1) Проблемная процедура (MMF+RtlCompareMemory) выделена а mmfc.exe.

    2) Изменен сабкласс комбобокса для ведения лога длительностей операций сравнения. Длительность измеряется через QueryPerformansCounter, измерение индицируется через GetTickCount, лог автоматом записывается в файл.

    3) NB: если читатель знает (а еще лучше - если сам накодил) скоростной компаратор громадных бинарников, не учтенный в FCDD, - просьба поделиться!
     

    Вложения:

    • fcdd.zip
      Размер файла:
      486,5 КБ
      Просмотров:
      352
  20. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    замените этим, плз: fcdd-4.zip
     

    Вложения:

    • fcdd-4.zip
      Размер файла:
      486,9 КБ
      Просмотров:
      376
    Последнее редактирование: 27 июн 2017