comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotMethodData.java @ 21551:5324104ac4f3

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