changeset 8611:6c4db417385a

added API to reset the profiling information for a method added some test cases that check the recorded profiling information
author Christian Haeubl <haeubl@ssw.jku.at>
date Wed, 27 Mar 2013 17:25:59 +0100
parents 5407d1dd6450
children 02ef91b94656
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/oops/method.cpp src/share/vm/oops/method.hpp src/share/vm/oops/methodData.cpp src/share/vm/oops/methodData.hpp
diffstat 10 files changed, 336 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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.
      */
--- /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();
+    }
+}
--- 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);
 }
--- 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);
 }
--- 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<Object, Object> getCompilerStorage() {
         if (compilerStorage == null) {
             compilerStorage = new ConcurrentHashMap<>();
--- 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() {
--- 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
--- 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; }
--- 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
--- 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); }