blob: 23f025b0a759b703474b0b2efb0ee264466e0a20 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.perftests.blob;
17
18import android.app.blob.BlobHandle;
19import android.app.blob.BlobStoreManager;
20import android.content.Context;
21import android.perftests.utils.ManualBenchmarkState;
22import android.perftests.utils.PerfManualStatusReporter;
23import android.perftests.utils.TraceMarkParser;
24import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
25import android.support.test.uiautomator.UiDevice;
26
27import androidx.test.filters.LargeTest;
28import androidx.test.platform.app.InstrumentationRegistry;
29
30import com.android.utils.blob.DummyBlobData;
31
32import org.junit.After;
33import org.junit.Before;
34import org.junit.Rule;
35import org.junit.Test;
36import org.junit.runner.RunWith;
37import org.junit.runners.Parameterized;
38
39import java.io.IOException;
40import java.util.ArrayList;
41import java.util.Arrays;
42import java.util.Base64;
43import java.util.Collection;
44import java.util.List;
45import java.util.concurrent.CompletableFuture;
46import java.util.concurrent.TimeUnit;
47
48@LargeTest
49@RunWith(Parameterized.class)
50public class BlobStorePerfTests {
51 // From frameworks/native/cmds/atrace/atrace.cpp
52 private static final String ATRACE_CATEGORY_SYSTEM_SERVER = "ss";
53 // From f/b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
54 private static final String ATRACE_COMPUTE_DIGEST_PREFIX = "computeBlobDigest-";
55
56 private Context mContext;
57 private BlobStoreManager mBlobStoreManager;
58 private AtraceUtils mAtraceUtils;
59 private ManualBenchmarkState mState;
60
61 @Rule
62 public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
63
64 @Parameterized.Parameter(0)
65 public int fileSizeInMb;
66
67 @Parameterized.Parameters(name = "{0}MB")
68 public static Collection<Object[]> getParameters() {
69 return Arrays.asList(new Object[][] {
70 { 25 },
71 { 50 },
72 { 100 },
73 { 200 },
74 });
75 }
76
77 @Before
78 public void setUp() {
79 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
80 mBlobStoreManager = (BlobStoreManager) mContext.getSystemService(
81 Context.BLOB_STORE_SERVICE);
82 mAtraceUtils = AtraceUtils.getInstance(InstrumentationRegistry.getInstrumentation());
83 mState = mPerfManualStatusReporter.getBenchmarkState();
84 }
85
86 @After
87 public void tearDown() {
88 // TODO: Add a blob_store shell command to trigger idle maintenance to avoid hardcoding
89 // job id like this.
90 // From BlobStoreConfig.IDLE_JOB_ID = 191934935.
91 runShellCommand("cmd jobscheduler run -f android 191934935");
92 }
93
94 @Test
95 public void testComputeDigest() throws Exception {
96 mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
97 try {
98 final List<Long> durations = new ArrayList<>();
99 final DummyBlobData blobData = prepareDataBlob(fileSizeInMb);
100 final TraceMarkParser parser = new TraceMarkParser(
101 line -> line.name.startsWith(ATRACE_COMPUTE_DIGEST_PREFIX));
102 while (mState.keepRunning(durations)) {
103 commitBlob(blobData);
104
105 durations.clear();
106 collectDigestDurationsFromTrace(parser, durations);
107
108 deleteBlob(blobData.getBlobHandle());
109 }
110 } finally {
111 mAtraceUtils.stopTrace();
112 }
113 }
114
115 private void collectDigestDurationsFromTrace(TraceMarkParser parser, List<Long> durations) {
116 mAtraceUtils.performDump(parser, (key, slices) -> {
117 for (TraceMarkSlice slice : slices) {
118 durations.add(TimeUnit.MICROSECONDS.toNanos(slice.getDurationInMicroseconds()));
119 }
120 });
121 }
122
123 private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
124 final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
125 .setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
126 .build();
127 blobData.prepare();
128 return blobData;
129 }
130
131 private void commitBlob(DummyBlobData blobData) throws Exception {
132 final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
133 try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
134 blobData.writeToSession(session);
135 final CompletableFuture<Integer> callback = new CompletableFuture<>();
136 session.commit(mContext.getMainExecutor(), callback::complete);
137 // Ignore commit callback result.
138 callback.get();
139 }
140 }
141
142 private void deleteBlob(BlobHandle blobHandle) throws Exception {
143 runShellCommand(String.format(
144 "cmd blob_store delete-blob --algo %s --digest %s --label %s --expiry %d --tag %s",
145 blobHandle.algorithm,
146 Base64.getEncoder().encode(blobHandle.digest),
147 blobHandle.label,
148 blobHandle.expiryTimeMillis,
149 blobHandle.tag));
150 }
151
152 private String runShellCommand(String cmd) {
153 try {
154 return UiDevice.getInstance(
155 InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
156 } catch (IOException e) {
157 throw new RuntimeException(e);
158 }
159 }
160}