ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/MapLoops.java
Revision: 1.2
Committed: Sun Aug 7 19:25:55 2005 UTC (18 years, 8 months ago) by dl
Branch: MAIN
Changes since 1.1: +9 -6 lines
Log Message:
Add exchanger performance tests; update others

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 = 1000;
22 static int pinsert = 60;
23 static int premove = 2;
24 static int maxThreads = 100;
25 static int nops = 1000000;
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 shuffleKeys(key);
118 LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
119 CyclicBarrier barrier = new CyclicBarrier(i+1, timer);
120 for (int t = 0; t < i; ++t)
121 pool.execute(new Runner(t, map, key, barrier));
122 barrier.await();
123 barrier.await();
124 long time = timer.getTime();
125 long tpo = time / (i * (long)nops);
126 System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
127 double secs = (double)(time) / 1000000000.0;
128 System.out.println("\t " + secs + "s run time");
129 map.clear();
130 }
131
132 static class Runner implements Runnable {
133 final Map<Integer,Integer> map;
134 final Integer[] key;
135 final LoopHelpers.SimpleRandom rng;
136 final CyclicBarrier barrier;
137 int position;
138 int total;
139
140 Runner(int id, Map<Integer,Integer> map, Integer[] key, CyclicBarrier barrier) {
141 this.map = map;
142 this.key = key;
143 this.barrier = barrier;
144 position = key.length / 2;
145 rng = new LoopHelpers.SimpleRandom((id + 1) * 8862213513L);
146 rng.next();
147 }
148
149 int step() {
150 // random-walk around key positions, bunching accesses
151 int r = rng.next();
152 position += (r & 7) - 3;
153 while (position >= key.length) position -= key.length;
154 while (position < 0) position += key.length;
155
156 Integer k = key[position];
157 Integer x = map.get(k);
158
159 if (x != null) {
160 if (x.intValue() != k.intValue())
161 throw new Error("bad mapping: " + x + " to " + k);
162
163 if (r < removesPerMaxRandom) {
164 if (map.remove(k) != null) {
165 position = total % key.length; // move from position
166 return 2;
167 }
168 }
169 }
170 else if (r < insertsPerMaxRandom) {
171 ++position;
172 map.put(k, k);
173 return 2;
174 }
175
176 // Uncomment to add a little computation between accesses
177 // total += LoopHelpers.compute1(k.intValue());
178 total += r;
179 return 1;
180 }
181
182 public void run() {
183 try {
184 barrier.await();
185 int ops = nops;
186 while (ops > 0)
187 ops -= step();
188 barrier.await();
189 }
190 catch (Exception ex) {
191 ex.printStackTrace();
192 }
193 }
194 }
195 }
196