Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2192b22c authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sep11"

* changes:
  Remove advisory registerNativeAllocation().
  Hand-rolled linked list for Parcel performance.
parents e2a264d0 c2080995
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package android.os;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class ParcelObtainPerfTest {
    private static final int ITERATIONS = 1_000_000;

    @Test
    public void timeContention_01() throws Exception {
        timeContention(1);
    }

    @Test
    public void timeContention_04() throws Exception {
        timeContention(4);
    }

    @Test
    public void timeContention_16() throws Exception {
        timeContention(16);
    }

    private static void timeContention(int numThreads) throws Exception {
        final long start = SystemClock.elapsedRealtime();
        {
            final ObtainThread[] threads = new ObtainThread[numThreads];
            for (int i = 0; i < numThreads; i++) {
                final ObtainThread thread = new ObtainThread(ITERATIONS / numThreads);
                thread.start();
                threads[i] = thread;
            }
            for (int i = 0; i < numThreads; i++) {
                threads[i].join();
            }
        }
        final long duration = SystemClock.elapsedRealtime() - start;

        final Bundle results = new Bundle();
        results.putLong("duration", duration);
        InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
    }

    public static class ObtainThread extends Thread {
        public int iterations;

        public ObtainThread(int iterations) {
            this.iterations = iterations;
        }

        @Override
        public void run() {
            while (iterations-- > 0) {
                final Parcel data = Parcel.obtain();
                final Parcel reply = Parcel.obtain();
                try {
                    data.writeInt(32);
                    reply.writeInt(32);
                } finally {
                    reply.recycle();
                    data.recycle();
                }
            }
        }
    }
}
+0 −15
Original line number Diff line number Diff line
@@ -158,21 +158,6 @@ public class ParcelPerfTest {
        }
    }

    @Test
    public void timeObtainRecycle() {
        // Use up the pooled instances.
        // A lot bigger than the actual size but in case someone increased it.
        final int POOL_SIZE = 100;
        for (int i = 0; i < POOL_SIZE; i++) {
            Parcel.obtain();
        }

        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            Parcel.obtain().recycle();
        }
    }

    @Test
    public void timeWriteException() {
        timeWriteException(false);
+87 −70
Original line number Diff line number Diff line
@@ -33,9 +33,10 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;

import com.android.internal.annotations.GuardedBy;

import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.VMRuntime;

import libcore.util.ArrayUtils;
import libcore.util.SneakyThrow;
@@ -222,9 +223,31 @@ public final class Parcel {
     */
    private static boolean sParcelExceptionStackTrace;

    private static final int POOL_SIZE = 6;
    private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
    private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
    private static final Object sPoolSync = new Object();

    /** Next item in the linked list pool, if any */
    @GuardedBy("sPoolSync")
    private Parcel mPoolNext;

    /** Head of a linked list pool of {@link Parcel} objects */
    @GuardedBy("sPoolSync")
    private static Parcel sOwnedPool;
    /** Head of a linked list pool of {@link Parcel} objects */
    @GuardedBy("sPoolSync")
    private static Parcel sHolderPool;

    /** Total size of pool with head at {@link #sOwnedPool} */
    @GuardedBy("sPoolSync")
    private static int sOwnedPoolSize = 0;
    /** Total size of pool with head at {@link #sHolderPool} */
    @GuardedBy("sPoolSync")
    private static int sHolderPoolSize = 0;

    /**
     * We're willing to pool up to 32 objects, which is sized to accommodate
     * both a data and reply Parcel for the maximum of 16 Binder threads.
     */
    private static final int POOL_SIZE = 32;

    // Keep in sync with frameworks/native/include/private/binder/ParcelValTypes.h.
    private static final int VAL_NULL = -1;
@@ -285,7 +308,7 @@ public final class Parcel {
    @CriticalNative
    private static native int nativeDataCapacity(long nativePtr);
    @FastNative
    private static native long nativeSetDataSize(long nativePtr, int size);
    private static native void nativeSetDataSize(long nativePtr, int size);
    @CriticalNative
    private static native void nativeSetDataPosition(long nativePtr, int pos);
    @FastNative
@@ -314,7 +337,7 @@ public final class Parcel {
    @FastNative
    private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
    @FastNative
    private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
    private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);

    private static native byte[] nativeCreateByteArray(long nativePtr);
    private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
@@ -337,14 +360,14 @@ public final class Parcel {
    private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);

    private static native long nativeCreate();
    private static native long nativeFreeBuffer(long nativePtr);
    private static native void nativeFreeBuffer(long nativePtr);
    private static native void nativeDestroy(long nativePtr);

    private static native byte[] nativeMarshall(long nativePtr);
    private static native long nativeUnmarshall(
    private static native void nativeUnmarshall(
            long nativePtr, byte[] data, int offset, int length);
    private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
    private static native long nativeAppendFrom(
    private static native void nativeAppendFrom(
            long thisNativePtr, long otherNativePtr, int offset, int length);
    @CriticalNative
    private static native boolean nativeHasFileDescriptors(long nativePtr);
@@ -420,22 +443,27 @@ public final class Parcel {
     */
    @NonNull
    public static Parcel obtain() {
        final Parcel[] pool = sOwnedPool;
        synchronized (pool) {
            Parcel p;
            for (int i=0; i<POOL_SIZE; i++) {
                p = pool[i];
                if (p != null) {
                    pool[i] = null;
                    if (DEBUG_RECYCLE) {
                        p.mStack = new RuntimeException();
        Parcel res = null;
        synchronized (sPoolSync) {
            if (sOwnedPool != null) {
                res = sOwnedPool;
                sOwnedPool = res.mPoolNext;
                res.mPoolNext = null;
                sOwnedPoolSize--;
            }
                    p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                    return p;
        }

        // When no cache found above, create from scratch; otherwise prepare the
        // cached object to be used
        if (res == null) {
            res = new Parcel(0);
        } else {
            if (DEBUG_RECYCLE) {
                res.mStack = new RuntimeException();
            }
            res.mReadWriteHelper = ReadWriteHelper.DEFAULT;
        }
        return new Parcel(0);
        return res;
    }

    /**
@@ -446,19 +474,21 @@ public final class Parcel {
        if (DEBUG_RECYCLE) mStack = null;
        freeBuffer();

        final Parcel[] pool;
        if (mOwnsNativeParcelObject) {
            pool = sOwnedPool;
            synchronized (sPoolSync) {
                if (sOwnedPoolSize < POOL_SIZE) {
                    mPoolNext = sOwnedPool;
                    sOwnedPool = this;
                    sOwnedPoolSize++;
                }
            }
        } else {
            mNativePtr = 0;
            pool = sHolderPool;
        }

        synchronized (pool) {
            for (int i=0; i<POOL_SIZE; i++) {
                if (pool[i] == null) {
                    pool[i] = this;
                    return;
            synchronized (sPoolSync) {
                if (sHolderPoolSize < POOL_SIZE) {
                    mPoolNext = sHolderPool;
                    sHolderPool = this;
                    sHolderPoolSize++;
                }
            }
        }
@@ -532,7 +562,7 @@ public final class Parcel {
     * @param size The new number of bytes in the Parcel.
     */
    public final void setDataSize(int size) {
        updateNativeSize(nativeSetDataSize(mNativePtr, size));
        nativeSetDataSize(mNativePtr, size);
    }

    /**
@@ -584,11 +614,11 @@ public final class Parcel {
     * Set the bytes in data to be the raw bytes of this Parcel.
     */
    public final void unmarshall(@NonNull byte[] data, int offset, int length) {
        updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
        nativeUnmarshall(mNativePtr, data, offset, length);
    }

    public final void appendFrom(Parcel parcel, int offset, int length) {
        updateNativeSize(nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length));
        nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
    }

    /** @hide */
@@ -871,24 +901,7 @@ public final class Parcel {
     * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
     */
    public final void writeFileDescriptor(@NonNull FileDescriptor val) {
        updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
    }

    private void updateNativeSize(long newNativeSize) {
        if (mOwnsNativeParcelObject) {
            if (newNativeSize > Integer.MAX_VALUE) {
                newNativeSize = Integer.MAX_VALUE;
            }
            if (newNativeSize != mNativeSize) {
                int delta = (int) (newNativeSize - mNativeSize);
                if (delta > 0) {
                    VMRuntime.getRuntime().registerNativeAllocation(delta);
                } else {
                    VMRuntime.getRuntime().registerNativeFree(-delta);
                }
                mNativeSize = newNativeSize;
            }
        }
        nativeWriteFileDescriptor(mNativePtr, val);
    }

    /**
@@ -3496,22 +3509,27 @@ public final class Parcel {

    /** @hide */
    static protected final Parcel obtain(long obj) {
        final Parcel[] pool = sHolderPool;
        synchronized (pool) {
            Parcel p;
            for (int i=0; i<POOL_SIZE; i++) {
                p = pool[i];
                if (p != null) {
                    pool[i] = null;
                    if (DEBUG_RECYCLE) {
                        p.mStack = new RuntimeException();
        Parcel res = null;
        synchronized (sPoolSync) {
            if (sHolderPool != null) {
                res = sHolderPool;
                sHolderPool = res.mPoolNext;
                res.mPoolNext = null;
                sHolderPoolSize--;
            }
                    p.init(obj);
                    return p;
        }

        // When no cache found above, create from scratch; otherwise prepare the
        // cached object to be used
        if (res == null) {
            res = new Parcel(obj);
        } else {
            if (DEBUG_RECYCLE) {
                res.mStack = new RuntimeException();
            }
            res.init(obj);
        }
        return new Parcel(obj);
        return res;
    }

    private Parcel(long nativePtr) {
@@ -3535,7 +3553,7 @@ public final class Parcel {
    private void freeBuffer() {
        resetSqaushingState();
        if (mOwnsNativeParcelObject) {
            updateNativeSize(nativeFreeBuffer(mNativePtr));
            nativeFreeBuffer(mNativePtr);
        }
        mReadWriteHelper = ReadWriteHelper.DEFAULT;
    }
@@ -3545,7 +3563,6 @@ public final class Parcel {
        if (mNativePtr != 0) {
            if (mOwnsNativeParcelObject) {
                nativeDestroy(mNativePtr);
                updateNativeSize(0);
            }
            mNativePtr = 0;
        }
+14 −21
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ static jint android_os_Parcel_dataCapacity(jlong nativePtr)
    return parcel ? parcel->dataCapacity() : 0;
}

static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
@@ -122,9 +122,7 @@ static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nati
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
        return parcel->getOpenAshmemSize();
    }
    return 0;
}

static void android_os_Parcel_setDataPosition(jlong nativePtr, jint pos)
@@ -308,7 +306,7 @@ static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong
    }
}

static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
@@ -317,9 +315,7 @@ static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jl
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
        return parcel->getOpenAshmemSize();
    }
    return 0;
}

static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -506,14 +502,12 @@ static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
    return reinterpret_cast<jlong>(parcel);
}

static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        parcel->freeData();
        return parcel->getOpenAshmemSize();
    }
    return 0;
}

static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -551,12 +545,12 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
    return ret;
}

static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
                                          jbyteArray data, jint offset, jint length)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel == NULL || length < 0) {
       return 0;
       return;
    }

    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
@@ -570,7 +564,6 @@ static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativ

        env->ReleasePrimitiveArrayCritical(data, array, 0);
    }
    return parcel->getOpenAshmemSize();
}

static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisNativePtr,
@@ -588,23 +581,23 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN
    return thisParcel->compareData(*otherParcel);
}

static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
                                          jlong otherNativePtr, jint offset, jint length)
{
    Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
    if (thisParcel == NULL) {
       return 0;
       return;
    }
    Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
    if (otherParcel == NULL) {
       return thisParcel->getOpenAshmemSize();
       return;
    }

    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
    if (err != NO_ERROR) {
        signalExceptionForError(env, clazz, err);
    }
    return thisParcel->getOpenAshmemSize();
    return;
}

static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
@@ -720,7 +713,7 @@ static const JNINativeMethod gParcelMethods[] = {
    // @CriticalNative
    {"nativeDataCapacity",        "(J)I", (void*)android_os_Parcel_dataCapacity},
    // @FastNative
    {"nativeSetDataSize",         "(JI)J", (void*)android_os_Parcel_setDataSize},
    {"nativeSetDataSize",         "(JI)V", (void*)android_os_Parcel_setDataSize},
    // @CriticalNative
    {"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},
    // @FastNative
@@ -749,7 +742,7 @@ static const JNINativeMethod gParcelMethods[] = {
    // @FastNative
    {"nativeWriteStrongBinder",   "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
    // @FastNative
    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},

    {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
    {"nativeReadByteArray",       "(J[BI)Z", (void*)android_os_Parcel_readByteArray},
@@ -772,13 +765,13 @@ static const JNINativeMethod gParcelMethods[] = {
    {"nativeReadFileDescriptor",  "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},

    {"nativeCreate",              "()J", (void*)android_os_Parcel_create},
    {"nativeFreeBuffer",          "(J)J", (void*)android_os_Parcel_freeBuffer},
    {"nativeFreeBuffer",          "(J)V", (void*)android_os_Parcel_freeBuffer},
    {"nativeDestroy",             "(J)V", (void*)android_os_Parcel_destroy},

    {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
    {"nativeUnmarshall",          "(J[BII)J", (void*)android_os_Parcel_unmarshall},
    {"nativeUnmarshall",          "(J[BII)V", (void*)android_os_Parcel_unmarshall},
    {"nativeCompareData",         "(JJ)I", (void*)android_os_Parcel_compareData},
    {"nativeAppendFrom",          "(JJII)J", (void*)android_os_Parcel_appendFrom},
    {"nativeAppendFrom",          "(JJII)V", (void*)android_os_Parcel_appendFrom},
    // @CriticalNative
    {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
    {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},