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

Commit dcfc6364 authored by Aditya Gupta's avatar Aditya Gupta Committed by Android (Google) Code Review
Browse files

Merge "added benchmark for rubidium performance tests scripts Test: Ran atest...

Merge "added benchmark for rubidium performance tests scripts Test: Ran atest RubidiumPerfTests and verified all new added tests are successful Bug: 261463071" into tm-mainline-prod
parents e884b78d ed79aa71
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ android_test {
        "collector-device-lib-platform",
        "compatibility-device-util-axt",
        "platform-test-annotations",
        "framework-adservices-lib",
        "adservices-service-core",
        "androidx.core_core",
    ],
+72 −0

File added.

Preview size limit exceeded, changes collapsed.

+59 −0

File added.

Preview size limit exceeded, changes collapsed.

+251 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.rubidium.js;

import static com.android.adservices.service.js.JSScriptArgument.arrayArg;
import static com.android.adservices.service.js.JSScriptArgument.jsonArg;
import static com.android.adservices.service.js.JSScriptArgument.numericArg;
import static com.android.adservices.service.js.JSScriptArgument.recordArg;
import static com.android.adservices.service.js.JSScriptArgument.stringArg;
@@ -26,8 +27,14 @@ import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assume.assumeTrue;

import android.adservices.adselection.AdSelectionConfig;
import android.adservices.adselection.AdWithBid;
import android.adservices.common.AdData;
import android.adservices.common.AdSelectionSignals;
import android.adservices.common.AdTechIdentifier;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.Uri;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.util.Log;
@@ -37,6 +44,12 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.adservices.data.adselection.CustomAudienceSignals;
import com.android.adservices.service.adselection.AdDataArgument;
import com.android.adservices.service.adselection.AdSelectionConfigArgument;
import com.android.adservices.service.adselection.AdWithBidArgument;
import com.android.adservices.service.adselection.CustomAudienceBiddingSignalsArgument;
import com.android.adservices.service.adselection.CustomAudienceScoringSignalsArgument;
import com.android.adservices.service.js.IsolateSettings;
import com.android.adservices.service.js.JSScriptArgument;
import com.android.adservices.service.js.JSScriptArrayArgument;
@@ -46,9 +59,11 @@ import com.android.adservices.service.profiling.JSScriptEngineLogConstants;
import com.android.adservices.service.profiling.Profiler;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListenableFuture;

import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -58,14 +73,23 @@ import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
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;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/** To run the unit tests for this class, run "atest RubidiumPerfTests:JSScriptEnginePerfTests" */
@MediumTest
@@ -78,8 +102,12 @@ public class JSScriptEnginePerfTests {
    private static final JSScriptEngine sJSScriptEngine =
            JSScriptEngine.getInstanceForTesting(
                    sContext, Profiler.createInstance(JSScriptEngine.TAG));

    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
    private static final Clock CLOCK = Clock.fixed(Instant.now(), ZoneOffset.UTC);
    private static final Instant ACTIVATION_TIME = CLOCK.instant();
    private static final Instant EXPIRATION_TIME = CLOCK.instant().plus(Duration.ofDays(1));
    private static final AdSelectionSignals CONTEXTUAL_SIGNALS = AdSelectionSignals.EMPTY;
    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    @Before
    public void before() throws Exception {
@@ -162,6 +190,56 @@ public class JSScriptEnginePerfTests {
        runParametrizedTurtledoveScript(75);
    }

    @Test
    public void evaluate_rubidiumGenerateBid_parametrized_1Ad() throws Exception {
        runParameterizedRubidiumGenerateBid(1);
    }

    @Test
    public void evaluate_rubidiumGenerateBid_parametrized_10Ads() throws Exception {
        runParameterizedRubidiumGenerateBid(10);
    }

    @Test
    public void evaluate_rubidiumGenerateBid_parametrized_25Ads() throws Exception {
        runParameterizedRubidiumGenerateBid(25);
    }

    @Test
    public void evaluate_rubidiumGenerateBid_parametrized_50Ads() throws Exception {
        runParameterizedRubidiumGenerateBid(50);
    }

    @Test
    public void evaluate_rubidiumGenerateBid_parametrized_75Ads() throws Exception {
        runParameterizedRubidiumGenerateBid(75);
    }

    @Test
    public void evaluate_rubidiumScoreAd_parametrized_1Ad() throws Exception {
        runParameterizedRubidiumScoreAd(1);
    }

    @Test
    public void evaluate_rubidiumScoreAd_parametrized_10Ads() throws Exception {
        runParameterizedRubidiumScoreAd(10);
    }

    @Test
    public void evaluate_rubidiumScoreAd_parametrized_25Ads() throws Exception {
        runParameterizedRubidiumScoreAd(25);
    }

    @Test
    public void evaluate_rubidiumScoreAd_parametrized_50Ads() throws Exception {
        runParameterizedRubidiumScoreAd(50);
    }

    @Test
    public void evaluate_rubidiumScoreAd_parametrized_75Ads() throws Exception {
        runParameterizedRubidiumScoreAd(75);
    }

    @SuppressLint("DefaultLocale")
    private void runParametrizedTurtledoveScript(int numAds) throws Exception {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -190,7 +268,7 @@ public class JSScriptEnginePerfTests {
                            "(%s: %d)",
                            JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME, webviewExecTime);
            // The listener picks up logs from JSScriptEngine, so simulate logging from there.
            Log.d("JSScriptEngine", webviewExecTimeLog);
            Log.d(TAG, webviewExecTimeLog);
        }
    }

@@ -202,7 +280,9 @@ public class JSScriptEnginePerfTests {
                        ImmutableList.of(
                                stringArg(
                                        "renderUrl",
                                        "https://googleads.g.doubleclick.net/ads/simple-ad.html?adg_id=52836427830&cr_id=310927197297&cv_id=4"),
                                        "https://googleads.g.doubleclick.net/ads/simple-ad"
                                                + ".html?adg_id=52836427830&cr_id=310927197297"
                                                + "&cv_id=4"),
                                stringArrayArg(
                                        "metadata",
                                        ImmutableList.of(
@@ -350,4 +430,171 @@ public class JSScriptEnginePerfTests {
    private String readAsset(@NonNull String assetName) throws IOException {
        return new String(readBinaryAsset(assetName), StandardCharsets.UTF_8);
    }

    public void runParameterizedRubidiumGenerateBid(int numOfAds) throws Exception {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        state.pauseTiming();
        List<AdData> adDataList = getSampleAdDataList(numOfAds, "https://ads.example/");
        ImmutableList.Builder<JSScriptArgument> adDataListArgument = new ImmutableList.Builder<>();
        for (AdData adData : adDataList) {
            adDataListArgument.add(AdDataArgument.asScriptArgument("ignored", adData));
        }
        AdSelectionSignals perBuyerSignals = generatePerBuyerSignals(numOfAds);
        AdSelectionSignals auctionSignals = AdSelectionSignals.fromString("{\"auctionSignal1"
                + "\":\"auctionValue1\",\"auctionSignal2\":\"auctionValue2\"}");

        AdTechIdentifier buyer = AdTechIdentifier.fromString("https://example-dsp.com");
        AdSelectionSignals trustedBiddingSignals = AdSelectionSignals.fromString("{\"key1"
                + "\":\"tbs1\",\"key2\":{}}");
        CustomAudienceSignals customAudienceSignals = getSampleCustomAudienceSignals(buyer,
                "shoes-running");

        ImmutableList<JSScriptArgument> args = ImmutableList.<JSScriptArgument>builder()
                .add(arrayArg("ads", adDataListArgument.build()))
                .add(jsonArg("auctionSignals", auctionSignals))
                .add(jsonArg("perBuyerSignals", perBuyerSignals))
                .add(jsonArg("trustedBiddingSignals", trustedBiddingSignals))
                .add(jsonArg("contextualSignals", CONTEXTUAL_SIGNALS))
                .add(CustomAudienceBiddingSignalsArgument.asScriptArgument(
                        "customAudienceBiddingSignal", customAudienceSignals))
                .build();
        InputStream testJsInputStream = sContext.getAssets().open(
                "rubidium_bidding_logic_compiled.js");
        String jsTestFile = new String(testJsInputStream.readAllBytes(), StandardCharsets.UTF_8);
        //logging time taken to call JS
        state.resumeTiming();
        while (state.keepRunning()) {
            String res = callJSEngine(jsTestFile, args, "generateBidIterative");
            JSONObject jsonObject = new JSONObject(res);
            long webviewExecTime = jsonObject.getLong("duration");
            String webviewExecTimeLog =
                    String.format(Locale.ENGLISH,
                            "(%s: %d)",
                            JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME,
                            webviewExecTime);
            // The listener picks up logs from JSScriptEngine, so simulate logging from there.
            Log.d(TAG, webviewExecTimeLog);
        }
    }

    public void runParameterizedRubidiumScoreAd(int numOfAds) throws Exception {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        state.pauseTiming();
        String adRenderUrl = "https://rtb.example/creative";
        List<AdWithBid> adWithBidList = getSampleAdDataWithBidList(numOfAds, adRenderUrl);
        ImmutableList.Builder<JSScriptArgument> adWithBidArrayArgument =
                new ImmutableList.Builder<>();
        for (AdWithBid adWithBid : adWithBidList) {
            adWithBidArrayArgument.add(AdWithBidArgument.asScriptArgument("adWithBid", adWithBid));
        }
        AdTechIdentifier seller = AdTechIdentifier.fromString("www.example-ssp.com");
        AdSelectionSignals sellerSignals = AdSelectionSignals.fromString("{\"signals\":[]}");
        String trustedScoringSignalJson = String.format(Locale.ENGLISH,
                "{\"renderUrl\":{\"%s\":[]}}", adRenderUrl);
        AdSelectionSignals trustedScoringSignalsJson = AdSelectionSignals.fromString(
                trustedScoringSignalJson);

        AdTechIdentifier buyer1 = AdTechIdentifier.fromString("https://example-dsp.com");
        AdSelectionSignals buyer1Signals = AdSelectionSignals.fromString("{\"https://example-dsp"
                + ".com:1\":\"value1\",\"https://example-dsp.com:2\":\"value2\"}");
        Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals = ImmutableMap.of(buyer1,
                buyer1Signals);

        AdSelectionConfig adSelectionConfig = getSampleAdSelectionConfig(seller, sellerSignals,
                perBuyerSignals);
        CustomAudienceSignals customAudienceSignals = getSampleCustomAudienceSignals(buyer1,
                "shoes-running");

        ImmutableList<JSScriptArgument> args = ImmutableList.<JSScriptArgument>builder()
                .add(arrayArg("adsWithBids", adWithBidArrayArgument.build()))
                .add(AdSelectionConfigArgument.asScriptArgument(adSelectionConfig,
                        "adSelectionConfig"))
                .add(jsonArg("sellerSignals", sellerSignals))
                .add(jsonArg("trustedScoringSignals", trustedScoringSignalsJson))
                .add(jsonArg("contextualSignals", CONTEXTUAL_SIGNALS))
                .add(CustomAudienceScoringSignalsArgument.asScriptArgument(
                        "customAudienceScoringSignal", customAudienceSignals))
                .build();
        InputStream testJsInputStream = sContext.getAssets().open(
                "rubidium_scoring_logic_compiled.js");
        String jsTestFile = new String(testJsInputStream.readAllBytes(), StandardCharsets.UTF_8);
        //logging time taken to call JS
        state.resumeTiming();
        while (state.keepRunning()) {
            String res = callJSEngine(jsTestFile, args, "scoreAdIterative");
            JSONObject jsonObject = new JSONObject(res);
            long webviewExecTime = jsonObject.getLong("duration");
            String webviewExecTimeLog =
                    String.format(Locale.ENGLISH,
                            "(%s: %d)",
                            JSScriptEngineLogConstants.WEBVIEW_EXECUTION_TIME,
                            webviewExecTime);
            // The listener picks up logs from JSScriptEngine, so simulate logging from there.
            Log.d(TAG, webviewExecTimeLog);
        }
    }

    private List<AdWithBid> getSampleAdDataWithBidList(int size, String baseUri) {
        double initialBid = 1.23;
        return IntStream.rangeClosed(1, size).mapToObj(iterator -> {
            Uri renderUri = Uri.parse(String.format(Locale.ENGLISH, "%s%d", baseUri, iterator));
            String metaDataJson = String.format(Locale.ENGLISH, "{\"metadata\":[\"%d\",\"123\"]}",
                    iterator);
            AdData adData = new AdData.Builder().setRenderUri(renderUri).setMetadata(
                    metaDataJson).build();
            return new AdWithBid(adData, initialBid + iterator);
        }).collect(Collectors.toCollection(ArrayList::new));
    }

    private List<AdData> getSampleAdDataList(int size, String baseUri) {
        return IntStream.rangeClosed(1, size).mapToObj(iterator -> {
            Uri renderUri = Uri.parse(String.format(Locale.ENGLISH, "%s%d", baseUri, iterator));
            String metaDataJson = String.format(Locale.ENGLISH, "{\"metadata\":[\"%d\",\"123\"]}",
                    iterator);
            return new AdData.Builder().setRenderUri(renderUri).setMetadata(
                    metaDataJson).build();
        }).collect(Collectors.toCollection(ArrayList::new));
    }

    private CustomAudienceSignals getSampleCustomAudienceSignals(AdTechIdentifier buyer,
            String name) {
        String owner = "www.example-dsp.com";
        AdSelectionSignals userBiddingSignals = AdSelectionSignals.fromString("{\"signals\":[]}");
        return new CustomAudienceSignals.Builder()
                .setOwner(owner)
                .setBuyer(buyer)
                .setActivationTime(ACTIVATION_TIME)
                .setExpirationTime(EXPIRATION_TIME)
                .setUserBiddingSignals(userBiddingSignals)
                .setName(name)
                .build();
    }

    private AdSelectionConfig getSampleAdSelectionConfig(AdTechIdentifier seller,
            AdSelectionSignals sellerSignals,
            Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals) {
        Uri decisionLogicUri = Uri.parse("https://www.example-ssp.com/decide.js");
        Uri trustedScoringSignalsUri = Uri.parse("https://www.example-ssp.com/signals");
        List<AdTechIdentifier> buyers = ImmutableList.copyOf(
                new ArrayList<>(perBuyerSignals.keySet()));
        return new AdSelectionConfig.Builder()
                .setSeller(seller)
                .setDecisionLogicUri(decisionLogicUri)
                .setCustomAudienceBuyers(buyers)
                .setAdSelectionSignals(AdSelectionSignals.EMPTY)
                .setSellerSignals(sellerSignals)
                .setPerBuyerSignals(perBuyerSignals)
                .setTrustedScoringSignalsUri(trustedScoringSignalsUri)
                .build();
    }

    private AdSelectionSignals generatePerBuyerSignals(int size) {
        String signalArrayFormat = "[\"%d\",\"123\",%d]";
        String signalArray = IntStream.rangeClosed(1, size)
                .mapToObj(i -> String.format(Locale.ENGLISH, signalArrayFormat, i, i))
                .collect(Collectors.joining(", ", "[", "]"));
        return AdSelectionSignals.fromString(
                String.format(Locale.ENGLISH, "{\"signals\":[null,%s,[null]]}",
                        signalArray));
    }
}