Merge "Remove unused pooled lambda methods"

This commit is contained in:
Riddle Hsu
2022-09-27 12:08:31 +00:00
committed by Android (Google) Code Review
2 changed files with 458 additions and 955 deletions

View File

@@ -22,36 +22,24 @@ import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire
import android.os.Message;
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
import com.android.internal.util.function.DodecConsumer;
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.NonaConsumer;
import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.OctConsumer;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadConsumer;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.QuadPredicate;
import com.android.internal.util.function.QuintConsumer;
import com.android.internal.util.function.QuintFunction;
import com.android.internal.util.function.QuintPredicate;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.TriPredicate;
import com.android.internal.util.function.UndecConsumer;
import com.android.internal.util.function.UndecFunction;
import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
@@ -193,40 +181,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1) }
*/
static <A> PooledSupplier<Boolean> obtainSupplier(
Predicate<? super A> function,
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1) }
*/
static <A, R> PooledSupplier<R> obtainSupplier(
Function<? super A, ? extends R> function,
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -278,42 +232,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2) }
*/
static <A, B> PooledSupplier<Boolean> obtainSupplier(
BiPredicate<? super A, ? super B> function,
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2) }
*/
static <A, B, R> PooledSupplier<R> obtainSupplier(
BiFunction<? super A, ? super B, ? extends R> function,
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -410,24 +328,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 placeholder for a missing argument. Use {@link #__} to get one
* @param arg2 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg1) -> function(arg1, arg2) }
*/
static <A, B, R> PooledFunction<A, R> obtainFunction(
BiFunction<? super A, ? super B, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -464,24 +364,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 placeholder for a missing argument. Use {@link #__} to get one
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg2) -> function(arg1, arg2) }
*/
static <A, B, R> PooledFunction<B, R> obtainFunction(
BiFunction<? super A, ? super B, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -535,25 +417,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3) }
*/
static <A, B, C, R> PooledSupplier<R> obtainSupplier(
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -573,25 +436,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 placeholder for a missing argument. Use {@link #__} to get one
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg1) -> function(arg1, arg2, arg3) }
*/
static <A, B, C, R> PooledFunction<A, R> obtainFunction(
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -611,25 +455,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 placeholder for a missing argument. Use {@link #__} to get one
* @param arg3 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg2) -> function(arg1, arg2, arg3) }
*/
static <A, B, C, R> PooledFunction<B, R> obtainFunction(
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -649,25 +474,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 placeholder for a missing argument. Use {@link #__} to get one
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg3) -> function(arg1, arg2, arg3) }
*/
static <A, B, C, R> PooledFunction<C, R> obtainFunction(
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -723,26 +529,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4) }
*/
static <A, B, C, D, R> PooledSupplier<R> obtainSupplier(
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -763,26 +549,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 placeholder for a missing argument. Use {@link #__} to get one
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg1) -> function(arg1, arg2, arg3, arg4) }
*/
static <A, B, C, D, R> PooledFunction<A, R> obtainFunction(
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -803,26 +569,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 placeholder for a missing argument. Use {@link #__} to get one
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg2) -> function(arg1, arg2, arg3, arg4) }
*/
static <A, B, C, D, R> PooledFunction<B, R> obtainFunction(
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -843,26 +589,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 placeholder for a missing argument. Use {@link #__} to get one
* @param arg4 parameter supplied to {@code function} on call
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg3) -> function(arg1, arg2, arg3, arg4) }
*/
static <A, B, C, D, R> PooledFunction<C, R> obtainFunction(
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
null, null, null, null);
}
/**
* {@link PooledConsumer} factory
*
@@ -883,26 +609,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledFunction} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 placeholder for a missing argument. Use {@link #__} to get one
* @return a {@link PooledFunction}, equivalent to lambda:
* {@code (arg4) -> function(arg1, arg2, arg3, arg4) }
*/
static <A, B, C, D, R> PooledFunction<D, R> obtainFunction(
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -960,27 +666,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5) }
*/
static <A, B, C, D, E, R> PooledSupplier<R> obtainSupplier(
QuintFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? extends R>
function, A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1041,28 +726,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6) }
*/
static <A, B, C, D, E, F, R> PooledSupplier<R> obtainSupplier(
HexFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1125,30 +788,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7) }
*/
static <A, B, C, D, E, F, G, R> PooledSupplier<R> obtainSupplier(
HeptFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1214,31 +853,6 @@ public interface PooledLambda {
null, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @param arg8 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) }
*/
static <A, B, C, D, E, F, G, H, R> PooledSupplier<R> obtainSupplier(
OctFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? super H, ? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
null, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1307,32 +921,6 @@ public interface PooledLambda {
arg9, null, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @param arg8 parameter supplied to {@code function} on call
* @param arg9 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) }
*/
static <A, B, C, D, E, F, G, H, I, R> PooledSupplier<R> obtainSupplier(
NonaFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? super H, ? super I, ? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
arg9, null, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1403,33 +991,6 @@ public interface PooledLambda {
arg9, arg10, null, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @param arg8 parameter supplied to {@code function} on call
* @param arg9 parameter supplied to {@code function} on call
* @param arg10 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) }
*/
static <A, B, C, D, E, F, G, H, I, J, R> PooledSupplier<R> obtainSupplier(
DecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? super H, ? super I, ? super J, ? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
arg9, arg10, null, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1503,36 +1064,6 @@ public interface PooledLambda {
arg9, arg10, arg11, null);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @param arg8 parameter supplied to {@code function} on call
* @param arg9 parameter supplied to {@code function} on call
* @param arg10 parameter supplied to {@code function} on call
* @param arg11 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
* arg11) }
*/
static <A, B, C, D, E, F, G, H, I, J, K, R> PooledSupplier<R> obtainSupplier(
UndecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? super H, ? super I, ? super J, ? super K, ? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
arg9, arg10, arg11, null);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
@@ -1610,38 +1141,6 @@ public interface PooledLambda {
arg9, arg10, arg11, arg12);
}
/**
* {@link PooledSupplier} factory
*
* @param function non-capturing lambda(typically an unbounded method reference)
* to be invoked on call
* @param arg1 parameter supplied to {@code function} on call
* @param arg2 parameter supplied to {@code function} on call
* @param arg3 parameter supplied to {@code function} on call
* @param arg4 parameter supplied to {@code function} on call
* @param arg5 parameter supplied to {@code function} on call
* @param arg6 parameter supplied to {@code function} on call
* @param arg7 parameter supplied to {@code function} on call
* @param arg8 parameter supplied to {@code function} on call
* @param arg9 parameter supplied to {@code function} on call
* @param arg10 parameter supplied to {@code function} on call
* @param arg11 parameter supplied to {@code function} on call
* @param arg12 parameter supplied to {@code function} on call
* @return a {@link PooledSupplier}, equivalent to lambda:
* {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
* arg11) }
*/
static <A, B, C, D, E, F, G, H, I, J, K, L, R> PooledSupplier<R> obtainSupplier(
DodecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? super G, ? super H, ? super I, ? super J, ? super K, ? extends L,
? extends R> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
K arg11, L arg12) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
arg9, arg10, arg11, arg12);
}
/**
* Factory of {@link Message}s that contain an
* ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its

View File

@@ -1,454 +1,458 @@
/*
* Copyright (C) 2020 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 com.android.internal;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.util.Log;
import androidx.test.filters.LargeTest;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Compares the performance of regular lambda and pooled lambda. */
@LargeTest
public class LambdaPerfTest {
private static final boolean DEBUG = false;
private static final String TAG = LambdaPerfTest.class.getSimpleName();
private static final String LAMBDA_FORM_REGULAR = "regular";
private static final String LAMBDA_FORM_POOLED = "pooled";
private static final int WARMUP_ITERATIONS = 1000;
private static final int TEST_ITERATIONS = 3000000;
private static final int TASK_COUNT = 10;
private static final long DELAY_AFTER_BENCH_MS = 1000;
private String mMethodName;
private final Bundle mTestResults = new Bundle();
private final ArrayList<Task> mTasks = new ArrayList<>();
// The member fields are used to ensure lambda capturing. They don't have the actual meaning.
private final Task mTask = new Task();
private final Rect mBounds = new Rect();
private int mTaskId;
private long mTime;
private boolean mTop;
@Rule
public final TestRule mRule = (base, description) -> new Statement() {
@Override
public void evaluate() throws Throwable {
mMethodName = description.getMethodName();
mTasks.clear();
for (int i = 0; i < TASK_COUNT; i++) {
final Task t = new Task();
mTasks.add(t);
}
base.evaluate();
getInstrumentation().sendStatus(Activity.RESULT_OK, mTestResults);
}
};
@Test
public void test1ParamConsumer() {
evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTask)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTask);
forAllTask(c);
c.recycle();
});
}
@Test
public void test2PrimitiveParamsConsumer() {
// Not in Integer#IntegerCache (-128~127) for autoboxing, that will create new object.
mTaskId = 12345;
mTime = 54321;
evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTaskId, mTime)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTaskId, mTime);
forAllTask(c);
c.recycle();
});
}
@Test
public void test3ParamsPredicate() {
mTop = true;
// In Integer#IntegerCache.
mTaskId = 10;
evaluate(LAMBDA_FORM_REGULAR, () -> handleTask(t -> t.doSomething(mBounds, mTop, mTaskId)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledPredicate c = PooledLambda.obtainPredicate(Task::doSomething,
PooledLambda.__(Task.class), mBounds, mTop, mTaskId);
handleTask(c);
c.recycle();
});
}
@Test
public void testMessage() {
evaluate(LAMBDA_FORM_REGULAR, () -> {
final Message m = Message.obtain().setCallback(() -> mTask.doSomething(mTaskId, mTime));
m.getCallback().run();
m.recycle();
});
evaluate(LAMBDA_FORM_POOLED, () -> {
final Message m = PooledLambda.obtainMessage(Task::doSomething, mTask, mTaskId, mTime);
m.getCallback().run();
m.recycle();
});
}
@Test
public void testRunnable() {
evaluate(LAMBDA_FORM_REGULAR, () -> {
final Runnable r = mTask::doSomething;
r.run();
});
evaluate(LAMBDA_FORM_POOLED, () -> {
final Runnable r = PooledLambda.obtainRunnable(Task::doSomething, mTask).recycleOnUse();
r.run();
});
}
@Test
public void testMultiThread() {
final int numThread = 3;
final Runnable regularAction = () -> forAllTask(t -> t.doSomething(mTask));
final Runnable[] regularActions = new Runnable[numThread];
Arrays.fill(regularActions, regularAction);
evaluateMultiThread(LAMBDA_FORM_REGULAR, regularActions);
final Runnable pooledAction = () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTask);
forAllTask(c);
c.recycle();
};
final Runnable[] pooledActions = new Runnable[numThread];
Arrays.fill(pooledActions, pooledAction);
evaluateMultiThread(LAMBDA_FORM_POOLED, pooledActions);
}
private void forAllTask(Consumer<Task> callback) {
for (int i = mTasks.size() - 1; i >= 0; i--) {
callback.accept(mTasks.get(i));
}
}
private void handleTask(Predicate<Task> callback) {
for (int i = mTasks.size() - 1; i >= 0; i--) {
final Task task = mTasks.get(i);
if (callback.test(task)) {
return;
}
}
}
private void evaluate(String title, Runnable action) {
for (int i = 0; i < WARMUP_ITERATIONS; i++) {
action.run();
}
performGc();
final GcStatus startGcStatus = getGcStatus();
final long startTime = SystemClock.elapsedRealtime();
for (int i = 0; i < TEST_ITERATIONS; i++) {
action.run();
}
evaluateResult(title, startGcStatus, startTime);
}
private void evaluateMultiThread(String title, Runnable[] actions) {
performGc();
final CountDownLatch latch = new CountDownLatch(actions.length);
final GcStatus startGcStatus = getGcStatus();
final long startTime = SystemClock.elapsedRealtime();
for (Runnable action : actions) {
new Thread() {
@Override
public void run() {
for (int i = 0; i < TEST_ITERATIONS; i++) {
action.run();
}
latch.countDown();
};
}.start();
}
try {
latch.await();
} catch (InterruptedException ignored) {
}
evaluateResult(title, startGcStatus, startTime);
}
private void evaluateResult(String title, GcStatus startStatus, long startTime) {
final float elapsed = SystemClock.elapsedRealtime() - startTime;
// Sleep a while to see if GC may happen.
SystemClock.sleep(DELAY_AFTER_BENCH_MS);
final GcStatus endStatus = getGcStatus();
final GcInfo info = startStatus.calculateGcTime(endStatus, title, mTestResults);
Log.i(TAG, mMethodName + "_" + title + " execution time: "
+ elapsed + "ms (avg=" + String.format("%.5f", elapsed / TEST_ITERATIONS) + "ms)"
+ " GC time: " + String.format("%.3f", info.mTotalGcTime) + "ms"
+ " GC paused time: " + String.format("%.3f", info.mTotalGcPausedTime) + "ms");
}
/** Cleans the test environment. */
private static void performGc() {
System.gc();
System.runFinalization();
System.gc();
}
private static GcStatus getGcStatus() {
if (DEBUG) {
Log.i(TAG, "===== Read GC dump =====");
}
final GcStatus status = new GcStatus();
final List<String> vmDump = getVmDump();
Assume.assumeFalse("VM dump is empty", vmDump.isEmpty());
for (String line : vmDump) {
status.visit(line);
if (line.startsWith("DALVIK THREADS")) {
break;
}
}
return status;
}
private static List<String> getVmDump() {
final int myPid = Process.myPid();
// Another approach Debug#dumpJavaBacktraceToFileTimeout requires setenforce 0.
Process.sendSignal(myPid, Process.SIGNAL_QUIT);
// Give a chance to handle the signal.
SystemClock.sleep(100);
String dump = null;
final String pattern = myPid + " written to: ";
final List<String> logs = shell("logcat -v brief -d tombstoned:I *:S");
for (int i = logs.size() - 1; i >= 0; i--) {
final String log = logs.get(i);
// Log pattern: Traces for pid 9717 written to: /data/anr/trace_07
final int pos = log.indexOf(pattern);
if (pos > 0) {
dump = log.substring(pattern.length() + pos);
break;
}
}
Assume.assumeNotNull("Unable to find VM dump", dump);
// It requires system or root uid to read the trace.
return shell("cat " + dump);
}
private static List<String> shell(String command) {
final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(
getInstrumentation().getUiAutomation().executeShellCommand(command));
final ArrayList<String> lines = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = br.readLine()) != null) {
lines.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lines;
}
/** An empty class which provides some methods with different type arguments. */
static class Task {
void doSomething() {
}
void doSomething(Task t) {
}
void doSomething(int taskId, long time) {
}
boolean doSomething(Rect bounds, boolean top, int taskId) {
return false;
}
}
static class ValPattern {
static final int TYPE_COUNT = 0;
static final int TYPE_TIME = 1;
static final String PATTERN_COUNT = "(\\d+)";
static final String PATTERN_TIME = "(\\d+\\.?\\d+)(\\w+)";
final String mRawPattern;
final Pattern mPattern;
final int mType;
int mIntValue;
float mFloatValue;
ValPattern(String p, int type) {
mRawPattern = p;
mPattern = Pattern.compile(
p + (type == TYPE_TIME ? PATTERN_TIME : PATTERN_COUNT) + ".*");
mType = type;
}
boolean visit(String line) {
final Matcher matcher = mPattern.matcher(line);
if (!matcher.matches()) {
return false;
}
final String value = matcher.group(1);
if (value == null) {
return false;
}
if (mType == TYPE_COUNT) {
mIntValue = Integer.parseInt(value);
return true;
}
final float time = Float.parseFloat(value);
final String unit = matcher.group(2);
if (unit == null) {
return false;
}
// Refer to art/libartbase/base/time_utils.cc
switch (unit) {
case "s":
mFloatValue = time * 1000;
break;
case "ms":
mFloatValue = time;
break;
case "us":
mFloatValue = time / 1000;
break;
case "ns":
mFloatValue = time / 1000 / 1000;
break;
default:
throw new IllegalArgumentException();
}
return true;
}
@Override
public String toString() {
return mRawPattern + (mType == TYPE_TIME ? (mFloatValue + "ms") : mIntValue);
}
}
/** Parses the dump pattern of Heap::DumpGcPerformanceInfo. */
private static class GcStatus {
private static final int TOTAL_GC_TIME_INDEX = 1;
private static final int TOTAL_GC_PAUSED_TIME_INDEX = 5;
// Refer to art/runtime/gc/heap.cc
final ValPattern[] mPatterns = {
new ValPattern("Total GC count: ", ValPattern.TYPE_COUNT),
new ValPattern("Total GC time: ", ValPattern.TYPE_TIME),
new ValPattern("Total time waiting for GC to complete: ", ValPattern.TYPE_TIME),
new ValPattern("Total blocking GC count: ", ValPattern.TYPE_COUNT),
new ValPattern("Total blocking GC time: ", ValPattern.TYPE_TIME),
new ValPattern("Total mutator paused time: ", ValPattern.TYPE_TIME),
new ValPattern("Total number of allocations ", ValPattern.TYPE_COUNT),
new ValPattern("concurrent copying paused: Sum: ", ValPattern.TYPE_TIME),
new ValPattern("concurrent copying total time: ", ValPattern.TYPE_TIME),
new ValPattern("concurrent copying freed: ", ValPattern.TYPE_COUNT),
new ValPattern("Peak regions allocated ", ValPattern.TYPE_COUNT),
};
void visit(String dumpLine) {
for (ValPattern p : mPatterns) {
if (p.visit(dumpLine)) {
if (DEBUG) {
Log.i(TAG, " " + p);
}
}
}
}
GcInfo calculateGcTime(GcStatus newStatus, String title, Bundle result) {
Log.i(TAG, "===== GC status of " + title + " =====");
final GcInfo info = new GcInfo();
for (int i = 0; i < mPatterns.length; i++) {
final ValPattern p = mPatterns[i];
if (p.mType == ValPattern.TYPE_COUNT) {
final int diff = newStatus.mPatterns[i].mIntValue - p.mIntValue;
Log.i(TAG, " " + p.mRawPattern + diff);
if (diff > 0) {
result.putInt("[" + title + "] " + p.mRawPattern, diff);
}
continue;
}
final float diff = newStatus.mPatterns[i].mFloatValue - p.mFloatValue;
Log.i(TAG, " " + p.mRawPattern + diff + "ms");
if (diff > 0) {
result.putFloat("[" + title + "] " + p.mRawPattern + "(ms)", diff);
}
if (i == TOTAL_GC_TIME_INDEX) {
info.mTotalGcTime = diff;
} else if (i == TOTAL_GC_PAUSED_TIME_INDEX) {
info.mTotalGcPausedTime = diff;
}
}
return info;
}
}
private static class GcInfo {
float mTotalGcTime;
float mTotalGcPausedTime;
}
}
/*
* Copyright (C) 2020 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 com.android.internal;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.util.Log;
import androidx.test.filters.LargeTest;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Compares the performance of regular lambda and pooled lambda. */
@LargeTest
public class LambdaPerfTest {
private static final boolean DEBUG = false;
private static final String TAG = LambdaPerfTest.class.getSimpleName();
private static final String LAMBDA_FORM_REGULAR = "regular";
private static final String LAMBDA_FORM_POOLED = "pooled";
private static final int WARMUP_ITERATIONS = 1000;
private static final int TEST_ITERATIONS = 3000000;
private static final int TASK_COUNT = 10;
private static final long DELAY_AFTER_BENCH_MS = 1000;
private String mMethodName;
private final Bundle mTestResults = new Bundle();
private final ArrayList<Task> mTasks = new ArrayList<>();
// The member fields are used to ensure lambda capturing. They don't have the actual meaning.
private final Task mTask = new Task();
private final Rect mBounds = new Rect();
private int mTaskId;
private long mTime;
private boolean mTop;
@Rule
public final TestRule mRule = (base, description) -> new Statement() {
@Override
public void evaluate() throws Throwable {
mMethodName = description.getMethodName();
mTasks.clear();
for (int i = 0; i < TASK_COUNT; i++) {
final Task t = new Task();
mTasks.add(t);
}
base.evaluate();
getInstrumentation().sendStatus(Activity.RESULT_OK, mTestResults);
}
};
@Test
public void test1ParamConsumer() {
evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTask)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTask);
forAllTask(c);
c.recycle();
});
}
@Test
public void test2PrimitiveParamsConsumer() {
// Not in Integer#IntegerCache (-128~127) for autoboxing, that may create new object.
mTaskId = 12345;
mTime = 54321;
evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTaskId, mTime)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTaskId, mTime);
forAllTask(c);
c.recycle();
});
}
@Test
public void test3ParamsPredicate() {
mTop = true;
// In Integer#IntegerCache.
mTaskId = 10;
evaluate(LAMBDA_FORM_REGULAR, () -> handleTask(t -> t.doSomething(mBounds, mTop, mTaskId)));
evaluate(LAMBDA_FORM_POOLED, () -> {
final PooledPredicate c = PooledLambda.obtainPredicate(Task::doSomething,
PooledLambda.__(Task.class), mBounds, mTop, mTaskId);
handleTask(c);
c.recycle();
});
}
@Test
public void testMessage() {
evaluate(LAMBDA_FORM_REGULAR, () -> {
final Message m = Message.obtain().setCallback(() -> mTask.doSomething(mTaskId, mTime));
m.getCallback().run();
m.recycle();
});
evaluate(LAMBDA_FORM_POOLED, () -> {
final Message m = PooledLambda.obtainMessage(Task::doSomething, mTask, mTaskId, mTime);
m.getCallback().run();
m.recycle();
});
}
@Test
public void testRunnable() {
evaluate(LAMBDA_FORM_REGULAR, () -> {
final Runnable r = mTask::doSomething;
r.run();
});
evaluate(LAMBDA_FORM_POOLED, () -> {
final Runnable r = PooledLambda.obtainRunnable(Task::doSomething, mTask).recycleOnUse();
r.run();
});
}
@Test
public void testMultiThread() {
final int numThread = 3;
final Runnable regularAction = () -> forAllTask(t -> t.doSomething(mTask));
final Runnable[] regularActions = new Runnable[numThread];
Arrays.fill(regularActions, regularAction);
evaluateMultiThread(LAMBDA_FORM_REGULAR, regularActions);
final Runnable pooledAction = () -> {
final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
PooledLambda.__(Task.class), mTask);
forAllTask(c);
c.recycle();
};
final Runnable[] pooledActions = new Runnable[numThread];
Arrays.fill(pooledActions, pooledAction);
evaluateMultiThread(LAMBDA_FORM_POOLED, pooledActions);
}
private void forAllTask(Consumer<Task> callback) {
for (int i = mTasks.size() - 1; i >= 0; i--) {
callback.accept(mTasks.get(i));
}
}
private void handleTask(Predicate<Task> callback) {
for (int i = mTasks.size() - 1; i >= 0; i--) {
final Task task = mTasks.get(i);
if (callback.test(task)) {
return;
}
}
}
private void evaluate(String title, Runnable action) {
for (int i = 0; i < WARMUP_ITERATIONS; i++) {
action.run();
}
performGc();
final GcStatus startGcStatus = getGcStatus();
final long startTime = SystemClock.elapsedRealtime();
for (int i = 0; i < TEST_ITERATIONS; i++) {
action.run();
}
evaluateResult(title, startGcStatus, startTime);
}
private void evaluateMultiThread(String title, Runnable[] actions) {
performGc();
final CountDownLatch latch = new CountDownLatch(actions.length);
final GcStatus startGcStatus = getGcStatus();
final long startTime = SystemClock.elapsedRealtime();
for (Runnable action : actions) {
new Thread() {
@Override
public void run() {
for (int i = 0; i < TEST_ITERATIONS; i++) {
action.run();
}
latch.countDown();
};
}.start();
}
try {
latch.await();
} catch (InterruptedException ignored) {
}
evaluateResult(title, startGcStatus, startTime);
}
private void evaluateResult(String title, GcStatus startStatus, long startTime) {
final float elapsed = SystemClock.elapsedRealtime() - startTime;
// Sleep a while to see if GC may happen.
SystemClock.sleep(DELAY_AFTER_BENCH_MS);
final GcStatus endStatus = getGcStatus();
final GcInfo info = startStatus.calculateGcTime(endStatus, title, mTestResults);
mTestResults.putFloat("[" + title + "-execution-time]", elapsed);
Log.i(TAG, mMethodName + "_" + title + " execution time: "
+ elapsed + "ms (avg=" + String.format("%.5f", elapsed / TEST_ITERATIONS) + "ms)"
+ " GC time: " + String.format("%.3f", info.mTotalGcTime) + "ms"
+ " GC paused time: " + String.format("%.3f", info.mTotalGcPausedTime) + "ms");
}
/** Cleans the test environment. */
private static void performGc() {
System.gc();
System.runFinalization();
System.gc();
}
private static GcStatus getGcStatus() {
if (DEBUG) {
Log.i(TAG, "===== Read GC dump =====");
}
final GcStatus status = new GcStatus();
final List<String> vmDump = getVmDump();
Assume.assumeFalse("VM dump is empty", vmDump.isEmpty());
for (String line : vmDump) {
status.visit(line);
if (line.startsWith("DALVIK THREADS")) {
break;
}
}
return status;
}
private static List<String> getVmDump() {
final int myPid = Process.myPid();
// Another approach Debug#dumpJavaBacktraceToFileTimeout requires setenforce 0.
Process.sendSignal(myPid, Process.SIGNAL_QUIT);
// Give a chance to handle the signal.
SystemClock.sleep(100);
String dump = null;
final String pattern = myPid + " written to: ";
final List<String> logs = shell("logcat -v brief -d tombstoned:I *:S");
for (int i = logs.size() - 1; i >= 0; i--) {
final String log = logs.get(i);
// Log pattern: Traces for pid 9717 written to: /data/anr/trace_07
final int pos = log.indexOf(pattern);
if (pos > 0) {
dump = log.substring(pattern.length() + pos);
if (!dump.startsWith("/data/anr/")) {
dump = "/data/anr/" + dump;
}
break;
}
}
Assume.assumeNotNull("Unable to find VM dump", dump);
// It requires system or root uid to read the trace.
return shell("cat " + dump);
}
private static List<String> shell(String command) {
final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(
getInstrumentation().getUiAutomation().executeShellCommand(command));
final ArrayList<String> lines = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = br.readLine()) != null) {
lines.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lines;
}
/** An empty class which provides some methods with different type arguments. */
static class Task {
void doSomething() {
}
void doSomething(Task t) {
}
void doSomething(int taskId, long time) {
}
boolean doSomething(Rect bounds, boolean top, int taskId) {
return false;
}
}
static class ValPattern {
static final int TYPE_COUNT = 0;
static final int TYPE_TIME = 1;
static final String PATTERN_COUNT = "(\\d+)";
static final String PATTERN_TIME = "(\\d+\\.?\\d+)(\\w+)";
final String mRawPattern;
final Pattern mPattern;
final int mType;
int mIntValue;
float mFloatValue;
ValPattern(String p, int type) {
mRawPattern = p;
mPattern = Pattern.compile(
p + (type == TYPE_TIME ? PATTERN_TIME : PATTERN_COUNT) + ".*");
mType = type;
}
boolean visit(String line) {
final Matcher matcher = mPattern.matcher(line);
if (!matcher.matches()) {
return false;
}
final String value = matcher.group(1);
if (value == null) {
return false;
}
if (mType == TYPE_COUNT) {
mIntValue = Integer.parseInt(value);
return true;
}
final float time = Float.parseFloat(value);
final String unit = matcher.group(2);
if (unit == null) {
return false;
}
// Refer to art/libartbase/base/time_utils.cc
switch (unit) {
case "s":
mFloatValue = time * 1000;
break;
case "ms":
mFloatValue = time;
break;
case "us":
mFloatValue = time / 1000;
break;
case "ns":
mFloatValue = time / 1000 / 1000;
break;
default:
throw new IllegalArgumentException();
}
return true;
}
@Override
public String toString() {
return mRawPattern + (mType == TYPE_TIME ? (mFloatValue + "ms") : mIntValue);
}
}
/** Parses the dump pattern of Heap::DumpGcPerformanceInfo. */
private static class GcStatus {
private static final int TOTAL_GC_TIME_INDEX = 1;
private static final int TOTAL_GC_PAUSED_TIME_INDEX = 5;
// Refer to art/runtime/gc/heap.cc
final ValPattern[] mPatterns = {
new ValPattern("Total GC count: ", ValPattern.TYPE_COUNT),
new ValPattern("Total GC time: ", ValPattern.TYPE_TIME),
new ValPattern("Total time waiting for GC to complete: ", ValPattern.TYPE_TIME),
new ValPattern("Total blocking GC count: ", ValPattern.TYPE_COUNT),
new ValPattern("Total blocking GC time: ", ValPattern.TYPE_TIME),
new ValPattern("Total mutator paused time: ", ValPattern.TYPE_TIME),
new ValPattern("Total number of allocations ", ValPattern.TYPE_COUNT),
new ValPattern("concurrent copying paused: Sum: ", ValPattern.TYPE_TIME),
new ValPattern("concurrent copying total time: ", ValPattern.TYPE_TIME),
new ValPattern("concurrent copying freed: ", ValPattern.TYPE_COUNT),
new ValPattern("Peak regions allocated ", ValPattern.TYPE_COUNT),
};
void visit(String dumpLine) {
for (ValPattern p : mPatterns) {
if (p.visit(dumpLine)) {
if (DEBUG) {
Log.i(TAG, " " + p);
}
}
}
}
GcInfo calculateGcTime(GcStatus newStatus, String title, Bundle result) {
Log.i(TAG, "===== GC status of " + title + " =====");
final GcInfo info = new GcInfo();
for (int i = 0; i < mPatterns.length; i++) {
final ValPattern p = mPatterns[i];
if (p.mType == ValPattern.TYPE_COUNT) {
final int diff = newStatus.mPatterns[i].mIntValue - p.mIntValue;
Log.i(TAG, " " + p.mRawPattern + diff);
if (diff > 0) {
result.putInt("[" + title + "] " + p.mRawPattern, diff);
}
continue;
}
final float diff = newStatus.mPatterns[i].mFloatValue - p.mFloatValue;
Log.i(TAG, " " + p.mRawPattern + diff + "ms");
if (diff > 0) {
result.putFloat("[" + title + "] " + p.mRawPattern + "(ms)", diff);
}
if (i == TOTAL_GC_TIME_INDEX) {
info.mTotalGcTime = diff;
} else if (i == TOTAL_GC_PAUSED_TIME_INDEX) {
info.mTotalGcPausedTime = diff;
}
}
return info;
}
}
private static class GcInfo {
float mTotalGcTime;
float mTotalGcPausedTime;
}
}