java - 如何加速这段 Java 代码?

标签 java optimization benchmarking compiler-optimization micro-optimization

我正在尝试对 Java 执行一项简单任务的速度进行基准测试:将一个巨大的文件读入内存,然后对数据执行一些无意义的计算。所有类型的优化都很重要。无论是以不同方式重写代码还是使用不同的 JVM,欺骗 JIT ..

输入文件是一个 5 亿长的列表,由逗号分隔的 32 位整数对组成。像这样:

44439,5023
33140,22257
...

此文件在我的机器上占用 5.5GB。该程序不能使用超过 8GB 的 RAM,并且只能使用一个单线程

package speedracer;

import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Main
{
    public static void main(String[] args)
    {
        int[] list = new int[1000000000];

        long start1 = System.nanoTime();
        parse(list);
        long end1 = System.nanoTime();

        System.out.println("Parsing took: " + (end1 - start1) / 1000000000.0);

        int rs = 0;
        long start2 = System.nanoTime();

        for (int k = 0; k < list.length; k++) {
            rs = calc(list[k++], list[k++], list[k++], list[k]);
        }

        long end2 = System.nanoTime();

        System.out.println(rs);
        System.out.println("Calculations took: " + (end2 - start2) / 1000000000.0);
    }

    public static int calc(final int a1, final int a2, final int b1, final int b2)
    {
        int c1 = (a1 + a2) ^ a2;
        int c2 = (b1 - b2) << 4;

        for (int z = 0; z < 100; z++) {
            c1 ^= z + c2;
        }

        return c1;
    }

    public static void parse(int[] list)
    {
        FileChannel fc = null;
        int i = 0;

        MappedByteBuffer byteBuffer;

        try {
            fc = new FileInputStream("in.txt").getChannel();

            long size = fc.size();
            long allocated = 0;
            long allocate = 0;

            while (size > allocated) {

               if ((size - allocated) > Integer.MAX_VALUE) {
                   allocate = Integer.MAX_VALUE;
               } else {
                   allocate = size - allocated;
               }

               byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, allocated, allocate);
               byteBuffer.clear();

               allocated += allocate;

               int number = 0;

               while (byteBuffer.hasRemaining()) {
                   char val = (char) byteBuffer.get();
                   if (val == '\n' || val == ',') {
                        list[i] = number;

                        number = 0;
                        i++;
                   } else {
                       number = number * 10 + (val - '0');
                   }
                }
            }

            fc.close();

        } catch (Exception e) {
            System.err.println("Parsing error: " + e);
        }
    }
}

我已经尝试了所有我能想到的。尝试不同的阅读器,尝试了 openjdk6、sunjdk6、sunjdk7。尝试了不同的阅读器。由于 MappedByteBuffer 不能一次映射超过 2GB 的内存,因此不得不进行一些难看的解析。我在跑:

   Linux AS292 2.6.38-11-generic #48-Ubuntu SMP 
   Fri Jul 29 19:02:55 UTC 2011 
   x86_64 GNU/Linux. Ubuntu 11.04. 
   CPU: is Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz.

目前,我的结果是解析:26.50 秒,计算:11.27 秒。我正在与类似的 C++ 基准进行竞争,该基准在大致相同的时间内执行 IO,但计算仅需 4.5 秒。我的主要目标是以任何可能的方式减少计算时间。有什么想法吗?

更新:似乎主要的速度提升可能来自所谓的Auto-Vectorization。 .我能够找到一些提示,表明当前 Sun 的 JIT 仅进行“一些矢量化”,但我无法真正确认。找到一些具有更好的自动矢量化优化支持的 JVM 或 JIT 会很棒。

最佳答案

首先,-O3 启用:

-finline-functions
-ftree-vectorize

除其他外...

所以看起来它实际上可能是向量化的。

编辑: 这已经得到证实。 (见评论) C++ 版本确实被编译器矢量化了。在禁用矢量化的情况下,C++ 版本实际上比 Java 版本运行得慢一些

假设 JIT 没有向量化循环,Java 版本可能很难/不可能匹配 C++ 版本的速度。


现在,如果我是一个聪明的 C/C++ 编译器,下面是我将如何安排该循环(在 x64 上):

int c1 = (a1 + a2) ^ a2;
int c2 = (b1 - b2) << 4;

int tmp0 = c1;
int tmp1 = 0;
int tmp2 = 0;
int tmp3 = 0;

int z0 = 0;
int z1 = 1;
int z2 = 2;
int z3 = 3;

do{
    tmp0 ^= z0 + c2;
    tmp1 ^= z1 + c2;
    tmp2 ^= z2 + c2;
    tmp3 ^= z3 + c2;
    z0 += 4;
    z1 += 4;
    z2 += 4;
    z3 += 4;
}while (z0 < 100);

tmp0 ^= tmp1;
tmp2 ^= tmp3;

tmp0 ^= tmp2;

return tmp0;

请注意,此循环是完全可向量化的。

更好的是,我会完全展开这个循环。这些是 C/C++ 编译器会做的事情。但现在的问题是,JIT 会这样做吗?

关于java - 如何加速这段 Java 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7451342/

相关文章:

benchmarking - BLAS 库基准

java - 同步集合中的 ConcurrentModificationException

java - 为 DecimalFormat 类指定自定义格式

css - 空类定义陷阱?

html - 如何为 Mozilla Firefox 优化网页?我的页面在 Firefox 上显示不正确。在 chrome 中,它是完美的

c# - 如何优化XML的书写方式?

java - 使用罗马数字删除编号

java - 如何使用 SimpleXML 跨序列化保留结构?

Python 与 C++ Tensorflow 推理

清除一个小整数数组 : memset vs. for 循环