Тестирование производительности вычисления md5 на разных языках

Artmoneyse

Администратор
Команда форума
Администратор
Решил проверить скорость работы вычисления хеш суммы md5 на разных языках.
Возможно, по некоторым языкам значения были получены не точно, можно оптимизировать алгоритмы.
Но, всё же данный пример иллюстрирует тот факт, что не важно на каком языке писать, если говнокодить, хвалёный супер быстрый язык не поможет.

Суть теста, вычисление хеш суммы файла в цикле, 20 000раз.
Для теста взят файл libssl-1_1.dll (520Кб), по сути подойдет любой аналогичного размера.
Процессор i7-3770, по тесту php был другой (мощнее).

Результаты:
VB6 - 26 секунд
C++ (VC 2017) - 36 секунд
php 8 - 23 секунды
Java 17 - 49 секунд

Код который использовался прикреплю постами ниже
 
Последнее редактирование:

Artmoneyse

Администратор
Команда форума
Администратор
Visual Basic 6.0
Библиотека "advapi32"
Visual Basic:
Private Sub Form_Load()
    Dim start_time As Long
    Dim end_time As Long
    Dim i As Integer
        start_time = (Now - DateSerial(1970, 1, 1)) * 86400
            For i = 0 To 20000
                GetMD5 (App.Path & "\libssl-1_1.dll") ' b9b344d670a8fae332cda7bf7d9a98d2
            Next i
        end_time = (Now - DateSerial(1970, 1, 1)) * 86400
    MsgBox end_time - start_time & " sec"
End Sub
Visual Basic:
Option Explicit
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Public Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Public Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Public Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, ByRef phHash As Long) As Long
Public Declare Function CryptHashData Lib "advapi32.dll" (ByVal hHash As Long, pbData As Any, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long
Public Declare Function CryptGetHashParam Lib "advapi32.dll" (ByVal pCryptHash As Long, ByVal dwParam As Long, ByRef pbData As Any, ByRef pcbData As Long, ByVal dwFlags As Long) As Long
Public Declare Function CryptDestroyHash Lib "advapi32.dll" (ByVal hHash As Long) As Long
Public Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwFlags As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hHandle As Long) As Long

Public Const OPEN_EXISTING As Long = 3
Public Const GENERIC_READ As Long = &H80000000
Public Const FILE_SHARE_READ As Long = &H1
Public Const PROV_RSA_FULL As Long = 1
Public Const CRYPT_VERIFYCONTEXT = &HF0000000
Public Const HP_HASHVAL As Long = 2
Public Const CALG_MD5 As Long = 32771
Public Const lMD5Length As Long = 16

Public Function GetMD5(sFile$) As String
    Dim hFile&, uBuffer() As Byte, lFileSize&, lBytesRead&, uMD5(lMD5Length) As Byte
    Dim i&, hCrypt&, hHash&, sMD5$

    hFile = CreateFile(sFile, GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, ByVal 0&, ByVal 0&)

    If hFile > 0 Then
        lFileSize = GetFileSize(hFile, ByVal 0&)
        'File size must be greater than 0
        If lFileSize > 0 Then
            'Prepare the buffer
            ReDim uBuffer(lFileSize - 1)

            'Read the file
            If ReadFile(hFile, uBuffer(0), lFileSize, lBytesRead, ByVal 0&) <> 0 Then
                If lBytesRead <> lFileSize Then
                    ReDim Preserve uBuffer(lBytesRead - 1)
                End If
          
                'Acquire the context, create the hash, and hash the data
                If CryptAcquireContext(hCrypt, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) <> 0 Then
                    If CryptCreateHash(hCrypt, CALG_MD5, 0&, 0&, hHash) <> 0 Then
                        If CryptHashData(hHash, uBuffer(0), lBytesRead, ByVal 0&) <> 0 Then
                            If CryptGetHashParam(hHash, HP_HASHVAL, uMD5(0), lMD5Length, 0) <> 0 Then
                                'Build the MD5 string
                                For i = 0 To lMD5Length - 1
                                    sMD5 = sMD5 & (Right$("0" & Hex$(uMD5(i)), 2))
                                Next i
                            End If
                        End If

                        'Destroy the hash
                        CryptDestroyHash hHash
                    End If
              
                    CryptReleaseContext hCrypt, 0
                End If
            End If
        End If
        CloseHandle hFile
    End If
    GetMD5 = LCase$(sMD5)
End Function
 
Последнее редактирование:

Artmoneyse

Администратор
Команда форума
Администратор
C++ Visual Studio 2017
C++:
#include <iostream>
#include "md5.h"
#include <Windows.h>
#include <ctime>

int main()
{
    std::time_t start_time = std::time(0);  // is an integer type
    for (int i = 0; i < 20000; i++)
    {
        md5file("libssl-1_1.dll");
    }

    std::time_t end_time = std::time(0);  // is an integer type

    std::cout << end_time - start_time << " sec\n";
    Sleep(5000);
}
C++:
#ifndef MD5_H
#define MD5_H

#define _CRT_SECURE_NO_WARNINGS

#include <string>
#include <cstring>

std::string md5(std::string dat);
std::string md5(const void* dat, size_t len);
std::string md5file(const char* filename);
std::string md5file(std::FILE* file);
std::string md5sum6(std::string dat);
std::string md5sum6(const void* dat, size_t len);

#endif // end of MD5_H
C++:
#include "md5.h"

#ifndef HAVE_OPENSSL

#define F(x, y, z)   ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z)   ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z)   ((x) ^ (y) ^ (z))
#define I(x, y, z)   ((y) ^ ((x) | ~(z)))
#define STEP(f, a, b, c, d, x, t, s) \
        (a) += f((b), (c), (d)) + (x) + (t); \
        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
        (a) += (b);

#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
            (*(MD5_u32 *)&ptr[(n) * 4])
#define GET(n) \
            SET(n)
#else
#define SET(n) \
            (ctx->block[(n)] = \
            (MD5_u32)ptr[(n) * 4] | \
            ((MD5_u32)ptr[(n) * 4 + 1] << 8) | \
            ((MD5_u32)ptr[(n) * 4 + 2] << 16) | \
            ((MD5_u32)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
            (ctx->block[(n)])
#endif

typedef unsigned int MD5_u32;

typedef struct {
    MD5_u32 lo, hi;
    MD5_u32 a, b, c, d;
    unsigned char buffer[64];
    MD5_u32 block[16];
} MD5_CTX;

static void MD5_Init(MD5_CTX *ctx);
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
static void MD5_Final(unsigned char *result, MD5_CTX *ctx);

static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) {
    const unsigned char *ptr;
    MD5_u32 a, b, c, d;
    MD5_u32 saved_a, saved_b, saved_c, saved_d;

    ptr = (const unsigned char*)data;

    a = ctx->a;
    b = ctx->b;
    c = ctx->c;
    d = ctx->d;

    do {
        saved_a = a;
        saved_b = b;
        saved_c = c;
        saved_d = d;

        STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
            STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
            STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
            STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
            STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
            STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
            STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
            STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
            STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
            STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
            STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
            STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
            STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
            STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
            STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
            STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
            STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
            STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
            STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
            STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
            STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
            STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
            STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
            STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
            STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
            STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
            STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
            STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
            STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
            STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
            STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
            STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
            STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
            STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
            STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
            STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
            STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
            STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
            STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
            STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
            STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
            STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
            STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
            STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
            STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
            STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
            STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
            STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
            STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
            STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
            STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
            STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
            STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
            STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
            STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
            STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
            STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
            STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
            STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
            STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
            STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
            STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
            STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
            STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)

            a += saved_a;
        b += saved_b;
        c += saved_c;
        d += saved_d;

        ptr += 64;
    } while (size -= 64);

    ctx->a = a;
    ctx->b = b;
    ctx->c = c;
    ctx->d = d;

    return ptr;
}

void MD5_Init(MD5_CTX *ctx) {
    ctx->a = 0x67452301;
    ctx->b = 0xefcdab89;
    ctx->c = 0x98badcfe;
    ctx->d = 0x10325476;

    ctx->lo = 0;
    ctx->hi = 0;
}

void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) {
    MD5_u32 saved_lo;
    unsigned long used, free;

    saved_lo = ctx->lo;
    if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
        ctx->hi++;
    ctx->hi += size >> 29;
    used = saved_lo & 0x3f;

    if (used) {
        free = 64 - used;
        if (size < free) {
            memcpy(&ctx->buffer[used], data, size);
            return;
        }

        memcpy(&ctx->buffer[used], data, free);
        data = (unsigned char *)data + free;
        size -= free;
        body(ctx, ctx->buffer, 64);
    }

    if (size >= 64) {
        data = body(ctx, data, size & ~(unsigned long)0x3f);
        size &= 0x3f;
    }

    memcpy(ctx->buffer, data, size);
}

void MD5_Final(unsigned char *result, MD5_CTX *ctx) {
    unsigned long used, free;
    used = ctx->lo & 0x3f;
    ctx->buffer[used++] = 0x80;
    free = 64 - used;

    if (free < 8) {
        memset(&ctx->buffer[used], 0, free);
        body(ctx, ctx->buffer, 64);
        used = 0;
        free = 64;
    }

    memset(&ctx->buffer[used], 0, free - 8);

    ctx->lo <<= 3;
    ctx->buffer[56] = ctx->lo;
    ctx->buffer[57] = ctx->lo >> 8;
    ctx->buffer[58] = ctx->lo >> 16;
    ctx->buffer[59] = ctx->lo >> 24;
    ctx->buffer[60] = ctx->hi;
    ctx->buffer[61] = ctx->hi >> 8;
    ctx->buffer[62] = ctx->hi >> 16;
    ctx->buffer[63] = ctx->hi >> 24;
    body(ctx, ctx->buffer, 64);
    result[0] = ctx->a;
    result[1] = ctx->a >> 8;
    result[2] = ctx->a >> 16;
    result[3] = ctx->a >> 24;
    result[4] = ctx->b;
    result[5] = ctx->b >> 8;
    result[6] = ctx->b >> 16;
    result[7] = ctx->b >> 24;
    result[8] = ctx->c;
    result[9] = ctx->c >> 8;
    result[10] = ctx->c >> 16;
    result[11] = ctx->c >> 24;
    result[12] = ctx->d;
    result[13] = ctx->d >> 8;
    result[14] = ctx->d >> 16;
    result[15] = ctx->d >> 24;
    memset(ctx, 0, sizeof(*ctx));
}
#else
#include <openssl/md5.h>
#endif


using namespace std;

/* Return Calculated raw result(always little-endian), the size is always 16 */
void md5bin(const void* dat, size_t len, unsigned char out[16]) {
    MD5_CTX c;
    MD5_Init(&c);
    MD5_Update(&c, dat, len);
    MD5_Final(out, &c);
}

static char hb2hex(unsigned char hb) {
    hb = hb & 0xF;
    return hb < 10 ? '0' + hb : hb - 10 + 'a';
}

string md5file(const char* filename) {
    std::FILE* file = std::fopen(filename, "rb");
    string res = md5file(file);
    std::fclose(file);
    return res;
}

string md5file(std::FILE* file) {

    MD5_CTX c;
    MD5_Init(&c);

    char buff[BUFSIZ];
    unsigned char out[16];
    size_t len = 0;
    while ((len = std::fread(buff, sizeof(char), BUFSIZ, file)) > 0) {
        MD5_Update(&c, buff, len);
    }
    MD5_Final(out, &c);

    string res;
    for (size_t i = 0; i < 16; ++i) {
        res.push_back(hb2hex(out[i] >> 4));
        res.push_back(hb2hex(out[i]));
    }
    return res;
}

string md5(const void* dat, size_t len) {
    string res;
    unsigned char out[16];
    md5bin(dat, len, out);
    for (size_t i = 0; i < 16; ++i) {
        res.push_back(hb2hex(out[i] >> 4));
        res.push_back(hb2hex(out[i]));
    }
    return res;
}

std::string md5(std::string dat) {
    return md5(dat.c_str(), dat.length());
}

/* Generate shorter md5sum by something like base62 instead of base16 or base10. 0~61 are represented by 0-9a-zA-Z */
string md5sum6(const void* dat, size_t len) {
    static const char* tbl = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    string res;
    unsigned char out[16];
    md5bin(dat, len, out);
    for (size_t i = 0; i < 6; ++i) {
        res.push_back(tbl[out[i] % 62]);
    }
    return res;
}

std::string md5sum6(std::string dat) {
    return md5sum6(dat.c_str(), dat.length());
}
 

Artmoneyse

Администратор
Команда форума
Администратор
php 8
PHP:
<?php
$file = 'libssl-1_1.dll';
$start = microtime( true );
for ($i = 1; $i < 20000; $i++) {
    md5_file($file);
}
echo sprintf( '%.2f sec.', microtime( true ) - $start );
?>
 

Artmoneyse

Администратор
Команда форума
Администратор
Java 17
Библиотека "commons-codec-1.15.jar"
Java:
package ua.artmoneyse.test;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) {
        
        long start_time = System.currentTimeMillis() / 1000;
        for (int x = 0; x < 20000; x++) {
            try {
                InputStream is = Files.newInputStream(Paths.get("libssl-1_1.dll"));
                String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long end_time = System.currentTimeMillis() / 1000;
        System.out.println(end_time - start_time + " sec");
    }
}
 
Сверху