Loading apct-tests/perftests/core/AndroidManifest.xml +12 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.android.perftests.core"> <permission android:name="com.android.perftests.core.TestPermission" /> Loading Loading @@ -33,6 +34,17 @@ android:exported="false" android:process=":some_provider" /> <!-- We remove EmojiCompat initializer here because it may crash the test process if the initializer runs while TypefaceSerializationPerfTest is running. --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer" tools:node="remove" /> </provider> <service android:name="android.view.autofill.MyAutofillService" android:label="PERF AutofillService" Loading apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java +64 −11 Original line number Diff line number Diff line Loading @@ -17,10 +17,13 @@ package android.graphics.perftests; import android.graphics.Typeface; import android.os.Debug; import android.os.SharedMemory; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.os.SystemClock; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; import android.util.ArrayMap; import android.util.Log; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -37,16 +40,33 @@ import java.util.Map; @RunWith(AndroidJUnit4.class) public class TypefaceSerializationPerfTest { private static final String TAG = "TypefaceSerializationPerfTest"; @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter(); @Test public void testSerializeFontMap() throws Exception { Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap(); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning()) { long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { long startTime = System.nanoTime(); Typeface.serializeFontMap(systemFontMap); elapsedTime = System.nanoTime() - startTime; } } @Test public void testSerializeFontMap_memory() throws Exception { Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap(); SharedMemory memory = Typeface.serializeFontMap(systemFontMap); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning(memory.getSize())) { // Rate-limiting SystemClock.sleep(100); } } Loading @@ -54,22 +74,54 @@ public class TypefaceSerializationPerfTest { public void testDeserializeFontMap() throws Exception { SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); ArrayMap<String, Typeface> out = new ArrayMap<>(); long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { long startTime = System.nanoTime(); buffer.position(0); Typeface.deserializeFontMap(buffer, out); elapsedTime = System.nanoTime() - startTime; } } @Test public void testDeserializeFontMap_memory() throws Exception { SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); ArrayMap<String, Typeface> out = new ArrayMap<>(); while (state.keepRunning()) { // Diff of native heap allocation size (in bytes) before and after deserializeFontMap. // Note: we don't measure memory usage of setSystemFontMap because setSystemFontMap sets // some global variables, and it's hard to clear them. long heapDiff = 0; // Sometimes heapDiff may become negative due to GC. // Use 0 in that case to avoid crashing in keepRunning. while (state.keepRunning(Math.max(0, heapDiff))) { buffer.position(0); long baselineSize = Debug.getNativeHeapAllocatedSize(); Typeface.deserializeFontMap(buffer, out); long currentSize = Debug.getNativeHeapAllocatedSize(); heapDiff = currentSize - baselineSize; Log.i(TAG, String.format("native heap alloc: current = %d, baseline = %d, diff = %d", currentSize, baselineSize, heapDiff)); // Release native objects here to minimize the impact of GC. for (Typeface typeface : out.values()) { typeface.releaseNativeObjectForTest(); } out.clear(); } } @Test public void testSetSystemFontMap() throws Exception { SharedMemory memory = null; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { // Explicitly destroy lazy-loaded typefaces, so that we don't hit the mmap limit // (max_map_count). Typeface.destroySystemFontMap(); Loading @@ -78,8 +130,9 @@ public class TypefaceSerializationPerfTest { memory.close(); } memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); state.resumeTiming(); long startTime = System.nanoTime(); Typeface.setSystemFontMap(memory); elapsedTime = System.nanoTime() - startTime; } } } graphics/java/android/graphics/Typeface.java +28 −1 Original line number Diff line number Diff line Loading @@ -1176,6 +1176,17 @@ public class Typeface { mWeight = nativeGetWeight(ni); } /** * Releases the underlying native object. * * <p>For testing only. Do not use the instance after this method is called. * It is safe to call this method twice or more on the same instance. * @hide */ public void releaseNativeObjectForTest() { mCleaner.run(); } private static Typeface getSystemDefaultTypeface(@NonNull String familyName) { Typeface tf = sSystemFontMap.get(familyName); return tf == null ? Typeface.DEFAULT : tf; Loading Loading @@ -1425,7 +1436,7 @@ public class Typeface { public static void destroySystemFontMap() { synchronized (SYSTEM_FONT_MAP_LOCK) { for (Typeface typeface : sSystemFontMap.values()) { typeface.mCleaner.run(); typeface.releaseNativeObjectForTest(); } sSystemFontMap.clear(); if (sSystemFontMapBuffer != null) { Loading @@ -1433,7 +1444,23 @@ public class Typeface { } sSystemFontMapBuffer = null; sSystemFontMapSharedMemory = null; synchronized (sStyledCacheLock) { destroyTypefaceCacheLocked(sStyledTypefaceCache); } synchronized (sWeightCacheLock) { destroyTypefaceCacheLocked(sWeightTypefaceCache); } } } private static void destroyTypefaceCacheLocked(LongSparseArray<SparseArray<Typeface>> cache) { for (int i = 0; i < cache.size(); i++) { SparseArray<Typeface> array = cache.valueAt(i); for (int j = 0; j < array.size(); j++) { array.valueAt(j).releaseNativeObjectForTest(); } } cache.clear(); } /** @hide */ Loading Loading
apct-tests/perftests/core/AndroidManifest.xml +12 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.android.perftests.core"> <permission android:name="com.android.perftests.core.TestPermission" /> Loading Loading @@ -33,6 +34,17 @@ android:exported="false" android:process=":some_provider" /> <!-- We remove EmojiCompat initializer here because it may crash the test process if the initializer runs while TypefaceSerializationPerfTest is running. --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer" tools:node="remove" /> </provider> <service android:name="android.view.autofill.MyAutofillService" android:label="PERF AutofillService" Loading
apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java +64 −11 Original line number Diff line number Diff line Loading @@ -17,10 +17,13 @@ package android.graphics.perftests; import android.graphics.Typeface; import android.os.Debug; import android.os.SharedMemory; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.os.SystemClock; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; import android.util.ArrayMap; import android.util.Log; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -37,16 +40,33 @@ import java.util.Map; @RunWith(AndroidJUnit4.class) public class TypefaceSerializationPerfTest { private static final String TAG = "TypefaceSerializationPerfTest"; @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter(); @Test public void testSerializeFontMap() throws Exception { Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap(); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning()) { long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { long startTime = System.nanoTime(); Typeface.serializeFontMap(systemFontMap); elapsedTime = System.nanoTime() - startTime; } } @Test public void testSerializeFontMap_memory() throws Exception { Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap(); SharedMemory memory = Typeface.serializeFontMap(systemFontMap); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning(memory.getSize())) { // Rate-limiting SystemClock.sleep(100); } } Loading @@ -54,22 +74,54 @@ public class TypefaceSerializationPerfTest { public void testDeserializeFontMap() throws Exception { SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); ArrayMap<String, Typeface> out = new ArrayMap<>(); long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { long startTime = System.nanoTime(); buffer.position(0); Typeface.deserializeFontMap(buffer, out); elapsedTime = System.nanoTime() - startTime; } } @Test public void testDeserializeFontMap_memory() throws Exception { SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); ArrayMap<String, Typeface> out = new ArrayMap<>(); while (state.keepRunning()) { // Diff of native heap allocation size (in bytes) before and after deserializeFontMap. // Note: we don't measure memory usage of setSystemFontMap because setSystemFontMap sets // some global variables, and it's hard to clear them. long heapDiff = 0; // Sometimes heapDiff may become negative due to GC. // Use 0 in that case to avoid crashing in keepRunning. while (state.keepRunning(Math.max(0, heapDiff))) { buffer.position(0); long baselineSize = Debug.getNativeHeapAllocatedSize(); Typeface.deserializeFontMap(buffer, out); long currentSize = Debug.getNativeHeapAllocatedSize(); heapDiff = currentSize - baselineSize; Log.i(TAG, String.format("native heap alloc: current = %d, baseline = %d, diff = %d", currentSize, baselineSize, heapDiff)); // Release native objects here to minimize the impact of GC. for (Typeface typeface : out.values()) { typeface.releaseNativeObjectForTest(); } out.clear(); } } @Test public void testSetSystemFontMap() throws Exception { SharedMemory memory = null; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); long elapsedTime = 0; while (state.keepRunning(elapsedTime)) { // Explicitly destroy lazy-loaded typefaces, so that we don't hit the mmap limit // (max_map_count). Typeface.destroySystemFontMap(); Loading @@ -78,8 +130,9 @@ public class TypefaceSerializationPerfTest { memory.close(); } memory = Typeface.serializeFontMap(Typeface.getSystemFontMap()); state.resumeTiming(); long startTime = System.nanoTime(); Typeface.setSystemFontMap(memory); elapsedTime = System.nanoTime() - startTime; } } }
graphics/java/android/graphics/Typeface.java +28 −1 Original line number Diff line number Diff line Loading @@ -1176,6 +1176,17 @@ public class Typeface { mWeight = nativeGetWeight(ni); } /** * Releases the underlying native object. * * <p>For testing only. Do not use the instance after this method is called. * It is safe to call this method twice or more on the same instance. * @hide */ public void releaseNativeObjectForTest() { mCleaner.run(); } private static Typeface getSystemDefaultTypeface(@NonNull String familyName) { Typeface tf = sSystemFontMap.get(familyName); return tf == null ? Typeface.DEFAULT : tf; Loading Loading @@ -1425,7 +1436,7 @@ public class Typeface { public static void destroySystemFontMap() { synchronized (SYSTEM_FONT_MAP_LOCK) { for (Typeface typeface : sSystemFontMap.values()) { typeface.mCleaner.run(); typeface.releaseNativeObjectForTest(); } sSystemFontMap.clear(); if (sSystemFontMapBuffer != null) { Loading @@ -1433,7 +1444,23 @@ public class Typeface { } sSystemFontMapBuffer = null; sSystemFontMapSharedMemory = null; synchronized (sStyledCacheLock) { destroyTypefaceCacheLocked(sStyledTypefaceCache); } synchronized (sWeightCacheLock) { destroyTypefaceCacheLocked(sWeightTypefaceCache); } } } private static void destroyTypefaceCacheLocked(LongSparseArray<SparseArray<Typeface>> cache) { for (int i = 0; i < cache.size(); i++) { SparseArray<Typeface> array = cache.valueAt(i); for (int j = 0; j < array.size(); j++) { array.valueAt(j).releaseNativeObjectForTest(); } } cache.clear(); } /** @hide */ Loading