1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.vm.ci.hotspot; 24 25 import static java.lang.String.*; 26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; 27 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 28 29 import java.util.*; 30 31 import jdk.vm.ci.hotspot.HotSpotMethodDataAccessor.*; 32 import jdk.vm.ci.meta.*; 33 import jdk.vm.ci.meta.JavaMethodProfile.*; 34 import jdk.vm.ci.meta.JavaTypeProfile.*; 35 import sun.misc.*; 36 37 /** 38 * Access to a HotSpot MethodData structure (defined in methodData.hpp). 39 */ 40 public final class HotSpotMethodData { 41 42 private static final HotSpotVMConfig config = runtime().getConfig(); 43 private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); 44 private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); 45 46 // sorted by tag 47 // @formatter:off 48 private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { 49 null, 50 new BitData(), 51 new CounterData(), 52 new JumpData(), 53 new TypeCheckData(), 54 new VirtualCallData(), 55 new RetData(), 56 new BranchData(), 57 new MultiBranchData(), 58 new ArgInfoData(), 59 null, // call_type_data_tag 60 null, // virtual_call_type_data_tag 61 null, // parameters_type_data_tag 62 null, // speculative_trap_data_tag 63 }; 64 // @formatter:on 65 66 /** 67 * Reference to the C++ MethodData object. 68 */ 69 private final long metaspaceMethodData; 70 @SuppressWarnings("unused") private final HotSpotResolvedJavaMethodImpl method; 71 72 public HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) { 73 this.metaspaceMethodData = metaspaceMethodData; 74 this.method = method; 75 } 76 77 /** 78 * @return value of the MethodData::_data_size field 79 */ 80 private int normalDataSize() { 81 return UNSAFE.getInt(metaspaceMethodData + config.methodDataDataSize); 82 } 83 84 /** 85 * Returns the size of the extra data records. This method does the same calculation as 86 * MethodData::extra_data_size(). 87 * 88 * @return size of extra data records 89 */ 90 private int extraDataSize() { 91 final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); 92 final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + config.methodDataSize); 93 return extraDataLimit - extraDataBase; 94 } 95 96 public boolean hasNormalData() { 97 return normalDataSize() > 0; 98 } 99 100 public boolean hasExtraData() { 101 return extraDataSize() > 0; 102 } 103 104 public int getExtraDataBeginOffset() { 105 return normalDataSize(); 106 } 107 108 public boolean isWithin(int position) { 109 return position >= 0 && position < normalDataSize() + extraDataSize(); 110 } 111 112 public int getDeoptimizationCount(DeoptimizationReason reason) { 113 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 114 int reasonIndex = metaAccess.convertDeoptReason(reason); 115 return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; 116 } 117 118 public int getOSRDeoptimizationCount(DeoptimizationReason reason) { 119 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 120 int reasonIndex = metaAccess.convertDeoptReason(reason); 121 return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; 122 } 123 124 public HotSpotMethodDataAccessor getNormalData(int position) { 125 if (position >= normalDataSize()) { 126 return null; 127 } 128 129 HotSpotMethodDataAccessor result = getData(position); 130 assert result != null : "NO_DATA tag is not allowed"; 131 return result; 132 } 133 134 public HotSpotMethodDataAccessor getExtraData(int position) { 135 if (position >= normalDataSize() + extraDataSize()) { 136 return null; 137 } 138 HotSpotMethodDataAccessor data = getData(position); 139 if (data != null) { 140 return data; 141 } 142 return data; 143 } 144 145 public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { 146 if (exceptionPossiblyNotRecorded) { 147 return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; 148 } else { 149 return NO_DATA_NO_EXCEPTION_ACCESSOR; 150 } 151 } 152 153 private HotSpotMethodDataAccessor getData(int position) { 154 assert position >= 0 : "out of bounds"; 155 final Tag tag = AbstractMethodData.readTag(this, position); 156 HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; 157 assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; 158 return accessor; 159 } 160 161 private int readUnsignedByte(int position, int offsetInBytes) { 162 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 163 return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; 164 } 165 166 private int readUnsignedShort(int position, int offsetInBytes) { 167 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 168 return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; 169 } 170 171 /** 172 * Since the values are stored in cells (platform words) this method uses 173 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 174 */ 175 private long readUnsignedInt(int position, int offsetInBytes) { 176 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 177 return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; 178 } 179 180 private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { 181 long value = readUnsignedInt(position, offsetInBytes); 182 return truncateLongToInt(value); 183 } 184 185 /** 186 * Since the values are stored in cells (platform words) this method uses 187 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 188 */ 189 private int readInt(int position, int offsetInBytes) { 190 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 191 return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes); 192 } 193 194 private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { 195 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 196 return runtime().compilerToVm.getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes); 197 } 198 199 private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { 200 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 201 return runtime().compilerToVm.getResolvedJavaType(null, metaspaceMethodData + fullOffsetInBytes, false); 202 } 203 204 private static int truncateLongToInt(long value) { 205 return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; 206 } 207 208 private static int computeFullOffset(int position, int offsetInBytes) { 209 return config.methodDataOopDataOffset + position + offsetInBytes; 210 } 211 212 private static int cellIndexToOffset(int cells) { 213 return config.dataLayoutHeaderSize + cellsToBytes(cells); 214 } 215 216 private static int cellsToBytes(int cells) { 217 return cells * config.dataLayoutCellSize; 218 } 219 220 /** 221 * Returns whether profiling ran long enough that the profile information is mature. Other 222 * informational data will still be valid even if the profile isn't mature. 223 */ 224 public boolean isProfileMature() { 225 return runtime().getCompilerToVM().isMature(metaspaceMethodData); 226 } 227 228 @Override 229 public String toString() { 230 StringBuilder sb = new StringBuilder(); 231 String nl = String.format("%n"); 232 String nlIndent = String.format("%n%38s", ""); 233 if (hasNormalData()) { 234 int pos = 0; 235 HotSpotMethodDataAccessor data; 236 while ((data = getNormalData(pos)) != null) { 237 if (pos != 0) { 238 sb.append(nl); 239 } 240 int bci = data.getBCI(this, pos); 241 sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); 242 sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); 243 pos = pos + data.getSize(this, pos); 244 } 245 } 246 247 if (hasExtraData()) { 248 int pos = getExtraDataBeginOffset(); 249 HotSpotMethodDataAccessor data; 250 while ((data = getExtraData(pos)) != null) { 251 if (pos == getExtraDataBeginOffset()) { 252 sb.append(nl).append("--- Extra data:"); 253 } 254 int bci = data.getBCI(this, pos); 255 sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); 256 sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); 257 pos = pos + data.getSize(this, pos); 258 } 259 260 } 261 return sb.toString(); 262 } 263 264 private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { 265 266 /** 267 * Corresponds to {@code exception_seen_flag}. 268 */ 269 private static final int EXCEPTIONS_MASK = 0x2; 270 271 private final Tag tag; 272 private final int staticSize; 273 274 protected AbstractMethodData(Tag tag, int staticSize) { 275 this.tag = tag; 276 this.staticSize = staticSize; 277 } 278 279 public Tag getTag() { 280 return tag; 281 } 282 283 public static Tag readTag(HotSpotMethodData data, int position) { 284 final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); 285 return Tag.getEnum(tag); 286 } 287 288 @Override 289 public int getBCI(HotSpotMethodData data, int position) { 290 return data.readUnsignedShort(position, config.dataLayoutBCIOffset); 291 } 292 293 @Override 294 public int getSize(HotSpotMethodData data, int position) { 295 return staticSize + getDynamicSize(data, position); 296 } 297 298 @Override 299 public TriState getExceptionSeen(HotSpotMethodData data, int position) { 300 return TriState.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); 301 } 302 303 @Override 304 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 305 return null; 306 } 307 308 @Override 309 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 310 return null; 311 } 312 313 @Override 314 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 315 return -1; 316 } 317 318 @Override 319 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 320 return null; 321 } 322 323 @Override 324 public int getExecutionCount(HotSpotMethodData data, int position) { 325 return -1; 326 } 327 328 @Override 329 public TriState getNullSeen(HotSpotMethodData data, int position) { 330 return TriState.UNKNOWN; 331 } 332 333 protected int getFlags(HotSpotMethodData data, int position) { 334 return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); 335 } 336 337 /** 338 * @param data 339 * @param position 340 */ 341 protected int getDynamicSize(HotSpotMethodData data, int position) { 342 return 0; 343 } 344 345 public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); 346 } 347 348 private static class NoMethodData extends AbstractMethodData { 349 350 private static final int NO_DATA_SIZE = cellIndexToOffset(0); 351 352 private final TriState exceptionSeen; 353 354 protected NoMethodData(TriState exceptionSeen) { 355 super(Tag.No, NO_DATA_SIZE); 356 this.exceptionSeen = exceptionSeen; 357 } 358 359 @Override 360 public int getBCI(HotSpotMethodData data, int position) { 361 return -1; 362 } 363 364 @Override 365 public TriState getExceptionSeen(HotSpotMethodData data, int position) { 366 return exceptionSeen; 367 } 368 369 @Override 370 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 371 return sb; 372 } 373 } 374 375 private static class BitData extends AbstractMethodData { 376 377 private static final int BIT_DATA_SIZE = cellIndexToOffset(0); 378 private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; 379 380 private BitData() { 381 super(Tag.BitData, BIT_DATA_SIZE); 382 } 383 384 protected BitData(Tag tag, int staticSize) { 385 super(tag, staticSize); 386 } 387 388 @Override 389 public TriState getNullSeen(HotSpotMethodData data, int position) { 390 return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); 391 } 392 393 @Override 394 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 395 return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); 396 } 397 } 398 399 private static class CounterData extends BitData { 400 401 private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); 402 private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); 403 404 public CounterData() { 405 super(Tag.CounterData, COUNTER_DATA_SIZE); 406 } 407 408 protected CounterData(Tag tag, int staticSize) { 409 super(tag, staticSize); 410 } 411 412 @Override 413 public int getExecutionCount(HotSpotMethodData data, int position) { 414 return getCounterValue(data, position); 415 } 416 417 protected int getCounterValue(HotSpotMethodData data, int position) { 418 return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); 419 } 420 421 @Override 422 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 423 return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); 424 } 425 } 426 427 private static class JumpData extends AbstractMethodData { 428 429 private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); 430 protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); 431 protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); 432 433 public JumpData() { 434 super(Tag.JumpData, JUMP_DATA_SIZE); 435 } 436 437 protected JumpData(Tag tag, int staticSize) { 438 super(tag, staticSize); 439 } 440 441 @Override 442 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 443 return getExecutionCount(data, position) != 0 ? 1 : 0; 444 } 445 446 @Override 447 public int getExecutionCount(HotSpotMethodData data, int position) { 448 return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); 449 } 450 451 public int getTakenDisplacement(HotSpotMethodData data, int position) { 452 return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); 453 } 454 455 @Override 456 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 457 return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); 458 } 459 } 460 461 static class RawItemProfile<T> { 462 final int entries; 463 final T[] items; 464 final long[] counts; 465 final long totalCount; 466 467 public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) { 468 this.entries = entries; 469 this.items = items; 470 this.counts = counts; 471 this.totalCount = totalCount; 472 } 473 } 474 475 private abstract static class AbstractTypeData extends CounterData { 476 477 protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2); 478 479 protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1); 480 protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); 481 protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); 482 483 protected AbstractTypeData(Tag tag, int staticSize) { 484 super(tag, staticSize); 485 } 486 487 @Override 488 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 489 return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); 490 } 491 492 private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) { 493 int typeProfileWidth = config.typeProfileWidth; 494 495 ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; 496 long[] counts = new long[typeProfileWidth]; 497 long totalCount = 0; 498 int entries = 0; 499 500 outer: for (int i = 0; i < typeProfileWidth; i++) { 501 HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); 502 if (receiverKlass != null) { 503 HotSpotResolvedObjectTypeImpl klass = receiverKlass; 504 long count = data.readUnsignedInt(position, getTypeCountOffset(i)); 505 /* 506 * Because of races in the profile collection machinery it's possible for a 507 * class to appear multiple times so merge them to make the profile look 508 * rational. 509 */ 510 for (int j = 0; j < entries; j++) { 511 if (types[j].equals(klass)) { 512 totalCount += count; 513 counts[j] += count; 514 continue outer; 515 } 516 } 517 types[entries] = klass; 518 totalCount += count; 519 counts[entries] = count; 520 entries++; 521 } 522 } 523 524 totalCount += getTypesNotRecordedExecutionCount(data, position); 525 return new RawItemProfile<>(entries, types, counts, totalCount); 526 } 527 528 protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); 529 530 private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) { 531 if (profile.entries <= 0 || profile.totalCount <= 0) { 532 return null; 533 } 534 535 ProfiledType[] ptypes = new ProfiledType[profile.entries]; 536 double totalProbability = 0.0; 537 for (int i = 0; i < profile.entries; i++) { 538 double p = profile.counts[i]; 539 p = p / profile.totalCount; 540 totalProbability += p; 541 ptypes[i] = new ProfiledType(profile.items[i], p); 542 } 543 544 Arrays.sort(ptypes); 545 546 double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 547 assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; 548 return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); 549 } 550 551 private static int getTypeOffset(int row) { 552 return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; 553 } 554 555 protected static int getTypeCountOffset(int row) { 556 return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; 557 } 558 559 @Override 560 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 561 RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos); 562 TriState nullSeen = getNullSeen(data, pos); 563 TriState exceptionSeen = getExceptionSeen(data, pos); 564 sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, 565 getTypesNotRecordedExecutionCount(data, pos), profile.entries)); 566 for (int i = 0; i < profile.entries; i++) { 567 long count = profile.counts[i]; 568 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); 569 } 570 return sb; 571 } 572 } 573 574 private static class TypeCheckData extends AbstractTypeData { 575 576 private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 577 578 public TypeCheckData() { 579 super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); 580 } 581 582 @Override 583 public int getExecutionCount(HotSpotMethodData data, int position) { 584 return -1; 585 } 586 587 @Override 588 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 589 return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); 590 } 591 } 592 593 private static class VirtualCallData extends AbstractTypeData { 594 595 private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); 596 private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 597 private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 598 599 public VirtualCallData() { 600 super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); 601 } 602 603 @Override 604 public int getExecutionCount(HotSpotMethodData data, int position) { 605 final int typeProfileWidth = config.typeProfileWidth; 606 607 long total = 0; 608 for (int i = 0; i < typeProfileWidth; i++) { 609 total += data.readUnsignedInt(position, getTypeCountOffset(i)); 610 } 611 612 total += getCounterValue(data, position); 613 return truncateLongToInt(total); 614 } 615 616 @Override 617 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 618 return getCounterValue(data, position); 619 } 620 621 private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { 622 return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); 623 } 624 625 @Override 626 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 627 return createMethodProfile(getRawMethodProfile(data, position)); 628 } 629 630 private static RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) { 631 int profileWidth = config.methodProfileWidth; 632 633 ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; 634 long[] counts = new long[profileWidth]; 635 long totalCount = 0; 636 int entries = 0; 637 638 for (int i = 0; i < profileWidth; i++) { 639 HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); 640 if (method != null) { 641 methods[entries] = method; 642 long count = data.readUnsignedInt(position, getMethodCountOffset(i)); 643 totalCount += count; 644 counts[entries] = count; 645 646 entries++; 647 } 648 } 649 650 totalCount += getMethodsNotRecordedExecutionCount(data, position); 651 return new RawItemProfile<>(entries, methods, counts, totalCount); 652 } 653 654 private static JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 655 if (profile.entries <= 0 || profile.totalCount <= 0) { 656 return null; 657 } 658 659 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 660 double totalProbability = 0.0; 661 for (int i = 0; i < profile.entries; i++) { 662 double p = profile.counts[i]; 663 p = p / profile.totalCount; 664 totalProbability += p; 665 pmethods[i] = new ProfiledMethod(profile.items[i], p); 666 } 667 668 Arrays.sort(pmethods); 669 670 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 671 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 672 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 673 } 674 675 private static int getMethodOffset(int row) { 676 return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; 677 } 678 679 private static int getMethodCountOffset(int row) { 680 return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; 681 } 682 683 @Override 684 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 685 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 686 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 687 for (int i = 0; i < profile.entries; i++) { 688 long count = profile.counts[i]; 689 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 690 } 691 return sb; 692 } 693 } 694 695 private static class RetData extends CounterData { 696 697 private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); 698 private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; 699 700 public RetData() { 701 super(Tag.RetData, RET_DATA_SIZE); 702 } 703 } 704 705 private static class BranchData extends JumpData { 706 707 private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); 708 private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); 709 710 public BranchData() { 711 super(Tag.BranchData, BRANCH_DATA_SIZE); 712 } 713 714 @Override 715 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 716 long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); 717 long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 718 long total = takenCount + notTakenCount; 719 720 return total <= 0 ? -1 : takenCount / (double) total; 721 } 722 723 @Override 724 public int getExecutionCount(HotSpotMethodData data, int position) { 725 long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 726 return truncateLongToInt(count); 727 } 728 729 @Override 730 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 731 long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); 732 long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); 733 double takenProbability = getBranchTakenProbability(data, pos); 734 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 735 } 736 } 737 738 private static class ArrayData extends AbstractMethodData { 739 740 private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); 741 protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); 742 743 public ArrayData(Tag tag, int staticSize) { 744 super(tag, staticSize); 745 } 746 747 @Override 748 protected int getDynamicSize(HotSpotMethodData data, int position) { 749 return cellsToBytes(getLength(data, position)); 750 } 751 752 protected static int getLength(HotSpotMethodData data, int position) { 753 return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); 754 } 755 756 @Override 757 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 758 return sb.append(format("length(%d)", getLength(data, pos))); 759 } 760 } 761 762 private static class MultiBranchData extends ArrayData { 763 764 private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); 765 private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; 766 private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); 767 private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); 768 private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); 769 770 public MultiBranchData() { 771 super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); 772 } 773 774 @Override 775 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 776 int arrayLength = getLength(data, position); 777 assert arrayLength > 0 : "switch must have at least the default case"; 778 assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 779 780 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 781 long totalCount = 0; 782 double[] result = new double[length]; 783 784 // default case is first in HotSpot but last for the compiler 785 long count = readCount(data, position, 0); 786 totalCount += count; 787 result[length - 1] = count; 788 789 for (int i = 1; i < length; i++) { 790 count = readCount(data, position, i); 791 totalCount += count; 792 result[i - 1] = count; 793 } 794 795 if (totalCount <= 0) { 796 return null; 797 } else { 798 for (int i = 0; i < length; i++) { 799 result[i] = result[i] / totalCount; 800 } 801 return result; 802 } 803 } 804 805 private static long readCount(HotSpotMethodData data, int position, int i) { 806 int offset; 807 long count; 808 offset = getCountOffset(i); 809 count = data.readUnsignedInt(position, offset); 810 return count; 811 } 812 813 @Override 814 public int getExecutionCount(HotSpotMethodData data, int position) { 815 int arrayLength = getLength(data, position); 816 assert arrayLength > 0 : "switch must have at least the default case"; 817 assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 818 819 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 820 long totalCount = 0; 821 for (int i = 0; i < length; i++) { 822 int offset = getCountOffset(i); 823 totalCount += data.readUnsignedInt(position, offset); 824 } 825 826 return truncateLongToInt(totalCount); 827 } 828 829 private static int getCountOffset(int index) { 830 return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 831 } 832 833 private static int getDisplacementOffset(int index) { 834 return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 835 } 836 837 @Override 838 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 839 int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 840 sb.append(format("entries(%d)", entries)); 841 for (int i = 0; i < entries; i++) { 842 sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); 843 } 844 return sb; 845 } 846 } 847 848 private static class ArgInfoData extends ArrayData { 849 850 private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); 851 852 public ArgInfoData() { 853 super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); 854 } 855 } 856 857 public void setCompiledIRSize(int size) { 858 UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); 859 } 860 861 public int getCompiledIRSize() { 862 return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); 863 } 864 }