Пятница, 29 Марта 2024, 15:18

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Форум игроделов » Программирование » C/C++ » Посчитать хеш
Посчитать хеш
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, ладно, это уже высший пилотаж :D

Жду плюса в репу! А все думают, что Фалько лох - ничего не смыслит в программировании. Гуру с 30 лет опыта!!! B)
drcrackДата: Воскресенье, 17 Июня 2018, 23:43 | Сообщение # 18
старожил
Сейчас нет на сайте
Цитата
это уже высший пилотаж

не, высший это если еще сверху добавить многопоточность :D
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
Форум игроделов » Программирование » C/C++ » Посчитать хеш
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг