001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.io; 019 020import static org.hamcrest.MatcherAssert.assertThat; 021import static org.hamcrest.Matchers.lessThan; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertTrue; 024 025import java.io.IOException; 026import java.lang.management.ManagementFactory; 027import java.lang.management.RuntimeMXBean; 028import java.nio.ByteBuffer; 029import java.util.ArrayList; 030import java.util.Arrays; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Map; 034import java.util.TreeMap; 035import java.util.concurrent.ConcurrentHashMap; 036import java.util.concurrent.ConcurrentSkipListMap; 037import java.util.concurrent.CopyOnWriteArrayList; 038import java.util.concurrent.CopyOnWriteArraySet; 039import java.util.concurrent.TimeUnit; 040import java.util.concurrent.atomic.AtomicBoolean; 041import java.util.concurrent.atomic.AtomicInteger; 042import java.util.concurrent.atomic.AtomicLong; 043import java.util.concurrent.atomic.AtomicReference; 044import java.util.concurrent.locks.ReentrantReadWriteLock; 045import org.apache.hadoop.hbase.HBaseClassTestRule; 046import org.apache.hadoop.hbase.KeyValue; 047import org.apache.hadoop.hbase.client.Delete; 048import org.apache.hadoop.hbase.client.Mutation; 049import org.apache.hadoop.hbase.client.Put; 050import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; 051import org.apache.hadoop.hbase.io.hfile.ExclusiveMemHFileBlock; 052import org.apache.hadoop.hbase.io.hfile.HFileBlock; 053import org.apache.hadoop.hbase.io.hfile.HFileContext; 054import org.apache.hadoop.hbase.io.hfile.LruBlockCache; 055import org.apache.hadoop.hbase.io.hfile.LruCachedBlock; 056import org.apache.hadoop.hbase.io.hfile.SharedMemHFileBlock; 057import org.apache.hadoop.hbase.regionserver.CSLMImmutableSegment; 058import org.apache.hadoop.hbase.regionserver.CellArrayImmutableSegment; 059import org.apache.hadoop.hbase.regionserver.CellArrayMap; 060import org.apache.hadoop.hbase.regionserver.CellSet; 061import org.apache.hadoop.hbase.regionserver.CompactingMemStore; 062import org.apache.hadoop.hbase.regionserver.CompactionPipeline; 063import org.apache.hadoop.hbase.regionserver.DefaultMemStore; 064import org.apache.hadoop.hbase.regionserver.HRegion; 065import org.apache.hadoop.hbase.regionserver.HStore; 066import org.apache.hadoop.hbase.regionserver.ImmutableSegment; 067import org.apache.hadoop.hbase.regionserver.MemStoreCompactor; 068import org.apache.hadoop.hbase.regionserver.MutableSegment; 069import org.apache.hadoop.hbase.regionserver.Segment; 070import org.apache.hadoop.hbase.regionserver.StoreContext; 071import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.NonSyncTimeRangeTracker; 072import org.apache.hadoop.hbase.regionserver.TimeRangeTracker.SyncTimeRangeTracker; 073import org.apache.hadoop.hbase.regionserver.throttle.StoreHotnessProtector; 074import org.apache.hadoop.hbase.testclassification.IOTests; 075import org.apache.hadoop.hbase.testclassification.SmallTests; 076import org.apache.hadoop.hbase.util.ClassSize; 077import org.junit.BeforeClass; 078import org.junit.ClassRule; 079import org.junit.Test; 080import org.junit.experimental.categories.Category; 081import org.slf4j.Logger; 082import org.slf4j.LoggerFactory; 083 084/** 085 * Testing the sizing that HeapSize offers and compares to the size given by ClassSize. 086 */ 087@Category({ IOTests.class, SmallTests.class }) 088public class TestHeapSize { 089 090 @ClassRule 091 public static final HBaseClassTestRule CLASS_RULE = 092 HBaseClassTestRule.forClass(TestHeapSize.class); 093 094 private static final Logger LOG = LoggerFactory.getLogger(TestHeapSize.class); 095 // List of classes implementing HeapSize 096 // BatchOperation, BatchUpdate, BlockIndex, Entry, Entry<K,V>, HStoreKey 097 // KeyValue, LruBlockCache, Put, WALKey 098 099 @BeforeClass 100 public static void beforeClass() throws Exception { 101 // Print detail on jvm so we know what is different should below test fail. 102 RuntimeMXBean b = ManagementFactory.getRuntimeMXBean(); 103 LOG.info("name=" + b.getName()); 104 LOG.info("specname=" + b.getSpecName()); 105 LOG.info("specvendor=" + b.getSpecVendor()); 106 LOG.info("vmname=" + b.getVmName()); 107 LOG.info("vmversion=" + b.getVmVersion()); 108 LOG.info("vmvendor=" + b.getVmVendor()); 109 Map<String, String> p = b.getSystemProperties(); 110 LOG.info("properties=" + p); 111 } 112 113 /** 114 * Test our hard-coded sizing of native java objects 115 */ 116 @Test 117 public void testNativeSizes() throws IOException { 118 Class<?> cl; 119 long expected; 120 long actual; 121 122 // ArrayList 123 cl = ArrayList.class; 124 expected = ClassSize.estimateBase(cl, false); 125 actual = ClassSize.ARRAYLIST; 126 if (expected != actual) { 127 ClassSize.estimateBase(cl, true); 128 assertEquals(expected, actual); 129 } 130 131 // ByteBuffer 132 cl = ByteBuffer.class; 133 expected = ClassSize.estimateBase(cl, false); 134 actual = ClassSize.BYTE_BUFFER; 135 if (expected != actual) { 136 ClassSize.estimateBase(cl, true); 137 assertEquals(expected, actual); 138 } 139 140 // Integer 141 cl = Integer.class; 142 expected = ClassSize.estimateBase(cl, false); 143 actual = ClassSize.INTEGER; 144 if (expected != actual) { 145 ClassSize.estimateBase(cl, true); 146 assertEquals(expected, actual); 147 } 148 149 // Map.Entry 150 // Interface is public, all others are not. Hard to size via ClassSize 151 // cl = Map.Entry.class; 152 // expected = ClassSize.estimateBase(cl, false); 153 // actual = ClassSize.MAP_ENTRY; 154 // if(expected != actual) { 155 // ClassSize.estimateBase(cl, true); 156 // assertEquals(expected, actual); 157 // } 158 159 // Object 160 cl = Object.class; 161 expected = ClassSize.estimateBase(cl, false); 162 actual = ClassSize.align(ClassSize.OBJECT); 163 if (expected != actual) { 164 ClassSize.estimateBase(cl, true); 165 assertEquals(expected, actual); 166 } 167 168 // TreeMap 169 cl = TreeMap.class; 170 expected = ClassSize.estimateBase(cl, false); 171 actual = ClassSize.TREEMAP; 172 if (expected != actual) { 173 ClassSize.estimateBase(cl, true); 174 assertEquals(expected, actual); 175 } 176 177 // String 178 cl = String.class; 179 expected = ClassSize.estimateBase(cl, false); 180 actual = ClassSize.STRING; 181 if (expected != actual) { 182 ClassSize.estimateBase(cl, true); 183 assertEquals(expected, actual); 184 } 185 186 // ConcurrentHashMap 187 cl = ConcurrentHashMap.class; 188 expected = ClassSize.estimateBase(cl, false); 189 actual = ClassSize.CONCURRENT_HASHMAP; 190 if (expected != actual) { 191 ClassSize.estimateBase(cl, true); 192 assertEquals(expected, actual); 193 } 194 195 // ConcurrentSkipListMap 196 cl = ConcurrentSkipListMap.class; 197 expected = ClassSize.estimateBase(cl, false); 198 actual = ClassSize.CONCURRENT_SKIPLISTMAP; 199 if (expected != actual) { 200 ClassSize.estimateBase(cl, true); 201 assertEquals(expected, actual); 202 } 203 204 // CellArrayMap 205 cl = CellArrayMap.class; 206 expected = ClassSize.estimateBase(cl, false); 207 actual = ClassSize.CELL_ARRAY_MAP; 208 if (expected != actual) { 209 ClassSize.estimateBase(cl, true); 210 assertEquals(expected, actual); 211 } 212 213 // ReentrantReadWriteLock 214 cl = ReentrantReadWriteLock.class; 215 expected = ClassSize.estimateBase(cl, false); 216 actual = ClassSize.REENTRANT_LOCK; 217 if (expected != actual) { 218 ClassSize.estimateBase(cl, true); 219 assertEquals(expected, actual); 220 } 221 222 // AtomicLong 223 cl = AtomicLong.class; 224 expected = ClassSize.estimateBase(cl, false); 225 actual = ClassSize.ATOMIC_LONG; 226 if (expected != actual) { 227 ClassSize.estimateBase(cl, true); 228 assertEquals(expected, actual); 229 } 230 231 // AtomicInteger 232 cl = AtomicInteger.class; 233 expected = ClassSize.estimateBase(cl, false); 234 actual = ClassSize.ATOMIC_INTEGER; 235 if (expected != actual) { 236 ClassSize.estimateBase(cl, true); 237 assertEquals(expected, actual); 238 } 239 240 // AtomicBoolean 241 cl = AtomicBoolean.class; 242 expected = ClassSize.estimateBase(cl, false); 243 actual = ClassSize.ATOMIC_BOOLEAN; 244 if (expected != actual) { 245 ClassSize.estimateBase(cl, true); 246 assertEquals(expected, actual); 247 } 248 249 // CopyOnWriteArraySet 250 cl = CopyOnWriteArraySet.class; 251 expected = ClassSize.estimateBase(cl, false); 252 actual = ClassSize.COPYONWRITE_ARRAYSET; 253 if (expected != actual) { 254 ClassSize.estimateBase(cl, true); 255 assertEquals(expected, actual); 256 } 257 258 // CopyOnWriteArrayList 259 cl = CopyOnWriteArrayList.class; 260 expected = ClassSize.estimateBase(cl, false); 261 actual = ClassSize.COPYONWRITE_ARRAYLIST; 262 if (expected != actual) { 263 ClassSize.estimateBase(cl, true); 264 assertEquals(expected, actual); 265 } 266 267 // SyncTimeRangeTracker 268 cl = SyncTimeRangeTracker.class; 269 expected = ClassSize.estimateBase(cl, false); 270 actual = ClassSize.SYNC_TIMERANGE_TRACKER; 271 if (expected != actual) { 272 ClassSize.estimateBase(cl, true); 273 assertEquals(expected, actual); 274 } 275 276 // NonSyncTimeRangeTracker 277 cl = NonSyncTimeRangeTracker.class; 278 expected = ClassSize.estimateBase(cl, false); 279 actual = ClassSize.NON_SYNC_TIMERANGE_TRACKER; 280 if (expected != actual) { 281 ClassSize.estimateBase(cl, true); 282 assertEquals(expected, actual); 283 } 284 285 // CellSet 286 cl = CellSet.class; 287 expected = ClassSize.estimateBase(cl, false); 288 actual = ClassSize.CELL_SET; 289 if (expected != actual) { 290 ClassSize.estimateBase(cl, true); 291 assertEquals(expected, actual); 292 } 293 } 294 295 /** 296 * Testing the classes that implements HeapSize and are a part of 0.20. Some are not tested here 297 * for example BlockIndex which is tested in TestHFile since it is a non public class 298 */ 299 @Test 300 public void testSizes() throws IOException { 301 Class<?> cl; 302 long expected; 303 long actual; 304 305 // KeyValue 306 cl = KeyValue.class; 307 expected = ClassSize.estimateBase(cl, false); 308 KeyValue kv = new KeyValue(); 309 actual = kv.heapSize(); 310 if (expected != actual) { 311 ClassSize.estimateBase(cl, true); 312 assertEquals(expected, actual); 313 } 314 315 // LruBlockCache Overhead 316 cl = LruBlockCache.class; 317 actual = LruBlockCache.CACHE_FIXED_OVERHEAD; 318 expected = ClassSize.estimateBase(cl, false); 319 if (expected != actual) { 320 ClassSize.estimateBase(cl, true); 321 assertEquals(expected, actual); 322 } 323 324 // CachedBlock Fixed Overhead 325 // We really need "deep" sizing but ClassSize does not do this. 326 // Perhaps we should do all these more in this style.... 327 cl = LruCachedBlock.class; 328 actual = LruCachedBlock.PER_BLOCK_OVERHEAD; 329 expected = ClassSize.estimateBase(cl, false); 330 expected += ClassSize.estimateBase(String.class, false); 331 expected += ClassSize.estimateBase(ByteBuffer.class, false); 332 if (expected != actual) { 333 ClassSize.estimateBase(cl, true); 334 ClassSize.estimateBase(String.class, true); 335 ClassSize.estimateBase(ByteBuffer.class, true); 336 assertEquals(expected, actual); 337 } 338 339 // DefaultMemStore Overhead 340 cl = DefaultMemStore.class; 341 actual = DefaultMemStore.FIXED_OVERHEAD; 342 expected = ClassSize.estimateBase(cl, false); 343 if (expected != actual) { 344 ClassSize.estimateBase(cl, true); 345 assertEquals(expected, actual); 346 } 347 348 // DefaultMemStore Deep Overhead 349 actual = DefaultMemStore.DEEP_OVERHEAD; 350 expected = ClassSize.estimateBase(cl, false); 351 if (expected != actual) { 352 ClassSize.estimateBase(cl, true); 353 assertEquals(expected, actual); 354 } 355 356 // CompactingMemStore Deep Overhead 357 cl = CompactingMemStore.class; 358 actual = CompactingMemStore.DEEP_OVERHEAD; 359 expected = ClassSize.estimateBase(cl, false); 360 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 361 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 362 expected += ClassSize.estimateBase(CompactionPipeline.class, false); 363 expected += ClassSize.estimateBase(LinkedList.class, false); // inside CompactionPipeline 364 expected += ClassSize.estimateBase(LinkedList.class, false); // inside CompactionPipeline 365 expected += ClassSize.estimateBase(MemStoreCompactor.class, false); 366 expected += ClassSize.estimateBase(AtomicBoolean.class, false);// inside MemStoreCompactor 367 if (expected != actual) { 368 ClassSize.estimateBase(cl, true); 369 ClassSize.estimateBase(AtomicBoolean.class, true); 370 ClassSize.estimateBase(AtomicBoolean.class, true); 371 ClassSize.estimateBase(CompactionPipeline.class, true); 372 ClassSize.estimateBase(LinkedList.class, true); 373 ClassSize.estimateBase(LinkedList.class, true); 374 ClassSize.estimateBase(MemStoreCompactor.class, true); 375 ClassSize.estimateBase(AtomicBoolean.class, true); 376 assertEquals(expected, actual); 377 } 378 379 // Segment Deep overhead 380 cl = Segment.class; 381 actual = Segment.DEEP_OVERHEAD; 382 expected = ClassSize.estimateBase(cl, false); 383 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 384 expected += ClassSize.estimateBase(AtomicReference.class, false); 385 expected += ClassSize.estimateBase(CellSet.class, false); 386 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 387 if (expected != actual) { 388 ClassSize.estimateBase(cl, true); 389 ClassSize.estimateBase(AtomicLong.class, true); 390 ClassSize.estimateBase(AtomicReference.class, true); 391 ClassSize.estimateBase(CellSet.class, true); 392 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 393 assertEquals(expected, actual); 394 } 395 396 // MutableSegment Deep overhead 397 cl = MutableSegment.class; 398 actual = MutableSegment.DEEP_OVERHEAD; 399 expected = ClassSize.estimateBase(cl, false); 400 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 401 expected += ClassSize.estimateBase(AtomicReference.class, false); 402 expected += ClassSize.estimateBase(CellSet.class, false); 403 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 404 expected += ClassSize.estimateBase(SyncTimeRangeTracker.class, false); 405 expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false); 406 expected += ClassSize.estimateBase(AtomicBoolean.class, false); 407 if (expected != actual) { 408 ClassSize.estimateBase(cl, true); 409 ClassSize.estimateBase(AtomicLong.class, true); 410 ClassSize.estimateBase(AtomicLong.class, true); 411 ClassSize.estimateBase(AtomicReference.class, true); 412 ClassSize.estimateBase(CellSet.class, true); 413 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 414 ClassSize.estimateBase(SyncTimeRangeTracker.class, true); 415 ClassSize.estimateBase(ConcurrentSkipListMap.class, true); 416 ClassSize.estimateBase(AtomicBoolean.class, true); 417 assertEquals(expected, actual); 418 } 419 420 // ImmutableSegments Deep overhead 421 cl = ImmutableSegment.class; 422 actual = ImmutableSegment.DEEP_OVERHEAD; 423 expected = ClassSize.estimateBase(cl, false); 424 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 425 expected += ClassSize.estimateBase(AtomicReference.class, false); 426 expected += ClassSize.estimateBase(CellSet.class, false); 427 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 428 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 429 if (expected != actual) { 430 ClassSize.estimateBase(cl, true); 431 ClassSize.estimateBase(AtomicLong.class, true); 432 ClassSize.estimateBase(AtomicLong.class, true); 433 ClassSize.estimateBase(AtomicReference.class, true); 434 ClassSize.estimateBase(CellSet.class, true); 435 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 436 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 437 assertEquals(expected, actual); 438 } 439 440 cl = CSLMImmutableSegment.class; 441 actual = CSLMImmutableSegment.DEEP_OVERHEAD_CSLM; 442 expected = ClassSize.estimateBase(cl, false); 443 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 444 expected += ClassSize.estimateBase(AtomicReference.class, false); 445 expected += ClassSize.estimateBase(CellSet.class, false); 446 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 447 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 448 expected += ClassSize.estimateBase(ConcurrentSkipListMap.class, false); 449 if (expected != actual) { 450 ClassSize.estimateBase(cl, true); 451 ClassSize.estimateBase(AtomicLong.class, true); 452 ClassSize.estimateBase(AtomicLong.class, true); 453 ClassSize.estimateBase(AtomicReference.class, true); 454 ClassSize.estimateBase(CellSet.class, true); 455 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 456 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 457 ClassSize.estimateBase(ConcurrentSkipListMap.class, true); 458 assertEquals(expected, actual); 459 } 460 cl = CellArrayImmutableSegment.class; 461 actual = CellArrayImmutableSegment.DEEP_OVERHEAD_CAM; 462 expected = ClassSize.estimateBase(cl, false); 463 expected += 2 * ClassSize.estimateBase(AtomicLong.class, false); 464 expected += ClassSize.estimateBase(AtomicReference.class, false); 465 expected += ClassSize.estimateBase(CellSet.class, false); 466 expected += ClassSize.estimateBase(ReentrantReadWriteLock.class, false); 467 expected += ClassSize.estimateBase(NonSyncTimeRangeTracker.class, false); 468 expected += ClassSize.estimateBase(CellArrayMap.class, false); 469 if (expected != actual) { 470 ClassSize.estimateBase(cl, true); 471 ClassSize.estimateBase(AtomicLong.class, true); 472 ClassSize.estimateBase(AtomicLong.class, true); 473 ClassSize.estimateBase(AtomicReference.class, true); 474 ClassSize.estimateBase(CellSet.class, true); 475 ClassSize.estimateBase(ReentrantReadWriteLock.class, true); 476 ClassSize.estimateBase(NonSyncTimeRangeTracker.class, true); 477 ClassSize.estimateBase(CellArrayMap.class, true); 478 assertEquals(expected, actual); 479 } 480 481 // Store Overhead 482 cl = HStore.class; 483 actual = HStore.FIXED_OVERHEAD; 484 expected = ClassSize.estimateBase(cl, false); 485 if (expected != actual) { 486 ClassSize.estimateBase(cl, true); 487 assertEquals(expected, actual); 488 } 489 490 // Region Overhead 491 cl = HRegion.class; 492 actual = HRegion.FIXED_OVERHEAD; 493 expected = ClassSize.estimateBase(cl, false); 494 if (expected != actual) { 495 ClassSize.estimateBase(cl, true); 496 assertEquals(expected, actual); 497 } 498 499 cl = StoreHotnessProtector.class; 500 actual = StoreHotnessProtector.FIXED_SIZE; 501 expected = ClassSize.estimateBase(cl, false); 502 if (expected != actual) { 503 ClassSize.estimateBase(cl, true); 504 assertEquals(expected, actual); 505 } 506 507 // Block cache key overhead. Only tests fixed overhead as estimating heap 508 // size of strings is hard. 509 cl = BlockCacheKey.class; 510 actual = BlockCacheKey.FIXED_OVERHEAD; 511 expected = ClassSize.estimateBase(cl, false); 512 if (expected != actual) { 513 ClassSize.estimateBase(cl, true); 514 assertEquals(expected, actual); 515 } 516 517 // Currently NOT testing Deep Overheads of many of these classes. 518 // Deep overheads cover a vast majority of stuff, but will not be 100% 519 // accurate because it's unclear when we're referencing stuff that's already 520 // accounted for. But we have satisfied our two core requirements. 521 // Sizing is quite accurate now, and our tests will throw errors if 522 // any of these classes are modified without updating overhead sizes. 523 } 524 525 @Test 526 public void testHFileBlockSize() throws IOException { 527 long expected; 528 long actual; 529 530 actual = HFileContext.FIXED_OVERHEAD; 531 expected = ClassSize.estimateBase(HFileContext.class, false); 532 assertEquals(expected, actual); 533 534 actual = HFileBlock.FIXED_OVERHEAD; 535 expected = ClassSize.estimateBase(HFileBlock.class, false); 536 assertEquals(expected, actual); 537 538 actual = ExclusiveMemHFileBlock.FIXED_OVERHEAD; 539 expected = ClassSize.estimateBase(ExclusiveMemHFileBlock.class, false); 540 assertEquals(expected, actual); 541 542 actual = SharedMemHFileBlock.FIXED_OVERHEAD; 543 expected = ClassSize.estimateBase(SharedMemHFileBlock.class, false); 544 assertEquals(expected, actual); 545 } 546 547 @Test 548 public void testMutations() { 549 Class<?> cl; 550 long expected; 551 long actual; 552 553 cl = TimeRange.class; 554 actual = ClassSize.TIMERANGE; 555 expected = ClassSize.estimateBase(cl, false); 556 if (expected != actual) { 557 ClassSize.estimateBase(cl, true); 558 assertEquals(expected, actual); 559 } 560 561 byte[] row = new byte[] { 0 }; 562 cl = Put.class; 563 actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY); 564 expected = ClassSize.estimateBase(cl, false); 565 // The actual TreeMap is not included in the above calculation 566 expected += ClassSize.align(ClassSize.TREEMAP); 567 expected += ClassSize.align(ClassSize.INTEGER); // priority 568 if (expected != actual) { 569 ClassSize.estimateBase(cl, true); 570 assertEquals(expected, actual); 571 } 572 573 cl = Delete.class; 574 actual = Mutation.MUTATION_OVERHEAD + ClassSize.align(ClassSize.ARRAY); 575 expected = ClassSize.estimateBase(cl, false); 576 // The actual TreeMap is not included in the above calculation 577 expected += ClassSize.align(ClassSize.TREEMAP); 578 expected += ClassSize.align(ClassSize.INTEGER); // priority 579 if (expected != actual) { 580 ClassSize.estimateBase(cl, true); 581 assertEquals(expected, actual); 582 } 583 } 584 585 @Test 586 public void testReferenceSize() { 587 LOG.info("ClassSize.REFERENCE is " + ClassSize.REFERENCE); 588 // oop should be either 4 or 8 589 assertTrue(ClassSize.REFERENCE == 4 || ClassSize.REFERENCE == 8); 590 } 591 592 @Test 593 public void testObjectSize() throws IOException { 594 LOG.info("header:" + ClassSize.OBJECT); 595 LOG.info("array header:" + ClassSize.ARRAY); 596 597 if (ClassSize.is32BitJVM()) { 598 assertEquals(ClassSize.OBJECT, 8); 599 } else { 600 assertTrue(ClassSize.OBJECT == 12 || ClassSize.OBJECT == 16); // depending on CompressedOops 601 } 602 if (ClassSize.useUnsafeLayout()) { 603 assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 4); 604 } else { 605 assertEquals(ClassSize.ARRAY, ClassSize.OBJECT + 8); 606 } 607 } 608 609 private long calcFixedOverhead(List<Class<?>> classList) { 610 long overhead = 0; 611 for (Class<?> clazz : classList) { 612 overhead += ClassSize.estimateBase(clazz, false); 613 } 614 return overhead; 615 } 616 617 @Test 618 public void testAutoCalcFixedOverhead() throws InterruptedException { 619 List<Class<?>> classList = Arrays.asList(HFileContext.class, HRegion.class, BlockCacheKey.class, 620 HFileBlock.class, HStore.class, LruBlockCache.class, StoreContext.class); 621 for (int i = 0; i < 10; i++) { 622 // warm up 623 calcFixedOverhead(classList); 624 } 625 long startNs = System.nanoTime(); 626 long overhead = 0; 627 for (int i = 0; i < 100; i++) { 628 overhead += calcFixedOverhead(classList); 629 } 630 long costNs = System.nanoTime() - startNs; 631 LOG.info("overhead = {}, cost {} ns", overhead, costNs); 632 // the single computation cost should be less than 5ms 633 assertThat(costNs, lessThan(TimeUnit.MILLISECONDS.toNanos(5) * classList.size() * 100)); 634 } 635}