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