# HG changeset patch # User Christian Haeubl # Date 1364401559 -3600 # Node ID 6c4db417385afa70686ead0477fd72d9b5bcbd7c # Parent 5407d1dd64505ee50ebd7fab7253aeebdb81f31b added API to reset the profiling information for a method added some test cases that check the recorded profiling information diff -r 5407d1dd6450 -r 6c4db417385a graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Wed Mar 27 10:36:57 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Wed Mar 27 17:25:59 2013 +0100 @@ -125,6 +125,11 @@ ProfilingInfo getProfilingInfo(); /** + * Invalidates the profiling information and restarts profiling upon the next invocation. + */ + void reprofile(); + + /** * Returns a map that the compiler can use to store objects that should survive the current * compilation. */ diff -r 5407d1dd6450 -r 6c4db417385a graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Wed Mar 27 17:25:59 2013 +0100 @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import static org.junit.Assert.*; + +import java.io.*; +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; + +public class ProfilingInfoTest extends GraalCompilerTest { + + private static final int N = 100; + + @Test + public void testBranchTakenProbability() { + ProfilingInfo info = profile("branchProbabilitySnippet", 0); + assertEquals(0.0, info.getBranchTakenProbability(1)); + assertEquals(100, info.getExecutionCount(1)); + assertEquals(-1.0, info.getBranchTakenProbability(8)); + assertEquals(0, info.getExecutionCount(8)); + + info = profile("branchProbabilitySnippet", 1); + assertEquals(1.0, info.getBranchTakenProbability(1)); + assertEquals(100, info.getExecutionCount(1)); + assertEquals(0.0, info.getBranchTakenProbability(8)); + assertEquals(100, info.getExecutionCount(8)); + + info = profile("branchProbabilitySnippet", 2); + assertEquals(1.0, info.getBranchTakenProbability(1)); + assertEquals(100, info.getExecutionCount(1)); + assertEquals(1.0, info.getBranchTakenProbability(8)); + assertEquals(100, info.getExecutionCount(8)); + } + + public static int branchProbabilitySnippet(int value) { + if (value == 0) { + return -1; + } else if (value == 1) { + return -2; + } else { + return -3; + } + } + + @Test + public void testSwitchProbabilities() { + ProfilingInfo info = profile("switchProbabilitySnippet", 0); + assertEquals(new double[]{1.0, 0.0, 0.0}, info.getSwitchProbabilities(1)); + + info = profile("switchProbabilitySnippet", 1); + assertEquals(new double[]{0.0, 1.0, 0.0}, info.getSwitchProbabilities(1)); + + info = profile("switchProbabilitySnippet", 2); + assertEquals(new double[]{0.0, 0.0, 1.0}, info.getSwitchProbabilities(1)); + } + + public static int switchProbabilitySnippet(int value) { + switch (value) { + case 0: + return -1; + case 1: + return -2; + default: + return -3; + } + } + + @Test + public void testTypeProfileInvokeVirtual() { + testTypeProfile("invokeVirtualSnippet", 1); + } + + public static int invokeVirtualSnippet(Object obj) { + return obj.hashCode(); + } + + @Test + public void testTypeProfileInvokeInterface() { + testTypeProfile("invokeInterfaceSnippet", 1); + } + + public static int invokeInterfaceSnippet(CharSequence a) { + return a.length(); + } + + @Test + public void testTypeProfileCheckCast() { + testTypeProfile("checkCastSnippet", 1); + } + + public static Serializable checkCastSnippet(Object obj) { + return (Serializable) obj; + } + + @Test + public void testTypeProfileInstanceOf() { + testTypeProfile("instanceOfSnippet", 1); + } + + public static boolean instanceOfSnippet(Object obj) { + return obj instanceof Serializable; + } + + private void testTypeProfile(String methodName, int bci) { + ResolvedJavaType stringType = runtime.lookupJavaType(String.class); + ResolvedJavaType stringBuilderType = runtime.lookupJavaType(StringBuilder.class); + + ProfilingInfo info = profile(methodName, "ABC"); + JavaTypeProfile typeProfile = info.getTypeProfile(bci); + assertEquals(0.0, typeProfile.getNotRecordedProbability()); + assertEquals(1, typeProfile.getTypes().length); + assertEquals(stringType, typeProfile.getTypes()[0].getType()); + assertEquals(1.0, typeProfile.getTypes()[0].getProbability()); + + continueProfiling(methodName, new StringBuilder()); + typeProfile = info.getTypeProfile(bci); + assertEquals(0.0, typeProfile.getNotRecordedProbability()); + assertEquals(2, typeProfile.getTypes().length); + assertEquals(stringType, typeProfile.getTypes()[0].getType()); + assertEquals(stringBuilderType, typeProfile.getTypes()[1].getType()); + assertEquals(0.5, typeProfile.getTypes()[0].getProbability()); + assertEquals(0.5, typeProfile.getTypes()[1].getProbability()); + } + + @Test + public void testExceptionSeen() { + ProfilingInfo info = profile("nullPointerExceptionSnippet", (Object) null); + assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + info = profile("nullPointerExceptionSnippet", 5); + assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[0]); + assertEquals(TriState.TRUE, info.getExceptionSeen(2)); + + info = profile("arrayIndexOutOfBoundsExceptionSnippet", new int[1]); + assertEquals(TriState.FALSE, info.getExceptionSeen(2)); + + info = profile("checkCastExceptionSnippet", 5); + assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + info = profile("checkCastExceptionSnippet", "ABC"); + assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + + info = profile("invokeWithExceptionSnippet", true); + assertEquals(TriState.TRUE, info.getExceptionSeen(1)); + + info = profile("invokeWithExceptionSnippet", false); + assertEquals(TriState.FALSE, info.getExceptionSeen(1)); + } + + public static int nullPointerExceptionSnippet(Object obj) { + try { + return obj.hashCode(); + } catch (NullPointerException e) { + return 1; + } + } + + public static int arrayIndexOutOfBoundsExceptionSnippet(int[] array) { + try { + return array[0]; + } catch (ArrayIndexOutOfBoundsException e) { + return 1; + } + } + + public static int checkCastExceptionSnippet(Object obj) { + try { + return ((String) obj).length(); + } catch (ClassCastException e) { + return 1; + } + } + + public static int invokeWithExceptionSnippet(boolean doThrow) { + try { + return throwException(doThrow); + } catch (IllegalArgumentException e) { + return 1; + } + } + + private static int throwException(boolean doThrow) { + if (doThrow) { + throw new IllegalArgumentException(); + } else { + return 1; + } + } + + @Test + public void testNullSeen() { + ProfilingInfo info = profile("instanceOfSnippet", 1); + assertEquals(TriState.FALSE, info.getNullSeen(1)); + + continueProfiling("instanceOfSnippet", "ABC"); + assertEquals(TriState.FALSE, info.getNullSeen(1)); + + continueProfiling("instanceOfSnippet", (Object) null); + assertEquals(TriState.TRUE, info.getNullSeen(1)); + + continueProfiling("instanceOfSnippet", 0.0); + assertEquals(TriState.TRUE, info.getNullSeen(1)); + + info = profile("instanceOfSnippet", (Object) null); + assertEquals(TriState.TRUE, info.getNullSeen(1)); + } + + @Test + public void testDeoptimizationCount() { + // TODO (chaeubl): implement + } + + private ProfilingInfo profile(String methodName, Object... args) { + return profile(true, methodName, args); + } + + private void continueProfiling(String methodName, Object... args) { + profile(false, methodName, args); + } + + private ProfilingInfo profile(boolean resetProfile, String methodName, Object... args) { + Method method = getMethod(methodName); + Assert.assertTrue(Modifier.isStatic(method.getModifiers())); + + ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + if (resetProfile) { + javaMethod.reprofile(); + } + + for (int i = 0; i < N; ++i) { + try { + method.invoke(null, args); + } catch (Throwable e) { + fail("method should not throw an exception: " + e.toString()); + } + } + + return javaMethod.getProfilingInfo(); + } +} diff -r 5407d1dd6450 -r 6c4db417385a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Mar 27 10:36:57 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Mar 27 17:25:59 2013 +0100 @@ -212,4 +212,11 @@ Local[] getLocalVariableTable(HotSpotResolvedJavaMethod method); String getFileName(HotSpotResolvedJavaType method); + + /** + * Invalidates the profiling information and restarts profiling upon the next invocation. + * + * @param metaspaceMethod the metaspace Method object + */ + void reprofile(long metaspaceMethod); } diff -r 5407d1dd6450 -r 6c4db417385a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Mar 27 10:36:57 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Mar 27 17:25:59 2013 +0100 @@ -152,4 +152,7 @@ @Override public native String getFileName(HotSpotResolvedJavaType method); + + @Override + public native void reprofile(long metaspaceMethod); } diff -r 5407d1dd6450 -r 6c4db417385a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Mar 27 10:36:57 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Mar 27 17:25:59 2013 +0100 @@ -231,6 +231,11 @@ } @Override + public void reprofile() { + HotSpotGraalRuntime.getInstance().getCompilerToVM().reprofile(metaspaceMethod); + } + + @Override public Map getCompilerStorage() { if (compilerStorage == null) { compilerStorage = new ConcurrentHashMap<>(); diff -r 5407d1dd6450 -r 6c4db417385a src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 27 10:36:57 2013 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 27 17:25:59 2013 +0100 @@ -1007,6 +1007,28 @@ C2V_END + +C2V_VMENTRY(void, reprofile, (JNIEnv *env, jobject, jlong metaspace_method)) + Method* method = asMethod(metaspace_method); + method->reset_counters(); + + nmethod* code = method->code(); + if (code != NULL) { + code->make_not_entrant(); + } + + MethodData* method_data = method->method_data(); + if (method_data == NULL) { + ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); + method_data = MethodData::allocate(loader_data, method, CHECK); + method->set_method_data(method_data); + } else { + method_data->initialize(); + } +C2V_END + + + #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -1080,6 +1102,7 @@ {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, {CC"getLocalVariableTable", CC"("HS_RESOLVED_METHOD")["LOCAL, FN_PTR(getLocalVariableTable)}, {CC"getFileName", CC"("HS_RESOLVED_JAVA_TYPE")"STRING, FN_PTR(getFileName)}, + {CC"reprofile", CC"("METASPACE_METHOD")V", FN_PTR(reprofile)}, }; int CompilerToVM_methods_count() { diff -r 5407d1dd6450 -r 6c4db417385a src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Wed Mar 27 10:36:57 2013 +0100 +++ b/src/share/vm/oops/method.cpp Wed Mar 27 17:25:59 2013 +0100 @@ -1940,3 +1940,15 @@ guarantee(md == NULL || md->is_methodData(), "should be method data"); } + +#ifdef GRAAL +void Method::reset_counters() { + invocation_counter()->reset(); + backedge_counter()->reset(); + _interpreter_invocation_count = 0; + _interpreter_throwout_count = 0; +#ifndef PRODUCT + _compiled_invocation_count = 0; +#endif +} +#endif diff -r 5407d1dd6450 -r 6c4db417385a src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Wed Mar 27 10:36:57 2013 +0100 +++ b/src/share/vm/oops/method.hpp Wed Mar 27 17:25:59 2013 +0100 @@ -370,6 +370,8 @@ void set_graal_priority(int prio) { _graal_priority = prio; } int graal_priority() { return _graal_priority; } + + void reset_counters(); #endif // GRAAL bool was_executed_more_than(int n); @@ -386,7 +388,7 @@ if (TieredCompilation) ShouldNotReachHere(); return ++_interpreter_invocation_count; } - + #ifndef PRODUCT int compiled_invocation_count() const { return _compiled_invocation_count; } void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; } diff -r 5407d1dd6450 -r 6c4db417385a src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Wed Mar 27 10:36:57 2013 +0100 +++ b/src/share/vm/oops/methodData.cpp Wed Mar 27 17:25:59 2013 +0100 @@ -659,10 +659,14 @@ // Initialize the MethodData* corresponding to a given method. MethodData::MethodData(methodHandle method, int size, TRAPS) { + // Set the method back-pointer. + _method = method(); + initialize(); +} + +void MethodData::initialize() { No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; - // Set the method back-pointer. - _method = method(); if (TieredCompilation) { _invocation_counter.init(); @@ -689,7 +693,7 @@ // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data - BytecodeStream stream(method); + BytecodeStream stream(method()); Bytecodes::Code c; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); @@ -705,6 +709,8 @@ int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0); object_size += extra_size; + Copy::zero_to_bytes((HeapWord*) extra_data_base(), extra_size); + #ifndef GRAALVM // Add a cell to record information about modified arguments. // Set up _args_modified array after traps cells so that diff -r 5407d1dd6450 -r 6c4db417385a src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Wed Mar 27 10:36:57 2013 +0100 +++ b/src/share/vm/oops/methodData.hpp Wed Mar 27 17:25:59 2013 +0100 @@ -1178,6 +1178,7 @@ MethodData() {}; // For ciMethodData bool is_methodData() const volatile { return true; } + void initialize(); // Whole-method sticky bits and flags enum { @@ -1295,10 +1296,7 @@ static bool bytecode_has_profile(Bytecodes::Code code) { return bytecode_cell_count(code) != no_profile_data; } - - // Perform initialization of a new MethodData* - void initialize(methodHandle method); - + // My size int size_in_bytes() const { return _size; } int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); }