chromium/components/performance_manager/graph/policies/prefetch_virtual_memory_policy.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/performance_manager/graph/policies/prefetch_virtual_memory_policy.h"

#include <utility>

#include "base/files/file_util.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/trace_event/base_tracing.h"

namespace performance_manager::policies {

PrefetchVirtualMemoryPolicy::PrefetchVirtualMemoryPolicy(
    base::FilePath file_to_prefetch)
    : file_to_prefetch_(std::move(file_to_prefetch)),
      last_prefetch_time_(base::TimeTicks::Now()),
      ongoing_preread_(false),
      weak_ptr_factory_(this) {
  TRACE_EVENT_INSTANT("browser",
                      "PrefetchVirtualMemoryPolicy::"
                      "PrefetchVirtualMemoryPolicy");
}

PrefetchVirtualMemoryPolicy::~PrefetchVirtualMemoryPolicy() {
  TRACE_EVENT_INSTANT("browser",
                      "PrefetchVirtualMemoryPolicy::~"
                      "PrefetchVirtualMemoryPolicy");
}

void PrefetchVirtualMemoryPolicy::OnPassedToGraph(Graph* graph) {
  DCHECK(graph->HasOnlySystemNode());
  graph->AddProcessNodeObserver(this);
}

void PrefetchVirtualMemoryPolicy::OnTakenFromGraph(Graph* graph) {
  graph->RemoveProcessNodeObserver(this);
}

// When a process is added to the graph check if we need to refresh the main
// DLL contents in RAM.
void PrefetchVirtualMemoryPolicy::OnProcessNodeAdded(
    const ProcessNode* process_node) {
  if (NeedToRefresh() && !ongoing_preread_) {
    TRACE_EVENT0("browser", "PrefetchVirtualMemoryPolicy::NeedToRefresh");
    ongoing_preread_ = true;
    base::ThreadPool::PostTaskAndReply(
        FROM_HERE,
        {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
        base::BindOnce(
            [](base::FilePath file) {
              base::PreReadFile(file,
                                /*is_executable=*/true,
                                /*sequential=*/false);
            },
            file_to_prefetch_),
        base::BindOnce(
            [](base::WeakPtr<PrefetchVirtualMemoryPolicy> policy) {
              if (policy) {
                policy->ongoing_preread_ = false;
              }
            },
            weak_ptr_factory_.GetWeakPtr()));
  }
}

bool PrefetchVirtualMemoryPolicy::NeedToRefresh() {
  // Interval at which we will refresh the main browser DLL.
  constexpr base::TimeDelta kRefreshDelay = base::Seconds(5);

  base::TimeTicks now = base::TimeTicks::Now();
  base::TimeDelta elapsed = now - last_prefetch_time_;
  if (elapsed > kRefreshDelay) {
    last_prefetch_time_ = now;
    return true;
  }
  return false;
}

}  // namespace performance_manager::policies