Merge "Add benchmarks for WASM bidding logic" into tm-mainline-prod

This commit is contained in:
TreeHugger Robot
2022-07-20 15:43:25 +00:00
committed by Android (Google) Code Review
4 changed files with 110 additions and 12 deletions

View File

@@ -33,6 +33,7 @@ android_test {
"compatibility-device-util-axt",
"platform-test-annotations",
"adservices-service-core",
"androidx.core_core",
],
test_suites: ["device-tests"],
data: [":perfetto_artifacts"],

Binary file not shown.

View File

@@ -0,0 +1,24 @@
function generateBid(ad, wasmModule) {
let input = ad.metadata.input;
const instance = new WebAssembly.Instance(wasmModule);
const memory = instance.exports.memory;
const input_in_memory = new Float32Array(memory.buffer, 0, 200);
for (let i = 0; i < input.length; ++i) {
input_in_memory[i] = input[i];
}
const results = [
instance.exports.nn_forward_model0(input_in_memory.length, input_in_memory),
instance.exports.nn_forward_model1(input_in_memory.length, input_in_memory),
instance.exports.nn_forward_model2(input_in_memory.length, input_in_memory),
instance.exports.nn_forward_model3(input_in_memory.length, input_in_memory),
instance.exports.nn_forward_model4(input_in_memory.length, input_in_memory),
];
const bid = results.map(x => Math.max(x, 1)).reduce((x, y) => x * y);
return {
ad: 'example',
bid: bid,
render: ad.renderUrl
}
}

View File

@@ -24,6 +24,9 @@ import static com.android.adservices.service.js.JSScriptArgument.stringArrayArg;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
import android.annotation.SuppressLint;
import android.content.Context;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -45,48 +48,44 @@ import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import org.json.JSONArray;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/** To run the unit tests for this class, run "atest RubidiumPerfTests:JSScriptEnginePerfTests" */
@MediumTest
@RunWith(AndroidJUnit4.class)
public class JSScriptEnginePerfTests {
private static final String TAG = JSScriptEnginePerfTests.class.getSimpleName();
private static final String TAG = JSScriptEngine.TAG;
private static final Context sContext = ApplicationProvider.getApplicationContext();
private static final ExecutorService sExecutorService = Executors.newFixedThreadPool(10);
private static JSScriptEngine sJSScriptEngine;
private static final JSScriptEngine sJSScriptEngine =
JSScriptEngine.getInstanceForTesting(
sContext, Profiler.createInstance(JSScriptEngine.TAG));
@Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Before
public void before() throws Exception {
Profiler profiler = Profiler.createInstance(JSScriptEngine.TAG);
sJSScriptEngine = JSScriptEngine.getInstanceForTesting(sContext, profiler);
// Warm up the sandbox env.
callJSEngine(
"function test() { return \"hello world\";" + " }", ImmutableList.of(), "test");
}
@After
public void after() {
sJSScriptEngine.shutdown();
}
@Test
public void evaluate_helloWorld() throws Exception {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -156,6 +155,7 @@ public class JSScriptEnginePerfTests {
runParametrizedTurtledoveScript(75);
}
@SuppressLint("DefaultLocale")
private void runParametrizedTurtledoveScript(int numAds) throws Exception {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
@@ -220,7 +220,34 @@ public class JSScriptEnginePerfTests {
return arrayArg("foo", Collections.nCopies(numCustomAudiences, interestGroupArg));
}
private static String callJSEngine(
@Test
public void evaluate_turtledoveWasm() throws Exception {
assumeTrue(sJSScriptEngine.isWasmSupported().get(3, TimeUnit.SECONDS));
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
String jsTestFile = readAsset("generate_bid_using_wasm.js");
byte[] wasmTestFile = readBinaryAsset("generate_bid.wasm");
JSScriptArgument[] inputBytes = new JSScriptArgument[200];
Random rand = new Random();
for (int i = 0; i < inputBytes.length; i++) {
byte value = (byte) (rand.nextInt(2 * Byte.MAX_VALUE) - Byte.MIN_VALUE);
inputBytes[i] = JSScriptArgument.numericArg("_", value);
}
JSScriptArgument adDataArgument =
recordArg(
"ad",
stringArg("render_url", "http://google.com"),
recordArg("metadata", JSScriptArgument.arrayArg("input", inputBytes)));
state.resumeTiming();
while (state.keepRunning()) {
callJSEngine(jsTestFile, wasmTestFile, ImmutableList.of(adDataArgument), "generateBid");
}
}
private String callJSEngine(
@NonNull String jsScript,
@NonNull List<JSScriptArgument> args,
@NonNull String functionName)
@@ -228,6 +255,15 @@ public class JSScriptEnginePerfTests {
return callJSEngine(sJSScriptEngine, jsScript, args, functionName);
}
private String callJSEngine(
@NonNull String jsScript,
@NonNull byte[] wasmScript,
@NonNull List<JSScriptArgument> args,
@NonNull String functionName)
throws Exception {
return callJSEngine(sJSScriptEngine, jsScript, wasmScript, args, functionName);
}
private static String callJSEngine(
@NonNull JSScriptEngine jsScriptEngine,
@NonNull String jsScript,
@@ -241,6 +277,21 @@ public class JSScriptEnginePerfTests {
return futureResult.get();
}
private String callJSEngine(
@NonNull JSScriptEngine jsScriptEngine,
@NonNull String jsScript,
@NonNull byte[] wasmScript,
@NonNull List<JSScriptArgument> args,
@NonNull String functionName)
throws Exception {
CountDownLatch resultLatch = new CountDownLatch(1);
ListenableFuture<String> futureResult =
callJSEngineAsync(
jsScriptEngine, jsScript, wasmScript, args, functionName, resultLatch);
resultLatch.await();
return futureResult.get();
}
private static ListenableFuture<String> callJSEngineAsync(
@NonNull String jsScript,
@NonNull List<JSScriptArgument> args,
@@ -261,4 +312,26 @@ public class JSScriptEnginePerfTests {
result.addListener(resultLatch::countDown, sExecutorService);
return result;
}
private ListenableFuture<String> callJSEngineAsync(
@NonNull JSScriptEngine engine,
@NonNull String jsScript,
@NonNull byte[] wasmScript,
@NonNull List<JSScriptArgument> args,
@NonNull String functionName,
@NonNull CountDownLatch resultLatch) {
Objects.requireNonNull(engine);
Objects.requireNonNull(resultLatch);
ListenableFuture<String> result = engine.evaluate(jsScript, wasmScript, args, functionName);
result.addListener(resultLatch::countDown, sExecutorService);
return result;
}
private byte[] readBinaryAsset(@NonNull String assetName) throws IOException {
return sContext.getAssets().open(assetName).readAllBytes();
}
private String readAsset(@NonNull String assetName) throws IOException {
return new String(readBinaryAsset(assetName), StandardCharsets.UTF_8);
}
}