Protected Audience: prepare contexts only if we received promises
We're currently preparing more bidder contexts than we need. Aborted auctions are likely a major cause of unused contexts. Only prepare contexts if we've received promises (using promises as an indicator that an auction is likely to proceed). Bug: 405175230 Change-Id: I5a0c64d39cfe90029ea4384cd16e4ed025b24baa Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6377184 Reviewed-by: Russ Hamilton <behamilton@google.com> Commit-Queue: Abigail Katcoff <abigailkatcoff@chromium.org> Cr-Commit-Position: refs/heads/main@{#1436100}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
e1ba85a165
commit
d161f23cf4
content/services/auction_worklet
@ -788,6 +788,12 @@ void BidderWorklet::FinishGenerateBid(
|
||||
task->finalize_generate_bid_receiver_id = std::nullopt;
|
||||
task->wait_promises = base::TimeTicks::Now() - task->trace_wait_deps_start;
|
||||
GenerateBidIfReady(task);
|
||||
if (!finalized_any_bid_) {
|
||||
finalized_any_bid_ = true;
|
||||
if (features::kFledgeWaitForPromisesToPrepareContexts.Get()) {
|
||||
MaybePrepareContexts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BidderWorklet::GenerateBidTask::GenerateBidTask() = default;
|
||||
@ -2499,6 +2505,8 @@ void BidderWorklet::MaybePrepareContexts() {
|
||||
if (!base::FeatureList::IsEnabled(
|
||||
features::kFledgePrepareBidderContextsInAdvance) ||
|
||||
generate_bid_tasks_.empty() || !IsCodeReady() ||
|
||||
(!finalized_any_bid_ &&
|
||||
features::kFledgeWaitForPromisesToPrepareContexts.Get()) ||
|
||||
base::FeatureList::IsEnabled(features::kFledgeAlwaysReuseBidderContext)) {
|
||||
return;
|
||||
}
|
||||
|
@ -947,6 +947,11 @@ class CONTENT_EXPORT BidderWorklet : public mojom::BidderWorklet,
|
||||
GenerateBidTaskList::iterator>
|
||||
finalize_receiver_set_;
|
||||
|
||||
// Whether any bid was finalized. We use this as a heuristic to indicate that
|
||||
// at least one auction is going to proceed without being aborted. In
|
||||
// particular, we use it to determine whether we should prepare contexts.
|
||||
bool finalized_any_bid_ = false;
|
||||
|
||||
ClosePipeCallback close_pipe_callback_;
|
||||
|
||||
// Errors that occurred while loading the code, if any.
|
||||
|
@ -884,6 +884,22 @@ class BidderWorkletTest : public testing::Test {
|
||||
direct_from_seller_auction_signals_header_ad_slot_);
|
||||
}
|
||||
|
||||
void FinishGenerateBid(
|
||||
mojo::AssociatedRemote<auction_worklet::mojom::GenerateBidFinalizer>&
|
||||
bid_finalizer) {
|
||||
bid_finalizer->FinishGenerateBid(
|
||||
auction_signals_, per_buyer_signals_, per_buyer_timeout_,
|
||||
per_buyer_currency_,
|
||||
provide_direct_from_seller_signals_late_
|
||||
? direct_from_seller_per_buyer_signals_
|
||||
: std::nullopt,
|
||||
direct_from_seller_per_buyer_signals_header_ad_slot_,
|
||||
provide_direct_from_seller_signals_late_
|
||||
? direct_from_seller_auction_signals_
|
||||
: std::nullopt,
|
||||
direct_from_seller_auction_signals_header_ad_slot_);
|
||||
}
|
||||
|
||||
// Calls BeginGenerateBid()/FinishGenerateBid(), expecting the
|
||||
// GenerateBidClient's OnGenerateBidComplete() method never to be invoked.
|
||||
void GenerateBidExpectingNeverCompletes(
|
||||
@ -9138,6 +9154,116 @@ TEST_P(BidderWorkletMultiThreadingTest,
|
||||
"Ads.InterestGroup.Auction.PremadeContextsScheduledPerThread", 0);
|
||||
}
|
||||
|
||||
TEST_P(BidderWorkletMultiThreadingTest,
|
||||
PreparesContextsIfFinishGenerateBidBeforeOrAfterJavascriptDownload) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeatureWithParameters(
|
||||
features::kFledgePrepareBidderContextsInAdvance,
|
||||
{{"WaitForPromisesToPrepareContexts", "true"}});
|
||||
interest_group_trusted_bidding_signals_url_ = GURL("https://signals.test/");
|
||||
const GURL kFullSignalsUrl(
|
||||
"https://signals.test/?hostname=top.window.test&interestGroupNames=Fred");
|
||||
|
||||
const char kJson[] = R"({"perInterestGroupData":
|
||||
{"Fred": {"priorityVector": {"foo": 1.0}}}
|
||||
})";
|
||||
|
||||
for (bool finalize_before_js_download : {true, false}) {
|
||||
SCOPED_TRACE(finalize_before_js_download);
|
||||
url_loader_factory_.ClearResponses();
|
||||
auto bidder_worklet = CreateWorklet();
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
generate_bid_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
mojo::AssociatedRemote<auction_worklet::mojom::GenerateBidFinalizer>
|
||||
bid_finalizer;
|
||||
|
||||
BeginGenerateBid(bidder_worklet.get(),
|
||||
bid_finalizer.BindNewEndpointAndPassReceiver());
|
||||
|
||||
if (finalize_before_js_download) {
|
||||
FinishGenerateBid(bid_finalizer);
|
||||
task_environment_.RunUntilIdle();
|
||||
AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_,
|
||||
CreateBasicGenerateBidScript());
|
||||
} else {
|
||||
AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_,
|
||||
CreateBasicGenerateBidScript());
|
||||
task_environment_.RunUntilIdle();
|
||||
FinishGenerateBid(bid_finalizer);
|
||||
}
|
||||
|
||||
task_environment_.RunUntilIdle();
|
||||
EXPECT_FALSE(generate_bid_run_loop_->AnyQuitCalled());
|
||||
|
||||
histogram_tester.ExpectTotalCount(
|
||||
"Ads.InterestGroup.Auction.UsedPremadeContext", 0);
|
||||
|
||||
AddBidderJsonResponse(&url_loader_factory_, kFullSignalsUrl, kJson);
|
||||
task_environment_.RunUntilIdle();
|
||||
|
||||
generate_bid_run_loop_->Run();
|
||||
generate_bid_run_loop_.reset();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
"Ads.InterestGroup.Auction.UsedPremadeContext", true, 1);
|
||||
histogram_tester.ExpectTotalCount(
|
||||
"Ads.InterestGroup.Auction.PremadeContextsScheduledPerThread", 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BidderWorkletMultiThreadingTest,
|
||||
DoesNotPrepareContextsBeforeFinishGenerateBidIfWaitForPromisesEnabled) {
|
||||
interest_group_trusted_bidding_signals_url_ = GURL("https://signals.test/");
|
||||
const GURL kFullSignalsUrl(
|
||||
"https://signals.test/?hostname=top.window.test&interestGroupNames=Fred");
|
||||
|
||||
const char kJson[] = R"({"perInterestGroupData":
|
||||
{"Fred": {"priorityVector": {"foo": 1.0}}}
|
||||
})";
|
||||
|
||||
for (bool wait_for_promises : {true, false}) {
|
||||
SCOPED_TRACE(wait_for_promises);
|
||||
url_loader_factory_.ClearResponses();
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeatureWithParameters(
|
||||
features::kFledgePrepareBidderContextsInAdvance,
|
||||
{{"WaitForPromisesToPrepareContexts",
|
||||
wait_for_promises ? "true" : "false"}});
|
||||
auto bidder_worklet = CreateWorklet();
|
||||
AddJavascriptResponse(&url_loader_factory_, interest_group_bidding_url_,
|
||||
CreateBasicGenerateBidScript());
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
generate_bid_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
mojo::AssociatedRemote<auction_worklet::mojom::GenerateBidFinalizer>
|
||||
bid_finalizer;
|
||||
BeginGenerateBid(bidder_worklet.get(),
|
||||
bid_finalizer.BindNewEndpointAndPassReceiver());
|
||||
task_environment_.RunUntilIdle();
|
||||
EXPECT_FALSE(generate_bid_run_loop_->AnyQuitCalled());
|
||||
|
||||
histogram_tester.ExpectTotalCount(
|
||||
"Ads.InterestGroup.Auction.UsedPremadeContext", 0);
|
||||
|
||||
AddBidderJsonResponse(&url_loader_factory_, kFullSignalsUrl, kJson);
|
||||
task_environment_.RunUntilIdle();
|
||||
|
||||
// FinishGenerateBid should cause us to generate our bid, but because this
|
||||
// is coming after signals, we never got a chance to prepare contexts.
|
||||
FinishGenerateBid(bid_finalizer);
|
||||
|
||||
generate_bid_run_loop_->Run();
|
||||
generate_bid_run_loop_.reset();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
"Ads.InterestGroup.Auction.UsedPremadeContext", !wait_for_promises, 1);
|
||||
histogram_tester.ExpectTotalCount(
|
||||
"Ads.InterestGroup.Auction.PremadeContextsScheduledPerThread",
|
||||
!wait_for_promises);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BidderWorkletMultiThreadingTest,
|
||||
DoesNotMakeMorePremadeContextsAfterFirstGenerateBid) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
|
@ -61,6 +61,11 @@ BASE_FEATURE_PARAM(int,
|
||||
&kFledgePrepareBidderContextsInAdvance,
|
||||
"BidderContextsMultiplier",
|
||||
1);
|
||||
BASE_FEATURE_PARAM(bool,
|
||||
kFledgeWaitForPromisesToPrepareContexts,
|
||||
&kFledgePrepareBidderContextsInAdvance,
|
||||
"WaitForPromisesToPrepareContexts",
|
||||
false);
|
||||
|
||||
BASE_FEATURE(kFledgeBidderUseBalancingThreadSelector,
|
||||
"FledgeBidderUseBalancingThreadSelector",
|
||||
|
@ -45,6 +45,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
|
||||
kFledgeMinBidderContextsPerThreadInAdvance);
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(int, kFledgeBidderContextsDivisor);
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(int, kFledgeBidderContextsMultiplier);
|
||||
CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(
|
||||
bool,
|
||||
kFledgeWaitForPromisesToPrepareContexts);
|
||||
|
||||
// Instead of using a hash to assign group-by-origin IGs to threads, use
|
||||
// a round robin on joining-origin while ensuring a maximum allowed imbalance
|
||||
|
Reference in New Issue
Block a user