Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc

Issue 2901383002: Buffer cross frame paint timing updates. (Closed)
Patch Set: fix android build Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h " 5 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h "
6 6
7 #include <ostream> 7 #include <ostream>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/metrics/histogram_macros.h" 11 #include "base/metrics/histogram_macros.h"
12 #include "base/optional.h" 12 #include "base/optional.h"
13 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h" 13 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h"
14 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface. h" 14 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface. h"
15 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" 15 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
16 #include "chrome/browser/page_load_metrics/page_load_tracker.h" 16 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
17 #include "chrome/common/page_load_metrics/page_load_metrics_constants.h" 17 #include "chrome/common/page_load_metrics/page_load_metrics_constants.h"
18 #include "content/public/browser/navigation_handle.h" 18 #include "content/public/browser/navigation_handle.h"
19 #include "content/public/browser/render_frame_host.h" 19 #include "content/public/browser/render_frame_host.h"
20 20
21 namespace page_load_metrics { 21 namespace page_load_metrics {
22 22
23 namespace internal { 23 namespace internal {
24 24
25 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus"; 25 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus";
26 const char kPageLoadTimingDispatchStatus[] = 26 const char kPageLoadTimingDispatchStatus[] =
27 "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch"; 27 "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch";
28 const char kHistogramOutOfOrderTiming[] =
29 "PageLoad.Internal.OutOfOrderInterFrameTiming";
30 const char kHistogramOutOfOrderTimingBuffered[] =
31 "PageLoad.Internal.OutOfOrderInterFrameTiming.AfterBuffering";
28 32
29 } // namespace internal 33 } // namespace internal
30 34
31 namespace { 35 namespace {
32 36
33 // Helper to allow use of Optional<> values in LOG() messages. 37 // Helper to allow use of Optional<> values in LOG() messages.
34 std::ostream& operator<<(std::ostream& os, 38 std::ostream& operator<<(std::ostream& os,
35 const base::Optional<base::TimeDelta>& opt) { 39 const base::Optional<base::TimeDelta>& opt) {
36 if (opt) 40 if (opt)
37 os << opt.value(); 41 os << opt.value();
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 timing.paint_timing->first_meaningful_paint)) { 197 timing.paint_timing->first_meaningful_paint)) {
194 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint 198 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint
195 << " for first_meaningful_paint " 199 << " for first_meaningful_paint "
196 << timing.paint_timing->first_meaningful_paint; 200 << timing.paint_timing->first_meaningful_paint;
197 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; 201 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT;
198 } 202 }
199 203
200 return internal::VALID; 204 return internal::VALID;
201 } 205 }
202 206
207 // If the updated value has an earlier time than the current value, log so we
208 // can keep track of how often this happens.
209 void LogIfOutOfOrderTiming(const base::Optional<base::TimeDelta>& current,
210 const base::Optional<base::TimeDelta>& update) {
211 if (!current || !update)
212 return;
213
214 if (update < current) {
215 PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTimingBuffered,
216 current.value() - update.value());
217 }
218 }
219
220 // PaintTimingMerger merges paint timing values received from different frames
221 // together.
222 class PaintTimingMerger {
Charlie Harrison 2017/05/26 19:31:34 This feels a bit weird as a class. It's only alloc
Bryan McQuade 2017/05/26 20:07:32 Yeah, I wasn't planning to make this a helper clas
Charlie Harrison 2017/05/30 14:49:07 Those reasons make sense to me. I was thinking of
223 public:
224 explicit PaintTimingMerger(mojom::PaintTiming* target) : target_(target) {}
225
226 // Merge paint timing values from |new_paint_timing| into the target
227 // PaintTiming.
228 void Merge(base::TimeDelta navigation_start_offset,
229 const mojom::PaintTiming& new_paint_timing,
230 bool is_main_frame);
231
232 // Whether we merged a new value, for a paint timing field we didn't
233 // previously have a value for in the target PaintTiming.
234 bool did_merge_new_timing_value() const {
235 return did_merge_new_timing_value_;
236 }
237
238 private:
239 void MaybeUpdateTimeDelta(
240 base::Optional<base::TimeDelta>* inout_existing_value,
241 base::TimeDelta navigation_start_offset,
242 const base::Optional<base::TimeDelta>& optional_candidate_new_value);
243
244 // The target PaintTiming we are merging values into.
245 mojom::PaintTiming* const target_;
246
247 // Whether we merged a new value, for a paint timing field we didn't
248 // previously have a value for in |target_|.
249 bool did_merge_new_timing_value_ = false;
250
251 DISALLOW_COPY_AND_ASSIGN(PaintTimingMerger);
252 };
253
203 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if 254 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if
204 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < 255 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| <
205 // |inout_existing_value|. 256 // |inout_existing_value|.
206 void MaybeUpdateTimeDelta( 257 void PaintTimingMerger::MaybeUpdateTimeDelta(
207 base::Optional<base::TimeDelta>* inout_existing_value, 258 base::Optional<base::TimeDelta>* inout_existing_value,
208 base::TimeDelta navigation_start_offset, 259 base::TimeDelta navigation_start_offset,
209 const base::Optional<base::TimeDelta>& optional_candidate_new_value) { 260 const base::Optional<base::TimeDelta>& optional_candidate_new_value) {
210 // If we don't get a new value, there's nothing to do 261 // If we don't get a new value, there's nothing to do
211 if (!optional_candidate_new_value) 262 if (!optional_candidate_new_value)
212 return; 263 return;
213 264
214 // optional_candidate_new_value is relative to navigation start in its 265 // optional_candidate_new_value is relative to navigation start in its
215 // frame. We need to adjust it to be relative to navigation start in the main 266 // frame. We need to adjust it to be relative to navigation start in the main
216 // frame, so offset it by navigation_start_offset. 267 // frame, so offset it by navigation_start_offset.
217 base::TimeDelta candidate_new_value = 268 base::TimeDelta candidate_new_value =
218 navigation_start_offset + optional_candidate_new_value.value(); 269 navigation_start_offset + optional_candidate_new_value.value();
219 270
220 if (*inout_existing_value) { 271 if (*inout_existing_value) {
221 // If we have a new value, but it is after the existing value, then keep the 272 // If we have a new value, but it is after the existing value, then keep the
222 // existing value. 273 // existing value.
223 if (*inout_existing_value <= candidate_new_value) 274 if (*inout_existing_value <= candidate_new_value)
224 return; 275 return;
225 276
226 // We received a new timing event, but with a timestamp before the timestamp 277 // We received a new timing event, but with a timestamp before the timestamp
227 // of a timing update we had received previously. We expect this to happen 278 // of a timing update we had received previously. We expect this to happen
228 // occasionally, as inter-frame updates can arrive out of order. Record a 279 // occasionally, as inter-frame updates can arrive out of order. Record a
229 // histogram to track how frequently it happens, along with the magnitude 280 // histogram to track how frequently it happens, along with the magnitude
230 // of the delta. 281 // of the delta.
231 PAGE_LOAD_HISTOGRAM("PageLoad.Internal.OutOfOrderInterFrameTiming", 282 PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTiming,
232 inout_existing_value->value() - candidate_new_value); 283 inout_existing_value->value() - candidate_new_value);
284 } else {
285 did_merge_new_timing_value_ = true;
233 } 286 }
234 287
235 *inout_existing_value = candidate_new_value; 288 *inout_existing_value = candidate_new_value;
236 } 289 }
237 290
291 void PaintTimingMerger::Merge(base::TimeDelta navigation_start_offset,
292 const mojom::PaintTiming& new_paint_timing,
293 bool is_main_frame) {
294 MaybeUpdateTimeDelta(&target_->first_paint, navigation_start_offset,
295 new_paint_timing.first_paint);
296 MaybeUpdateTimeDelta(&target_->first_text_paint, navigation_start_offset,
297 new_paint_timing.first_text_paint);
298 MaybeUpdateTimeDelta(&target_->first_image_paint, navigation_start_offset,
299 new_paint_timing.first_image_paint);
300 MaybeUpdateTimeDelta(&target_->first_contentful_paint,
301 navigation_start_offset,
302 new_paint_timing.first_contentful_paint);
303 if (is_main_frame) {
304 // first meaningful paint is only tracked in the main frame.
305 target_->first_meaningful_paint = new_paint_timing.first_meaningful_paint;
306 }
307 }
308
238 } // namespace 309 } // namespace
239 310
240 PageLoadMetricsUpdateDispatcher::PageLoadMetricsUpdateDispatcher( 311 PageLoadMetricsUpdateDispatcher::PageLoadMetricsUpdateDispatcher(
241 PageLoadMetricsUpdateDispatcher::Client* client, 312 PageLoadMetricsUpdateDispatcher::Client* client,
242 content::NavigationHandle* navigation_handle, 313 content::NavigationHandle* navigation_handle,
243 PageLoadMetricsEmbedderInterface* embedder_interface) 314 PageLoadMetricsEmbedderInterface* embedder_interface)
244 : client_(client), 315 : client_(client),
245 embedder_interface_(embedder_interface), 316 embedder_interface_(embedder_interface),
317 timer_(embedder_interface->CreateTimer()),
246 navigation_start_(navigation_handle->NavigationStart()), 318 navigation_start_(navigation_handle->NavigationStart()),
247 current_merged_page_timing_(CreatePageLoadTiming()), 319 current_merged_page_timing_(CreatePageLoadTiming()),
248 pending_merged_page_timing_(CreatePageLoadTiming()), 320 pending_merged_page_timing_(CreatePageLoadTiming()),
249 main_frame_metadata_(mojom::PageLoadMetadata::New()), 321 main_frame_metadata_(mojom::PageLoadMetadata::New()),
250 subframe_metadata_(mojom::PageLoadMetadata::New()) {} 322 subframe_metadata_(mojom::PageLoadMetadata::New()) {}
251 323
252 PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() {} 324 PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() {
325 if (timer_->IsRunning()) {
326 timer_->Stop();
Charlie Harrison 2017/05/26 19:31:34 It feels wrong that we need to explicitly stop the
Bryan McQuade 2017/05/26 20:07:32 Looking at your comment there, you suggested retai
327 DispatchTimingUpdates();
Charlie Harrison 2017/05/26 19:31:34 Maybe user Timer::user_task to avoid duplicating t
Bryan McQuade 2017/05/26 20:07:32 Need to circle back on this one - will look and se
Bryan McQuade 2017/05/26 21:51:32 I look a look - it appears to not be possible to k
Charlie Harrison 2017/05/30 14:49:07 Yeah I feel like this comment was piggybacking on
Bryan McQuade 2017/05/30 15:30:22 My understanding is that it's safe to call Run() o
328 }
329 }
253 330
254 void PageLoadMetricsUpdateDispatcher::UpdateMetrics( 331 void PageLoadMetricsUpdateDispatcher::UpdateMetrics(
255 content::RenderFrameHost* render_frame_host, 332 content::RenderFrameHost* render_frame_host,
256 const mojom::PageLoadTiming& new_timing, 333 const mojom::PageLoadTiming& new_timing,
257 const mojom::PageLoadMetadata& new_metadata) { 334 const mojom::PageLoadMetadata& new_metadata) {
258 if (render_frame_host->GetParent() == nullptr) { 335 if (render_frame_host->GetParent() == nullptr) {
259 UpdateMainFrameMetadata(new_metadata); 336 UpdateMainFrameMetadata(new_metadata);
260 UpdateMainFrameTiming(new_timing); 337 UpdateMainFrameTiming(new_timing);
261 } else { 338 } else {
262 UpdateSubFrameMetadata(new_metadata); 339 UpdateSubFrameMetadata(new_metadata);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 const auto it = subframe_navigation_start_offset_.find( 373 const auto it = subframe_navigation_start_offset_.find(
297 render_frame_host->GetFrameTreeNodeId()); 374 render_frame_host->GetFrameTreeNodeId());
298 if (it == subframe_navigation_start_offset_.end()) { 375 if (it == subframe_navigation_start_offset_.end()) {
299 // We received timing information for an untracked load. Ignore it. 376 // We received timing information for an untracked load. Ignore it.
300 return; 377 return;
301 } 378 }
302 379
303 client_->OnSubFrameTimingChanged(new_timing); 380 client_->OnSubFrameTimingChanged(new_timing);
304 381
305 base::TimeDelta navigation_start_offset = it->second; 382 base::TimeDelta navigation_start_offset = it->second;
306 MergePaintTiming(navigation_start_offset, *(new_timing.paint_timing), 383 PaintTimingMerger merger(pending_merged_page_timing_->paint_timing.get());
307 false /* is_main_frame */); 384 merger.Merge(navigation_start_offset, *new_timing.paint_timing,
385 false /* is_main_frame */);
308 386
309 DispatchTimingUpdates(); 387 MaybeDispatchTimingUpdates(merger.did_merge_new_timing_value());
310 }
311
312 void PageLoadMetricsUpdateDispatcher::MergePaintTiming(
313 base::TimeDelta navigation_start_offset,
314 const mojom::PaintTiming& new_paint_timing,
315 bool is_main_frame) {
316 MaybeUpdateTimeDelta(&pending_merged_page_timing_->paint_timing->first_paint,
317 navigation_start_offset, new_paint_timing.first_paint);
318 MaybeUpdateTimeDelta(
319 &pending_merged_page_timing_->paint_timing->first_text_paint,
320 navigation_start_offset, new_paint_timing.first_text_paint);
321 MaybeUpdateTimeDelta(
322 &pending_merged_page_timing_->paint_timing->first_image_paint,
323 navigation_start_offset, new_paint_timing.first_image_paint);
324 MaybeUpdateTimeDelta(
325 &pending_merged_page_timing_->paint_timing->first_contentful_paint,
326 navigation_start_offset, new_paint_timing.first_contentful_paint);
327 if (is_main_frame) {
328 // first meaningful paint is only tracked in the main frame.
329 pending_merged_page_timing_->paint_timing->first_meaningful_paint =
330 new_paint_timing.first_meaningful_paint;
331 }
332 } 388 }
333 389
334 void PageLoadMetricsUpdateDispatcher::UpdateSubFrameMetadata( 390 void PageLoadMetricsUpdateDispatcher::UpdateSubFrameMetadata(
335 const mojom::PageLoadMetadata& subframe_metadata) { 391 const mojom::PageLoadMetadata& subframe_metadata) {
336 // Merge the subframe loading behavior flags with any we've already observed, 392 // Merge the subframe loading behavior flags with any we've already observed,
337 // possibly from other subframes. 393 // possibly from other subframes.
338 const int last_subframe_loading_behavior_flags = 394 const int last_subframe_loading_behavior_flags =
339 subframe_metadata_->behavior_flags; 395 subframe_metadata_->behavior_flags;
340 subframe_metadata_->behavior_flags |= subframe_metadata.behavior_flags; 396 subframe_metadata_->behavior_flags |= subframe_metadata.behavior_flags;
341 if (last_subframe_loading_behavior_flags == 397 if (last_subframe_loading_behavior_flags ==
(...skipping 25 matching lines...) Expand all
367 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); 423 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING);
368 return; 424 return;
369 } 425 }
370 426
371 mojom::PaintTimingPtr last_paint_timing = 427 mojom::PaintTimingPtr last_paint_timing =
372 std::move(pending_merged_page_timing_->paint_timing); 428 std::move(pending_merged_page_timing_->paint_timing);
373 // Update the pending_merged_page_timing_, making sure to merge the previously 429 // Update the pending_merged_page_timing_, making sure to merge the previously
374 // observed |paint_timing|, which is tracked across all frames in the page. 430 // observed |paint_timing|, which is tracked across all frames in the page.
375 pending_merged_page_timing_ = new_timing.Clone(); 431 pending_merged_page_timing_ = new_timing.Clone();
376 pending_merged_page_timing_->paint_timing = std::move(last_paint_timing); 432 pending_merged_page_timing_->paint_timing = std::move(last_paint_timing);
377 MergePaintTiming(base::TimeDelta(), *new_timing.paint_timing,
378 true /* is_main_frame */);
379 433
380 DispatchTimingUpdates(); 434 PaintTimingMerger merger(pending_merged_page_timing_->paint_timing.get());
435 merger.Merge(base::TimeDelta(), *new_timing.paint_timing,
436 true /* is_main_frame */);
437
438 MaybeDispatchTimingUpdates(merger.did_merge_new_timing_value());
381 } 439 }
382 440
383 void PageLoadMetricsUpdateDispatcher::UpdateMainFrameMetadata( 441 void PageLoadMetricsUpdateDispatcher::UpdateMainFrameMetadata(
384 const mojom::PageLoadMetadata& new_metadata) { 442 const mojom::PageLoadMetadata& new_metadata) {
385 if (main_frame_metadata_->Equals(new_metadata)) 443 if (main_frame_metadata_->Equals(new_metadata))
386 return; 444 return;
387 445
388 // Ensure flags sent previously are still present in the new metadata fields. 446 // Ensure flags sent previously are still present in the new metadata fields.
389 const bool valid_behavior_descendent = 447 const bool valid_behavior_descendent =
390 (main_frame_metadata_->behavior_flags & new_metadata.behavior_flags) == 448 (main_frame_metadata_->behavior_flags & new_metadata.behavior_flags) ==
391 main_frame_metadata_->behavior_flags; 449 main_frame_metadata_->behavior_flags;
392 if (!valid_behavior_descendent) { 450 if (!valid_behavior_descendent) {
393 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); 451 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT);
394 return; 452 return;
395 } 453 }
396 454
397 main_frame_metadata_ = new_metadata.Clone(); 455 main_frame_metadata_ = new_metadata.Clone();
398 client_->OnMainFrameMetadataChanged(); 456 client_->OnMainFrameMetadataChanged();
399 } 457 }
400 458
459 void PageLoadMetricsUpdateDispatcher::MaybeDispatchTimingUpdates(
460 bool did_merge_new_timing_value) {
461 // If we merged a new timing value, then we should buffer updates for
462 // |kBufferTimerDelayMillis|, to allow for any other out of order timings to
463 // arrive before we dispatch the minimum observed timings to observers.
464 if (did_merge_new_timing_value) {
465 timer_->Start(
466 FROM_HERE, base::TimeDelta::FromMilliseconds(kBufferTimerDelayMillis),
467 base::Bind(&PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates,
468 base::Unretained(this)));
469 } else {
470 DispatchTimingUpdates();
471 }
472 }
473
401 void PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates() { 474 void PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates() {
475 if (timer_->IsRunning())
Charlie Harrison 2017/05/26 19:31:34 I would prefer if we could DCHECK(!timer_->IsRunni
Bryan McQuade 2017/05/26 20:07:32 Done
476 return;
477
402 if (pending_merged_page_timing_->paint_timing->first_paint) { 478 if (pending_merged_page_timing_->paint_timing->first_paint) {
403 if (!pending_merged_page_timing_->parse_timing->parse_start || 479 if (!pending_merged_page_timing_->parse_timing->parse_start ||
404 !pending_merged_page_timing_->document_timing->first_layout) { 480 !pending_merged_page_timing_->document_timing->first_layout) {
405 // When merging paint events across frames, we can sometimes encounter 481 // When merging paint events across frames, we can sometimes encounter
406 // cases where we've received a first paint event for a child frame before 482 // cases where we've received a first paint event for a child frame before
407 // receiving required earlier events in the main frame, due to buffering 483 // receiving required earlier events in the main frame, due to buffering
408 // in the render process which results in out of order delivery. For 484 // in the render process which results in out of order delivery. For
409 // example, we may receive a notification for a first paint in a child 485 // example, we may receive a notification for a first paint in a child
410 // frame before we've received a notification for parse start or first 486 // frame before we've received a notification for parse start or first
411 // layout in the main frame. In these cases, we delay sending timing 487 // layout in the main frame. In these cases, we delay sending timing
412 // updates until we've received all expected events (e.g. wait to receive 488 // updates until we've received all expected events (e.g. wait to receive
413 // a parse or layout event before dispatching a paint event), so observers 489 // a parse or layout event before dispatching a paint event), so observers
414 // can make assumptions about ordering of these events in their callbacks. 490 // can make assumptions about ordering of these events in their callbacks.
415 return; 491 return;
416 } 492 }
417 } 493 }
418 494
419 if (current_merged_page_timing_->Equals(*pending_merged_page_timing_)) 495 if (current_merged_page_timing_->Equals(*pending_merged_page_timing_))
420 return; 496 return;
497
498 LogIfOutOfOrderTiming(current_merged_page_timing_->paint_timing->first_paint,
499 pending_merged_page_timing_->paint_timing->first_paint);
500 LogIfOutOfOrderTiming(
501 current_merged_page_timing_->paint_timing->first_text_paint,
502 pending_merged_page_timing_->paint_timing->first_text_paint);
503 LogIfOutOfOrderTiming(
504 current_merged_page_timing_->paint_timing->first_image_paint,
505 pending_merged_page_timing_->paint_timing->first_image_paint);
506 LogIfOutOfOrderTiming(
507 current_merged_page_timing_->paint_timing->first_contentful_paint,
508 pending_merged_page_timing_->paint_timing->first_contentful_paint);
509
421 current_merged_page_timing_ = pending_merged_page_timing_->Clone(); 510 current_merged_page_timing_ = pending_merged_page_timing_->Clone();
422 511
423 internal::PageLoadTimingStatus status = 512 internal::PageLoadTimingStatus status =
424 IsValidPageLoadTiming(*pending_merged_page_timing_); 513 IsValidPageLoadTiming(*pending_merged_page_timing_);
425 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status, 514 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status,
426 internal::LAST_PAGE_LOAD_TIMING_STATUS); 515 internal::LAST_PAGE_LOAD_TIMING_STATUS);
427 516
428 client_->OnTimingChanged(); 517 client_->OnTimingChanged();
429 } 518 }
430 519
431 } // namespace page_load_metrics 520 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698