diff options
author | Neil Fuller <nfuller@google.com> | 2014-09-29 17:56:01 +0100 |
---|---|---|
committer | Neil Fuller <nfuller@google.com> | 2014-10-15 11:47:58 +0100 |
commit | 32b88b48daa7383880088246d7222dd93cf55285 (patch) | |
tree | d1c65c20baca6fe7194028fa1647be3167389918 | |
parent | d7baaed89e498ad3cf7d9c487d6cae967e562ea4 (diff) | |
download | base-32b88b48daa7383880088246d7222dd93cf55285.tar.gz |
Replacing FloatMath native implementation with calls to Math
On modern versions of Android running in AOT mode
FloatMath is slower than Math. Calls to Math.sqrt(),
etc. are replaced by intrinsics which can be as small
as a single CPU opcode.
When running in interpreted mode the new
implementation is unfortunately slower, but I'm
judging this acceptable and likely to be improved
over time. This change saves a small amount of native
code.
Example timings:
Mako AOSP AOT:
Method: Original / New / Direct call to Math
ceil: 596ns / 146.ns / 111ns
sqrt: 694ns / 56ns / 25ns
Mako AOSP interpreted:
Method: Original / New / Direct call to Math
ceil: 1900ns / 2307ns / 1485ns
sqrt: 1998ns / 2603ns / 1788ns
Other calls Mako AOT:
Method: Original / New
cos: 635ns / 270ns
exp: 566ns / 324ns
floor: 604ns / 150ns
hypot: 631ns / 232ns
pow: 936ns / 643ns
sin: 641ns / 299ns
The advice to use Math directly, in preference to
FloatMath, is still good. FloatMath will be deprecated
separately.
Bug: https://code.google.com/p/android/issues/detail?id=36199
Change-Id: I8d1947d88b3c576643138b1df589fb9da7c1ab88
-rw-r--r-- | core/java/android/util/FloatMath.java | 11 | ||||
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 3 | ||||
-rw-r--r-- | core/jni/android_util_FloatMath.cpp | 61 | ||||
-rw-r--r-- | core/tests/benchmarks/src/android/util/FloatMathBenchmark.java | 103 |
5 files changed, 110 insertions, 69 deletions
diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java index 0ffd5bd61098..d33ca0d9e26c 100644 --- a/core/java/android/util/FloatMath.java +++ b/core/java/android/util/FloatMath.java @@ -17,10 +17,13 @@ package android.util; /** - * Math routines similar to those found in {@link java.lang.Math}. On - * versions of Android with a JIT, these are significantly slower than - * the equivalent {@code Math} functions, which should be used in preference - * to these. + * Math routines similar to those found in {@link java.lang.Math}. + * + * <p>Historically these methods were faster than the equivalent double-based + * {@link java.lang.Math} methods. On versions of Android with a JIT they + * became slower and have since been re-implemented to wrap calls to + * {@link java.lang.Math}. {@link java.lang.Math} should be used in + * preference. */ public class FloatMath { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 5d10f3c6404c..9b3b09111a44 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -80,7 +80,6 @@ LOCAL_SRC_FILES:= \ android_util_Binder.cpp \ android_util_EventLog.cpp \ android_util_Log.cpp \ - android_util_FloatMath.cpp \ android_util_Process.cpp \ android_util_StringBlock.cpp \ android_util_XmlBlock.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 0d2cdb9ab171..796a0c3039f9 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -90,8 +90,6 @@ extern int register_android_media_AudioTrack(JNIEnv *env); extern int register_android_media_JetPlayer(JNIEnv *env); extern int register_android_media_ToneGenerator(JNIEnv *env); -extern int register_android_util_FloatMath(JNIEnv* env); - namespace android { /* @@ -1229,7 +1227,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), - REG_JNI(register_android_util_FloatMath), REG_JNI(register_android_content_AssetManager), REG_JNI(register_android_content_StringBlock), REG_JNI(register_android_content_XmlBlock), diff --git a/core/jni/android_util_FloatMath.cpp b/core/jni/android_util_FloatMath.cpp deleted file mode 100644 index 73b7a6fc310c..000000000000 --- a/core/jni/android_util_FloatMath.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "jni.h" -#include <android_runtime/AndroidRuntime.h> -#include <math.h> -#include <float.h> -#include "SkTypes.h" - -class MathUtilsGlue { -public: - static float FloorF(JNIEnv* env, jobject clazz, float x) { - return floorf(x); - } - - static float CeilF(JNIEnv* env, jobject clazz, float x) { - return ceilf(x); - } - - static float SinF(JNIEnv* env, jobject clazz, float x) { - return sinf(x); - } - - static float CosF(JNIEnv* env, jobject clazz, float x) { - return cosf(x); - } - - static float SqrtF(JNIEnv* env, jobject clazz, float x) { - return sqrtf(x); - } - - static float ExpF(JNIEnv* env, jobject clazz, float x) { - return expf(x); - } - - static float PowF(JNIEnv* env, jobject clazz, float x, float y) { - return powf(x, y); - } - - static float HypotF(JNIEnv* env, jobject clazz, float x, float y) { - return hypotf(x, y); - } -}; - -static JNINativeMethod gMathUtilsMethods[] = { - {"floor", "(F)F", (void*) MathUtilsGlue::FloorF}, - {"ceil", "(F)F", (void*) MathUtilsGlue::CeilF}, - {"sin", "(F)F", (void*) MathUtilsGlue::SinF}, - {"cos", "(F)F", (void*) MathUtilsGlue::CosF}, - {"sqrt", "(F)F", (void*) MathUtilsGlue::SqrtF}, - {"exp", "(F)F", (void*) MathUtilsGlue::ExpF}, - {"pow", "(FF)F", (void*) MathUtilsGlue::PowF}, - {"hypot", "(FF)F", (void*) MathUtilsGlue::HypotF}, -}; - -int register_android_util_FloatMath(JNIEnv* env) -{ - int result = android::AndroidRuntime::registerNativeMethods(env, - "android/util/FloatMath", - gMathUtilsMethods, - SK_ARRAY_COUNT(gMathUtilsMethods)); - return result; -} - diff --git a/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java b/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java new file mode 100644 index 000000000000..4f3649245196 --- /dev/null +++ b/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java @@ -0,0 +1,103 @@ +package android.util; + +import com.google.caliper.Param; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; + +import android.util.FloatMath; + +import dalvik.system.VMDebug; + +public class FloatMathBenchmark extends SimpleBenchmark { + + public float timeFloatMathCeil(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.ceil(100.123f); + } + return f; + } + + public float timeFloatMathCeil_math(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += (float) Math.ceil(100.123f); + } + return f; + } + + public float timeFloatMathCos(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.cos(100.123f); + } + return f; + } + + public float timeFloatMathExp(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.exp(100.123f); + } + return f; + } + + public float timeFloatMathFloor(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.floor(100.123f); + } + return f; + } + + public float timeFloatMathHypot(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.hypot(100.123f, 100.123f); + } + return f; + } + + public float timeFloatMathPow(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.pow(10.123f, 10.123f); + } + return f; + } + + public float timeFloatMathSin(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.sin(100.123f); + } + return f; + } + + public float timeFloatMathSqrt(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += FloatMath.sqrt(100.123f); + } + return f; + } + + public float timeFloatMathSqrt_math(int reps) { + // Keep an answer so we don't optimize the method call away. + float f = 0.0f; + for (int i = 0; i < reps; i++) { + f += (float) Math.sqrt(100.123f); + } + return f; + } + +} |