Commit 3d256ea0 authored by Edwin Joe's avatar Edwin Joe Committed by Commit Bot

Added a PausableElapsedTimer.

There are some cases where an elapsed timer that can be paused is
useful.

An example case is recording surface embedding time to UMA metric.
Currently, the surface embedding time is recorded by simply taking
the different between the TimeTicks of the surface id allocation time
and the TimeTicks of when Surface::OnWillBeDrawn is called.
However, it is possible that surface id is allocated when the Renderer
is not visible, i.e. when the child changes size while hidden.
In this case, the surface embedding time will be arbitrarily inflated
since Surface::OnWillBeDrawn will not be called until it becomes
visible.

By using a pausable elapsed timer, the surface embedding time can be
paused if the renderer is hidden, and resumed when it becomes visible
again.

Bug: 949967
Change-Id: Ide8e5b67a06bae7d3ca1352574c477f35e32369c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1576331Reviewed-by: default avatarJonathan Ross <jonross@chromium.org>
Commit-Queue: Edwin Joe <ejoe@google.com>
Cr-Commit-Position: refs/heads/master@{#653372}
parent 2e9940c4
...@@ -151,6 +151,8 @@ viz_component("common") { ...@@ -151,6 +151,8 @@ viz_component("common") {
"hit_test/hit_test_data_builder.h", "hit_test/hit_test_data_builder.h",
"hit_test/hit_test_region_list.cc", "hit_test/hit_test_region_list.cc",
"hit_test/hit_test_region_list.h", "hit_test/hit_test_region_list.h",
"pausable_elapsed_timer.cc",
"pausable_elapsed_timer.h",
"presentation_feedback_map.h", "presentation_feedback_map.h",
"quads/compositor_frame.cc", "quads/compositor_frame.cc",
"quads/compositor_frame.h", "quads/compositor_frame.h",
...@@ -309,6 +311,7 @@ viz_source_set("unit_tests") { ...@@ -309,6 +311,7 @@ viz_source_set("unit_tests") {
"gl_scaler_test_util.h", "gl_scaler_test_util.h",
"gl_scaler_unittest.cc", "gl_scaler_unittest.cc",
"gpu/context_cache_controller_unittest.cc", "gpu/context_cache_controller_unittest.cc",
"pausable_elapsed_timer_unittest.cc",
"quads/draw_quad_unittest.cc", "quads/draw_quad_unittest.cc",
"quads/render_pass_unittest.cc", "quads/render_pass_unittest.cc",
"resources/platform_color_unittest.cc", "resources/platform_color_unittest.cc",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/pausable_elapsed_timer.h"
namespace viz {
PausableElapsedTimer::PausableElapsedTimer() {}
base::TimeDelta PausableElapsedTimer::Elapsed() const {
if (active_timer_)
return previous_elapsed_ + active_timer_->Elapsed();
else
return previous_elapsed_;
}
void PausableElapsedTimer::Pause() {
if (!active_timer_)
return;
previous_elapsed_ += active_timer_->Elapsed();
active_timer_.reset();
}
void PausableElapsedTimer::Resume() {
if (!active_timer_)
active_timer_.emplace();
}
} // namespace viz
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_PAUSABLE_ELAPSED_TIMER_H_
#define COMPONENTS_VIZ_COMMON_PAUSABLE_ELAPSED_TIMER_H_
#include "base/macros.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "components/viz/common/viz_common_export.h"
namespace viz {
// A extension of base::ElapsedTimer to support pausing. The timer starts off in
// a paused state. This allows the calculation of the duration of a task to not
// include the time when it is not running.
class VIZ_COMMON_EXPORT PausableElapsedTimer {
public:
PausableElapsedTimer();
// Returns the time elapsed since object construction excluding the time when
// the timer is paused.
base::TimeDelta Elapsed() const;
// Pause the timer. No-op if already paused.
void Pause();
// Resume the timer. No-op is not currently paused.
void Resume();
private:
base::Optional<base::ElapsedTimer> active_timer_;
base::TimeDelta previous_elapsed_;
DISALLOW_COPY_AND_ASSIGN(PausableElapsedTimer);
};
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_PAUSABLE_ELAPSED_TIMER_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/pausable_elapsed_timer.h"
#include "base/test/scoped_mock_clock_override.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
class PausableElapsedTimerTest : public testing::Test {
protected:
base::ScopedMockClockOverride mock_clock_;
};
// The timer starts as paused.
TEST_F(PausableElapsedTimerTest, StartsAsPaused) {
PausableElapsedTimer timer;
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(2));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(0));
}
// Get the elapsed time while paused, without any pause before.
TEST_F(PausableElapsedTimerTest, ElapsedWhilePaused) {
PausableElapsedTimer timer;
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(5));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(5));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(5));
}
// Get the elapsed time while unpaused with pausing in between.
TEST_F(PausableElapsedTimerTest, WithPausing) {
PausableElapsedTimer timer;
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(2));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(3));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(5));
}
// Get the elapsed time while paused, with some pauses before.
TEST_F(PausableElapsedTimerTest, ElpasedWhilePausedWithPausesBefore) {
PausableElapsedTimer timer;
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(2));
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(3));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(7));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(4));
}
// Pausing while already paused should not change the internal time.
TEST_F(PausableElapsedTimerTest, PausingWhilePaused) {
PausableElapsedTimer timer;
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(2));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(4));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(1));
}
// Resuming while not paused should not change the internal time.
TEST_F(PausableElapsedTimerTest, ResumingWhileNotPaused) {
PausableElapsedTimer timer;
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
timer.Pause();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(3));
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(5));
timer.Resume();
mock_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
EXPECT_EQ(timer.Elapsed(), base::TimeDelta::FromMilliseconds(16));
}
} // namespace viz
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