Посчитать хеш
|
|
Quad69 | Дата: Воскресенье, 17 Июня 2018, 19:53 | Сообщение # 1 |
заслуженный участник
Сейчас нет на сайте
| Пишу DLL'ку для Game Maker Studio 2 которая будет считать хеш файла Adler32. Саму функцию написал правильно, всё работает, но скорость просто ужасная.
Для сравнения есть файл 350мб: md5_file который есть в gms считает за ~2 секунды, функция которую написал я считает это больше 20 секунд.
С C++ знаком очень плохо, поэтому прошу помощи, проверьте где и что не так.
Код #include "stdafx.h" #include "MHash.h" #include <stdio.h>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT double adler32_file(char* filename) { FILE *fid = fopen(filename, "rb"); if (fid == NULL) return(0);
unsigned char c;
unsigned long s1 = 1; unsigned long s2 = 0;
while(true) { c = fgetc(fid);
if (feof(fid)) break;
s1 = (s1 + c) % 65521; s2 = (s2 + s1) % 65521; }
return (s2 << 16) + s1; }
Сообщение отредактировал maksim1221232 - Среда, 27 Июня 2018, 01:21 |
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 19:58 | Сообщение # 2 |
старожил
Сейчас нет на сайте
| maksim1221232, читать по одному байтику из файла - узкое место. Закачайте файл в буффер, потом из буффера читайте.
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 20:36 | Сообщение # 3 |
заслуженный участник
Сейчас нет на сайте
| Как это можно сделать?
Нашел какой то кусок кода, переписал немного, но считает теперь не правильно.
Код DLLEXPORT double adler32_file(char* filename) { FILE * ptrFile = fopen(filename, "rb");
if (ptrFile == NULL) return(-1);
fseek(ptrFile, 0, SEEK_END); long lSize = ftell(ptrFile); rewind(ptrFile);
char * buffer = (char*)malloc(sizeof(char) * lSize); if (buffer == NULL) return(-2);
size_t result = fread(buffer, 1, lSize, ptrFile); if (result != lSize) return(-3);
puts(buffer);
int buffSize = strlen(buffer); unsigned long s1 = 1; unsigned long s2 = 0;
for (int i = 0; i <= buffSize; i++) { s1 = (s1 + buffer[i]) % 65521; s2 = (s2 + s1) % 65521; }
fclose(ptrFile); free(buffer); return (s2 << 16) + s1; }
Сообщение отредактировал maksim1221232 - Воскресенье, 17 Июня 2018, 20:36 |
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 20:43 | Сообщение # 4 |
старожил
Сейчас нет на сайте
| maksim1221232, 1. Уберите puts(buffer). 2. strlen использовать нельзя. Берите величину lSize, которую Вы уже получили. 3. <= buffSize - будет переполнение. Равно знак надо убрать.
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 21:00 | Сообщение # 5 |
заслуженный участник
Сейчас нет на сайте
| Теперь считает правильно, но все ровно md5_file почему то быстрее... p.s md5 2 секунды, adler32 4 секунды.
|
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 21:08 | Сообщение # 6 |
старожил
Сейчас нет на сайте
| maksim1221232, попробуйте считывать не весь файл в буффер, а порциями, скажем по 1М - эксперементально выберете оптимальную величину буффера.
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 21:29 | Сообщение # 7 |
заслуженный участник
Сейчас нет на сайте
| Код FILE * ptrFile = fopen(filename, "rb");
if (ptrFile == NULL) return(-1);
long pSize = (1024 * 1024 * 1024) * 16;
unsigned char * buffer = (unsigned char*)malloc(sizeof(unsigned char) * pSize); if (buffer == NULL) return(-2);
unsigned long s1 = 1; unsigned long s2 = 0;
while (true) { size_t result = fread(buffer, 1, pSize, ptrFile);
for (int i = 0; i < result; i++) { s1 = (s1 + buffer[i]) % 65521; s2 = (s2 + s1) % 65521; }
if (feof(ptrFile)) break; }
fclose(ptrFile); free(buffer); return (s2 << 16) + s1; Теперь вообще не работает...
Сообщение отредактировал maksim1221232 - Воскресенье, 17 Июня 2018, 21:29 |
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 21:37 | Сообщение # 8 |
старожил
Сейчас нет на сайте
| maksim1221232,
1. ты запросил 16Г буффер. Великовато. 2. if (feof(ptrFile)) break; не совсем корректно. Лучше когда размер прочитанного буффера не совпадает с запрашиваемым.
То есть result ! = pSize break;
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 21:51 | Сообщение # 9 |
заслуженный участник
Сейчас нет на сайте
| 3.4сек если читать по 700кб, ниже не нашел.
|
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 21:59 | Сообщение # 10 |
старожил
Сейчас нет на сайте
| maksim1221232, дальнейшая оптимизация:
% 65521 можно не каждый раз делать, а как только превысили эту цифру, то есть if > 65521 then % делать;
Сообщение отредактировал falcoware - Воскресенье, 17 Июня 2018, 22:01 |
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 22:18 | Сообщение # 11 |
заслуженный участник
Сейчас нет на сайте
| Код DLLEXPORT double adler32_file(char* filename) { FILE * ptrFile = fopen(filename, "rb");
if (ptrFile == NULL) return(-1);
const unsigned int pSize = 1024 * 128;
unsigned char * buffer = (unsigned char*)malloc(pSize); if (buffer == NULL) return(-2); unsigned long s1 = 1, s2 = 0;
size_t result; while (true) { result = fread(buffer, 1, pSize, ptrFile);
for (int i = 0; i < result; i++){ s1 = s1 + buffer[i]; if (s1 > 65520) s1 %= 65521; s2 = s2 + s1; if (s2 > 65520) s2 %= 65521; } if (result != pSize) break; }
fclose(ptrFile); free(buffer); return (s2 << 16) + s1; }
1.6сек, можно уже оставить, но как по мне странно что хеш считается так долго, хотя adler32 во много раз быстрее md5
Сообщение отредактировал maksim1221232 - Воскресенье, 17 Июня 2018, 22:19 |
|
| |
drcrack | Дата: Воскресенье, 17 Июня 2018, 22:18 | Сообщение # 12 |
старожил
Сейчас нет на сайте
| Не пишу на С++ уже давно, поэтому точный код не подскажу, но вообще в таком случае было бы логично использовать неблокирующее чтение, чтобы считать один блок пока грузится следующий
|
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 22:25 | Сообщение # 13 |
старожил
Сейчас нет на сайте
| drcrack, хорошая идея. Вынеси чтение буффера в функцию таймера. И когда приступаешь считать хеш буффера - в это время читай в таймере следующий буффер!
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 22:45 | Сообщение # 14 |
заслуженный участник
Сейчас нет на сайте
| Это мне уже не под силу, в гугле нет примеров которые бы у меня работали.
|
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 22:52 | Сообщение # 15 |
старожил
Сейчас нет на сайте
| maksim1221232,
SetTimer(NULL, 1, 10, TIMERPROC MylpTimerFunc);
TIMERPROC MylpTimerFunc() { g_bReadReady = FALSE; if(g_bNeedRead){ read.... g_bReadReady = TRUE; } }
{ g_bNeedRead = TRUE; for (int i = 0; i < result; i++){ s1 = s1 + buffer[i]; if (s1 > 65520) s1 %= 65521; s2 = s2 + s1; if (s2 > 65520) s2 %= 65521; } g_bNeedRead = FALSE; while(!g_bReadReady){;;} }
|
|
| |
Quad69 | Дата: Воскресенье, 17 Июня 2018, 23:14 | Сообщение # 16 |
заслуженный участник
Сейчас нет на сайте
| Все ровно не понял, оно половину красным подчеркивает.
|
|
| |
falcoware | Дата: Воскресенье, 17 Июня 2018, 23:19 | Сообщение # 17 |
старожил
Сейчас нет на сайте
| maksim1221232, ладно, это уже высший пилотаж
Жду плюса в репу! А все думают, что Фалько лох - ничего не смыслит в программировании. Гуру с 30 лет опыта!!!
|
|
| |
drcrack | Дата: Воскресенье, 17 Июня 2018, 23:43 | Сообщение # 18 |
старожил
Сейчас нет на сайте
| Цитата это уже высший пилотаж не, высший это если еще сверху добавить многопоточность
|
|
| |
afq | Дата: Понедельник, 18 Июня 2018, 04:22 | Сообщение # 19 |
Разработчик
Сейчас нет на сайте
| maksim1221232, возможно время ещё занимает выделение памяти, попробуй получить размер файла, и от этого уже знать сколько нужно выделить. Так у тебя проблем не будет с любым размеров файла. Добавлено (18 Июня 2018, 04:19) --------------------------------------------- Но если размеры файлов очень большие могут быть, то циклическое считывание файла по 512 мб хватит. Добавлено (18 Июня 2018, 04:22) --------------------------------------------- falcoware, а точно нужен таймер, можно же использовать поточную функцию. Посчитал размер файла, один поток одну часть обрабатывает, другой поток другую.
|
|
| |
drcrack | Дата: Понедельник, 18 Июня 2018, 04:29 | Сообщение # 20 |
старожил
Сейчас нет на сайте
| Цитата maksim1221232, возможно время ещё занимает выделение памяти, попробуй получить размер файла, и от этого уже знать сколько нужно выделить. Так у тебя проблем не будет с любым размеров файла. это все ерунда в сравнении с чтением с диска современные hdd это около 150 мб/с линейного чтения, а файл 350 мб
Цитата falcoware, а точно нужен таймер, можно же использовать поточную функцию. Посчитал размер файла, один поток одну часть обрабатывает, другой поток другую. по причинам, написанным выше, на самом деле одного потока будет достаточно — ну не сможешь ты получать файл быстрее чем диск его тебе может отдавать
алгоритм примерно такой нужен: 1. прочитать 1 блок 2. запросить 2 блок в неблокирующем режиме 3. считать хеш первого блока 4. ждать пока 2 блок будет загружен в память 5. повторять с пункта 2 пока не кончится файл
Сообщение отредактировал drcrack - Понедельник, 18 Июня 2018, 04:34 |
|
| |