Commit 328fc7ff authored by Roman Aleksandrov's avatar Roman Aleksandrov Committed by Commit Bot

VersionUpdater: Add new update progress calculation.

Add new update progress calculation which is based on total time left
expectation. New update progress is gradually changed during the update.

Bug: 1117036
Change-Id: I11478e06af64137ebc7643495d198537d1031657
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2358681Reviewed-by: default avatarRoman Sorokin [CET] <rsorokin@chromium.org>
Commit-Queue: Roman Aleksandrov <raleksandrov@google.com>
Cr-Commit-Position: refs/heads/master@{#799621}
parent e4b5cae2
...@@ -18,16 +18,25 @@ constexpr base::TimeDelta kDownloadTime = base::TimeDelta::FromMinutes(50); ...@@ -18,16 +18,25 @@ constexpr base::TimeDelta kDownloadTime = base::TimeDelta::FromMinutes(50);
constexpr base::TimeDelta kVerifyingTime = base::TimeDelta::FromMinutes(5); constexpr base::TimeDelta kVerifyingTime = base::TimeDelta::FromMinutes(5);
constexpr base::TimeDelta kFinalizingTime = base::TimeDelta::FromMinutes(5); constexpr base::TimeDelta kFinalizingTime = base::TimeDelta::FromMinutes(5);
struct StageTimeExpectation { // Progress in percent falls on a stage. Should be 100 in total.
const int kDownloadProgress = 90;
const int kVerifyingProgress = 5;
const int kFinalizingProgress = 5;
const int kTotalProgress = 100;
struct StageTimeExpectationProgress {
update_engine::Operation stage_; update_engine::Operation stage_;
base::TimeDelta time_estimation_; base::TimeDelta time_estimation_;
int progress_;
}; };
// Stages for which |estimated_time_left| should be calculated. // Stages for which `estimated_time_left` and progress should be calculated.
constexpr StageTimeExpectation kStages[] = { constexpr StageTimeExpectationProgress kStages[] = {
{update_engine::Operation::DOWNLOADING, kDownloadTime}, {update_engine::Operation::DOWNLOADING, kDownloadTime, kDownloadProgress},
{update_engine::Operation::VERIFYING, kVerifyingTime}, {update_engine::Operation::VERIFYING, kVerifyingTime, kVerifyingProgress},
{update_engine::Operation::FINALIZING, kFinalizingTime}, {update_engine::Operation::FINALIZING, kFinalizingTime,
kFinalizingProgress},
}; };
// Minimum timestep between two consecutive measurements for the download rates. // Minimum timestep between two consecutive measurements for the download rates.
...@@ -74,12 +83,14 @@ base::TimeDelta UpdateTimeEstimator::GetDownloadTimeLeft() const { ...@@ -74,12 +83,14 @@ base::TimeDelta UpdateTimeEstimator::GetDownloadTimeLeft() const {
return download_time_left_; return download_time_left_;
} }
base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const { UpdateTimeEstimator::UpdateStatus UpdateTimeEstimator::GetUpdateStatus() const {
base::TimeDelta time_left_estimation; base::TimeDelta time_left_estimation;
int progress_left = 0;
bool stage_found = false; bool stage_found = false;
for (const auto& el : kStages) { for (const auto& el : kStages) {
if (stage_found) { if (stage_found) {
time_left_estimation += el.time_estimation_; time_left_estimation += el.time_estimation_;
progress_left += el.progress_;
} }
if (el.stage_ != current_stage_) if (el.stage_ != current_stage_)
continue; continue;
...@@ -90,6 +101,7 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const { ...@@ -90,6 +101,7 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const {
tick_clock_->NowTicks() - stage_started_time_; tick_clock_->NowTicks() - stage_started_time_;
const base::TimeDelta time_left = const base::TimeDelta time_left =
std::max(el.time_estimation_ - time_spent, base::TimeDelta()); std::max(el.time_estimation_ - time_spent, base::TimeDelta());
// Time left calculation.
if (current_stage_ == update_engine::Operation::DOWNLOADING && if (current_stage_ == update_engine::Operation::DOWNLOADING &&
has_download_time_estimation_) { has_download_time_estimation_) {
const base::TimeDelta time_left_speed_estimation = const base::TimeDelta time_left_speed_estimation =
...@@ -98,8 +110,18 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const { ...@@ -98,8 +110,18 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const {
} else { } else {
time_left_estimation += time_left; time_left_estimation += time_left;
} }
// Progress left calculation.
if (current_stage_ == update_engine::Operation::DOWNLOADING) {
const double download_progress_left = 1.0 - download_last_progress_;
const int current_stage_progress_left =
base::ClampRound(download_progress_left * el.progress_);
progress_left += current_stage_progress_left;
} else {
progress_left +=
base::ClampRound((time_left / el.time_estimation_) * el.progress_);
}
} }
return time_left_estimation; return {time_left_estimation, kTotalProgress - progress_left};
} }
void UpdateTimeEstimator::UpdateForTotalTimeLeftEstimation( void UpdateTimeEstimator::UpdateForTotalTimeLeftEstimation(
......
...@@ -17,6 +17,10 @@ namespace chromeos { ...@@ -17,6 +17,10 @@ namespace chromeos {
// Helper class that gives time left expectations. // Helper class that gives time left expectations.
class UpdateTimeEstimator { class UpdateTimeEstimator {
public: public:
struct UpdateStatus {
base::TimeDelta time_left;
int progress;
};
UpdateTimeEstimator(); UpdateTimeEstimator();
// Updates data needed for estimation. // Updates data needed for estimation.
...@@ -29,8 +33,9 @@ class UpdateTimeEstimator { ...@@ -29,8 +33,9 @@ class UpdateTimeEstimator {
// Estimate time left for a downloading stage to complete. // Estimate time left for a downloading stage to complete.
base::TimeDelta GetDownloadTimeLeft() const; base::TimeDelta GetDownloadTimeLeft() const;
// Estimate time left for an update to complete. // Estimate time left for an update to complete and current update progress in
base::TimeDelta GetTimeLeft() const; // procents.
UpdateStatus GetUpdateStatus() const;
void set_tick_clock_for_testing(const base::TickClock* tick_clock) { void set_tick_clock_for_testing(const base::TickClock* tick_clock) {
tick_clock_ = tick_clock; tick_clock_ = tick_clock;
......
...@@ -13,6 +13,8 @@ constexpr int kFinalizingTimeInSeconds = 5 * 60; ...@@ -13,6 +13,8 @@ constexpr int kFinalizingTimeInSeconds = 5 * 60;
constexpr base::TimeDelta kTimeAdvanceSeconds10 = constexpr base::TimeDelta kTimeAdvanceSeconds10 =
base::TimeDelta::FromSeconds(10); base::TimeDelta::FromSeconds(10);
constexpr base::TimeDelta kTimeAdvanceSeconds60 =
base::TimeDelta::FromSeconds(60);
constexpr base::TimeDelta kZeroTime = base::TimeDelta(); constexpr base::TimeDelta kZeroTime = base::TimeDelta();
} // anonymous namespace } // anonymous namespace
...@@ -67,12 +69,41 @@ TEST_F(UpdateTimeEstimatorUnitTest, TotalTimeLeft) { ...@@ -67,12 +69,41 @@ TEST_F(UpdateTimeEstimatorUnitTest, TotalTimeLeft) {
time_estimator_.Update(status); time_estimator_.Update(status);
tick_clock_.Advance(kTimeAdvanceSeconds10); tick_clock_.Advance(kTimeAdvanceSeconds10);
EXPECT_EQ(time_estimator_.GetTimeLeft(), EXPECT_EQ(time_estimator_.GetUpdateStatus().time_left,
base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds) - base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds) -
kTimeAdvanceSeconds10); kTimeAdvanceSeconds10);
tick_clock_.Advance(base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds)); tick_clock_.Advance(base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds));
EXPECT_EQ(time_estimator_.GetTimeLeft(), kZeroTime); EXPECT_EQ(time_estimator_.GetUpdateStatus().time_left, kZeroTime);
}
TEST_F(UpdateTimeEstimatorUnitTest, DownloadingProgress) {
update_engine::StatusResult status =
CreateStatusResult(update_engine::Operation::DOWNLOADING, 1.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 0);
tick_clock_.Advance(kTimeAdvanceSeconds10);
status.set_progress(0.01);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 1);
tick_clock_.Advance(kTimeAdvanceSeconds10);
status.set_progress(0.10);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 9);
status = CreateStatusResult(update_engine::Operation::VERIFYING, 0.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 90);
tick_clock_.Advance(kTimeAdvanceSeconds60);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 91);
status = CreateStatusResult(update_engine::Operation::FINALIZING, 0.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 95);
tick_clock_.Advance(kTimeAdvanceSeconds60);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 96);
} }
} // namespace chromeos } // namespace chromeos
...@@ -253,7 +253,9 @@ void VersionUpdater::UpdateStatusChanged( ...@@ -253,7 +253,9 @@ void VersionUpdater::UpdateStatusChanged(
} }
if (time_estimator_.HasTotalTime(status.current_operation())) { if (time_estimator_.HasTotalTime(status.current_operation())) {
update_info_.total_time_left = time_estimator_.GetTimeLeft(); const auto update_status = time_estimator_.GetUpdateStatus();
update_info_.total_time_left = update_status.time_left;
update_info_.better_update_progress = update_status.progress;
if (!refresh_timer_) { if (!refresh_timer_) {
refresh_timer_ = std::make_unique<base::RepeatingTimer>(tick_clock_); refresh_timer_ = std::make_unique<base::RepeatingTimer>(tick_clock_);
refresh_timer_->Start(FROM_HERE, kUpdateTime, this, refresh_timer_->Start(FROM_HERE, kUpdateTime, this,
...@@ -272,7 +274,9 @@ void VersionUpdater::UpdateStatusChanged( ...@@ -272,7 +274,9 @@ void VersionUpdater::UpdateStatusChanged(
} }
void VersionUpdater::RefreshTimeLeftEstimation() { void VersionUpdater::RefreshTimeLeftEstimation() {
update_info_.total_time_left = time_estimator_.GetTimeLeft(); const auto update_status = time_estimator_.GetUpdateStatus();
update_info_.total_time_left = update_status.time_left;
update_info_.better_update_progress = update_status.progress;
delegate_->UpdateInfoChanged(update_info_); delegate_->UpdateInfoChanged(update_info_);
} }
......
...@@ -52,6 +52,8 @@ class VersionUpdater : public UpdateEngineClient::Observer, ...@@ -52,6 +52,8 @@ class VersionUpdater : public UpdateEngineClient::Observer,
// Time left for an update to finish in seconds. // Time left for an update to finish in seconds.
base::TimeDelta total_time_left; base::TimeDelta total_time_left;
// Progress of an update which is based on total time left expectation.
int better_update_progress = 0;
// Estimated time left for only downloading stage, in seconds. // Estimated time left for only downloading stage, in seconds.
// TODO(crbug.com/1101317): Remove when better update is launched. // TODO(crbug.com/1101317): Remove when better update is launched.
......
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