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