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 it's a monomorphic call site, attribute all the counts to the first type (if any is recorded). 584 if (entries == 1) { 585 counts[0] = totalCount; 586 } 587 588 return new RawItemProfile<>(entries, methods, counts, totalCount); 589 } 590 591 private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 592 if (profile.entries <= 0 || profile.totalCount <= 0) { 593 return null; 594 } 595 596 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 597 double totalProbability = 0.0; 598 for (int i = 0; i < profile.entries; i++) { 599 double p = profile.counts[i]; 600 p = p / profile.totalCount; 601 totalProbability += p; 602 pmethods[i] = new ProfiledMethod(profile.items[i], p); 603 } 604 605 Arrays.sort(pmethods); 606 607 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 608 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 609 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 610 } 611 612 private static int getMethodOffset(int row) { 613 return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; 614 } 615 616 private static int getMethodCountOffset(int row) { 617 return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; 618 } 619 620 @Override 621 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 622 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 623 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 624 for (int i = 0; i < profile.entries; i++) { 625 long count = profile.counts[i]; 626 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 627 } 628 return sb; 629 } 630 } 631 632 static class VirtualCallTypeData extends VirtualCallData { 633 634 VirtualCallTypeData(HotSpotVMConfig config, int tag) { 635 super(config, tag, 0); 636 } 637 638 @Override 639 protected int getDynamicSize(HotSpotMethodData data, int position) { 640 assert staticSize == 0; 641 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position); 642 } 643 } 644 645 static final int RET_DATA_ROW_SIZE = cellsToBytes(3); 646 static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; 647 648 static class RetData extends CounterData { 649 650 RetData(HotSpotVMConfig config, int tag) { 651 super(config, tag, RET_DATA_SIZE); 652 } 653 } 654 655 static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); 656 static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(config.branchDataNotTakenOffset); 657 658 static class BranchData extends JumpData { 659 660 BranchData(HotSpotVMConfig config, int tag) { 661 super(config, tag, BRANCH_DATA_SIZE); 662 } 663 664 @Override 665 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 666 long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); 667 long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 668 long total = takenCount + notTakenCount; 669 670 return total <= 0 ? -1 : takenCount / (double) total; 671 } 672 673 @Override 674 public int getExecutionCount(HotSpotMethodData data, int position) { 675 long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 676 return truncateLongToInt(count); 677 } 678 679 @Override 680 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 681 long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); 682 long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); 683 double takenProbability = getBranchTakenProbability(data, pos); 684 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 685 } 686 } 687 688 static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(config.arrayDataArrayLenOffset); 689 static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(config.arrayDataArrayStartOffset); 690 691 static class ArrayData extends HotSpotMethodDataAccessor { 692 693 ArrayData(HotSpotVMConfig config, int tag, int staticSize) { 694 super(config, tag, staticSize); 695 } 696 697 @Override 698 protected int getDynamicSize(HotSpotMethodData data, int position) { 699 return cellsToBytes(getLength(data, position)); 700 } 701 702 protected static int getLength(HotSpotMethodData data, int position) { 703 return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); 704 } 705 706 @Override 707 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 708 return sb.append(format("length(%d)", getLength(data, pos))); 709 } 710 } 711 712 static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); 713 static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = config.multiBranchDataPerCaseCellCount; 714 static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); 715 static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); 716 static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); 717 718 static class MultiBranchData extends ArrayData { 719 720 MultiBranchData(HotSpotVMConfig config, int tag) { 721 super(config, tag, MULTI_BRANCH_DATA_SIZE); 722 } 723 724 @Override 725 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 726 int arrayLength = getLength(data, position); 727 assert arrayLength > 0 : "switch must have at least the default case"; 728 assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 729 730 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 731 long totalCount = 0; 732 double[] result = new double[length]; 733 734 // default case is first in HotSpot but last for the compiler 735 long count = readCount(data, position, 0); 736 totalCount += count; 737 result[length - 1] = count; 738 739 for (int i = 1; i < length; i++) { 740 count = readCount(data, position, i); 741 totalCount += count; 742 result[i - 1] = count; 743 } 744 745 if (totalCount <= 0) { 746 return null; 747 } else { 748 for (int i = 0; i < length; i++) { 749 result[i] = result[i] / totalCount; 750 } 751 return result; 752 } 753 } 754 755 private static long readCount(HotSpotMethodData data, int position, int i) { 756 int offset; 757 long count; 758 offset = getCountOffset(i); 759 count = data.readUnsignedInt(position, offset); 760 return count; 761 } 762 763 @Override 764 public int getExecutionCount(HotSpotMethodData data, int position) { 765 int arrayLength = getLength(data, position); 766 assert arrayLength > 0 : "switch must have at least the default case"; 767 assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 768 769 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 770 long totalCount = 0; 771 for (int i = 0; i < length; i++) { 772 int offset = getCountOffset(i); 773 totalCount += data.readUnsignedInt(position, offset); 774 } 775 776 return truncateLongToInt(totalCount); 777 } 778 779 private static int getCountOffset(int index) { 780 return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 781 } 782 783 private static int getDisplacementOffset(int index) { 784 return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 785 } 786 787 @Override 788 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 789 int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 790 sb.append(format("entries(%d)", entries)); 791 for (int i = 0; i < entries; i++) { 792 sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); 793 } 794 return sb; 795 } 796 } 797 798 static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); 799 800 static class ArgInfoData extends ArrayData { 801 802 ArgInfoData(HotSpotVMConfig config, int tag) { 803 super(config, tag, ARG_INFO_DATA_SIZE); 804 } 805 } 806 807 static class UnknownProfileData extends HotSpotMethodDataAccessor { 808 UnknownProfileData(HotSpotVMConfig config, int tag) { 809 super(config, tag, 0); 810 } 811 812 @Override 813 protected int getDynamicSize(HotSpotMethodData data, int position) { 814 assert staticSize == 0; 815 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position); 816 } 817 818 @Override 819 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 820 sb.append("unknown profile data with tag: " + tag); 821 return sb; 822 } 823 } 824 825 public void setCompiledIRSize(int size) { 826 UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); 827 } 828 829 public int getCompiledIRSize() { 830 return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); 831 } 832 833 // sorted by tag 834 // @formatter:off 835 static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { 836 null, 837 new BitData(config, config.dataLayoutBitDataTag), 838 new CounterData(config, config.dataLayoutCounterDataTag), 839 new JumpData(config, config.dataLayoutJumpDataTag), 840 new ReceiverTypeData(config, config.dataLayoutReceiverTypeDataTag), 841 new VirtualCallData(config, config.dataLayoutVirtualCallDataTag), 842 new RetData(config, config.dataLayoutRetDataTag), 843 new BranchData(config, config.dataLayoutBranchDataTag), 844 new MultiBranchData(config, config.dataLayoutMultiBranchDataTag), 845 new ArgInfoData(config, config.dataLayoutArgInfoDataTag), 846 new UnknownProfileData(config, config.dataLayoutCallTypeDataTag), 847 new VirtualCallTypeData(config, config.dataLayoutVirtualCallTypeDataTag), 848 new UnknownProfileData(config, config.dataLayoutParametersTypeDataTag), 849 new UnknownProfileData(config, config.dataLayoutSpeculativeTrapDataTag), 850 }; 851 852 private static boolean checkAccessorTags() { 853 int expectedTag = 0; 854 for (HotSpotMethodDataAccessor accessor : PROFILE_DATA_ACCESSORS) { 855 if (expectedTag == 0) { 856 assert accessor == null; 857 } else { 858 assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor; 859 } 860 expectedTag++; 861 } 862 return true; 863 } 864 865 static { 866 assert checkAccessorTags(); 867 } 868 // @formatter:on 869 }