ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/MapLoops.java
Revision: 1.1
Committed: Mon May 2 19:19:38 2005 UTC (19 years ago) by dl
Branch: MAIN
Log Message:
Put misc performance tests into CVS

File Contents

# Content
1 /*
2 * @test
3 * @synopsis Exercise multithreaded maps, by default
4 * ConcurrentHashMap. Each thread does a random walk though elements
5 * of "key" array. On each iteration, it checks if table includes key.
6 * If absent, with probablility pinsert it inserts it, and if present,
7 * with probablility premove it removes it. (pinsert and premove are
8 * expressed as percentages to simplify parsing from command line.)
9 */
10 /*
11 * Written by Doug Lea with assistance from members of JCP JSR-166
12 * Expert Group and released to the public domain. Use, modify, and
13 * redistribute this code in any way without acknowledgement.
14 */
15
16
17 import java.util.*;
18 import java.util.concurrent.*;
19
20 public class MapLoops {
21 static int nkeys = 10000;
22 static int pinsert = 60;
23 static int premove = 2;
24 static int maxThreads = 100;
25 static int nops = 8000000;
26 static int removesPerMaxRandom;
27 static int insertsPerMaxRandom;
28
29 static final ExecutorService pool = Executors.newCachedThreadPool();
30
31 public static void main(String[] args) throws Exception {
32
33 Class mapClass = null;
34 if (args.length > 0) {
35 try {
36 mapClass = Class.forName(args[0]);
37 } catch(ClassNotFoundException e) {
38 throw new RuntimeException("Class " + args[0] + " not found.");
39 }
40 }
41 else
42 mapClass = java.util.concurrent.ConcurrentHashMap.class;
43
44 if (args.length > 1)
45 maxThreads = Integer.parseInt(args[1]);
46
47 if (args.length > 2)
48 nkeys = Integer.parseInt(args[2]);
49
50 if (args.length > 3)
51 pinsert = Integer.parseInt(args[3]);
52
53 if (args.length > 4)
54 premove = Integer.parseInt(args[4]);
55
56 if (args.length > 5)
57 nops = Integer.parseInt(args[5]);
58
59 // normalize probabilities wrt random number generator
60 removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
61 insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
62
63 System.out.print("Class: " + mapClass.getName());
64 System.out.print(" threads: " + maxThreads);
65 System.out.print(" size: " + nkeys);
66 System.out.print(" ins: " + pinsert);
67 System.out.print(" rem: " + premove);
68 System.out.print(" ops: " + nops);
69 System.out.println();
70
71 int k = 1;
72 int warmups = 2;
73 for (int i = 1; i <= maxThreads;) {
74 Thread.sleep(100);
75 test(i, nkeys, mapClass);
76 if (warmups > 0)
77 --warmups;
78 else if (i == k) {
79 k = i << 1;
80 i = i + (i >>> 1);
81 }
82 else if (i == 1 && k == 2) {
83 i = k;
84 warmups = 1;
85 }
86 else
87 i = k;
88 }
89 pool.shutdown();
90 }
91
92 static Integer[] makeKeys(int n) {
93 LoopHelpers.SimpleRandom rng = new LoopHelpers.SimpleRandom();
94 Integer[] key = new Integer[n];
95 for (int i = 0; i < key.length; ++i)
96 key[i] = new Integer(rng.next());
97 return key;
98 }
99
100 static void shuffleKeys(Integer[] key) {
101 Random rng = new Random();
102 for (int i = key.length; i > 1; --i) {
103 int j = rng.nextInt(i);
104 Integer tmp = key[j];
105 key[j] = key[i-1];
106 key[i-1] = tmp;
107 }
108 }
109
110 static void test(int i, int nkeys, Class mapClass) throws Exception {
111 System.out.print("Threads: " + i + "\t:");
112 Map<Integer, Integer> map = (Map<Integer,Integer>)mapClass.newInstance();
113 Integer[] key = makeKeys(nkeys);
114 // Uncomment to start with a non-empty table
115 // for (int j = 0; j < nkeys; j += 4) // start 1/4 occupied
116 // map.put(key[j], key[j]);
117 LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
118 CyclicBarrier barrier = new CyclicBarrier(i+1, timer);
119 for (int t = 0; t < i; ++t)
120 pool.execute(new Runner(map, key, barrier));
121 barrier.await();
122 barrier.await();
123 long time = timer.getTime();
124 long tpo = time / (i * (long)nops);
125 System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
126 double secs = (double)(time) / 1000000000.0;
127 System.out.println("\t " + secs + "s run time");
128 map.clear();
129 }
130
131 static class Runner implements Runnable {
132 final Map<Integer,Integer> map;
133 final Integer[] key;
134 final LoopHelpers.SimpleRandom rng = new LoopHelpers.SimpleRandom();
135 final CyclicBarrier barrier;
136 int position;
137 int total;
138
139 Runner(Map<Integer,Integer> map, Integer[] key, CyclicBarrier barrier) {
140 this.map = map;
141 this.key = key;
142 this.barrier = barrier;
143 position = key.length / 2;
144 }
145
146 int step() {
147 // random-walk around key positions, bunching accesses
148 int r = rng.next();
149 position += (r & 7) - 3;
150 while (position >= key.length) position -= key.length;
151 while (position < 0) position += key.length;
152
153 Integer k = key[position];
154 Integer x = map.get(k);
155
156 if (x != null) {
157 if (x.intValue() != k.intValue())
158 throw new Error("bad mapping: " + x + " to " + k);
159
160 if (r < removesPerMaxRandom) {
161 if (map.remove(k) != null) {
162 position = total % key.length; // move from position
163 return 2;
164 }
165 }
166 }
167 else if (r < insertsPerMaxRandom) {
168 ++position;
169 map.put(k, k);
170 return 2;
171 }
172
173 // Uncomment to add a little computation between accesses
174 // total += LoopHelpers.compute1(k.intValue());
175 total += r;
176 return 1;
177 }
178
179 public void run() {
180 try {
181 barrier.await();
182 int ops = nops;
183 while (ops > 0)
184 ops -= step();
185 barrier.await();
186 }
187 catch (Exception ex) {
188 ex.printStackTrace();
189 }
190 }
191 }
192 }
193