代码之家  ›  专栏  ›  技术社区  ›  Thomas Mueller

查找Java字节数组的缓存行的开始位置

  •  3
  • Thomas Mueller  · 技术社区  · 6 年前

    对于高性能阻塞的Bloom过滤器,我希望将数据与缓存线对齐。(我知道在C中这样做更容易,但是我想使用Java。)

    我确实有一个解决方案,但我不确定它是正确的,还是有更好的方法。我的解决方案尝试使用以下算法查找缓存线的起始位置:

    • 对于每个可能的偏移量o(0..63;我假设缓存线长度为64)
    • 启动从数据[O]读取并将其写入数据[O+8]的线程
    • 在主线程中,将“1”写入数据[O],然后等待直到数据[O+8]结束(因此,等待另一个线程)
    • 重复那个

    然后,测量这有多快,基本上一个100万循环(在每个线程中)的增量是多少。我的逻辑是,如果数据在不同的缓存线中,速度会变慢。

    这里是我的代码:

    public static void main(String... args) {
        for(int i=0; i<20; i++) {
            int size = (int) (1000 + Math.random() * 1000);
            byte[] data = new byte[size];
            int cacheLineOffset = getCacheLineOffset(data);
            System.out.println("offset: " + cacheLineOffset);
        }
    }
    
    private static int getCacheLineOffset(byte[] data) {
        for (int i = 0; i < 10; i++) {
            int x = tryGetCacheLineOffset(data, i + 3);
            if (x != -1) {
                return x;
            }
        }
        System.out.println("Cache line start not found");
        return 0;
    }
    
    private static int tryGetCacheLineOffset(byte[] data, int testCount) {
        // assume synchronization between two threads is faster(?)
        // if each thread works on the same cache line
        int[] counters = new int[64];
        int testOffset = 8;
        for (int test = 0; test < testCount; test++) {
            for (int offset = 0; offset < 64; offset++) {
                final int o = offset;
                final Semaphore sema = new Semaphore(0);
                Thread t = new Thread() {
                    public void run() {
                        try {
                            sema.acquire();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        for (int i = 0; i < 1000000; i++) {
                            data[o + testOffset] = data[o];
                        }
                    }
                };
                t.start();
                sema.release();
                data[o] = 1;
                int counter = 0;
                byte waitfor = 1;
                for (int i = 0; i < 1000000; i++) {
                    byte x = data[o + testOffset];
                    if (x == waitfor) {
                        data[o]++;
                        counter++;
                        waitfor++;
                    }
                }
                try {
                    t.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                counters[offset] += counter;
            }
        }
        Arrays.fill(data, 0, testOffset + 64, (byte) 0);
        int low = Integer.MAX_VALUE, high = Integer.MIN_VALUE;
        for (int i = 0; i < 64; i++) {
            // average of 3
            int avg3 = (counters[(i - 1 + 64) % 64] + counters[i] + counters[(i + 1) % 64]) / 3;
            low = Math.min(low, avg3);
            high = Math.max(high, avg3);
        }
        if (low * 1.1 > high) {
            // no significant difference between low and high
            return -1;
        }
        int lowCount = 0;
        boolean[] isLow = new boolean[64];
        for (int i = 0; i < 64; i++) {
            if (counters[i] < (low + high) / 2) {
                isLow[i] = true;
                lowCount++;
            }
        }
        if (lowCount != 8) {
            // unclear
            return -1;
        }
        for (int i = 0; i < 64; i++) {
            if (isLow[(i - 1 + 64) % 64] && !isLow[i]) {
                return i;
            }
        }
        return -1;
    }
    

    它打印(示例):

    offset: 16
    offset: 24
    offset: 0
    offset: 40
    offset: 40
    offset: 8
    offset: 24
    offset: 40
    ...
    

    因此,Java中的数组似乎与8字节对齐。

    2 回复  |  直到 6 年前
        1
  •  2
  •   maaartinus    6 年前

    ByteBuffer

        2
  •  2
  •   Eugene    6 年前

    Java Object Layout java-9 String byte[] LATIN-1 coder byte

    false-sharing Unsafe GC

    not be the first one JIT C2

    jdk.internal.vm.annotation.Contended
    

    Alekesy Shipilev's