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