快速MD5库并不比Java 7 MD5快?

Gan*_*alf 1 java performance benchmarking md5

所以我一直在寻找一种更快的方法来计算MD5校验和并在Fast MD5库中运行 - 但是当我在我的机器上使用Java 7进行基准测试时,它比Java版本慢.

要么我做一些愚蠢的事情(非常可能),要么Java 7已经实现了更好的算法(也可能).这是我超级简单的"基准" - 也许我今天没有足够的咖啡......

    MD5 digest = new MD5();
    System.out.println(MD5.initNativeLibrary(true));
    byte[] buff = IOUtils.readFully(new FileInputStream(new File("blahblah.bin")), 64000000, true);
    ByteBuffer buffer = ByteBuffer.wrap(buff);
    for (int j = 0; j < 100; j++) {
        start = System.currentTimeMillis();
        String md5Base64 = Utilities.getDigestBase64(buffer);
        end = System.currentTimeMillis();
        total = total + (end-start);
    }
    System.out.println("Took " + ((total)/100.00) + " ms. for " + buff.length+" bytes");
    total = 0;
    for (int i = 0; i < 100; i++) {
        start = System.currentTimeMillis();
        digest.Init();
        digest.Update(buff);
        digest.Final();
        end = System.currentTimeMillis();
        total = total + (end-start);
    }
    System.out.println("Took " + ((total)/100.00) + " ms. for " + buff.length+" bytes");
Run Code Online (Sandbox Code Playgroud)

我得到:

Took 247.99 ms. for 64000000 bytes
Took 295.16 ms. for 64000000 bytes
Run Code Online (Sandbox Code Playgroud)

根据评论,我一遍又一遍地运行benchamrk,得到了最奇怪的结果.FastMD5计算保持不变,但Java 7版本变慢.????

Took 246.54 ms. for 64000000 bytes
Took 294.69 ms. for 64000000 bytes
************************************
Took 540.55 ms. for 64000000 bytes
Took 292.69 ms. for 64000000 bytes
************************************
Took 537.07 ms. for 64000000 bytes
Took 292.12 ms. for 64000000 bytes
Run Code Online (Sandbox Code Playgroud)

Mar*_* A. 13

让我们首先回答您问题的简单部分:

我认为当你再次运行代码时,你的Java 7执行时间会大致加倍,因为如果你只是将你发布的代码放入for循环中,你就会忘记total在第二次,第三次,第四次,...之前重置为0. Java 7测试(对于第一个测试,它可能从变量初始化设置为0).

因此,通过简单地减去未设置回0的偏移来修复表格给出:

Took 246.54 ms. for 64000000 bytes
Took 294.69 ms. for 64000000 bytes              <---.
************************************                |
Took 245.86 ms. for 64000000 bytes   (subtracting 294.69)
Took 292.69 ms. for 64000000 bytes              <---.
************************************                |
Took 244.38 ms. for 64000000 bytes   (subtracting 292.69)
Took 292.12 ms. for 64000000 bytes
Run Code Online (Sandbox Code Playgroud)

现在,事情似乎非常一致,甚至显示了其他一个回复中提到的"JVM热身",它只有大约1%的差异.

现在,为什么Java 7的性能优于FastMD5?

他们可能使用了更好的算法,该算法更适合Java编译器之后执行的优化.

例如,nio ByteBuffers专门设计用于通过使用DMA等本机内容来更快地访问内存.因此,MD5的Java 7实现使用a ByteBuffer作为输入而不是a 的事实byte[]让我认为他们实际上正在利用这些功能(否则他们可能也只是采用了这些功能byte[].)

再说Utilities一遍,我们可能需要知道你的对象究竟做了什么,然后比较FastMD5的源代码和Java实现.

但我会说:你的结果(总计= 0修复)对我来说非常有意义,你可能只是喜欢你可以减少对外部库的依赖!;)

顺便说一句:在3.5GHz CPU上,您看到的性能差异仅相当于每个处理的数据字节大约2-3个CPU时钟周期(每个字节总共大约15个时钟周期).因此,鉴于差异非常小,很可能,它将取决于所使用的确切平台和JVM,其中一个最终会更快.

加成

您的基准测试数字表明您可以使用两个MD5实现处理大约220-260MB/s,如果您查看Google搜索显示的其他声称规格(例如http://www.zorinaq.com/papers/md5),这听起来很合理-amd64.html在"结果实现"下.所以,与你收到的所有其他回复相反,我觉得我相信你的数字.

如果您想要更加确定,请改变byte []的大小,并查看处理时间的结果变化.如果事情按预期工作,您将看到一个线性关系,您可以使用此函数:

total/100.0 = m * buff.length + b           (your usual y = mx + b)
Run Code Online (Sandbox Code Playgroud)

这里m是每字节的处理时间,应该是大约1/250MB/s = 4ns /字节,并且b是函数用于初始化局部变量等的设置时间,以及所System.currentTimeMillis();花费的时间.这个数字应该相当小(可能小于1毫秒).

然后,要确定哪两种算法更适合您,您需要比较mAND b.如果您经常处理小型数据阵列,b可能比m确定哪种算法更好更重要,而对于大型数据集,更小的算法m更好


Jul*_*eau 5

我写了自己的基准。我的答案:

It Depends!
Run Code Online (Sandbox Code Playgroud)

这是我的结果(在 3.4-trunk-amd64 linux 和 Java 1.7.0_05 上运行):

1.) 对于少量数据,Java 胜出。

TINY DATA new byte[12]      SMALL DATA new byte[123]

Java builtin MD5...         Java builtin MD5...
encode 55 MB/s              encode 217 MB/s
encode 55 MB/s              encode 215 MB/s

Java Fast-MD5...            Java Fast-MD5...
encode 31 MB/s              encode 150 MB/s
encode 32 MB/s              encode 159 MB/s

Native Fast-MD5...          Native Fast-MD5...
encode 22 MB/s              encode 133 MB/s
encode 22 MB/s              encode 133 MB/s
Run Code Online (Sandbox Code Playgroud)

2.) 从 1KB 数据开始,Native Fast-MD5 总是胜出:

MEDIUM DATA new byte[1234]  LARGE DATA new byte[12345]

Java builtin MD5...         Java builtin MD5...
encode 351 MB/s             encode 366 MB/s
encode 351 MB/s             encode 369 MB/s

Java Fast-MD5...            Java Fast-MD5...
encode 300 MB/s             encode 325 MB/s
encode 298 MB/s             encode 322 MB/s

Native Fast-MD5...          Native Fast-MD5...
encode 434 MB/s             encode 582 MB/s
encode 450 MB/s             encode 574 MB/s
Run Code Online (Sandbox Code Playgroud)

3.) 速度在 12KB 后似乎稳定。123KB 没有真正的变化:

X-LARGE DATA new byte[123456]

Java builtin MD5...
encode 367 MB/s
encode 370 MB/s

Java Fast-MD5...
encode 325 MB/s
encode 324 MB/s

Native Fast-MD5...
encode 571 MB/s
encode 599 MB/s
Run Code Online (Sandbox Code Playgroud)

结论:

  • 在我的设置中,Java 的内置 MD5 总是胜过 Fast-MD5 的后备(非本地)实现。

  • 随着数据块变大,所有实现都会加速。

  • Fast-MD5 的本机实现是具有更大数据块(1KB 或更大)的赢家。

甘道夫问题:

  • 您确定您正在设置 Fast-MD5 安装以正确使用本机代码(例如,Fast-MD5 能够找到 MD5.so 或 MD5.dll)?

我真的不可能将一个基准放在一起作为“sscce”——它有 150 行!你可以在这里下载它,而不是:

http://juliusdavies.ca/base64bench/

像这样运行它(在用 ant 构建之后):

java ca.juliusdavies.base64bench.MD5BenchByte2Byte MD5.so
Run Code Online (Sandbox Code Playgroud)

这是基准源代码的直接链接:

http://juliusdavies.ca/base64bench/exploded/base64bench/src/java/ca/juliusdavies/base64bench/MD5BenchByte2Byte.java.html