java - L3 cpu 缓存 java 基准测试显示奇怪的结果

标签 java caching memory jvm cpu-cache

看完这篇article我决定在我的笔记本电脑上检查一下。这个想法是创建大小为 [1..40] Mb 的数组,然后迭代它 1024 次(例如,对于大小为 1 的数组,步长为 1024,对于大小为 2 mb 的数组,步长为 2048 等)。我的代码是:

public class L3CacheBenchmark {

    @State(Scope.Benchmark)
    public static class P {

        @Param({
                       "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                       "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                       "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
                       "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
               })
        public int size;
    }

    @State(Scope.Thread)
    public static class ThreadData {

        byte[] array;
        int    len;

        @Setup
        public void setup(P p) {
            array = new byte[p.size * 1024 * 1024];
            len = array.length;
        }
    }


    @Benchmark
    public byte[] testMethod(ThreadData data) {
        int step = (data.len / 1024) - 1;
        for (int k = 0; k < data.len; k += step) {
            data.array[k] = 1;
        }
        return data.array;
    }

}

和结果:

Benchmark                    (size)   Mode  Cnt       Score       Error  Units
L3CacheBenchmark.testMethod       1  thrpt  100  310521,031 ±  1124,590  ops/s
L3CacheBenchmark.testMethod       2  thrpt  100  331853,495 ±  1124,547  ops/s
L3CacheBenchmark.testMethod       3  thrpt  100  311499,659 ±   745,414  ops/s
L3CacheBenchmark.testMethod       4  thrpt  100  290270,382 ±  8501,690  ops/s
L3CacheBenchmark.testMethod       5  thrpt  100  212929,246 ± 14847,931  ops/s
L3CacheBenchmark.testMethod       6  thrpt  100  315968,138 ±  4454,210  ops/s
L3CacheBenchmark.testMethod       7  thrpt  100  209679,904 ± 26050,365  ops/s
L3CacheBenchmark.testMethod       8  thrpt  100   60409,187 ±   212,548  ops/s
L3CacheBenchmark.testMethod       9  thrpt  100  221290,756 ± 28970,586  ops/s
L3CacheBenchmark.testMethod      10  thrpt  100  322865,687 ±  1545,967  ops/s
L3CacheBenchmark.testMethod      11  thrpt  100  263153,747 ± 18497,624  ops/s
L3CacheBenchmark.testMethod      12  thrpt  100  298683,205 ±  1277,032  ops/s
L3CacheBenchmark.testMethod      13  thrpt  100  180984,220 ± 26611,649  ops/s
L3CacheBenchmark.testMethod      14  thrpt  100  324815,938 ±  1657,303  ops/s
L3CacheBenchmark.testMethod      15  thrpt  100  264965,412 ±  9335,923  ops/s
L3CacheBenchmark.testMethod      16  thrpt  100   58830,825 ±   291,412  ops/s
L3CacheBenchmark.testMethod      17  thrpt  100  255576,829 ±  7083,025  ops/s
L3CacheBenchmark.testMethod      18  thrpt  100  324174,133 ±  2247,157  ops/s
L3CacheBenchmark.testMethod      19  thrpt  100  212969,202 ± 18204,625  ops/s
L3CacheBenchmark.testMethod      20  thrpt  100  295246,470 ±  1224,817  ops/s
L3CacheBenchmark.testMethod      21  thrpt  100  251762,642 ± 23405,100  ops/s
L3CacheBenchmark.testMethod      22  thrpt  100  323196,428 ±  2245,465  ops/s
L3CacheBenchmark.testMethod      23  thrpt  100  254588,338 ± 23845,090  ops/s
L3CacheBenchmark.testMethod      24  thrpt  100   53373,580 ±   252,183  ops/s
L3CacheBenchmark.testMethod      25  thrpt  100  213220,459 ± 20440,716  ops/s
L3CacheBenchmark.testMethod      26  thrpt  100  322625,597 ±  2076,341  ops/s
L3CacheBenchmark.testMethod      27  thrpt  100  293643,720 ±  5260,010  ops/s
L3CacheBenchmark.testMethod      28  thrpt  100  297432,240 ±  1186,920  ops/s
L3CacheBenchmark.testMethod      29  thrpt  100  169277,701 ± 25040,239  ops/s
L3CacheBenchmark.testMethod      30  thrpt  100  324230,899 ±  1579,103  ops/s
L3CacheBenchmark.testMethod      31  thrpt  100  193981,979 ± 12478,424  ops/s
L3CacheBenchmark.testMethod      32  thrpt  100   53761,030 ±   259,888  ops/s
L3CacheBenchmark.testMethod      33  thrpt  100  213585,493 ± 23543,671  ops/s
L3CacheBenchmark.testMethod      34  thrpt  100  325214,062 ±  1758,479  ops/s
L3CacheBenchmark.testMethod      35  thrpt  100  306652,634 ±  2237,818  ops/s
L3CacheBenchmark.testMethod      36  thrpt  100  297992,930 ±  1019,248  ops/s
L3CacheBenchmark.testMethod      37  thrpt  100  181671,812 ± 21984,441  ops/s
L3CacheBenchmark.testMethod      38  thrpt  100  321929,616 ±  1798,747  ops/s
L3CacheBenchmark.testMethod      39  thrpt  100  251587,385 ± 12292,670  ops/s
L3CacheBenchmark.testMethod      40  thrpt  100   49777,196 ±   227,620  ops/s

如您所见,吞吐量不同,最显着的差异是对于大小为 8 的倍数的数组:速度下降几乎是 4 倍。此外,例如,大小为 37 Mb 的阵列的速度几乎是 38 Mb 的两倍。我没有找到对我的发现的任何合乎逻辑的解释。

附言CPU i7 4700mq 6 Mb 高速缓存:http://www.cpu-world.com/CPUs/Core_i7/Intel-Core%20i7-4700MQ%20Mobile%20processor.html

是什么导致了这种行为?

最佳答案

您正在观察 cache associativity 的效果.

256 KB 8-way set associative cache

您的 CPU 每个核心具有 256 KB 8 路组关联二级缓存。它最多可以存储 256 KB/64 缓存行,其中具有相同索引位的行不超过 8 行。

您的基准循环写入 1025 个不同的地址。但是,根据步长,这些地址可能会落入少数集合中,从而导致冲突并从缓存中逐出。当 stride (step) = 8191、16383、24575 等时,这正是您的情况。

为了验证这个理论,使用-prof perfnorm 选项重新运行 JMH 基准测试。
以下是 size = 8 和 size = 9 的统计数据:

L3CacheBenchmark.testMethod:CPI                      8  thrpt      1.173  #/op
L3CacheBenchmark.testMethod:L1-dcache-load-misses    8  thrpt   1048.088  #/op
L3CacheBenchmark.testMethod:L1-dcache-loads          8  thrpt   1073.767  #/op
L3CacheBenchmark.testMethod:L1-dcache-store-misses   8  thrpt   1049.491  #/op
L3CacheBenchmark.testMethod:L1-dcache-stores         8  thrpt   1060.069  #/op
L3CacheBenchmark.testMethod:L1-icache-load-misses    8  thrpt      1.209  #/op
L3CacheBenchmark.testMethod:LLC-load-misses          8  thrpt      0.082  #/op
L3CacheBenchmark.testMethod:LLC-loads                8  thrpt      1.399  #/op
L3CacheBenchmark.testMethod:LLC-store-misses         8  thrpt      0.077  #/op
L3CacheBenchmark.testMethod:LLC-stores               8  thrpt   1035.877  #/op
L3CacheBenchmark.testMethod:branch-misses            8  thrpt      1.234  #/op
L3CacheBenchmark.testMethod:branches                 8  thrpt   2096.674  #/op
L3CacheBenchmark.testMethod:cycles                   8  thrpt  13520.964  #/op
L3CacheBenchmark.testMethod:dTLB-load-misses         8  thrpt      0.057  #/op
L3CacheBenchmark.testMethod:dTLB-loads               8  thrpt   1086.355  #/op
L3CacheBenchmark.testMethod:dTLB-store-misses        8  thrpt      0.020  #/op
L3CacheBenchmark.testMethod:dTLB-stores              8  thrpt   1068.579  #/op
L3CacheBenchmark.testMethod:iTLB-load-misses         8  thrpt      0.044  #/op
L3CacheBenchmark.testMethod:iTLB-loads               8  thrpt      0.018  #/op
L3CacheBenchmark.testMethod:instructions             8  thrpt  11530.742  #/op
L3CacheBenchmark.testMethod:stalled-cycles-backend   8  thrpt   8315.437  #/op
L3CacheBenchmark.testMethod:stalled-cycles-frontend  8  thrpt  10359.447  #/op

L3CacheBenchmark.testMethod:CPI                      9  thrpt      0.871  #/op
L3CacheBenchmark.testMethod:L1-dcache-load-misses    9  thrpt   1055.973  #/op
L3CacheBenchmark.testMethod:L1-dcache-loads          9  thrpt   1068.958  #/op
L3CacheBenchmark.testMethod:L1-dcache-store-misses   9  thrpt   1045.480  #/op
L3CacheBenchmark.testMethod:L1-dcache-stores         9  thrpt   1057.328  #/op
L3CacheBenchmark.testMethod:L1-icache-load-misses    9  thrpt      1.108  #/op
L3CacheBenchmark.testMethod:LLC-load-misses          9  thrpt      0.174  #/op
L3CacheBenchmark.testMethod:LLC-loads                9  thrpt      0.304  #/op
L3CacheBenchmark.testMethod:LLC-store-misses         9  thrpt      0.045  #/op
L3CacheBenchmark.testMethod:LLC-stores               9  thrpt      0.350  #/op
L3CacheBenchmark.testMethod:branch-misses            9  thrpt      1.072  #/op
L3CacheBenchmark.testMethod:branches                 9  thrpt   2099.846  #/op
L3CacheBenchmark.testMethod:cycles                   9  thrpt  10041.724  #/op
L3CacheBenchmark.testMethod:dTLB-load-misses         9  thrpt      0.086  #/op
L3CacheBenchmark.testMethod:dTLB-loads               9  thrpt   1073.633  #/op
L3CacheBenchmark.testMethod:dTLB-store-misses        9  thrpt      0.045  #/op
L3CacheBenchmark.testMethod:dTLB-stores              9  thrpt   1054.587  #/op
L3CacheBenchmark.testMethod:iTLB-load-misses         9  thrpt      0.044  #/op
L3CacheBenchmark.testMethod:iTLB-loads               9  thrpt      0.037  #/op
L3CacheBenchmark.testMethod:instructions             9  thrpt  11529.996  #/op
L3CacheBenchmark.testMethod:stalled-cycles-backend   9  thrpt   3439.278  #/op
L3CacheBenchmark.testMethod:stalled-cycles-frontend  9  thrpt   6888.714  #/op

最显着的是 LLC-stores 的区别:大小为 8 时为 1035,大小为 9 时几乎没有。这意味着存储的数据不适合 L2 缓存并转到L3.


顺便说一句,您的基准测试无法衡量 L3 缓存的效果,因为它只涉及少量数据(大约 64 KB)。为了进行公平测试,您需要读取和写入分配数组的整个范围。

关于java - L3 cpu 缓存 java 基准测试显示奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43161089/

相关文章:

Java for each 与常规 for - 它们是否等效?

caching - 为什么会有多层缓存

java - 简单的 Android 应用程序即将 OOM

c# - C#中的字符串常量内存池

objective-c - 我应该释放一个被移除的 child 吗?

java - MATLAB : access uigetdir's internal java methods

java - iText 添加 LTV 信息

java - 进度条未显示在 webview 的 Relativelayout 中

php - Laravel 缓存返回损坏的数据(redis 驱动程序)

caching - Nginx add_header 和缓存控制