Mercurial > hg > truffle
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 } |