blob: f1442547cee6e34a878a1633d554aafeb1d00198 [file] [log] [blame]
Andy McFadden734155e2009-07-16 18:11:22 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Test the indirect reference table implementation.
19 */
20#include "Dalvik.h"
21
22#include <stdlib.h>
Jeff Brown476157d2011-10-26 18:41:12 -070023#include <sys/time.h>
Andy McFadden734155e2009-07-16 18:11:22 -070024
25#ifndef NDEBUG
26
Steve Block43084172012-01-04 20:04:51 +000027#define DBUG_MSG ALOGI
Andy McFadden734155e2009-07-16 18:11:22 -070028
Jeff Brown476157d2011-10-26 18:41:12 -070029class Stopwatch {
30public:
31 Stopwatch() {
32 reset();
33 }
34
35 void reset() {
36 start_ = now();
37 }
38
39 float elapsedSeconds() {
40 return (now() - start_) * 0.000001f;
41 }
42
43private:
44 u8 start_;
45
46 static u8 now() {
47#ifdef HAVE_POSIX_CLOCKS
48 struct timespec tm;
49 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
50 return tm.tv_sec * 1000000LL + tm.tv_nsec / 1000;
51#else
52 struct timeval tv;
53 gettimeofday(&tv, NULL);
54 return tv.tv_sec * 1000000LL + tv.tv_usec;
55#endif
56 }
57};
58
Andy McFadden734155e2009-07-16 18:11:22 -070059/*
60 * Basic add/get/delete tests in an unsegmented table.
61 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070062static bool basicTest()
Andy McFadden734155e2009-07-16 18:11:22 -070063{
64 static const int kTableMax = 20;
65 IndirectRefTable irt;
66 IndirectRef iref0, iref1, iref2, iref3;
67 IndirectRef manyRefs[kTableMax];
68 ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
69 Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
70 Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
71 Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
72 Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
Andy McFaddenab00d452009-08-19 07:21:41 -070073 const u4 cookie = IRT_FIRST_SEGMENT;
Andy McFadden734155e2009-07-16 18:11:22 -070074 bool result = false;
75
Elliott Hughesce096832011-06-20 17:50:41 -070076 if (!irt.init(kTableMax/2, kTableMax, kIndirectKindGlobal)) {
Andy McFadden734155e2009-07-16 18:11:22 -070077 return false;
78 }
79
80 iref0 = (IndirectRef) 0x11110;
Elliott Hughesce096832011-06-20 17:50:41 -070081 if (irt.remove(cookie, iref0)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +000082 ALOGE("unexpectedly successful removal");
Andy McFadden734155e2009-07-16 18:11:22 -070083 goto bail;
84 }
85
86 /*
87 * Add three, check, remove in the order in which they were added.
88 */
89 DBUG_MSG("+++ START fifo\n");
Elliott Hughesce096832011-06-20 17:50:41 -070090 iref0 = irt.add(cookie, obj0);
91 iref1 = irt.add(cookie, obj1);
92 iref2 = irt.add(cookie, obj2);
Andy McFadden734155e2009-07-16 18:11:22 -070093 if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +000094 ALOGE("trivial add1 failed");
Andy McFadden734155e2009-07-16 18:11:22 -070095 goto bail;
96 }
97
Elliott Hughesce096832011-06-20 17:50:41 -070098 if (irt.get(iref0) != obj0 ||
99 irt.get(iref1) != obj1 ||
100 irt.get(iref2) != obj2) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000101 ALOGE("objects don't match expected values %p %p %p vs. %p %p %p",
Elliott Hughesce096832011-06-20 17:50:41 -0700102 irt.get(iref0), irt.get(iref1), irt.get(iref2),
103 obj0, obj1, obj2);
Andy McFadden734155e2009-07-16 18:11:22 -0700104 goto bail;
105 } else {
106 DBUG_MSG("+++ obj1=%p --> iref1=%p\n", obj1, iref1);
107 }
108
Elliott Hughesce096832011-06-20 17:50:41 -0700109 if (!irt.remove(cookie, iref0) ||
110 !irt.remove(cookie, iref1) ||
111 !irt.remove(cookie, iref2))
Andy McFadden734155e2009-07-16 18:11:22 -0700112 {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000113 ALOGE("fifo deletion failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700114 goto bail;
115 }
116
117 /* table should be empty now */
Elliott Hughesce096832011-06-20 17:50:41 -0700118 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000119 ALOGE("fifo del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700120 goto bail;
121 }
122
123 /* get invalid entry (off the end of the list) */
Elliott Hughesce096832011-06-20 17:50:41 -0700124 if (irt.get(iref0) != kInvalidIndirectRefObject) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000125 ALOGE("stale entry get succeeded unexpectedly");
Andy McFadden734155e2009-07-16 18:11:22 -0700126 goto bail;
127 }
128
129 /*
130 * Add three, remove in the opposite order.
131 */
132 DBUG_MSG("+++ START lifo\n");
Elliott Hughesce096832011-06-20 17:50:41 -0700133 iref0 = irt.add(cookie, obj0);
134 iref1 = irt.add(cookie, obj1);
135 iref2 = irt.add(cookie, obj2);
Andy McFadden734155e2009-07-16 18:11:22 -0700136 if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000137 ALOGE("trivial add2 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700138 goto bail;
139 }
140
Elliott Hughesce096832011-06-20 17:50:41 -0700141 if (!irt.remove(cookie, iref2) ||
142 !irt.remove(cookie, iref1) ||
143 !irt.remove(cookie, iref0))
Andy McFadden734155e2009-07-16 18:11:22 -0700144 {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000145 ALOGE("lifo deletion failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700146 goto bail;
147 }
148
149 /* table should be empty now */
Elliott Hughesce096832011-06-20 17:50:41 -0700150 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000151 ALOGE("lifo del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700152 goto bail;
153 }
154
155 /*
156 * Add three, remove middle / middle / bottom / top. (Second attempt
157 * to remove middle should fail.)
158 */
159 DBUG_MSG("+++ START unorder\n");
Elliott Hughesce096832011-06-20 17:50:41 -0700160 iref0 = irt.add(cookie, obj0);
161 iref1 = irt.add(cookie, obj1);
162 iref2 = irt.add(cookie, obj2);
Andy McFadden734155e2009-07-16 18:11:22 -0700163 if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000164 ALOGE("trivial add3 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700165 goto bail;
166 }
167
Elliott Hughesce096832011-06-20 17:50:41 -0700168 if (irt.capacity() != 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000169 ALOGE("expected 3 entries, found %d", irt.capacity());
Andy McFadden734155e2009-07-16 18:11:22 -0700170 goto bail;
171 }
172
Elliott Hughesce096832011-06-20 17:50:41 -0700173 if (!irt.remove(cookie, iref1) || irt.remove(cookie, iref1)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000174 ALOGE("unorder deletion1 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700175 goto bail;
176 }
177
178 /* get invalid entry (from hole) */
Elliott Hughesce096832011-06-20 17:50:41 -0700179 if (irt.get(iref1) != kInvalidIndirectRefObject) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000180 ALOGE("hole get succeeded unexpectedly");
Andy McFadden734155e2009-07-16 18:11:22 -0700181 goto bail;
182 }
183
Elliott Hughesce096832011-06-20 17:50:41 -0700184 if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000185 ALOGE("unorder deletion2 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700186 goto bail;
187 }
188
189 /* table should be empty now */
Elliott Hughesce096832011-06-20 17:50:41 -0700190 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000191 ALOGE("unorder del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700192 goto bail;
193 }
194
195 /*
196 * Add four entries. Remove #1, add new entry, verify that table size
197 * is still 4 (i.e. holes are getting filled). Remove #1 and #3, verify
198 * that we delete one and don't hole-compact the other.
199 */
200 DBUG_MSG("+++ START hole fill\n");
Elliott Hughesce096832011-06-20 17:50:41 -0700201 iref0 = irt.add(cookie, obj0);
202 iref1 = irt.add(cookie, obj1);
203 iref2 = irt.add(cookie, obj2);
204 iref3 = irt.add(cookie, obj3);
Andy McFadden734155e2009-07-16 18:11:22 -0700205 if (iref0 == NULL || iref1 == NULL || iref2 == NULL || iref3 == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000206 ALOGE("trivial add4 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700207 goto bail;
208 }
Elliott Hughesce096832011-06-20 17:50:41 -0700209 if (!irt.remove(cookie, iref1)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000210 ALOGE("remove 1 of 4 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700211 goto bail;
212 }
Elliott Hughesce096832011-06-20 17:50:41 -0700213 iref1 = irt.add(cookie, obj1);
214 if (irt.capacity() != 4) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000215 ALOGE("hole not filled");
Andy McFadden734155e2009-07-16 18:11:22 -0700216 goto bail;
217 }
Elliott Hughesce096832011-06-20 17:50:41 -0700218 if (!irt.remove(cookie, iref1) || !irt.remove(cookie, iref3)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000219 ALOGE("remove 1/3 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700220 goto bail;
221 }
Elliott Hughesce096832011-06-20 17:50:41 -0700222 if (irt.capacity() != 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000223 ALOGE("should be 3 after two deletions");
Andy McFadden734155e2009-07-16 18:11:22 -0700224 goto bail;
225 }
Elliott Hughesce096832011-06-20 17:50:41 -0700226 if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000227 ALOGE("remove 2/0 failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700228 goto bail;
229 }
Elliott Hughesce096832011-06-20 17:50:41 -0700230 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000231 ALOGE("not empty after split remove");
Andy McFadden734155e2009-07-16 18:11:22 -0700232 goto bail;
233 }
234
235 /*
236 * Add an entry, remove it, add a new entry, and try to use the original
237 * iref. They have the same slot number but are for different objects.
238 * With the extended checks in place, this should fail.
239 */
240 DBUG_MSG("+++ START switched\n");
Elliott Hughesce096832011-06-20 17:50:41 -0700241 iref0 = irt.add(cookie, obj0);
242 irt.remove(cookie, iref0);
243 iref1 = irt.add(cookie, obj1);
244 if (irt.remove(cookie, iref0)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000245 ALOGE("mismatched del succeeded (%p vs %p)", iref0, iref1);
Andy McFadden734155e2009-07-16 18:11:22 -0700246 goto bail;
247 }
Elliott Hughesce096832011-06-20 17:50:41 -0700248 if (!irt.remove(cookie, iref1)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000249 ALOGE("switched del failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700250 goto bail;
251 }
Elliott Hughesce096832011-06-20 17:50:41 -0700252 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000253 ALOGE("switching del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700254 goto bail;
255 }
256
257 /*
258 * Same as above, but with the same object. A more rigorous checker
259 * (e.g. with slot serialization) will catch this.
260 */
Elliott Hughesce096832011-06-20 17:50:41 -0700261 DBUG_MSG("+++ START switched same object\n");
262 iref0 = irt.add(cookie, obj0);
263 irt.remove(cookie, iref0);
264 iref1 = irt.add(cookie, obj0);
Andy McFadden734155e2009-07-16 18:11:22 -0700265 if (iref0 != iref1) {
Andy McFadden5d599602009-08-31 16:39:23 -0700266 /* try 0, should not work */
Elliott Hughesce096832011-06-20 17:50:41 -0700267 if (irt.remove(cookie, iref0)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000268 ALOGE("temporal del succeeded (%p vs %p)", iref0, iref1);
Andy McFadden734155e2009-07-16 18:11:22 -0700269 goto bail;
270 }
Andy McFadden5d599602009-08-31 16:39:23 -0700271 }
Elliott Hughesce096832011-06-20 17:50:41 -0700272 if (!irt.remove(cookie, iref1)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000273 ALOGE("temporal cleanup failed");
Andy McFadden5d599602009-08-31 16:39:23 -0700274 goto bail;
Andy McFadden734155e2009-07-16 18:11:22 -0700275 }
Elliott Hughesce096832011-06-20 17:50:41 -0700276 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000277 ALOGE("temporal del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700278 goto bail;
279 }
280
Elliott Hughesce096832011-06-20 17:50:41 -0700281 DBUG_MSG("+++ START null lookup\n");
282 if (irt.get(NULL) != kInvalidIndirectRefObject) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000283 ALOGE("null lookup succeeded");
Elliott Hughesce096832011-06-20 17:50:41 -0700284 goto bail;
285 }
286
287 DBUG_MSG("+++ START stale lookup\n");
288 iref0 = irt.add(cookie, obj0);
289 irt.remove(cookie, iref0);
290 if (irt.get(iref0) != kInvalidIndirectRefObject) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000291 ALOGE("stale lookup succeeded");
Elliott Hughesce096832011-06-20 17:50:41 -0700292 goto bail;
293 }
294
Andy McFadden734155e2009-07-16 18:11:22 -0700295 /*
296 * Test table overflow.
297 */
298 DBUG_MSG("+++ START overflow\n");
299 int i;
300 for (i = 0; i < kTableMax; i++) {
Elliott Hughesce096832011-06-20 17:50:41 -0700301 manyRefs[i] = irt.add(cookie, obj0);
Andy McFadden734155e2009-07-16 18:11:22 -0700302 if (manyRefs[i] == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000303 ALOGE("Failed adding %d of %d", i, kTableMax);
Andy McFadden734155e2009-07-16 18:11:22 -0700304 goto bail;
305 }
306 }
Elliott Hughesce096832011-06-20 17:50:41 -0700307 if (irt.add(cookie, obj0) != NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000308 ALOGE("Table overflow succeeded");
Andy McFadden734155e2009-07-16 18:11:22 -0700309 goto bail;
310 }
Elliott Hughesce096832011-06-20 17:50:41 -0700311 if (irt.capacity() != (size_t)kTableMax) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000312 ALOGE("Expected %d entries, found %d", kTableMax, irt.capacity());
Andy McFadden734155e2009-07-16 18:11:22 -0700313 goto bail;
314 }
Jeff Brown5552e622011-10-26 17:04:54 -0700315 irt.dump("table with 20 entries, all filled");
Andy McFadden734155e2009-07-16 18:11:22 -0700316 for (i = 0; i < kTableMax-1; i++) {
Elliott Hughesce096832011-06-20 17:50:41 -0700317 if (!irt.remove(cookie, manyRefs[i])) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000318 ALOGE("multi-remove failed at %d", i);
Andy McFadden734155e2009-07-16 18:11:22 -0700319 goto bail;
320 }
321 }
Jeff Brown5552e622011-10-26 17:04:54 -0700322 irt.dump("table with 20 entries, 19 of them holes");
Andy McFadden734155e2009-07-16 18:11:22 -0700323 /* because of removal order, should have 20 entries, 19 of them holes */
Elliott Hughesce096832011-06-20 17:50:41 -0700324 if (irt.capacity() != (size_t)kTableMax) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000325 ALOGE("Expected %d entries (with holes), found %d",
Elliott Hughesce096832011-06-20 17:50:41 -0700326 kTableMax, irt.capacity());
Andy McFadden734155e2009-07-16 18:11:22 -0700327 goto bail;
328 }
Elliott Hughesce096832011-06-20 17:50:41 -0700329 if (!irt.remove(cookie, manyRefs[kTableMax-1])) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000330 ALOGE("multi-remove final failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700331 goto bail;
332 }
Elliott Hughesce096832011-06-20 17:50:41 -0700333 if (irt.capacity() != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000334 ALOGE("multi-del not empty");
Andy McFadden734155e2009-07-16 18:11:22 -0700335 goto bail;
336 }
337
Jeff Brown5552e622011-10-26 17:04:54 -0700338 /* Done */
Andy McFadden734155e2009-07-16 18:11:22 -0700339 DBUG_MSG("+++ basic test complete\n");
340 result = true;
341
342bail:
Elliott Hughesce096832011-06-20 17:50:41 -0700343 irt.destroy();
Andy McFadden734155e2009-07-16 18:11:22 -0700344 return result;
345}
346
Jeff Brown476157d2011-10-26 18:41:12 -0700347static bool performanceTest()
348{
349 static const int kTableMax = 100;
350 IndirectRefTable irt;
351 IndirectRef manyRefs[kTableMax];
352 ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
353 Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
354 const u4 cookie = IRT_FIRST_SEGMENT;
355 const int kLoops = 100000;
356 Stopwatch stopwatch;
357
358 DBUG_MSG("+++ START performance\n");
359
360 if (!irt.init(kTableMax, kTableMax, kIndirectKindGlobal)) {
361 return false;
362 }
363
364 stopwatch.reset();
365 for (int loop = 0; loop < kLoops; loop++) {
366 for (int i = 0; i < kTableMax; i++) {
367 manyRefs[i] = irt.add(cookie, obj0);
368 }
369 for (int i = 0; i < kTableMax; i++) {
370 irt.remove(cookie, manyRefs[i]);
371 }
372 }
373 DBUG_MSG("Add/remove %d objects FIFO order, %d iterations, %0.3fms / iteration",
374 kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000 / kLoops);
375
376 stopwatch.reset();
377 for (int loop = 0; loop < kLoops; loop++) {
378 for (int i = 0; i < kTableMax; i++) {
379 manyRefs[i] = irt.add(cookie, obj0);
380 }
381 for (int i = kTableMax; i-- > 0; ) {
382 irt.remove(cookie, manyRefs[i]);
383 }
384 }
385 DBUG_MSG("Add/remove %d objects LIFO order, %d iterations, %0.3fms / iteration",
386 kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000 / kLoops);
387
388 for (int i = 0; i < kTableMax; i++) {
389 manyRefs[i] = irt.add(cookie, obj0);
390 }
391 stopwatch.reset();
392 for (int loop = 0; loop < kLoops; loop++) {
393 for (int i = 0; i < kTableMax; i++) {
394 irt.get(manyRefs[i]);
395 }
396 }
397 DBUG_MSG("Get %d objects, %d iterations, %0.3fms / iteration",
398 kTableMax, kLoops, stopwatch.elapsedSeconds() * 1000 / kLoops);
399 for (int i = kTableMax; i-- > 0; ) {
400 irt.remove(cookie, manyRefs[i]);
401 }
402
403 irt.destroy();
404 return true;
405}
406
Andy McFadden734155e2009-07-16 18:11:22 -0700407/*
Andy McFadden734155e2009-07-16 18:11:22 -0700408 * Some quick tests.
409 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -0700410bool dvmTestIndirectRefTable()
Andy McFadden734155e2009-07-16 18:11:22 -0700411{
412 if (!basicTest()) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000413 ALOGE("IRT basic test failed");
Andy McFadden734155e2009-07-16 18:11:22 -0700414 return false;
415 }
Andy McFadden734155e2009-07-16 18:11:22 -0700416
Jeff Brown476157d2011-10-26 18:41:12 -0700417 if (!performanceTest()) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000418 ALOGE("IRT performance test failed");
Jeff Brown476157d2011-10-26 18:41:12 -0700419 return false;
420 }
421
Andy McFadden734155e2009-07-16 18:11:22 -0700422 return true;
423}
424
425#endif /*NDEBUG*/