| Index: components/translate/core/browser/ranker_model_loader.cc
|
| diff --git a/components/translate/core/browser/ranker_model_loader.cc b/components/translate/core/browser/ranker_model_loader.cc
|
| deleted file mode 100644
|
| index eb8175977c4f284b7204288d514ca2d79e88b13b..0000000000000000000000000000000000000000
|
| --- a/components/translate/core/browser/ranker_model_loader.cc
|
| +++ /dev/null
|
| @@ -1,309 +0,0 @@
|
| -// Copyright 2017 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/translate/core/browser/ranker_model_loader.h"
|
| -
|
| -#include <utility>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/command_line.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/files/important_file_writer.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/metrics/histogram_macros.h"
|
| -#include "base/profiler/scoped_tracker.h"
|
| -#include "base/sequenced_task_runner.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/task_scheduler/post_task.h"
|
| -#include "base/threading/sequenced_task_runner_handle.h"
|
| -#include "components/translate/core/browser/proto/ranker_model.pb.h"
|
| -#include "components/translate/core/browser/ranker_model.h"
|
| -#include "components/translate/core/browser/translate_url_fetcher.h"
|
| -
|
| -namespace translate {
|
| -namespace {
|
| -
|
| -using chrome_intelligence::RankerModel;
|
| -using chrome_intelligence::RankerModelProto;
|
| -
|
| -constexpr int kUrlFetcherId = 2;
|
| -
|
| -// The minimum duration, in minutes, between download attempts.
|
| -constexpr int kMinRetryDelayMins = 3;
|
| -
|
| -// Suffixes for the various histograms produced by the backend.
|
| -const char kWriteTimerHistogram[] = ".Timer.WriteModel";
|
| -const char kReadTimerHistogram[] = ".Timer.ReadModel";
|
| -const char kDownloadTimerHistogram[] = ".Timer.DownloadModel";
|
| -const char kParsetimerHistogram[] = ".Timer.ParseModel";
|
| -const char kModelStatusHistogram[] = ".Model.Status";
|
| -
|
| -// Helper function to UMA log a timer histograms.
|
| -void RecordTimerHistogram(const std::string& name, base::TimeDelta duration) {
|
| - base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
|
| - name, base::TimeDelta::FromMilliseconds(10),
|
| - base::TimeDelta::FromMilliseconds(200000), 100,
|
| - base::HistogramBase::kUmaTargetedHistogramFlag);
|
| - DCHECK(counter);
|
| - counter->AddTime(duration);
|
| -}
|
| -
|
| -// A helper class to produce a scoped timer histogram that supports using a
|
| -// non-static-const name.
|
| -class MyScopedHistogramTimer {
|
| - public:
|
| - MyScopedHistogramTimer(const base::StringPiece& name)
|
| - : name_(name.begin(), name.end()), start_(base::TimeTicks::Now()) {}
|
| -
|
| - ~MyScopedHistogramTimer() {
|
| - RecordTimerHistogram(name_, base::TimeTicks::Now() - start_);
|
| - }
|
| -
|
| - private:
|
| - const std::string name_;
|
| - const base::TimeTicks start_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(MyScopedHistogramTimer);
|
| -};
|
| -
|
| -std::string LoadFromFile(const base::FilePath& model_path) {
|
| - DCHECK(!model_path.empty());
|
| - DVLOG(2) << "Reading data from: " << model_path.value();
|
| - std::string data;
|
| - if (!base::ReadFileToString(model_path, &data) || data.empty()) {
|
| - DVLOG(2) << "Failed to read data from: " << model_path.value();
|
| - data.clear();
|
| - }
|
| - return data;
|
| -}
|
| -
|
| -void SaveToFile(const GURL& model_url,
|
| - const base::FilePath& model_path,
|
| - const std::string& model_data,
|
| - const std::string& uma_prefix) {
|
| - DVLOG(2) << "Saving model from '" << model_url << "'' to '"
|
| - << model_path.value() << "'.";
|
| - MyScopedHistogramTimer timer(uma_prefix + kWriteTimerHistogram);
|
| - base::ImportantFileWriter::WriteFileAtomically(model_path, model_data);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -RankerModelLoader::RankerModelLoader(
|
| - ValidateModelCallback validate_model_cb,
|
| - OnModelAvailableCallback on_model_available_cb,
|
| - base::FilePath model_path,
|
| - GURL model_url,
|
| - std::string uma_prefix)
|
| - : background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
|
| - {base::MayBlock(), base::TaskPriority::BACKGROUND,
|
| - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
|
| - validate_model_cb_(std::move(validate_model_cb)),
|
| - on_model_available_cb_(std::move(on_model_available_cb)),
|
| - model_path_(std::move(model_path)),
|
| - model_url_(std::move(model_url)),
|
| - uma_prefix_(std::move(uma_prefix)),
|
| - url_fetcher_(base::MakeUnique<TranslateURLFetcher>(kUrlFetcherId)),
|
| - weak_ptr_factory_(this) {}
|
| -
|
| -RankerModelLoader::~RankerModelLoader() {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| -}
|
| -
|
| -void RankerModelLoader::NotifyOfRankerActivity() {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - switch (state_) {
|
| - case LoaderState::NOT_STARTED:
|
| - if (!model_path_.empty()) {
|
| - StartLoadFromFile();
|
| - break;
|
| - }
|
| - // There was no configured model path. Switch the state to IDLE and
|
| - // fall through to consider the URL.
|
| - state_ = LoaderState::IDLE;
|
| - case LoaderState::IDLE:
|
| - if (model_url_.is_valid()) {
|
| - StartLoadFromURL();
|
| - break;
|
| - }
|
| - // There was no configured model URL. Switch the state to FINISHED and
|
| - // fall through.
|
| - state_ = LoaderState::FINISHED;
|
| - case LoaderState::FINISHED:
|
| - case LoaderState::LOADING_FROM_FILE:
|
| - case LoaderState::LOADING_FROM_URL:
|
| - // Nothing to do.
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void RankerModelLoader::StartLoadFromFile() {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - DCHECK_EQ(state_, LoaderState::NOT_STARTED);
|
| - DCHECK(!model_path_.empty());
|
| - state_ = LoaderState::LOADING_FROM_FILE;
|
| - load_start_time_ = base::TimeTicks::Now();
|
| - base::PostTaskAndReplyWithResult(background_task_runner_.get(), FROM_HERE,
|
| - base::Bind(&LoadFromFile, model_path_),
|
| - base::Bind(&RankerModelLoader::OnFileLoaded,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void RankerModelLoader::OnFileLoaded(const std::string& data) {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - DCHECK_EQ(state_, LoaderState::LOADING_FROM_FILE);
|
| -
|
| - // Record the duration of the download.
|
| - RecordTimerHistogram(uma_prefix_ + kReadTimerHistogram,
|
| - base::TimeTicks::Now() - load_start_time_);
|
| -
|
| - // Empty data means |model_path| wasn't successfully read. Otherwise,
|
| - // parse and validate the model.
|
| - std::unique_ptr<RankerModel> model;
|
| - if (data.empty()) {
|
| - ReportModelStatus(RankerModelStatus::LOAD_FROM_CACHE_FAILED);
|
| - } else {
|
| - model = CreateAndValidateModel(data);
|
| - }
|
| -
|
| - // If |model| is nullptr, then data is empty or the parse failed. Transition
|
| - // to IDLE, from which URL download can be attempted.
|
| - if (!model) {
|
| - state_ = LoaderState::IDLE;
|
| - } else {
|
| - // The model is valid. The client is willing/able to use it. Keep track
|
| - // of where it originated and whether or not is has expired.
|
| - std::string url_spec = model->GetSourceURL();
|
| - bool is_expired = model->IsExpired();
|
| - bool is_finished = url_spec == model_url_.spec() && !is_expired;
|
| -
|
| - DVLOG(2) << (is_expired ? "Expired m" : "M") << "odel in '"
|
| - << model_path_.value() << "' was originally downloaded from '"
|
| - << url_spec << "'.";
|
| -
|
| - // If the cached model came from currently configured |model_url_| and has
|
| - // not expired, transition to FINISHED, as there is no need for a model
|
| - // download; otherwise, transition to IDLE.
|
| - state_ = is_finished ? LoaderState::FINISHED : LoaderState::IDLE;
|
| -
|
| - // Transfer the model to the client.
|
| - on_model_available_cb_.Run(std::move(model));
|
| - }
|
| -
|
| - // Notify the state machine. This will immediately kick off a download if
|
| - // one is required, instead of waiting for the next organic detection of
|
| - // ranker activity.
|
| - NotifyOfRankerActivity();
|
| -}
|
| -
|
| -void RankerModelLoader::StartLoadFromURL() {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - DCHECK_EQ(state_, LoaderState::IDLE);
|
| - DCHECK(model_url_.is_valid());
|
| -
|
| - // Do nothing if the download attempts should be throttled.
|
| - if (base::TimeTicks::Now() < next_earliest_download_time_) {
|
| - DVLOG(2) << "Last download attempt was too recent.";
|
| - ReportModelStatus(RankerModelStatus::DOWNLOAD_THROTTLED);
|
| - return;
|
| - }
|
| -
|
| - // Kick off the next download attempt and reset the time of the next earliest
|
| - // allowable download attempt.
|
| - DVLOG(2) << "Downloading model from: " << model_url_;
|
| - state_ = LoaderState::LOADING_FROM_URL;
|
| - load_start_time_ = base::TimeTicks::Now();
|
| - next_earliest_download_time_ =
|
| - load_start_time_ + base::TimeDelta::FromMinutes(kMinRetryDelayMins);
|
| - bool request_started = url_fetcher_->Request(
|
| - model_url_, base::Bind(&RankerModelLoader::OnURLFetched,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| -
|
| - // |url_fetcher_| maintains a request retry counter. If all allowed attempts
|
| - // have already been exhausted, then the loader is finished and has abandoned
|
| - // loading the model.
|
| - if (!request_started) {
|
| - DVLOG(2) << "Model download abandoned.";
|
| - ReportModelStatus(RankerModelStatus::MODEL_LOADING_ABANDONED);
|
| - state_ = LoaderState::FINISHED;
|
| - }
|
| -}
|
| -
|
| -void RankerModelLoader::OnURLFetched(int /* id */,
|
| - bool success,
|
| - const std::string& data) {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - DCHECK_EQ(state_, LoaderState::LOADING_FROM_URL);
|
| -
|
| - // Record the duration of the download.
|
| - RecordTimerHistogram(uma_prefix_ + kDownloadTimerHistogram,
|
| - base::TimeTicks::Now() - load_start_time_);
|
| -
|
| - // On request failure, transition back to IDLE. The loader will retry, or
|
| - // enforce the max download attempts, later.
|
| - if (!success || data.empty()) {
|
| - DVLOG(2) << "Download from '" << model_url_ << "'' failed.";
|
| - ReportModelStatus(RankerModelStatus::DOWNLOAD_FAILED);
|
| - state_ = LoaderState::IDLE;
|
| - return;
|
| - }
|
| -
|
| - // Attempt to loads the model. If this fails, transition back to IDLE. The
|
| - // loader will retry, or enfore the max download attempts, later.
|
| - auto model = CreateAndValidateModel(data);
|
| - if (!model) {
|
| - DVLOG(2) << "Model from '" << model_url_ << "'' not valid.";
|
| - state_ = LoaderState::IDLE;
|
| - return;
|
| - }
|
| -
|
| - // The model is valid. Update the metadata to track the source URL and
|
| - // download timestamp.
|
| - auto* metadata = model->mutable_proto()->mutable_metadata();
|
| - metadata->set_source(model_url_.spec());
|
| - metadata->set_last_modified_sec(
|
| - (base::Time::Now() - base::Time()).InSeconds());
|
| -
|
| - // Cache the model to model_path_, in the background.
|
| - if (!model_path_.empty()) {
|
| - background_task_runner_->PostTask(
|
| - FROM_HERE, base::BindOnce(&SaveToFile, model_url_, model_path_,
|
| - model->SerializeAsString(), uma_prefix_));
|
| - }
|
| -
|
| - // The loader is finished. Transfer the model to the client.
|
| - state_ = LoaderState::FINISHED;
|
| - on_model_available_cb_.Run(std::move(model));
|
| -}
|
| -
|
| -std::unique_ptr<chrome_intelligence::RankerModel>
|
| -RankerModelLoader::CreateAndValidateModel(const std::string& data) {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - MyScopedHistogramTimer timer(uma_prefix_ + kParsetimerHistogram);
|
| - auto model = RankerModel::FromString(data);
|
| - if (ReportModelStatus(model ? validate_model_cb_.Run(*model)
|
| - : RankerModelStatus::PARSE_FAILED) !=
|
| - RankerModelStatus::OK) {
|
| - return nullptr;
|
| - }
|
| - return model;
|
| -}
|
| -
|
| -RankerModelStatus RankerModelLoader::ReportModelStatus(
|
| - RankerModelStatus model_status) {
|
| - DCHECK(sequence_checker_.CalledOnValidSequence());
|
| - base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
|
| - uma_prefix_ + kModelStatusHistogram, 1,
|
| - static_cast<int>(RankerModelStatus::MAX),
|
| - static_cast<int>(RankerModelStatus::MAX) + 1,
|
| - base::HistogramBase::kUmaTargetedHistogramFlag);
|
| - if (histogram)
|
| - histogram->Add(static_cast<int>(model_status));
|
| - return model_status;
|
| -}
|
| -
|
| -} // namespace translate
|
|
|