Commit 9eaaf647 authored by Eric Robinson's avatar Eric Robinson Committed by Commit Bot

Remove FrameData class in the AdsPageLoadMetricsObserver.

This CL removes the FrameData class entirely, favoring small subclasses
AggregateFrameData and FrameTreeData that do the various types of
computations and repeating some of the high-level functionality to call
those subclasses correctly in each class.

It organizes all of the data into a FrameData namespace for easily
containing/referencing it and not having it pollute the namespace and
most/many of the enums are moved out of the classes to sit in that
namespace for general referencing.  It also removes main_frame_data
from the APLMO, in favor of storing the portions of it we wish to
know about in aggregate_frame_data as computational components using
the subclasses.  It also moves the collection of current memory usage
for individual frames to sit under APLMO, much like the resource
tracking information already does, to make memory collection more
generic and so we don't store multiple maps, some of which contain
only one entry.

After this, there are still a few more minor clean-ups that could
potentially be done:
1) Uniformity around naming accessors and updaters, as right now we
use some combination of GetValueType/value_type and UpdateValueType/
set_value_type.  I've done some fixing of this in this CL, but more
could be done.
2) Migration of Heavy Ads logic out of FrameData.  This should really
be performed as part of APLMO, but it sits in FrameData right now.
3) Migration of UKM reporting out of FrameData.  We report all UMA in
APLMO but report UKM as part of FrameData, and they should both be
done at the same level, presumably in APLMO.
4) Remove kAnyVisibility in favor of accessors that just add the two
visibilities together, as this would simplify the logic in many areas
where we loop over two visibilities ("any" and the appropriate one)
setting them both, rather than just setting one.

Bug: 1136068
Change-Id: Id65950726064b5a52ff08db21bf4e988339427a6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2496201
Commit-Queue: Eric Robinson <ericrobinson@chromium.org>
Reviewed-by: default avatarJohn Delaney <johnidel@chromium.org>
Reviewed-by: default avatarJosh Karlin <jkarlin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825002}
parent 0aa4b42f
......@@ -94,13 +94,13 @@ namespace {
#define ADS_HISTOGRAM(suffix, hist_macro, visibility, value) \
switch (visibility) { \
case FrameData::kNonVisible: \
case ad_metrics::kNonVisible: \
hist_macro("PageLoad.Clients.Ads.NonVisible." suffix, value); \
break; \
case FrameData::kVisible: \
case ad_metrics::kVisible: \
hist_macro("PageLoad.Clients.Ads.Visible." suffix, value); \
break; \
case FrameData::kAnyVisibility: \
case ad_metrics::kAnyVisibility: \
hist_macro("PageLoad.Clients.Ads." suffix, value); \
break; \
}
......@@ -124,7 +124,7 @@ void RecordFeatureUsage(content::RenderFrameHost* rfh,
rfh, page_load_features);
}
std::string GetHeavyAdReportMessage(const FrameTreeData& frame_data,
std::string GetHeavyAdReportMessage(const ad_metrics::FrameTreeData& frame_data,
bool will_unload_adframe) {
const char kChromeStatusMessage[] =
"See https://www.chromestatus.com/feature/4800491902992384?utm_source=devtools";
......@@ -136,19 +136,19 @@ std::string GetHeavyAdReportMessage(const FrameTreeData& frame_data,
will_unload_adframe ? kInterventionMessage : kReportingOnlyMessage;
switch (frame_data.heavy_ad_status_with_noise()) {
case FrameData::HeavyAdStatus::kNetwork:
case ad_metrics::HeavyAdStatus::kNetwork:
return base::StrCat({intervention_mode,
" because its network usage exceeded the limit. ",
kChromeStatusMessage});
case FrameData::HeavyAdStatus::kTotalCpu:
case ad_metrics::HeavyAdStatus::kTotalCpu:
return base::StrCat({intervention_mode,
" because its total CPU usage exceeded the limit. ",
kChromeStatusMessage});
case FrameData::HeavyAdStatus::kPeakCpu:
case ad_metrics::HeavyAdStatus::kPeakCpu:
return base::StrCat({intervention_mode,
" because its peak CPU usage exceeded the limit. ",
kChromeStatusMessage});
case FrameData::HeavyAdStatus::kNone:
case ad_metrics::HeavyAdStatus::kNone:
NOTREACHED();
return "";
}
......@@ -165,15 +165,15 @@ using ResourceMimeType = AdsPageLoadMetricsObserver::ResourceMimeType;
const char kIgnoredByReloadHistogramName[] =
"PageLoad.Clients.Ads.HeavyAds.IgnoredByReload";
blink::mojom::HeavyAdReason GetHeavyAdReason(FrameData::HeavyAdStatus status) {
blink::mojom::HeavyAdReason GetHeavyAdReason(ad_metrics::HeavyAdStatus status) {
switch (status) {
case FrameData::HeavyAdStatus::kNetwork:
case ad_metrics::HeavyAdStatus::kNetwork:
return blink::mojom::HeavyAdReason::kNetworkTotalLimit;
case FrameData::HeavyAdStatus::kTotalCpu:
case ad_metrics::HeavyAdStatus::kTotalCpu:
return blink::mojom::HeavyAdReason::kCpuTotalLimit;
case FrameData::HeavyAdStatus::kPeakCpu:
case ad_metrics::HeavyAdStatus::kPeakCpu:
return blink::mojom::HeavyAdReason::kCpuPeakLimit;
case FrameData::HeavyAdStatus::kNone:
case ad_metrics::HeavyAdStatus::kNone:
NOTREACHED();
return blink::mojom::HeavyAdReason::kNetworkTotalLimit;
}
......@@ -218,7 +218,7 @@ AdsPageLoadMetricsObserver::FrameInstance::FrameInstance(
AdsPageLoadMetricsObserver::FrameInstance::~FrameInstance() = default;
FrameTreeData* AdsPageLoadMetricsObserver::FrameInstance::Get() {
ad_metrics::FrameTreeData* AdsPageLoadMetricsObserver::FrameInstance::Get() {
if (owned_frame_data_)
return owned_frame_data_.get();
if (unowned_frame_data_)
......@@ -228,7 +228,8 @@ FrameTreeData* AdsPageLoadMetricsObserver::FrameInstance::Get() {
return nullptr;
}
FrameTreeData* AdsPageLoadMetricsObserver::FrameInstance::GetOwnedFrame() {
ad_metrics::FrameTreeData*
AdsPageLoadMetricsObserver::FrameInstance::GetOwnedFrame() {
if (owned_frame_data_)
return owned_frame_data_.get();
return nullptr;
......@@ -275,9 +276,6 @@ AdsPageLoadMetricsObserver::OnStart(
// filtering isn't enabled.
if (observer_manager)
subresource_observer_.Add(observer_manager);
main_frame_data_ =
std::make_unique<FrameTreeData>(navigation_handle->GetFrameTreeNodeId(),
0 /* heavy_ad_network_threshold_noise */);
aggregate_frame_data_ = std::make_unique<AggregateFrameData>();
return CONTINUE_OBSERVING;
}
......@@ -291,9 +289,6 @@ AdsPageLoadMetricsObserver::OnCommit(
page_load_is_reload_ =
navigation_handle->GetReloadType() != content::ReloadType::NONE;
main_frame_data_->UpdateForNavigation(navigation_handle->GetRenderFrameHost(),
true /* frame_navigated */);
// The main frame is never considered an ad, so it should reference an empty
// FrameInstance.
ad_frames_data_.emplace(
......@@ -331,12 +326,12 @@ void AdsPageLoadMetricsObserver::OnTimingUpdate(
// If this is the earliest FCP for any frame in the root ad frame's subtree,
// set Creative Origin Status.
if (has_new_fcp) {
FrameData::OriginStatus origin_status =
ad_metrics::OriginStatus origin_status =
AdsPageLoadMetricsObserver::IsSubframeSameOriginToMainFrame(
subframe_rfh,
!ancestor_data->frame_navigated() /* use_parent_origin */)
? FrameData::OriginStatus::kSame
: FrameData::OriginStatus::kCross;
? ad_metrics::OriginStatus::kSame
: ad_metrics::OriginStatus::kCross;
ancestor_data->set_creative_origin_status(origin_status);
}
}
......@@ -350,19 +345,17 @@ void AdsPageLoadMetricsObserver::OnCpuTimingUpdate(
// Get the current time, considered to be when this update occurred.
base::TimeTicks current_time = clock_->NowTicks();
aggregate_frame_data_->UpdateCpuUsage(current_time, timing.task_time);
FrameTreeData* ancestor_data =
FindFrameData(subframe_rfh->GetFrameTreeNodeId());
aggregate_frame_data_->UpdateCpuUsage(current_time, timing.task_time,
ancestor_data);
if (ancestor_data) {
ancestor_data->UpdateCpuUsage(current_time, timing.task_time);
MaybeTriggerHeavyAdIntervention(subframe_rfh, ancestor_data);
} else {
aggregate_frame_data_->UpdateNonAdCpuUsage(current_time, timing.task_time);
}
}
// Given an ad being triggered for a frame or navigation, get its FrameData
// Given an ad being triggered for a frame or navigation, get its FrameTreeData
// and record it into the appropriate data structures.
void AdsPageLoadMetricsObserver::UpdateAdFrameData(
FrameTreeNodeId ad_id,
......@@ -448,8 +441,8 @@ void AdsPageLoadMetricsObserver::UpdateAdFrameData(
memory_request_->AddObserver(this);
}
// Construct a new FrameData to track this ad frame, and update it for the
// navigation.
// Construct a new FrameTreeData to track this ad frame, and update it for
// the navigation.
auto frame_data = std::make_unique<FrameTreeData>(
ad_id,
heavy_ad_threshold_noise_provider_->GetNetworkThresholdNoiseForFrame());
......@@ -474,8 +467,7 @@ void AdsPageLoadMetricsObserver::UpdateAdFrameData(
// frames navigation has been observed.
FrameInstance frame_instance;
if (ad_data)
frame_instance =
FrameInstance(FrameData::StaticAsWeakPtr<FrameTreeData>(ad_data));
frame_instance = FrameInstance(ad_data->AsWeakPtr());
ad_frames_data_[ad_id] = std::move(frame_instance);
}
......@@ -629,13 +621,10 @@ void AdsPageLoadMetricsObserver::FrameSizeChanged(
void AdsPageLoadMetricsObserver::MediaStartedPlaying(
const content::WebContentsObserver::MediaPlayerInfo& video_type,
content::RenderFrameHost* render_frame_host) {
if (render_frame_host == GetDelegate().GetWebContents()->GetMainFrame())
main_frame_data_->set_media_status(FrameData::MediaStatus::kPlayed);
FrameTreeData* ancestor_data =
FindFrameData(render_frame_host->GetFrameTreeNodeId());
if (ancestor_data)
ancestor_data->set_media_status(FrameData::MediaStatus::kPlayed);
ancestor_data->set_media_status(ad_metrics::MediaStatus::kPlayed);
}
void AdsPageLoadMetricsObserver::OnFrameIntersectionUpdate(
......@@ -749,12 +738,13 @@ void AdsPageLoadMetricsObserver::OnV8MemoryMeasurementAvailable(
FrameTreeData* ad_frame_data = FindFrameData(frame_node_id);
if (ad_frame_data) {
int64_t delta =
ad_frame_data->UpdateMemoryUsage(frame_node_id, bytes_used);
int64_t delta = UpdateMemoryUsageForFrame(frame_node_id, bytes_used);
ad_frame_data->UpdateMemoryUsage(delta);
UpdateAggregateMemoryUsage(delta, ad_frame_data->visibility());
} else if (!rfh->GetParent()) {
// |rfh| is the main frame.
main_frame_data_->UpdateMemoryUsage(frame_node_id, bytes_used);
int64_t delta = UpdateMemoryUsageForFrame(frame_node_id, bytes_used);
aggregate_frame_data_->update_main_frame_memory(delta);
}
}
}
......@@ -810,21 +800,44 @@ int AdsPageLoadMetricsObserver::GetUnaccountedAdBytes(
return is_new_ad ? resource->received_data_length - resource->delta_bytes : 0;
}
int64_t AdsPageLoadMetricsObserver::UpdateMemoryUsageForFrame(
FrameTreeNodeId frame_node_id,
uint64_t current_bytes) {
auto it = v8_current_memory_usage_map_.find(frame_node_id);
if (it == v8_current_memory_usage_map_.end()) {
v8_current_memory_usage_map_[frame_node_id] = current_bytes;
return current_bytes;
}
int64_t delta = current_bytes - it->second;
it->second = current_bytes;
return delta;
}
int64_t AdsPageLoadMetricsObserver::RemoveMemoryUsageForFrame(
FrameTreeNodeId frame_node_id) {
auto it = v8_current_memory_usage_map_.find(frame_node_id);
if (it == v8_current_memory_usage_map_.end())
return 0;
int64_t delta = -it->second;
v8_current_memory_usage_map_.erase(it);
return delta;
}
void AdsPageLoadMetricsObserver::ProcessResourceForPage(
int process_id,
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
auto mime_type = FrameData::GetResourceMimeType(resource);
auto mime_type =
ad_metrics::ResourceLoadAggregator::GetResourceMimeType(resource);
int unaccounted_ad_bytes = GetUnaccountedAdBytes(process_id, resource);
aggregate_frame_data_->ProcessResourceLoadInFrame(
resource, process_id, GetDelegate().GetResourceTracker());
bool is_main_frame = resource->is_main_frame_resource;
aggregate_frame_data_->ProcessResourceLoadInFrame(resource, is_main_frame);
if (unaccounted_ad_bytes)
aggregate_frame_data_->AdjustAdBytes(unaccounted_ad_bytes, mime_type);
if (resource->is_main_frame_resource) {
main_frame_data_->ProcessResourceLoadInFrame(
resource, process_id, GetDelegate().GetResourceTracker());
if (unaccounted_ad_bytes)
main_frame_data_->AdjustAdBytes(unaccounted_ad_bytes, mime_type);
}
aggregate_frame_data_->AdjustAdBytes(unaccounted_ad_bytes, mime_type,
is_main_frame);
}
void AdsPageLoadMetricsObserver::ProcessResourceForFrame(
......@@ -862,7 +875,8 @@ void AdsPageLoadMetricsObserver::ProcessResourceForFrame(
if (!ancestor_data)
return;
auto mime_type = FrameData::GetResourceMimeType(resource);
auto mime_type =
ad_metrics::ResourceLoadAggregator::GetResourceMimeType(resource);
int unaccounted_ad_bytes =
GetUnaccountedAdBytes(render_frame_host->GetProcess()->GetID(), resource);
if (unaccounted_ad_bytes)
......@@ -875,11 +889,13 @@ void AdsPageLoadMetricsObserver::ProcessResourceForFrame(
void AdsPageLoadMetricsObserver::RecordPageResourceTotalHistograms(
ukm::SourceId source_id) {
const auto& resource_data = aggregate_frame_data_->resource_data();
// Only records histograms on pages that have some ad bytes.
if (aggregate_frame_data_->ad_bytes() == 0)
if (resource_data.ad_bytes() == 0)
return;
PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Resources.Bytes.Ads2",
aggregate_frame_data_->ad_network_bytes());
resource_data.ad_network_bytes());
if (page_ad_density_tracker_.MaxPageAdDensityByArea() != -1) {
UMA_HISTOGRAM_PERCENTAGE("PageLoad.Clients.Ads.AdDensity.MaxPercentByArea",
......@@ -900,43 +916,41 @@ void AdsPageLoadMetricsObserver::RecordPageResourceTotalHistograms(
auto* ukm_recorder = ukm::UkmRecorder::Get();
ukm::builders::AdPageLoad builder(source_id);
builder.SetTotalBytes(aggregate_frame_data_->network_bytes() >> 10)
.SetAdBytes(aggregate_frame_data_->ad_network_bytes() >> 10)
.SetAdJavascriptBytes(aggregate_frame_data_->GetAdNetworkBytesForMime(
FrameData::ResourceMimeType::kJavascript) >>
builder.SetTotalBytes(resource_data.network_bytes() >> 10)
.SetAdBytes(resource_data.ad_network_bytes() >> 10)
.SetAdJavascriptBytes(resource_data.GetAdNetworkBytesForMime(
ad_metrics::ResourceMimeType::kJavascript) >>
10)
.SetAdVideoBytes(aggregate_frame_data_->GetAdNetworkBytesForMime(
FrameData::ResourceMimeType::kVideo) >>
.SetAdVideoBytes(resource_data.GetAdNetworkBytesForMime(
ad_metrics::ResourceMimeType::kVideo) >>
10)
.SetMainframeAdBytes(ukm::GetExponentialBucketMinForBytes(
main_frame_data_->ad_network_bytes()))
aggregate_frame_data_->main_frame_resource_data().ad_network_bytes()))
.SetMaxAdDensityByArea(page_ad_density_tracker_.MaxPageAdDensityByArea())
.SetMaxAdDensityByHeight(
page_ad_density_tracker_.MaxPageAdDensityByHeight());
// Record cpu metrics for the page.
builder.SetAdCpuTime(aggregate_frame_data_
->get_ad_data_by_visibility(
FrameData::FrameVisibility::kAnyVisibility)
.cpu_time.InMilliseconds());
builder.SetAdCpuTime(
aggregate_frame_data_->total_ad_cpu_usage().InMilliseconds());
builder.Record(ukm_recorder->Get());
}
void AdsPageLoadMetricsObserver::RecordHistograms(ukm::SourceId source_id) {
// Record per-frame metrics for any existing frames.
for (auto& id_and_instance : ad_frames_data_) {
// We only log metrics for FrameInstance which own a FrameData, otherwise we
// would be double counting frames.
// We only log metrics for FrameInstance which own a FrameTreeData,
// otherwise we would be double counting frames.
if (FrameTreeData* frame_data = id_and_instance.second.GetOwnedFrame()) {
RecordPerFrameMetrics(*frame_data, source_id);
}
}
RecordAggregateHistogramsForAdTagging(
FrameData::FrameVisibility::kNonVisible);
RecordAggregateHistogramsForAdTagging(FrameData::FrameVisibility::kVisible);
ad_metrics::FrameVisibility::kNonVisible);
RecordAggregateHistogramsForAdTagging(ad_metrics::FrameVisibility::kVisible);
RecordAggregateHistogramsForAdTagging(
FrameData::FrameVisibility::kAnyVisibility);
ad_metrics::FrameVisibility::kAnyVisibility);
RecordAggregateHistogramsForCpuUsage();
RecordAggregateHistogramsForHeavyAds();
RecordPageResourceTotalHistograms(source_id);
......@@ -946,40 +960,40 @@ void AdsPageLoadMetricsObserver::RecordAggregateHistogramsForCpuUsage() {
// If the page has an ad with the relevant visibility and non-zero bytes.
if (aggregate_frame_data_
->get_ad_data_by_visibility(
FrameData::FrameVisibility::kAnyVisibility)
ad_metrics::FrameVisibility::kAnyVisibility)
.frames == 0) {
return;
}
// Only record cpu usage aggregate data for the AnyVisibility suffix as these
// numbers do not change for different visibility types.
FrameData::FrameVisibility visibility =
FrameData::FrameVisibility::kAnyVisibility;
const auto& visibility_data =
aggregate_frame_data_->get_ad_data_by_visibility(visibility);
ad_metrics::FrameVisibility visibility =
ad_metrics::FrameVisibility::kAnyVisibility;
// Record the aggregate data, which is never considered activated.
// TODO(crbug/1109754): Does it make sense to include an aggregate peak
// windowed percent? Obviously this would be a max of maxes, but might be
// useful to have that for comparisons as well.
ADS_HISTOGRAM("Cpu.AdFrames.Aggregate.TotalUsage2", PAGE_LOAD_HISTOGRAM,
visibility, visibility_data.cpu_time);
ADS_HISTOGRAM(
"Cpu.NonAdFrames.Aggregate.TotalUsage2", PAGE_LOAD_HISTOGRAM, visibility,
aggregate_frame_data_->GetTotalCpuUsage() - visibility_data.cpu_time);
visibility, aggregate_frame_data_->total_ad_cpu_usage());
ADS_HISTOGRAM("Cpu.NonAdFrames.Aggregate.TotalUsage2", PAGE_LOAD_HISTOGRAM,
visibility,
aggregate_frame_data_->total_cpu_usage() -
aggregate_frame_data_->total_ad_cpu_usage());
ADS_HISTOGRAM("Cpu.NonAdFrames.Aggregate.PeakWindowedPercent2",
UMA_HISTOGRAM_PERCENTAGE, visibility,
aggregate_frame_data_->peak_windowed_non_ad_cpu_percent());
ADS_HISTOGRAM("Cpu.FullPage.TotalUsage2", PAGE_LOAD_HISTOGRAM, visibility,
aggregate_frame_data_->GetTotalCpuUsage());
aggregate_frame_data_->total_cpu_usage());
ADS_HISTOGRAM("Cpu.FullPage.PeakWindowedPercent2", UMA_HISTOGRAM_PERCENTAGE,
visibility, aggregate_frame_data_->peak_windowed_cpu_percent());
}
void AdsPageLoadMetricsObserver::RecordAggregateHistogramsForAdTagging(
FrameData::FrameVisibility visibility) {
if (aggregate_frame_data_->bytes() == 0)
ad_metrics::FrameVisibility visibility) {
const auto& resource_data = aggregate_frame_data_->resource_data();
if (resource_data.bytes() == 0)
return;
const auto& visibility_data =
......@@ -990,21 +1004,19 @@ void AdsPageLoadMetricsObserver::RecordAggregateHistogramsForAdTagging(
// Only record AllPages histograms for the AnyVisibility suffix as these
// numbers do not change for different visibility types.
if (visibility == FrameData::FrameVisibility::kAnyVisibility) {
if (visibility == ad_metrics::FrameVisibility::kAnyVisibility) {
ADS_HISTOGRAM("AllPages.PercentTotalBytesAds", UMA_HISTOGRAM_PERCENTAGE,
visibility,
aggregate_frame_data_->ad_bytes() * 100 /
aggregate_frame_data_->bytes());
if (aggregate_frame_data_->network_bytes()) {
resource_data.ad_bytes() * 100 / resource_data.bytes());
if (resource_data.network_bytes()) {
ADS_HISTOGRAM("AllPages.PercentNetworkBytesAds", UMA_HISTOGRAM_PERCENTAGE,
visibility,
aggregate_frame_data_->ad_network_bytes() * 100 /
aggregate_frame_data_->network_bytes());
resource_data.ad_network_bytes() * 100 /
resource_data.network_bytes());
}
ADS_HISTOGRAM("AllPages.NonAdNetworkBytes", PAGE_BYTES_HISTOGRAM,
visibility,
aggregate_frame_data_->network_bytes() -
aggregate_frame_data_->ad_network_bytes());
ADS_HISTOGRAM(
"AllPages.NonAdNetworkBytes", PAGE_BYTES_HISTOGRAM, visibility,
resource_data.network_bytes() - resource_data.ad_network_bytes());
}
// Only post AllPages and FrameCounts UMAs for pages that don't have ads.
......@@ -1012,24 +1024,23 @@ void AdsPageLoadMetricsObserver::RecordAggregateHistogramsForAdTagging(
return;
ADS_HISTOGRAM("Bytes.NonAdFrames.Aggregate.Total2", PAGE_BYTES_HISTOGRAM,
visibility,
aggregate_frame_data_->bytes() - visibility_data.bytes);
visibility, resource_data.bytes() - visibility_data.bytes);
ADS_HISTOGRAM("Bytes.FullPage.Total2", PAGE_BYTES_HISTOGRAM, visibility,
aggregate_frame_data_->bytes());
resource_data.bytes());
ADS_HISTOGRAM("Bytes.FullPage.Network", PAGE_BYTES_HISTOGRAM, visibility,
aggregate_frame_data_->network_bytes());
resource_data.network_bytes());
if (aggregate_frame_data_->bytes()) {
if (resource_data.bytes()) {
ADS_HISTOGRAM("Bytes.FullPage.Total2.PercentAdFrames",
UMA_HISTOGRAM_PERCENTAGE, visibility,
visibility_data.bytes * 100 / aggregate_frame_data_->bytes());
visibility_data.bytes * 100 / resource_data.bytes());
}
if (aggregate_frame_data_->network_bytes()) {
ADS_HISTOGRAM("Bytes.FullPage.Network.PercentAdFrames",
UMA_HISTOGRAM_PERCENTAGE, visibility,
visibility_data.network_bytes * 100 /
aggregate_frame_data_->network_bytes());
if (resource_data.network_bytes()) {
ADS_HISTOGRAM(
"Bytes.FullPage.Network.PercentAdFrames", UMA_HISTOGRAM_PERCENTAGE,
visibility,
visibility_data.network_bytes * 100 / resource_data.network_bytes());
}
ADS_HISTOGRAM("Bytes.AdFrames.Aggregate.Total2", PAGE_BYTES_HISTOGRAM,
......@@ -1039,25 +1050,27 @@ void AdsPageLoadMetricsObserver::RecordAggregateHistogramsForAdTagging(
if (memory_request_) {
ADS_HISTOGRAM("Memory.Aggregate.Max", PAGE_BYTES_HISTOGRAM, visibility,
visibility_data.max_memory);
visibility_data.memory.max_bytes_used());
}
// Only record same origin and main frame totals for the AnyVisibility suffix
// as these numbers do not change for different visibility types.
if (visibility != FrameData::FrameVisibility::kAnyVisibility)
if (visibility != ad_metrics::FrameVisibility::kAnyVisibility)
return;
const auto& main_frame_resource_data =
aggregate_frame_data_->main_frame_resource_data();
ADS_HISTOGRAM("Bytes.MainFrame.Network", PAGE_BYTES_HISTOGRAM, visibility,
main_frame_data_->network_bytes());
main_frame_resource_data.network_bytes());
ADS_HISTOGRAM("Bytes.MainFrame.Total2", PAGE_BYTES_HISTOGRAM, visibility,
main_frame_data_->bytes());
main_frame_resource_data.bytes());
ADS_HISTOGRAM("Bytes.MainFrame.Ads.Network", PAGE_BYTES_HISTOGRAM, visibility,
main_frame_data_->ad_network_bytes());
main_frame_resource_data.ad_network_bytes());
ADS_HISTOGRAM("Bytes.MainFrame.Ads.Total2", PAGE_BYTES_HISTOGRAM, visibility,
main_frame_data_->ad_bytes());
main_frame_resource_data.ad_bytes());
if (memory_request_) {
PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Memory.MainFrame.Max",
main_frame_data_->v8_max_memory_bytes_used());
aggregate_frame_data_->main_frame_max_memory());
UMA_HISTOGRAM_COUNTS_10000("PageLoad.Clients.Ads.Memory.UpdateCount",
num_memory_updates_);
UMA_HISTOGRAM_COUNTS_1000(
......@@ -1090,15 +1103,13 @@ void AdsPageLoadMetricsObserver::RecordPerFrameMetrics(
void AdsPageLoadMetricsObserver::RecordPerFrameHistogramsForCpuUsage(
const FrameTreeData& ad_frame_data) {
// This aggregate gets reported regardless of whether the frame used bytes.
aggregate_frame_data_->update_ad_cpu_time_by_visibility(
FrameData::FrameVisibility::kAnyVisibility,
ad_frame_data.GetTotalCpuUsage());
aggregate_frame_data_->update_ad_cpu_usage(ad_frame_data.GetTotalCpuUsage());
if (!ad_frame_data.ShouldRecordFrameForMetrics())
return;
// Record per-frame histograms to the appropriate visibility prefixes.
for (const auto visibility : {FrameData::FrameVisibility::kAnyVisibility,
for (const auto visibility : {ad_metrics::FrameVisibility::kAnyVisibility,
ad_frame_data.visibility()}) {
// Report the peak windowed usage, which is independent of activation status
// (measured only for the unactivated period).
......@@ -1107,15 +1118,15 @@ void AdsPageLoadMetricsObserver::RecordPerFrameHistogramsForCpuUsage(
ad_frame_data.peak_windowed_cpu_percent());
if (ad_frame_data.user_activation_status() ==
FrameData::UserActivationStatus::kNoActivation) {
ad_metrics::UserActivationStatus::kNoActivation) {
ADS_HISTOGRAM("Cpu.AdFrames.PerFrame.TotalUsage2.Unactivated",
PAGE_LOAD_HISTOGRAM, visibility,
ad_frame_data.GetTotalCpuUsage());
} else {
base::TimeDelta task_duration_pre = ad_frame_data.GetActivationCpuUsage(
FrameData::UserActivationStatus::kNoActivation);
ad_metrics::UserActivationStatus::kNoActivation);
base::TimeDelta task_duration_post = ad_frame_data.GetActivationCpuUsage(
FrameData::UserActivationStatus::kReceivedActivation);
ad_metrics::UserActivationStatus::kReceivedActivation);
base::TimeDelta task_duration_total =
task_duration_pre + task_duration_post;
ADS_HISTOGRAM("Cpu.AdFrames.PerFrame.TotalUsage2.Activated",
......@@ -1137,19 +1148,21 @@ void AdsPageLoadMetricsObserver::RecordPerFrameHistogramsForAdTagging(
RecordAdFrameIgnoredByRestrictedAdTagging(false /*ignored */);
// Record per-frame histograms to the appropriate visibility prefixes.
for (const auto visibility : {FrameData::FrameVisibility::kAnyVisibility,
for (const auto visibility : {ad_metrics::FrameVisibility::kAnyVisibility,
ad_frame_data.visibility()}) {
const auto& resource_data = ad_frame_data.resource_data();
// Update aggregate ad information.
aggregate_frame_data_->update_ad_bytes_by_visibility(visibility,
ad_frame_data.bytes());
resource_data.bytes());
aggregate_frame_data_->update_ad_network_bytes_by_visibility(
visibility, ad_frame_data.network_bytes());
visibility, resource_data.network_bytes());
aggregate_frame_data_->update_ad_frames_by_visibility(visibility, 1);
ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Total2", PAGE_BYTES_HISTOGRAM,
visibility, ad_frame_data.bytes());
visibility, resource_data.bytes());
ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Network", PAGE_BYTES_HISTOGRAM,
visibility, ad_frame_data.network_bytes());
visibility, resource_data.network_bytes());
if (memory_request_) {
ADS_HISTOGRAM("Memory.PerFrame.Max", PAGE_BYTES_HISTOGRAM, visibility,
ad_frame_data.v8_max_memory_bytes_used());
......@@ -1186,7 +1199,7 @@ void AdsPageLoadMetricsObserver::RecordPerFrameHistogramsForHeavyAds(
return;
// Record per-frame histograms to the appropriate visibility prefixes.
for (const auto visibility : {FrameData::FrameVisibility::kAnyVisibility,
for (const auto visibility : {ad_metrics::FrameVisibility::kAnyVisibility,
ad_frame_data.visibility()}) {
ADS_HISTOGRAM("HeavyAds.ComputedType2", UMA_HISTOGRAM_ENUMERATION,
visibility, ad_frame_data.heavy_ad_status());
......@@ -1197,7 +1210,7 @@ void AdsPageLoadMetricsObserver::RecordPerFrameHistogramsForHeavyAds(
// Only record the following histograms if the frame was a heavy ad.
if (ad_frame_data.heavy_ad_status_with_noise() ==
FrameData::HeavyAdStatus::kNone)
ad_metrics::HeavyAdStatus::kNone)
return;
heavy_ad_on_page_ = true;
......@@ -1226,7 +1239,8 @@ void AdsPageLoadMetricsObserver::RecordAdFrameIgnoredByRestrictedAdTagging(
"PageLoad.Clients.Ads.FrameCounts.IgnoredByRestrictedAdTagging", ignored);
}
FrameTreeData* AdsPageLoadMetricsObserver::FindFrameData(FrameTreeNodeId id) {
ad_metrics::FrameTreeData* AdsPageLoadMetricsObserver::FindFrameData(
FrameTreeNodeId id) {
const auto& id_and_data = ad_frames_data_.find(id);
if (id_and_data == ad_frames_data_.end())
return nullptr;
......@@ -1238,9 +1252,9 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
content::RenderFrameHost* render_frame_host,
FrameTreeData* frame_data) {
DCHECK(render_frame_host);
FrameData::HeavyAdAction action =
ad_metrics::HeavyAdAction action =
frame_data->MaybeTriggerHeavyAdIntervention();
if (action == FrameData::HeavyAdAction::kNone)
if (action == ad_metrics::HeavyAdAction::kNone)
return;
// Don't trigger the heavy ad intervention on reloads. Gate this behind the
......@@ -1251,14 +1265,14 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
// Skip firing the intervention, but mark that an action occurred on the
// frame.
if (page_load_is_reload_) {
frame_data->set_heavy_ad_action(FrameData::HeavyAdAction::kIgnored);
frame_data->set_heavy_ad_action(ad_metrics::HeavyAdAction::kIgnored);
return;
}
}
// Check to see if we are allowed to activate on this host.
if (IsBlocklisted()) {
frame_data->set_heavy_ad_action(FrameData::HeavyAdAction::kIgnored);
frame_data->set_heavy_ad_action(ad_metrics::HeavyAdAction::kIgnored);
return;
}
......@@ -1277,7 +1291,7 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
render_frame_host = render_frame_host->GetParent();
}
if (!render_frame_host) {
frame_data->set_heavy_ad_action(FrameData::HeavyAdAction::kIgnored);
frame_data->set_heavy_ad_action(ad_metrics::HeavyAdAction::kIgnored);
return;
}
......@@ -1288,7 +1302,7 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
// Add an inspector issue for the root of the ad subtree.
render_frame_host->ReportHeavyAdIssue(
action == FrameData::HeavyAdAction::kUnload
action == ad_metrics::HeavyAdAction::kUnload
? blink::mojom::HeavyAdResolutionStatus::kHeavyAdBlocked
: blink::mojom::HeavyAdResolutionStatus::kHeavyAdWarning,
GetHeavyAdReason(frame_data->heavy_ad_status_with_policy()));
......@@ -1301,7 +1315,7 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
// be available in the the unload handler.
const char kReportId[] = "HeavyAdIntervention";
std::string report_message = GetHeavyAdReportMessage(
*frame_data, action == FrameData::HeavyAdAction::kUnload);
*frame_data, action == ad_metrics::HeavyAdAction::kUnload);
for (content::RenderFrameHost* reporting_frame :
render_frame_host->GetFramesInSubtree()) {
reporting_frame->SendInterventionReport(kReportId, report_message);
......@@ -1321,20 +1335,21 @@ void AdsPageLoadMetricsObserver::MaybeTriggerHeavyAdIntervention(
blink::mojom::WebFeature::kHeavyAdIntervention);
ADS_HISTOGRAM("HeavyAds.InterventionType2", UMA_HISTOGRAM_ENUMERATION,
FrameData::FrameVisibility::kAnyVisibility,
ad_metrics::FrameVisibility::kAnyVisibility,
frame_data->heavy_ad_status_with_policy());
ADS_HISTOGRAM("HeavyAds.InterventionType2", UMA_HISTOGRAM_ENUMERATION,
frame_data->visibility(),
frame_data->heavy_ad_status_with_policy());
if (action != FrameData::HeavyAdAction::kUnload)
if (action != ad_metrics::HeavyAdAction::kUnload)
return;
// Record heavy ad network size only when an ad is unloaded as a result of
// network usage.
if (frame_data->heavy_ad_status() == FrameData::HeavyAdStatus::kNetwork) {
if (frame_data->heavy_ad_status() == ad_metrics::HeavyAdStatus::kNetwork) {
ADS_HISTOGRAM("HeavyAds.NetworkBytesAtFrameUnload", PAGE_BYTES_HISTOGRAM,
FrameData::kAnyVisibility, frame_data->network_bytes());
ad_metrics::kAnyVisibility,
frame_data->resource_data().network_bytes());
}
GetDelegate().GetWebContents()->GetController().LoadPostCommitErrorPage(
......@@ -1389,13 +1404,13 @@ HeavyAdBlocklist* AdsPageLoadMetricsObserver::GetHeavyAdBlocklist() {
void AdsPageLoadMetricsObserver::UpdateAggregateMemoryUsage(
int64_t delta_bytes,
FrameData::FrameVisibility frame_visibility) {
ad_metrics::FrameVisibility frame_visibility) {
// For both the given |frame_visibility| and kAnyVisibility, update the
// current aggregate memory usage by adding the needed delta, and then
// if the current aggregate usage is greater than the recorded
// max aggregate usage, update the max aggregate usage.
for (const auto visibility :
{FrameData::FrameVisibility::kAnyVisibility, frame_visibility}) {
{ad_metrics::FrameVisibility::kAnyVisibility, frame_visibility}) {
aggregate_frame_data_->update_ad_memory_by_visibility(visibility,
delta_bytes);
}
......@@ -1409,7 +1424,8 @@ void AdsPageLoadMetricsObserver::CleanupDeletedFrame(
if (!frame_data)
return;
int64_t delta_bytes = frame_data->OnFrameDeleted(id);
int64_t delta_bytes = RemoveMemoryUsageForFrame(id);
frame_data->UpdateMemoryUsage(delta_bytes);
UpdateAggregateMemoryUsage(delta_bytes, frame_data->visibility());
if (record_metrics)
......
......@@ -47,20 +47,9 @@ class AdsPageLoadMetricsObserver
public performance_manager::v8_memory::V8DetailedMemoryObserverAnySeq,
public subresource_filter::SubresourceFilterObserver {
public:
// Returns a new AdsPageLoadMetricsObserver. If the feature is disabled it
// returns nullptr.
static std::unique_ptr<AdsPageLoadMetricsObserver> CreateIfNeeded(
content::WebContents* web_contents);
// For a given subframe, returns whether or not the subframe's url would be
// considering same origin to the main frame's url. |use_parent_origin|
// indicates that the subframe's parent frames's origin should be used when
// performing the comparison.
static bool IsSubframeSameOriginToMainFrame(
content::RenderFrameHost* sub_host,
bool use_parent_origin);
using ResourceMimeType = FrameData::ResourceMimeType;
using AggregateFrameData = ad_metrics::AggregateFrameData;
using FrameTreeData = ad_metrics::FrameTreeData;
using ResourceMimeType = ad_metrics::ResourceMimeType;
// Helper class that generates a random amount of noise to apply to thresholds
// for heavy ads. A different noise should be generated for each frame.
......@@ -86,6 +75,19 @@ class AdsPageLoadMetricsObserver
const bool use_noise_;
};
// Returns a new AdsPageLoadMetricsObserver. If the feature is disabled it
// returns nullptr.
static std::unique_ptr<AdsPageLoadMetricsObserver> CreateIfNeeded(
content::WebContents* web_contents);
// For a given subframe, returns whether or not the subframe's url would be
// considering same origin to the main frame's url. |use_parent_origin|
// indicates that the subframe's parent frames's origin should be used when
// performing the comparison.
static bool IsSubframeSameOriginToMainFrame(
content::RenderFrameHost* sub_host,
bool use_parent_origin);
explicit AdsPageLoadMetricsObserver(base::TickClock* clock = nullptr,
HeavyAdBlocklist* blocklist = nullptr);
~AdsPageLoadMetricsObserver() override;
......@@ -141,7 +143,7 @@ class AdsPageLoadMetricsObserver
const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data) override;
void UpdateAggregateMemoryUsage(int64_t bytes,
FrameData::FrameVisibility visibility);
ad_metrics::FrameVisibility visibility);
void CleanupDeletedFrame(FrameTreeNodeId id,
FrameTreeData* frame_data,
......@@ -205,6 +207,14 @@ class AdsPageLoadMetricsObserver
int process_id,
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) const;
// Looks up the |frame_node_id| in the current memory usage map, updates it
// with the current bytes (or removes it), and returns the
// difference between the new value (0 if removed) and the old one, or the
// delta in the amount of memory the frame is using.
int64_t UpdateMemoryUsageForFrame(FrameTreeNodeId frame_node_id,
uint64_t current_bytes);
int64_t RemoveMemoryUsageForFrame(FrameTreeNodeId frame_node_id);
// Updates page level counters for resource loads.
void ProcessResourceForPage(
int process_id,
......@@ -217,7 +227,7 @@ class AdsPageLoadMetricsObserver
void RecordHistograms(ukm::SourceId source_id);
void RecordAggregateHistogramsForCpuUsage();
void RecordAggregateHistogramsForAdTagging(
FrameData::FrameVisibility visibility);
ad_metrics::FrameVisibility visibility);
void RecordAggregateHistogramsForHeavyAds();
// Should be called on all frames prior to recording any aggregate histograms.
......@@ -234,12 +244,12 @@ class AdsPageLoadMetricsObserver
// Records whether an ad frame was ignored by the Restricted Navigation
// AdTagging feature. For frames that are ignored, this is recorded when a
// FrameData object would have been created for them, or when their FrameData
// is deleted. For non-ignored frames, this is recorded when it is logged to
// metrics.
// FrameTreeData object would have been created for them, or when their
// FrameTreeData is deleted. For non-ignored frames, this is recorded when it
// is logged to metrics.
void RecordAdFrameIgnoredByRestrictedAdTagging(bool ignored);
// Find the FrameData object associated with a given FrameTreeNodeId in
// Find the FrameTreeData object associated with a given FrameTreeNodeId in
// |ad_frames_data_storage_|.
FrameTreeData* FindFrameData(FrameTreeNodeId id);
......@@ -255,8 +265,8 @@ class AdsPageLoadMetricsObserver
HeavyAdBlocklist* GetHeavyAdBlocklist();
// Maps a frame (by id) to the corresponding FrameInstance. Multiple frame ids
// can point to the same underlying FrameData. The responsible frame is the
// top-most frame labeled as an ad in the frame's ancestry, which may be
// can point to the same underlying FrameTreeData. The responsible frame is
// the top-most frame labeled as an ad in the frame's ancestry, which may be
// itself. If the frame is not an ad, the id will point to a FrameInstance
// where FrameInstance::Get() returns nullptr..
std::map<FrameTreeNodeId, FrameInstance> ad_frames_data_;
......@@ -270,8 +280,9 @@ class AdsPageLoadMetricsObserver
std::map<FrameTreeNodeId, page_load_metrics::mojom::ResourceDataUpdatePtr>
ongoing_navigation_resources_;
// Tracks byte counts only for resources loaded in the main frame.
std::unique_ptr<FrameTreeData> main_frame_data_;
// Per-frame memory usage by V8 in bytes. Memory data is stored for each frame
// on the page during the navigation.
std::unordered_map<FrameTreeNodeId, uint64_t> v8_current_memory_usage_map_;
// Tracks page-level information for the navigation.
std::unique_ptr<AggregateFrameData> aggregate_frame_data_;
......
......@@ -55,8 +55,8 @@
namespace {
using OriginStatus = FrameData::OriginStatus;
using OriginStatusWithThrottling = FrameData::OriginStatusWithThrottling;
using OriginStatus = ad_metrics::OriginStatus;
using OriginStatusWithThrottling = ad_metrics::OriginStatusWithThrottling;
using FrameTreeNodeId = int;
......@@ -239,7 +239,7 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
waiter->Wait();
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kSame, 1);
ad_metrics::OriginStatus::kSame, 1);
}
// Test that an empty embedded ad isn't reported at all.
......@@ -270,13 +270,13 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kSame, 1);
ad_metrics::OriginStatus::kSame, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_CrossOriginName,
static_cast<int>(FrameData::OriginStatus::kSame));
static_cast<int>(ad_metrics::OriginStatus::kSame));
}
// Test that an ad with a different origin as the main page is cross origin.
......@@ -303,13 +303,13 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
waiter->Wait();
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kCross, 1);
ad_metrics::OriginStatus::kCross, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_CrossOriginName,
static_cast<int>(FrameData::OriginStatus::kCross));
static_cast<int>(ad_metrics::OriginStatus::kCross));
}
// Verifies that the page ad density records the maximum value during
......@@ -675,8 +675,8 @@ class CreativeOriginAdsPageLoadMetricsObserverBrowserTest
void TestCreativeOriginStatus(
std::unique_ptr<Frame> main_frame,
FrameData::OriginStatus expected_status,
base::Optional<FrameData::OriginStatusWithThrottling>
ad_metrics::OriginStatus expected_status,
base::Optional<ad_metrics::OriginStatusWithThrottling>
expected_status_with_throttling) {
base::HistogramTester histogram_tester;
bool subframe_exists = main_frame->HasChild();
......@@ -742,8 +742,8 @@ IN_PROC_BROWSER_TEST_F(CreativeOriginAdsPageLoadMetricsObserverBrowserTest,
TestCreativeOriginStatus(
MakeFrame("a",
MakeFrame("a", MakeFrame("b", MakeFrame("c", nullptr), true))),
FrameData::OriginStatus::kCross,
FrameData::OriginStatusWithThrottling::kCrossAndUnthrottled);
ad_metrics::OriginStatus::kCross,
ad_metrics::OriginStatusWithThrottling::kCrossAndUnthrottled);
}
// Test that an ad creative with a different origin as the main page,
......@@ -854,10 +854,10 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectBucketCount(
kAdUserActivationHistogramId,
FrameData::UserActivationStatus::kReceivedActivation, 1);
ad_metrics::UserActivationStatus::kReceivedActivation, 1);
histogram_tester.ExpectBucketCount(
kAdUserActivationHistogramId,
FrameData::UserActivationStatus::kNoActivation, 1);
ad_metrics::UserActivationStatus::kNoActivation, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(2u, entries.size());
......@@ -1181,7 +1181,7 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_MediaName,
static_cast<int>(FrameData::MediaStatus::kNotPlayed));
static_cast<int>(ad_metrics::MediaStatus::kNotPlayed));
}
// Flaky on all platforms, http://crbug.com/972822.
......@@ -1221,7 +1221,7 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_MediaName,
static_cast<int>(FrameData::MediaStatus::kPlayed));
static_cast<int>(ad_metrics::MediaStatus::kPlayed));
}
IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
......@@ -1728,13 +1728,13 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
error_observer.WaitForNavigationFinished();
histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
// Check that the ad frame was navigated to the intervention page.
EXPECT_FALSE(error_observer.last_navigation_succeeded());
histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
histogram_tester.ExpectBucketCount(
"Blink.UseCounter.Features",
blink::mojom::WebFeature::kHeavyAdIntervention, 1);
......@@ -1859,13 +1859,13 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
error_observer.WaitForNavigationFinished();
histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
// Check that the ad frame was navigated to the intervention page.
EXPECT_FALSE(error_observer.last_navigation_succeeded());
histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
EXPECT_TRUE(ExecJs(
web_contents,
......@@ -1883,7 +1883,7 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
// Check that the intervention did not trigger on this frame.
histogram_tester.ExpectUniqueSample(kHeavyAdInterventionTypeHistogramId,
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
}
// Verifies that the blocklist is setup correctly and the intervention triggers
......@@ -2009,7 +2009,8 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
EXPECT_GE(elapsed_time.InMilliseconds(), 300);
// Ensure that there is a single entry that is at least the percent specified.
int min_percent = 100 * 300 / FrameData::kCpuWindowSize.InMilliseconds();
int min_percent =
100 * 300 / ad_metrics::PeakCpuAggregator::kWindowSize.InMilliseconds();
auto samples = histogram_tester.GetAllSamples(kPeakWindowdPercentHistogramId);
EXPECT_EQ(1u, samples.size());
EXPECT_EQ(1, samples.front().count);
......@@ -2045,7 +2046,8 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
// Ensure that there is a single entry that is at least the peak windowed
// percent of 400ms.
int min_percent = 100 * 400 / FrameData::kCpuWindowSize.InMilliseconds();
int min_percent =
100 * 400 / ad_metrics::PeakCpuAggregator::kWindowSize.InMilliseconds();
auto samples = histogram_tester.GetAllSamples(kPeakWindowdPercentHistogramId);
EXPECT_EQ(1u, samples.size());
EXPECT_EQ(1, samples.front().count);
......@@ -2127,7 +2129,8 @@ IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
// Ensure that there is a single entry that is at least the peak windowed
// percent of 400ms.
int min_percent = 100 * 300 / FrameData::kCpuWindowSize.InMilliseconds();
int min_percent =
100 * 300 / ad_metrics::PeakCpuAggregator::kWindowSize.InMilliseconds();
auto samples = histogram_tester.GetAllSamples(kPeakWindowdPercentHistogramId);
EXPECT_EQ(1u, samples.size());
EXPECT_EQ(1, samples.front().count);
......
......@@ -94,7 +94,7 @@ struct ExpectedFrameBytes {
struct CreativeOriginTest {
std::vector<std::string> urls;
size_t creative_index;
FrameData::OriginStatus expected_origin_status;
ad_metrics::OriginStatus expected_origin_status;
};
struct CreativeOriginTestWithThrottling {
......@@ -103,7 +103,7 @@ struct CreativeOriginTestWithThrottling {
std::vector<bool> throttled;
size_t creative_index;
bool should_paint;
FrameData::OriginStatusWithThrottling expected_origin_status;
ad_metrics::OriginStatusWithThrottling expected_origin_status;
};
enum class ResourceCached { kNotCached = 0, kCachedHttp, kCachedMemory };
......@@ -648,9 +648,9 @@ class AdsPageLoadMetricsObserverTest
ResourceDataUpdate(current_frame, ResourceCached::kNotCached, 10);
}
// In order to test that |creative_origin_status_| in FrameData is properly
// computed, we need to simulate first contentful paint for the ad creative
// first at |kCreativeFCPTime|.
// In order to test that |creative_origin_status_| in FrameTreeData is
// properly computed, we need to simulate first contentful paint for the ad
// creative first at |kCreativeFCPTime|.
base::TimeDelta eligible_time = kCreativeEligibleToPaintTime;
base::TimeDelta fcp_time = kCreativeFCPTime;
SimulateFirstEligibleToPaintOrFirstContentfulPaint(
......@@ -685,7 +685,7 @@ class AdsPageLoadMetricsObserverTest
// a vector of booleans to denote whether the corresponding frame in |urls|
// is to be throttled, and a single bool indicating whether or not to simulate
// any first contentful paints, so that the case
// FrameData::OriginStatusWithThrottling::kUnknownAndUnthrottled
// OriginStatusWithThrottling::kUnknownAndUnthrottled
// can be tested.
void TestCreativeOriginStatusWithThrottling(
const CreativeOriginTestWithThrottling& creative_origin_test) {
......@@ -724,7 +724,7 @@ class AdsPageLoadMetricsObserverTest
}
// In order to test that |creative_origin_status_| and
// |first_eligible_to_paint_| in FrameData are properly
// |first_eligible_to_paint_| in FrameTreeData are properly
// computed, we need to simulate eligibility to paint and first
// contentful paint for the ad creative, unless it is render-throttled,
// and then do similarly for the other subframes.
......@@ -1028,13 +1028,13 @@ TEST_F(AdsPageLoadMetricsObserverTest, AdsOriginStatusMetrics) {
// Trigger histograms by navigating away, then test them.
NavigateFrame(kAdUrl, main_frame);
histograms.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kCross, 1);
ad_metrics::OriginStatus::kCross, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_CrossOriginName,
static_cast<int64_t>(FrameData::OriginStatus::kCross));
static_cast<int64_t>(ad_metrics::OriginStatus::kCross));
}
// Add a non-ad subframe and an ad subframe and make sure the total count
......@@ -1051,13 +1051,13 @@ TEST_F(AdsPageLoadMetricsObserverTest, AdsOriginStatusMetrics) {
// Trigger histograms by navigating away, then test them.
NavigateFrame(kAdUrl, main_frame);
histograms.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kCross, 1);
ad_metrics::OriginStatus::kCross, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_CrossOriginName,
static_cast<int64_t>(FrameData::OriginStatus::kCross));
static_cast<int64_t>(ad_metrics::OriginStatus::kCross));
}
// Add an ad subframe in the same origin as the parent frame and make sure it
......@@ -1073,13 +1073,13 @@ TEST_F(AdsPageLoadMetricsObserverTest, AdsOriginStatusMetrics) {
// Trigger histograms by navigating away, then test them.
NavigateFrame(kAdUrl, main_frame);
histograms.ExpectUniqueSample(kCrossOriginHistogramId,
FrameData::OriginStatus::kSame, 1);
ad_metrics::OriginStatus::kSame, 1);
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
EXPECT_EQ(1u, entries.size());
ukm_recorder.ExpectEntryMetric(
entries.front(), ukm::builders::AdFrameLoad::kStatus_CrossOriginName,
static_cast<int64_t>(FrameData::OriginStatus::kSame));
static_cast<int64_t>(ad_metrics::OriginStatus::kSame));
}
}
......@@ -1806,7 +1806,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, TestCpuTimingMetricsOnActivation) {
// status of the frame in the ad frame tree that has its first contentful paint
// occur first.
TEST_F(AdsPageLoadMetricsObserverTest, CreativeOriginStatus) {
using OriginStatus = FrameData::OriginStatus;
using OriginStatus = ad_metrics::OriginStatus;
// Each CreativeOriginTest struct lists the urls of the frames in the frame
// tree, from main frame to leaf ad frame, along with the index of the ad
......@@ -1853,7 +1853,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, CreativeOriginStatus) {
// first contentful paint occur first, with throttling status determined by
// whether or not at least one frame in the ad frame tree was unthrottled.
TEST_F(AdsPageLoadMetricsObserverTest, CreativeOriginStatusWithThrottling) {
using OriginStatusWithThrottling = FrameData::OriginStatusWithThrottling;
using OriginStatusWithThrottling = ad_metrics::OriginStatusWithThrottling;
// Each CreativeOriginTestWithThrottling struct lists the urls of the frames
// in the frame tree, from main frame to leaf ad frame, and a corresponding
......@@ -2040,35 +2040,32 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdFeatureOff_UMARecorded) {
// Navigate again to trigger histograms.
NavigateFrame(kNonAdUrl, main_frame);
using HeavyAdStatus = ad_metrics::HeavyAdStatus;
histogram_tester().ExpectTotalCount(
SuffixedHistogram("HeavyAds.ComputedType2"), 4);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kNone, 1);
SuffixedHistogram("HeavyAds.ComputedType2"), HeavyAdStatus::kNone, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
SuffixedHistogram("HeavyAds.ComputedType2"), HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kPeakCpu, 1);
SuffixedHistogram("HeavyAds.ComputedType2"), HeavyAdStatus::kPeakCpu, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kTotalCpu, 1);
SuffixedHistogram("HeavyAds.ComputedType2"), HeavyAdStatus::kTotalCpu, 1);
histogram_tester().ExpectTotalCount(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"), 4);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kNone, 1);
HeavyAdStatus::kNone, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kNetwork, 1);
HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kPeakCpu, 1);
HeavyAdStatus::kPeakCpu, 1);
histogram_tester().ExpectBucketCount(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kTotalCpu, 1);
HeavyAdStatus::kTotalCpu, 1);
histogram_tester().ExpectTotalCount(
SuffixedHistogram("HeavyAds.InterventionType2"), 0);
......@@ -2119,7 +2116,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdNetworkUsage_InterventionFired) {
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kNetworkTotal),
1);
......@@ -2266,7 +2263,7 @@ TEST_F(AdsPageLoadMetricsObserverTest,
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kNetworkTotal),
1);
......@@ -2308,10 +2305,10 @@ TEST_F(AdsPageLoadMetricsObserverTest,
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kNone, 1);
ad_metrics::HeavyAdStatus::kNone, 1);
}
TEST_F(AdsPageLoadMetricsObserverTest,
......@@ -2350,7 +2347,7 @@ TEST_F(AdsPageLoadMetricsObserverTest,
EXPECT_TRUE(HasInterventionReportsAfterFlush(ad_frame));
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kTotalCpu, 1);
ad_metrics::HeavyAdStatus::kTotalCpu, 1);
EXPECT_EQ(kReportOnlyMessage, PopLastInterventionReportMessage());
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kCpuTotal),
......@@ -2364,10 +2361,10 @@ TEST_F(AdsPageLoadMetricsObserverTest,
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kTotalCpu, 1);
ad_metrics::HeavyAdStatus::kTotalCpu, 1);
}
TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdTotalCpuUsage_InterventionFired) {
......@@ -2402,7 +2399,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdTotalCpuUsage_InterventionFired) {
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kTotalCpu, 1);
ad_metrics::HeavyAdStatus::kTotalCpu, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kCpuTotal),
1);
......@@ -2442,7 +2439,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdPeakCpuUsage_InterventionFired) {
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kPeakCpu, 1);
ad_metrics::HeavyAdStatus::kPeakCpu, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kCpuPeak),
1);
......@@ -2497,14 +2494,14 @@ TEST_F(AdsPageLoadMetricsObserverTest,
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedType2"),
FrameData::HeavyAdStatus::kNone, 1);
ad_metrics::HeavyAdStatus::kNone, 1);
}
// Tests that each configurable unload policy allows the intervention to trigger
// on the correct frames.
TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdPolicyProvided) {
struct {
// |policy| maps to a FrameData::HeavyAdUnloadPolicy.
// |policy| maps to a HeavyAdUnloadPolicy.
std::string policy;
bool exceed_network;
bool exceed_cpu;
......@@ -2627,7 +2624,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdPageReload_MetricsRecorded) {
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.ComputedTypeWithThresholdNoise"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.UserDidReload"), true, 1);
}
......@@ -2753,7 +2750,7 @@ TEST_F(AdsPageLoadMetricsObserverTest,
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kNetworkTotal),
1);
......@@ -2790,7 +2787,7 @@ TEST_F(AdsPageLoadMetricsObserverTest, HeavyAdBlocklist_InterventionReported) {
waiter.WaitForError();
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.DisallowedByBlocklist"), false, 1);
......@@ -2839,7 +2836,7 @@ TEST_F(AdsPageLoadMetricsObserverTest,
EXPECT_FALSE(waiter.LastPageWasErrorPage());
histogram_tester().ExpectUniqueSample(
SuffixedHistogram("HeavyAds.InterventionType2"),
FrameData::HeavyAdStatus::kNetwork, 1);
ad_metrics::HeavyAdStatus::kNetwork, 1);
EXPECT_EQ(rfh_tester->GetHeavyAdIssueCount(
RenderFrameHostTester::HeavyAdIssueType::kNetworkTotal),
1);
......
......@@ -23,9 +23,6 @@
namespace {
using OriginStatus = FrameData::OriginStatus;
using OriginStatusWithThrottling = FrameData::OriginStatusWithThrottling;
// A frame with area less than kMinimumVisibleFrameArea is not considered
// visible.
const int kMinimumVisibleFrameArea = 25;
......@@ -33,15 +30,17 @@ const int kMinimumVisibleFrameArea = 25;
// Controls what types of heavy ads will be unloaded by the intervention.
const base::FeatureParam<int> kHeavyAdUnloadPolicyParam = {
&features::kHeavyAdIntervention, "kUnloadPolicy",
static_cast<int>(FrameData::HeavyAdUnloadPolicy::kAll)};
static_cast<int>(ad_metrics::HeavyAdUnloadPolicy::kAll)};
} // namespace
// static
constexpr base::TimeDelta FrameData::kCpuWindowSize;
namespace ad_metrics {
ResourceLoadAggregator::ResourceLoadAggregator() = default;
ResourceLoadAggregator::~ResourceLoadAggregator() = default;
// static
FrameData::ResourceMimeType FrameData::GetResourceMimeType(
ResourceMimeType ResourceLoadAggregator::GetResourceMimeType(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
if (blink::IsSupportedImageMimeType(resource->mime_type))
return ResourceMimeType::kImage;
......@@ -64,13 +63,8 @@ FrameData::ResourceMimeType FrameData::GetResourceMimeType(
return ResourceMimeType::kOther;
}
FrameData::FrameData() = default;
FrameData::~FrameData() = default;
void FrameData::ProcessResourceLoadInFrame(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
int process_id,
const page_load_metrics::ResourceTracker& resource_tracker) {
void ResourceLoadAggregator::ProcessResourceLoad(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
bytes_ += resource->delta_bytes;
network_bytes_ += resource->delta_bytes;
......@@ -93,63 +87,40 @@ void FrameData::ProcessResourceLoadInFrame(
}
}
void FrameData::AdjustAdBytes(int64_t unaccounted_ad_bytes,
void ResourceLoadAggregator::AdjustAdBytes(int64_t unaccounted_ad_bytes,
ResourceMimeType mime_type) {
ad_network_bytes_ += unaccounted_ad_bytes;
ad_bytes_ += unaccounted_ad_bytes;
ad_bytes_by_mime_[static_cast<size_t>(mime_type)] += unaccounted_ad_bytes;
}
void FrameData::UpdateCpuUsage(base::TimeTicks update_time,
base::TimeDelta update) {
// Update the overall usage for all of the relevant buckets.
cpu_by_activation_period_[static_cast<size_t>(user_activation_status_)] +=
update;
PeakCpuAggregator::PeakCpuAggregator() = default;
PeakCpuAggregator::~PeakCpuAggregator() = default;
// If the frame has been activated, then we don't update the peak usage.
if (user_activation_status_ == UserActivationStatus::kReceivedActivation)
return;
// Update the peak usage.
UpdatePeakWindowedPercent(update, update_time, cpu_total_for_current_window_,
cpu_updates_for_current_window_,
peak_windowed_cpu_percent_);
}
base::TimeDelta FrameData::GetActivationCpuUsage(
UserActivationStatus status) const {
return cpu_by_activation_period_[static_cast<int>(status)];
}
base::TimeDelta FrameData::GetTotalCpuUsage() const {
base::TimeDelta total_cpu_time;
for (base::TimeDelta cpu_time : cpu_by_activation_period_)
total_cpu_time += cpu_time;
return total_cpu_time;
}
size_t FrameData::GetAdNetworkBytesForMime(ResourceMimeType mime_type) const {
return ad_bytes_by_mime_[static_cast<size_t>(mime_type)];
}
// static
constexpr base::TimeDelta PeakCpuAggregator::kWindowSize;
void FrameData::UpdatePeakWindowedPercent(
void PeakCpuAggregator::UpdatePeakWindowedPercent(
base::TimeDelta cpu_usage_update,
base::TimeTicks update_time,
base::TimeDelta& current_window_total,
base::queue<CpuUpdateData>& current_window_updates,
int& peak_windowed_percent) {
current_window_total += cpu_usage_update;
current_window_updates.push(CpuUpdateData(update_time, cpu_usage_update));
base::TimeTicks cutoff_time = update_time - kCpuWindowSize;
while (!current_window_updates.empty() &&
current_window_updates.front().update_time < cutoff_time) {
current_window_total -= current_window_updates.front().usage_info;
current_window_updates.pop();
base::TimeTicks update_time) {
current_window_total_ += cpu_usage_update;
current_window_updates_.push(CpuUpdateData(update_time, cpu_usage_update));
base::TimeTicks cutoff_time = update_time - kWindowSize;
while (!current_window_updates_.empty() &&
current_window_updates_.front().update_time < cutoff_time) {
current_window_total_ -= current_window_updates_.front().usage_info;
current_window_updates_.pop();
}
int current_windowed_percent = 100 * current_window_total.InMilliseconds() /
kCpuWindowSize.InMilliseconds();
if (current_windowed_percent > peak_windowed_percent)
peak_windowed_percent = current_windowed_percent;
int current_windowed_percent = 100 * current_window_total_.InMilliseconds() /
kWindowSize.InMilliseconds();
if (current_windowed_percent > peak_windowed_percent_)
peak_windowed_percent_ = current_windowed_percent;
}
void MemoryUsageAggregator::UpdateUsage(int64_t delta_bytes) {
current_bytes_used_ += delta_bytes;
if (current_bytes_used_ > max_bytes_used_)
max_bytes_used_ = current_bytes_used_;
}
FrameTreeData::FrameTreeData(FrameTreeNodeId root_frame_tree_node_id,
......@@ -169,9 +140,13 @@ void FrameTreeData::MaybeUpdateFrameDepth(
frame_depth_ = render_frame_host->GetFrameDepth() - root_frame_depth_;
}
void FrameTreeData::UpdateMemoryUsage(int64_t delta_bytes) {
memory_usage_.UpdateUsage(delta_bytes);
}
bool FrameTreeData::ShouldRecordFrameForMetrics() const {
return bytes() != 0 || !GetTotalCpuUsage().is_zero() ||
v8_max_memory_bytes_used_ > 0;
return resource_data().bytes() != 0 || !GetTotalCpuUsage().is_zero() ||
memory_usage_.max_bytes_used() > 0;
}
void FrameTreeData::RecordAdFrameLoadUkmEvent(ukm::SourceId source_id) const {
......@@ -182,15 +157,16 @@ void FrameTreeData::RecordAdFrameLoadUkmEvent(ukm::SourceId source_id) const {
ukm::builders::AdFrameLoad builder(source_id);
builder
.SetLoading_NetworkBytes(
ukm::GetExponentialBucketMinForBytes(network_bytes()))
.SetLoading_CacheBytes2(
ukm::GetExponentialBucketMinForBytes((bytes() - network_bytes())))
ukm::GetExponentialBucketMinForBytes(resource_data().network_bytes()))
.SetLoading_CacheBytes2(ukm::GetExponentialBucketMinForBytes(
(resource_data().bytes() - resource_data().network_bytes())))
.SetLoading_VideoBytes(ukm::GetExponentialBucketMinForBytes(
GetAdNetworkBytesForMime(ResourceMimeType::kVideo)))
resource_data().GetAdNetworkBytesForMime(ResourceMimeType::kVideo)))
.SetLoading_JavascriptBytes(ukm::GetExponentialBucketMinForBytes(
GetAdNetworkBytesForMime(ResourceMimeType::kJavascript)))
resource_data().GetAdNetworkBytesForMime(
ResourceMimeType::kJavascript)))
.SetLoading_ImageBytes(ukm::GetExponentialBucketMinForBytes(
GetAdNetworkBytesForMime(ResourceMimeType::kImage)))
resource_data().GetAdNetworkBytesForMime(ResourceMimeType::kImage)))
.SetLoading_NumResources(num_resources_);
builder.SetCpuTime_Total(GetTotalCpuUsage().InMilliseconds());
......@@ -200,7 +176,7 @@ void FrameTreeData::RecordAdFrameLoadUkmEvent(ukm::SourceId source_id) const {
.InMilliseconds());
}
builder.SetCpuTime_PeakWindowedPercent(peak_windowed_cpu_percent_);
builder.SetCpuTime_PeakWindowedPercent(peak_cpu_.peak_windowed_percent());
builder
.SetVisibility_FrameWidth(
......@@ -221,7 +197,7 @@ void FrameTreeData::RecordAdFrameLoadUkmEvent(ukm::SourceId source_id) const {
builder.Record(ukm_recorder->Get());
}
FrameData::OriginStatusWithThrottling
OriginStatusWithThrottling
FrameTreeData::GetCreativeOriginStatusWithThrottling() const {
bool is_throttled = !first_eligible_to_paint().has_value();
......@@ -284,13 +260,13 @@ void FrameTreeData::UpdateFrameVisibility() {
: FrameVisibility::kNonVisible;
}
FrameData::HeavyAdStatus FrameTreeData::ComputeHeavyAdStatus(
HeavyAdStatus FrameTreeData::ComputeHeavyAdStatus(
bool use_network_threshold_noise,
HeavyAdUnloadPolicy policy) const {
if (policy == HeavyAdUnloadPolicy::kCpuOnly ||
policy == HeavyAdUnloadPolicy::kAll) {
// Check if the frame meets the peak CPU usage threshold.
if (peak_windowed_cpu_percent_ >=
if (peak_windowed_cpu_percent() >=
heavy_ad_thresholds::kMaxPeakWindowedPercent) {
return HeavyAdStatus::kPeakCpu;
}
......@@ -307,42 +283,30 @@ FrameData::HeavyAdStatus FrameTreeData::ComputeHeavyAdStatus(
(use_network_threshold_noise ? heavy_ad_network_threshold_noise_ : 0);
// Check if the frame meets the network threshold, possible including noise.
if (network_bytes_ >= network_threshold)
if (resource_data().network_bytes() >= network_threshold)
return HeavyAdStatus::kNetwork;
}
return HeavyAdStatus::kNone;
}
int64_t FrameTreeData::UpdateMemoryUsage(FrameTreeNodeId frame_node_id,
uint64_t current_bytes) {
auto it = v8_current_memory_usage_map_.find(frame_node_id);
uint64_t previous_bytes =
(it != v8_current_memory_usage_map_.end()) ? it->second : 0UL;
v8_current_memory_usage_map_[frame_node_id] = current_bytes;
int64_t delta = current_bytes - previous_bytes;
v8_current_memory_bytes_used_ += delta;
void FrameTreeData::UpdateCpuUsage(base::TimeTicks update_time,
base::TimeDelta update) {
// Update the overall usage for all of the relevant buckets.
cpu_usage_[static_cast<size_t>(user_activation_status_)] += update;
if (v8_current_memory_bytes_used_ > v8_max_memory_bytes_used_)
v8_max_memory_bytes_used_ = v8_current_memory_bytes_used_;
// If the frame has been activated, then we don't update the peak usage.
if (user_activation_status_ == UserActivationStatus::kReceivedActivation)
return;
return delta;
// Update the peak usage.
peak_cpu_.UpdatePeakWindowedPercent(update, update_time);
}
int64_t FrameTreeData::OnFrameDeleted(FrameTreeNodeId frame_node_id) {
auto it = v8_current_memory_usage_map_.find(frame_node_id);
if (it == v8_current_memory_usage_map_.end())
return 0;
DCHECK(v8_current_memory_bytes_used_ >= it->second);
v8_current_memory_bytes_used_ -= it->second;
int64_t delta = -it->second;
v8_current_memory_usage_map_.erase(it);
return delta;
base::TimeDelta FrameTreeData::GetTotalCpuUsage() const {
base::TimeDelta total_cpu_time;
for (base::TimeDelta cpu_time : cpu_usage_)
total_cpu_time += cpu_time;
return total_cpu_time;
}
void FrameTreeData::UpdateForNavigation(
......@@ -373,7 +337,12 @@ void FrameTreeData::ProcessResourceLoadInFrame(
content::GlobalRequestID global_id(process_id, resource->request_id);
if (!resource_tracker.HasPreviousUpdateForResource(global_id))
num_resources_++;
FrameData::ProcessResourceLoadInFrame(resource, process_id, resource_tracker);
resource_data_.ProcessResourceLoad(resource);
}
void FrameTreeData::AdjustAdBytes(int64_t unaccounted_ad_bytes,
ResourceMimeType mime_type) {
resource_data_.AdjustAdBytes(unaccounted_ad_bytes, mime_type);
}
void FrameTreeData::SetFrameSize(gfx::Size frame_size) {
......@@ -386,7 +355,7 @@ void FrameTreeData::SetDisplayState(bool is_display_none) {
UpdateFrameVisibility();
}
FrameData::HeavyAdAction FrameTreeData::MaybeTriggerHeavyAdIntervention() {
HeavyAdAction FrameTreeData::MaybeTriggerHeavyAdIntervention() {
// TODO(johnidel): This method currently does a lot of heavy lifting: tracking
// noised and unnoised metrics, determining feature action, and branching
// based on configuration. Consider splitting this out and letting AdsPLMO do
......@@ -441,10 +410,32 @@ FrameData::HeavyAdAction FrameTreeData::MaybeTriggerHeavyAdIntervention() {
AggregateFrameData::AggregateFrameData() = default;
AggregateFrameData::~AggregateFrameData() = default;
void AggregateFrameData::UpdateNonAdCpuUsage(base::TimeTicks update_time,
base::TimeDelta update) {
UpdatePeakWindowedPercent(update, update_time,
non_ad_cpu_total_for_current_window_,
non_ad_cpu_updates_for_current_window_,
peak_windowed_non_ad_cpu_percent_);
void AggregateFrameData::UpdateCpuUsage(base::TimeTicks update_time,
base::TimeDelta update,
bool is_ad) {
// Update the overall usage for all of the relevant buckets.
cpu_usage_ += update;
// Update the peak usage.
total_peak_cpu_.UpdatePeakWindowedPercent(update, update_time);
if (!is_ad)
non_ad_peak_cpu_.UpdatePeakWindowedPercent(update, update_time);
}
void AggregateFrameData::ProcessResourceLoadInFrame(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
bool is_main_frame) {
resource_data_.ProcessResourceLoad(resource);
if (is_main_frame)
main_frame_resource_data_.ProcessResourceLoad(resource);
}
void AggregateFrameData::AdjustAdBytes(int64_t unaccounted_ad_bytes,
ResourceMimeType mime_type,
bool is_main_frame) {
resource_data_.AdjustAdBytes(unaccounted_ad_bytes, mime_type);
if (is_main_frame)
main_frame_resource_data_.AdjustAdBytes(unaccounted_ad_bytes, mime_type);
}
} // namespace ad_metrics
......@@ -5,6 +5,9 @@
#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_AD_METRICS_FRAME_DATA_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_AD_METRICS_FRAME_DATA_H_
// TODO(crbug.com/1136068): Split this file up so that its various classes and
// enums are in different files as well.
#include <stdint.h>
#include <unordered_map>
......@@ -42,61 +45,54 @@ const int kMaxPeakWindowedPercent = 50;
} // namespace heavy_ad_thresholds
// TODO(crbug.com/1136068): Remove inheritance/base class here in favor of
// separate composable classes for the various types of computations that need
// to be performed (cpu, network, memory).
namespace ad_metrics {
// Store information received for a frame on the page. FrameData is meant
// to represent a frame along with its entire subtree, FrameTreeData, or
// an aggregation of frame data for a navigation, AggregateFrameData.
class FrameData : public base::SupportsWeakPtr<FrameData> {
public:
// The origin of the ad relative to the main frame's origin.
// Note: Logged to UMA, keep in sync with CrossOriginAdStatus in enums.xml.
// Add new entries to the end, and do not renumber.
enum class OriginStatus {
// The origin of the ad relative to the main frame's origin.
// Note: Logged to UMA, keep in sync with CrossOriginAdStatus in enums.xml.
// Add new entries to the end, and do not renumber.
enum class OriginStatus {
kUnknown = 0,
kSame = 1,
kCross = 2,
kMaxValue = kCross,
};
};
// Origin status further broken down by whether the ad frame tree has a
// frame currently not render-throttled (i.e. is eligible to be painted).
// Note that since creative origin status is based on first contentful paint,
// only ad frame trees with unknown creative origin status can be without any
// frames that are eligible to be painted.
// Note: Logged to UMA, keep in sync with
// CrossOriginCreativeStatusWithThrottling in enums.xml.
// Add new entries to the end, and do not renumber.
enum class OriginStatusWithThrottling {
// Origin status further broken down by whether the ad frame tree has a
// frame currently not render-throttled (i.e. is eligible to be painted).
// Note that since creative origin status is based on first contentful paint,
// only ad frame trees with unknown creative origin status can be without any
// frames that are eligible to be painted.
// Note: Logged to UMA, keep in sync with
// CrossOriginCreativeStatusWithThrottling in enums.xml.
// Add new entries to the end, and do not renumber.
enum class OriginStatusWithThrottling {
kUnknownAndUnthrottled = 0,
kUnknownAndThrottled = 1,
kSameAndUnthrottled = 2,
kCrossAndUnthrottled = 3,
kMaxValue = kCrossAndUnthrottled,
};
};
// The type of heavy ad this frame is classified as per the Heavy Ad
// Intervention.
enum class HeavyAdStatus {
// The type of heavy ad this frame is classified as per the Heavy Ad
// Intervention.
enum class HeavyAdStatus {
kNone = 0,
kNetwork = 1,
kTotalCpu = 2,
kPeakCpu = 3,
kMaxValue = kPeakCpu,
};
};
// Controls what values of HeavyAdStatus will be cause an unload due to the
// intervention.
enum class HeavyAdUnloadPolicy {
// Controls what values of HeavyAdStatus will be cause an unload due to the
// intervention.
enum class HeavyAdUnloadPolicy {
kNetworkOnly = 0,
kCpuOnly = 1,
kAll = 2,
};
};
// Represents how a frame should be treated by the heavy ad intervention.
enum class HeavyAdAction {
// Represents how a frame should be treated by the heavy ad intervention.
enum class HeavyAdAction {
// Nothing should be done, i.e. the ad is not heavy or the intervention is
// not enabled.
kNone = 0,
......@@ -106,29 +102,29 @@ class FrameData : public base::SupportsWeakPtr<FrameData> {
kUnload = 2,
// The frame was ignored, i.e. the blocklist was full or page is a reload.
kIgnored = 3,
};
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. For any additions, also update the
// corresponding PageEndReason enum in enums.xml.
enum class UserActivationStatus {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. For any additions, also update the
// corresponding PageEndReason enum in enums.xml.
enum class UserActivationStatus {
kNoActivation = 0,
kReceivedActivation = 1,
kMaxValue = kReceivedActivation,
};
};
// TODO(crbug.com/1136068): The above enums should sit in FrameTreeData.
// TODO(crbug.com/1136068): The above enums should sit in FrameTreeData.
// Whether or not the ad frame has a display: none styling.
enum FrameVisibility {
// Whether or not the ad frame has a display: none styling.
enum FrameVisibility {
kNonVisible = 0,
kVisible = 1,
kAnyVisibility = 2,
kMaxValue = kAnyVisibility,
};
};
// High level categories of mime types for resources loaded by the frame.
enum class ResourceMimeType {
// High level categories of mime types for resources loaded by the frame.
enum class ResourceMimeType {
kJavascript = 0,
kVideo = 1,
kImage = 2,
......@@ -136,69 +132,87 @@ class FrameData : public base::SupportsWeakPtr<FrameData> {
kHtml = 4,
kOther = 5,
kMaxValue = kOther,
};
};
// Whether or not media has been played in this frame. These values are
// persisted to logs. Entries should not be renumbered and numeric values
// should never be reused.
enum class MediaStatus {
// Whether or not media has been played in this frame. These values are
// persisted to logs. Entries should not be renumbered and numeric values
// should never be reused.
enum class MediaStatus {
kNotPlayed = 0,
kPlayed = 1,
kMaxValue = kPlayed,
};
};
// Window over which to consider cpu time spent in an ad_frame.
static constexpr base::TimeDelta kCpuWindowSize =
base::TimeDelta::FromSeconds(30);
class ResourceLoadAggregator {
public:
ResourceLoadAggregator();
~ResourceLoadAggregator();
using FrameTreeNodeId =
page_load_metrics::PageLoadMetricsObserver::FrameTreeNodeId;
// Updates the number of bytes loaded in the frame given a resource load.
void ProcessResourceLoad(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
// Adds additional bytes to the ad resource byte counts. This
// is used to notify the frame that some bytes were tagged as ad bytes after
// they were loaded.
void AdjustAdBytes(int64_t unaccounted_ad_bytes, ResourceMimeType mime_type);
// Get the mime type of a resource. This only returns a subset of mime types,
// grouped at a higher level. For example, all video mime types return the
// same value.
// TODO(crbug.com/1136068): This is used well out of the scope of the
// AdsPageLoadMetricsObserver and should sit in a common directory.
static ResourceMimeType GetResourceMimeType(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
// Updates the number of bytes loaded in the frame given a resource load.
virtual void ProcessResourceLoadInFrame(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
int process_id,
const page_load_metrics::ResourceTracker& resource_tracker);
// Accessors for the various data stored in the class.
// Adds additional bytes to the ad resource byte counts. This
// is used to notify the frame that some bytes were tagged as ad bytes after
// they were loaded.
void AdjustAdBytes(int64_t unaccounted_ad_bytes, ResourceMimeType mime_type);
size_t bytes() const { return bytes_; }
// Update CPU usage information with the timing |update| that was received at
// |update_time|.
void UpdateCpuUsage(base::TimeTicks update_time, base::TimeDelta update);
size_t network_bytes() const { return network_bytes_; }
// Get the cpu usage for the appropriate activation period.
base::TimeDelta GetActivationCpuUsage(UserActivationStatus status) const;
size_t ad_bytes() const { return ad_bytes_; }
// Get total cpu usage for the frame.
base::TimeDelta GetTotalCpuUsage() const;
size_t ad_network_bytes() const { return ad_network_bytes_; }
int peak_windowed_cpu_percent() const { return peak_windowed_cpu_percent_; }
size_t GetAdNetworkBytesForMime(ResourceMimeType mime_type) const {
return ad_bytes_by_mime_[static_cast<size_t>(mime_type)];
}
size_t bytes() const { return bytes_; }
private:
// Total bytes used to load resources in the frame, including headers.
size_t bytes_ = 0u;
size_t network_bytes_ = 0u;
size_t network_bytes() const { return network_bytes_; }
// Ad network bytes for different mime type resources loaded in the frame.
size_t ad_bytes_by_mime_[static_cast<size_t>(ResourceMimeType::kMaxValue) +
1] = {0};
size_t same_origin_bytes() const { return same_origin_bytes_; }
// Tracks the number of bytes that were used to load resources which were
// detected to be ads inside of this frame. For ad frames, these counts should
// match |frame_bytes| and |frame_network_bytes|.
size_t ad_bytes_ = 0u;
size_t ad_network_bytes_ = 0u;
};
size_t ad_bytes() const { return ad_bytes_; }
class PeakCpuAggregator {
public:
// Standard constructor / desturctor.
PeakCpuAggregator();
~PeakCpuAggregator();
size_t ad_network_bytes() const { return ad_network_bytes_; }
// Window over which to consider cpu time spent in an ad_frame.
static constexpr base::TimeDelta kWindowSize =
base::TimeDelta::FromSeconds(30);
size_t GetAdNetworkBytesForMime(ResourceMimeType mime_type) const;
// Update the peak window variables given the current update and update time.
void UpdatePeakWindowedPercent(base::TimeDelta cpu_usage_update,
base::TimeTicks update_time);
protected:
FrameData();
virtual ~FrameData();
// Accessor for the peak percent.
int peak_windowed_percent() const { return peak_windowed_percent_; }
private:
// Time updates for the frame with a timestamp indicating when they arrived.
// Used for windowed cpu load reporting.
struct CpuUpdateData {
......@@ -208,72 +222,65 @@ class FrameData : public base::SupportsWeakPtr<FrameData> {
: update_time(time), usage_info(info) {}
};
// Update the peak window variables given the current update and update time.
void UpdatePeakWindowedPercent(
base::TimeDelta cpu_usage_update,
base::TimeTicks update_time,
base::TimeDelta& current_window_total,
base::queue<CpuUpdateData>& current_window_updates,
int& peak_windowed_percent);
// Total bytes used to load resources in the frame, including headers.
size_t bytes_ = 0u;
size_t network_bytes_ = 0u;
// Ad network bytes for different mime type resources loaded in the frame.
size_t ad_bytes_by_mime_[static_cast<size_t>(ResourceMimeType::kMaxValue) +
1] = {0};
// Time spent by the frame in the cpu before and after activation.
base::TimeDelta cpu_by_activation_period_
[static_cast<size_t>(UserActivationStatus::kMaxValue) + 1] = {
base::TimeDelta(), base::TimeDelta()};
// The cpu time spent in the current window.
base::TimeDelta cpu_total_for_current_window_;
base::TimeDelta current_window_total_;
// The cpu updates themselves that are still relevant for the time window.
// Note: Since the window is 30 seconds and PageLoadMetrics updates arrive at
// most every half second, this can never have more than 60 elements.
base::queue<CpuUpdateData> cpu_updates_for_current_window_;
base::queue<CpuUpdateData> current_window_updates_;
// The peak windowed cpu load during the unactivated period.
int peak_windowed_cpu_percent_ = 0;
int peak_windowed_percent_ = 0;
};
// Tracks the number of bytes that were used to load resources which were
// detected to be ads inside of this frame. For ad frames, these counts should
// match |frame_bytes| and |frame_network_bytes|.
size_t ad_bytes_ = 0u;
size_t ad_network_bytes_ = 0u;
class MemoryUsageAggregator {
public:
void UpdateUsage(int64_t delta_bytes);
// The number of bytes that are same origin to the root ad frame.
size_t same_origin_bytes_ = 0u;
uint64_t max_bytes_used() const { return max_bytes_used_; }
// Whether or not the frame has been activated (clicked on). Aggregated frame
// data should never have this set to activated.
UserActivationStatus user_activation_status_ =
UserActivationStatus::kNoActivation;
private:
// Maximum concurrent memory usage by V8 in this ad frame tree.
// Tracks max value of |v8_current_memory_bytes_used_| for this frame tree.
uint64_t max_bytes_used_ = 0UL;
DISALLOW_COPY_AND_ASSIGN(FrameData);
// Current concurrent memory usage by V8 in this ad frame tree.
// Computation is best-effort, as it relies on individual asynchronous
// per-frame measurements, some of which may be stale.
uint64_t current_bytes_used_ = 0UL;
};
// FrameTreeData represents a frame along with its entire subtree, and is
// typically used to capture an ad creative. It stores frame-specific
// information (such as size, activation status, and origin), which is typically
// specific to the top frame in the tree.
class FrameTreeData : public FrameData {
class FrameTreeData : public base::SupportsWeakPtr<FrameTreeData> {
public:
// |root_frame_tree_node_id| is the root frame of the subtree that FrameData
// stores information for.
using FrameTreeNodeId =
page_load_metrics::PageLoadMetricsObserver::FrameTreeNodeId;
// |root_frame_tree_node_id| is the root frame of the subtree that
// FrameTreeData stores information for.
explicit FrameTreeData(FrameTreeNodeId root_frame_tree_node_id,
int heavy_ad_network_threshold_noise);
~FrameTreeData() override;
~FrameTreeData();
// From FrameData
// Processes a resource load in frame, calling ResourceLoadAggregator.
void ProcessResourceLoadInFrame(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
int process_id,
const page_load_metrics::ResourceTracker& resource_tracker) override;
const page_load_metrics::ResourceTracker& resource_tracker);
// Adjusts ad bytes after call to ProcessResourceLoadInFrame, calling
// ResourceLoadAggregator.
void AdjustAdBytes(int64_t unaccounted_ad_bytes, ResourceMimeType mime_type);
// Updates the cpu usage of this frame.
void UpdateCpuUsage(base::TimeTicks update_time, base::TimeDelta update);
// Get the total cpu usage of this frame;
base::TimeDelta GetTotalCpuUsage() const;
// Update the metadata of this frame if it is being navigated.
void UpdateForNavigation(content::RenderFrameHost* render_frame_host,
......@@ -289,13 +296,8 @@ class FrameTreeData : public FrameData {
// frame.
void MaybeUpdateFrameDepth(content::RenderFrameHost* render_frame_host);
// Updates the recorded bytes of memory used by V8 inside this ad frame tree
// and returns the delta in memory bytes usage.
int64_t UpdateMemoryUsage(FrameTreeNodeId frame_node_id,
uint64_t current_bytes);
// Returns the delta in memory bytes usage due to frame deletion.
int64_t OnFrameDeleted(FrameTreeNodeId frame_node_id);
// Updates the recorded bytes of memory used.
void UpdateMemoryUsage(int64_t delta_bytes);
// Returns whether the frame should be recorded for UKMs and UMA histograms.
// A frame should be recorded if it has non-zero bytes or non-zero CPU usage
......@@ -310,6 +312,11 @@ class FrameTreeData : public FrameData {
// by whether any frame in the ad frame tree is throttled.
OriginStatusWithThrottling GetCreativeOriginStatusWithThrottling() const;
// Get the cpu usage for the appropriate activation period.
base::TimeDelta GetActivationCpuUsage(UserActivationStatus status) const {
return cpu_usage_[static_cast<size_t>(status)];
}
FrameTreeNodeId root_frame_tree_node_id() const {
return root_frame_tree_node_id_;
}
......@@ -333,12 +340,8 @@ class FrameTreeData : public FrameData {
// Sets the display state of the frame and updates its visibility state.
void SetDisplayState(bool is_display_none);
uint64_t v8_current_memory_bytes_used() const {
return v8_current_memory_bytes_used_;
}
uint64_t v8_max_memory_bytes_used() const {
return v8_max_memory_bytes_used_;
return memory_usage_.max_bytes_used();
}
UserActivationStatus user_activation_status() const {
......@@ -389,6 +392,14 @@ class FrameTreeData : public FrameData {
heavy_ad_action_ = heavy_ad_action;
}
// Accessor for the total resource data of the frame tree.
const ResourceLoadAggregator& resource_data() const { return resource_data_; }
// Accessor for the peak windowed cpu usage of the frame tree.
int peak_windowed_cpu_percent() const {
return peak_cpu_.peak_windowed_percent();
}
private:
// Updates whether or not this frame meets the criteria for visibility.
void UpdateFrameVisibility();
......@@ -406,10 +417,11 @@ class FrameTreeData : public FrameData {
// tracking information for.
const FrameTreeNodeId root_frame_tree_node_id_;
// TODO(ericrobinson): May want to move this to ResourceLoadAggregator.
// Number of resources loaded by the frame (both complete and incomplete).
int num_resources_ = 0;
// The depth of this FrameData's root frame.
// The depth of this FrameTreeData's root frame.
unsigned int root_frame_depth_ = 0;
// The max depth of this frames frame tree.
......@@ -469,49 +481,63 @@ class FrameTreeData : public FrameData {
// Number of bytes of noise that should be added to the network threshold.
const int heavy_ad_network_threshold_noise_;
// Per-frame memory usage by V8 in bytes. Memory data is stored per subframe
// in the frame tree.
std::unordered_map<FrameTreeNodeId, uint64_t> v8_current_memory_usage_map_;
// Whether or not the frame has been activated (clicked on).
UserActivationStatus user_activation_status_ =
UserActivationStatus::kNoActivation;
// The cpu usage for both the activated and unactivated time periods.
base::TimeDelta
cpu_usage_[static_cast<size_t>(UserActivationStatus::kMaxValue) + 1];
// Maximum concurrent memory usage by V8 in this ad frame tree.
// Tracks max value of |v8_current_memory_bytes_used_| for this frame tree.
uint64_t v8_max_memory_bytes_used_ = 0UL;
// The resource data for this frame tree.
ResourceLoadAggregator resource_data_;
// Current concurrent memory usage by V8 in this ad frame tree.
// Computation is best-effort, as it relies on individual asynchronous
// per-frame measurements, some of which may be stale.
uint64_t v8_current_memory_bytes_used_ = 0UL;
// The peak cpu usage for this frame tree.
PeakCpuAggregator peak_cpu_;
// Memory usage by v8 in this ad frame tree.
MemoryUsageAggregator memory_usage_;
};
// AggregateFrameData stores information in aggregate for all the frames during
// a navigation. It contains specific information on various types of frames
// and their usage, such as ad vs. non-ad frames, as well as information about
// usage across the navigation as a whole.
class AggregateFrameData : public FrameData {
class AggregateFrameData {
public:
AggregateFrameData();
~AggregateFrameData() override;
~AggregateFrameData();
// Update the Aggregate non-ad peak windowed cpu percent.
void UpdateNonAdCpuUsage(base::TimeTicks update_time, base::TimeDelta update);
void ProcessResourceLoadInFrame(
const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
bool is_main_frame);
// Adjusts the overall page and potentially main frame ad bytes.
void AdjustAdBytes(int64_t unaccounted_ad_bytes,
ResourceMimeType mime_type,
bool is_main_frame);
// Updates the cpu usage for the page, given whether update is for an ad.
void UpdateCpuUsage(base::TimeTicks update_time,
base::TimeDelta update,
bool is_ad);
int peak_windowed_non_ad_cpu_percent() const {
return peak_windowed_non_ad_cpu_percent_;
return non_ad_peak_cpu_.peak_windowed_percent();
}
int peak_windowed_cpu_percent() const {
return total_peak_cpu_.peak_windowed_percent();
}
// TODO(crbug.com/1136068): The size_t members below should probably be of
// type int64.
// TODO(crbug.com/1136068): The size_t members should probably be int64_t.
struct AdDataByVisibility {
// The following members are aggregated when metrics are recorded for a
// frame on navigation.
// The following are aggregated when metrics are recorded on navigation.
size_t bytes = 0;
size_t network_bytes = 0;
size_t frames = 0;
base::TimeDelta cpu_time = base::TimeDelta();
// the following members are used for v8 memory consumption and are
// aggregated as memory updates are received.
uint64_t current_memory = 0;
uint64_t max_memory = 0;
// MemoryUsage is aggregated when a memory update is received.
MemoryUsageAggregator memory;
};
// Returns the appropriate AdDataByVisibility given the |visibility|.
......@@ -533,18 +559,32 @@ class AggregateFrameData : public FrameData {
size_t frames) {
ad_data_[static_cast<size_t>(visibility)].frames += frames;
}
void update_ad_cpu_time_by_visibility(FrameVisibility visibility,
base::TimeDelta cpu_time) {
ad_data_[static_cast<size_t>(visibility)].cpu_time += cpu_time;
void update_ad_memory_by_visibility(FrameVisibility visibility,
int64_t delta_bytes) {
ad_data_[static_cast<size_t>(visibility)].memory.UpdateUsage(delta_bytes);
}
// This updates the current memory and adjusts the max memory if necessary.
void update_ad_memory_by_visibility(FrameVisibility visibility,
int64_t memory) {
auto& ad_data = ad_data_[static_cast<size_t>(visibility)];
ad_data.current_memory += memory;
if (ad_data.current_memory > ad_data.max_memory)
ad_data.max_memory = ad_data.current_memory;
// Updates the memory for the main frame of the page.
void update_main_frame_memory(int64_t delta_memory) {
main_frame_memory_.UpdateUsage(delta_memory);
}
// Updates the total ad cpu usage for the page.
void update_ad_cpu_usage(base::TimeDelta usage) { ad_cpu_usage_ += usage; }
// Get the total memory usage for this page.
int64_t main_frame_max_memory() const {
return main_frame_memory_.max_bytes_used();
}
// Get the total cpu usage of this page.
base::TimeDelta total_cpu_usage() const { return cpu_usage_; }
base::TimeDelta total_ad_cpu_usage() const { return ad_cpu_usage_; }
// Accessor for the total resource data of the page.
const ResourceLoadAggregator& resource_data() const { return resource_data_; }
const ResourceLoadAggregator& main_frame_resource_data() const {
return main_frame_resource_data_;
}
private:
......@@ -552,11 +592,22 @@ class AggregateFrameData : public FrameData {
AdDataByVisibility
ad_data_[static_cast<size_t>(FrameVisibility::kMaxValue) + 1] = {};
// Since peak information cannot be computed by the difference of aggregated
// values, information for non-ad peak content must be retained.
base::TimeDelta non_ad_cpu_total_for_current_window_;
base::queue<CpuUpdateData> non_ad_cpu_updates_for_current_window_;
int peak_windowed_non_ad_cpu_percent_ = 0;
// The overall cpu usage for this page.
base::TimeDelta cpu_usage_ = base::TimeDelta();
base::TimeDelta ad_cpu_usage_ = base::TimeDelta();
// The memory used by the main frame.
MemoryUsageAggregator main_frame_memory_;
// The resource data for this page.
ResourceLoadAggregator resource_data_;
ResourceLoadAggregator main_frame_resource_data_;
// The peak cpu usages for this page.
PeakCpuAggregator total_peak_cpu_;
PeakCpuAggregator non_ad_peak_cpu_;
};
} // namespace ad_metrics
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_AD_METRICS_FRAME_DATA_H_
......@@ -58,7 +58,8 @@ void ResourceMetricsObserver::RecordResourceMimeHistograms(
resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached;
int64_t data_length = was_cached ? resource->encoded_body_length
: resource->received_data_length;
ResourceMimeType mime_type = FrameData::GetResourceMimeType(resource);
ResourceMimeType mime_type =
ad_metrics::ResourceLoadAggregator::GetResourceMimeType(resource);
if (mime_type == ResourceMimeType::kImage) {
RESOURCE_BYTES_HISTOGRAM("Mime.Image", was_cached, data_length);
} else if (mime_type == ResourceMimeType::kJavascript) {
......
......@@ -17,7 +17,7 @@
class ResourceMetricsObserver
: public page_load_metrics::PageLoadMetricsObserver {
public:
using ResourceMimeType = FrameData::ResourceMimeType;
using ResourceMimeType = ad_metrics::ResourceMimeType;
ResourceMetricsObserver();
~ResourceMetricsObserver() override;
......
......@@ -414,7 +414,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, VerifySameOriginWithoutNavigate) {
// Navigate away and ensure we report same origin.
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kSubresourceFilterOriginStatusHistogram,
FrameData::OriginStatus::kSame, 1);
ad_metrics::OriginStatus::kSame, 1);
}
IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, VerifyCrossOriginWithoutNavigate) {
......@@ -457,7 +457,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest,
// Navigate away and ensure we report cross origin.
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kSubresourceFilterOriginStatusHistogram,
FrameData::OriginStatus::kCross, 1);
ad_metrics::OriginStatus::kCross, 1);
}
// Ad script creates a frame and navigates it same origin.
......@@ -479,7 +479,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest,
// Navigate away and ensure we report same origin.
ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
histogram_tester.ExpectUniqueSample(kSubresourceFilterOriginStatusHistogram,
FrameData::OriginStatus::kSame, 1);
ad_metrics::OriginStatus::kSame, 1);
}
// Test that a subframe with a non-ad url but loaded by ad script is an ad.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment