View difference between Paste ID: 9y6zeU7c and gYcqgj1C
SHOW: | | - or go back to the newest paste.
1
package frans;
2
3
/**
4
 * Class to test access time (latency) for cache and RAM.
5
 * Sequential access and random access of values in a long[] array.
6
 * 
7
 * @author Frans Lundberg
8
 */
9
public class MemoryAccess {
10
    static final int SIZE_CACHE = 100000;           // 100003 is prime. Total: 0.8 MB.
11
    static final long REPS1_CACHE = 10 * 1000;      // for seq
12
    static final long REPS2_CACHE = 100 * 1000000;  // for random
13
    static final int SIZE_RAM = 500 * SIZE_CACHE;   // 400 MB of data
14
    static final long REPS1_RAM = 10;               // for seq
15
    static final long REPS2_RAM = 10 * 1000000;     // for random 
16
    
17
    /**
18
     * Sequential memory accesses to a long[] array. 
19
     * 'size' must be SIZE_CACHE or SIZE_RAM.
20
     */
21
    Result seq(final int size) {
22
        long[] data = new long[size];
23
        
24
        for (int i = 0; i < data.length; i++) {
25
            data[i] = 1;
26
        }
27
        
28
        long t0 = 0;
29
        long sum = 0;
30
        long count;
31
        
32
        t0 = System.nanoTime();
33
        
34
        if (size == SIZE_CACHE) {
35
            count = SIZE_CACHE * REPS1_CACHE;
36
            for (int k = 0; k < REPS1_CACHE; k++) {
37
                for (int i = 0; i < SIZE_CACHE; i++) {                
38
                    sum += data[i];
39
                }
40
            }
41
        } else if (size == SIZE_RAM) {
42
            count = SIZE_RAM * REPS1_RAM;
43
            for (int k = 0; k < REPS1_RAM; k++) {
44
                for (int i = 0; i < SIZE_RAM; i++) {                
45
                    sum += data[i];
46
                }
47
            }
48
        } else {
49
            throw new Error("Bad size: " + size);
50
        }
51
        
52
        double time = (System.nanoTime() - t0) * 1e-9;
53
        return new Result(count, time, sum);
54
    }
55
    
56
    
57
    /**
58
     * Random memory access to a long[] array. 
59
     * 'size' must be SIZE_CACHE or SIZE_RAM.
60
     */
61
    Result random(final int size) {
62
        long[] data = new long[size];
63
        long t0;
64
        long sum = 0;
65
        long index = 0;
66
        long count;
67
        
68
        for (int i = 0; i < size; i++) {
69
            data[i] = 1L;
70
        }
71
        
72
        t0 = System.nanoTime();
73
        
74
        if (size == SIZE_CACHE) {
75
            count = REPS2_CACHE;
76
            for (int k = 0; k < REPS2_CACHE; k++) {             
77
                sum += data[(int)(index % SIZE_CACHE)];
78
                index += 836413;
79
            }
80
        } else if (size == SIZE_RAM) {
81
            count = REPS2_RAM;
82
            for (int k = 0; k < REPS2_RAM; k++) {
83
                sum += data[(int)(index % SIZE_RAM)];
84
                index += 836413;
85
            }
86
        } else {
87
            throw new Error("Bad size: " + size);
88
        }
89
        
90
        double time = (System.nanoTime() - t0) * 1e-9;
91
        return new Result(count, time, sum);
92
    }
93
    
94
    void runTest(String name, TestMethod test) {
95
        int reps = 8;
96
        double minTime = Double.MAX_VALUE;
97
        Result winner = null;
98
        
99
        System.out.println("---- " + name + " ----");
100
        
101
        for (int i = 0; i < reps; i++) {
102
            Result res = test.run();
103
            if (res.time < minTime) {
104
                winner = res;
105
            }
106
        }
107
        
108
        System.out.println(winner.toString());
109
    }
110
    
111
    /** To store the result. */
112
    static class Result {
113
        long count;
114
        long sum;
115
        double time;
116
        
117
        Result(long count, double time, long sum) {
118
            this.count = count;
119
            this.time = time;
120
            this.sum = sum;
121
        }
122
        
123
        public String toString() {
124
            double nanos = (time * 1e9) / count;
125
            return String.format("Access time %.2f ns, time: %.3f s (sum:%d).\n", nanos, time, sum);
126
        }
127
    }
128
    
129
    static interface TestMethod {
130
        public Result run();
131
    }
132
    
133
    void go() {
134
        runTest("cacheSeq", new TestMethod() {
135
            public Result run() {
136
                return seq(SIZE_CACHE);
137
            }
138
        });
139
        
140
        runTest("cacheRan", new TestMethod() {
141
            public Result run() {
142
                return random(SIZE_CACHE);
143
            }
144
        });
145
        
146
        runTest("ramSeq", new TestMethod() { 
147
            public Result run() {
148
                return seq(SIZE_RAM);
149
            }
150
        });
151
        
152
        runTest("ramRan", new TestMethod() {
153
            public Result run() {
154
                return random(SIZE_RAM);
155
            }
156
        });
157
    }
158
    
159
    public static void main(String[] args) {
160
        new MemoryAccess().go();
161
    }
162
}
163
164
/*
165
131106
166
======
167
168-
"sequential" / "random" access are better terms. Now used.
168+
169-
Refactored. Result:
169+
170
    cacheRan     3.16 ns,  6.64 cycles
171
    ramSeq       0.56 ns,  1.37 cycles
172
    ramRan      20.07 ns, 42.16 cycles
173-
    cacheRan     4.39 ns,  9.20 cycles
173+
174
On my computer "Cissi":
175
    Ubuntu 12.04, CPU: Intel(R) Core(TM) i7-3687U CPU @ 2.10GHz, Cache: 4096 KiB.
176
    Java version:
177
        Oracle JVM 1.7.0_25.
178
        Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
179
180
sudo cat /proc/cpuinfo | grep "cache"   -->
181
  cache size    : 4096 KB
182
sudo cat /proc/cpuinfo | fgrep 'cpu MHz'
183
  Max freq: cpu MHz : 2101.000  <--> 0.476 ns / cycle
184
*/