0

Move performance scenario shared memory functions to a new file

This simplifies the core API in performance_scenarios.h by separating
out functions that are only used by the embedder to set up the scenario
system.

Bug: 365586676
Change-Id: Ie3df73686ac475172ac4b51b605776578509ed63
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6386727
Reviewed-by: Patrick Monette <pmonette@chromium.org>
Auto-Submit: Joe Mason <joenotcharles@google.com>
Commit-Queue: Joe Mason <joenotcharles@google.com>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1438138}
This commit is contained in:
Joe Mason
2025-03-26 08:23:30 -07:00
committed by Chromium LUCI CQ
parent 979c6f4f32
commit f01ea09d5c
19 changed files with 192 additions and 122 deletions

@ -7,7 +7,7 @@
#include <optional>
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
namespace base {
class SharedMemoryMapper;

@ -4,6 +4,9 @@
component("scenario_api") {
sources = [
"performance_scenario_memory.cc",
"performance_scenario_memory.h",
"performance_scenario_memory_forward.h",
"performance_scenario_observer.cc",
"performance_scenario_observer.h",
"performance_scenarios.cc",

@ -0,0 +1,72 @@
// Copyright 2025 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/scenario_api/performance_scenario_memory.h"
#include <optional>
#include <utility>
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/structured_shared_memory.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
namespace performance_scenarios {
namespace {
// Global pointers to the shared memory mappings.
scoped_refptr<RefCountedScenarioMapping>& MappingPtrForScope(
ScenarioScope scope) {
static base::NoDestructor<scoped_refptr<RefCountedScenarioMapping>>
current_process_mapping;
static base::NoDestructor<scoped_refptr<RefCountedScenarioMapping>>
global_mapping;
switch (scope) {
case ScenarioScope::kCurrentProcess:
return *current_process_mapping;
case ScenarioScope::kGlobal:
return *global_mapping;
}
NOTREACHED();
}
} // namespace
// TODO(crbug.com/365586676): Currently these are only mapped into browser and
// renderer processes. The global scenarios should also be mapped into utility
// processes.
ScopedReadOnlyScenarioMemory::ScopedReadOnlyScenarioMemory(
ScenarioScope scope,
base::ReadOnlySharedMemoryRegion region)
: scope_(scope) {
using SharedScenarioState = base::StructuredSharedMemory<ScenarioState>;
std::optional<SharedScenarioState::ReadOnlyMapping> mapping =
SharedScenarioState::MapReadOnlyRegion(std::move(region));
if (mapping.has_value()) {
MappingPtrForScope(scope_) =
base::MakeRefCounted<RefCountedScenarioMapping>(
std::move(mapping.value()));
}
// The ObserverList must be created after mapping the memory, because it reads
// the scenario state in its constructor.
PerformanceScenarioObserverList::CreateForScope(PassKey(), scope_);
}
ScopedReadOnlyScenarioMemory::~ScopedReadOnlyScenarioMemory() {
PerformanceScenarioObserverList::DestroyForScope(PassKey(), scope_);
MappingPtrForScope(scope_).reset();
}
scoped_refptr<RefCountedScenarioMapping> GetScenarioMappingForScope(
ScenarioScope scope) {
return MappingPtrForScope(scope);
}
} // namespace performance_scenarios

@ -0,0 +1,54 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_H_
#define COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_H_
#include "base/component_export.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/shared_memory_safety_checker.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory_forward.h" // IWYU pragma: export
#include "components/performance_manager/scenario_api/performance_scenarios.h"
namespace performance_scenarios {
// The full scenario state to copy over shared memory.
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wpadded"
struct COMPONENT_EXPORT(SCENARIO_API) ScenarioState {
base::subtle::SharedAtomic<LoadingScenario> loading;
base::subtle::SharedAtomic<InputScenario> input;
};
#pragma clang diagnostic pop
// A scoped object that maps shared memory for the scenario state into the
// current process as long as it exists.
class COMPONENT_EXPORT(SCENARIO_API) ScopedReadOnlyScenarioMemory {
public:
// Maps `region` into the current process, as a read-only view of the memory
// holding the scenario state for `scope`.
ScopedReadOnlyScenarioMemory(ScenarioScope scope,
base::ReadOnlySharedMemoryRegion region);
~ScopedReadOnlyScenarioMemory();
ScopedReadOnlyScenarioMemory(const ScopedReadOnlyScenarioMemory&) = delete;
ScopedReadOnlyScenarioMemory& operator=(const ScopedReadOnlyScenarioMemory&) =
delete;
private:
using PassKey = base::PassKey<ScopedReadOnlyScenarioMemory>;
ScenarioScope scope_;
};
// Returns a pointer to the shared memory mapping registered for `scope`, or
// nullptr if there isn't any.
COMPONENT_EXPORT(SCENARIO_API)
scoped_refptr<RefCountedScenarioMapping> GetScenarioMappingForScope(
ScenarioScope scope);
} // namespace performance_scenarios
#endif // COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_H_

@ -0,0 +1,29 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_FORWARD_H_
#define COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_FORWARD_H_
#include "base/memory/ref_counted.h"
#include "base/memory/structured_shared_memory.h"
namespace performance_scenarios {
// The full scenario state to copy over shared memory.
struct ScenarioState;
// A scoped object that maps shared memory for the scenario state into the
// current process as long as it exists.
class ScopedReadOnlyScenarioMemory;
// Pointers to the mapped shared memory are held in thread-safe scoped_refptr's.
// The memory will be unmapped when the final reference is dropped. Functions
// that copy values out of the shared memory must hold a reference to it so that
// it's not unmapped while reading.
using RefCountedScenarioMapping = base::RefCountedData<
base::StructuredSharedMemory<ScenarioState>::ReadOnlyMapping>;
} // namespace performance_scenarios
#endif // COMPONENTS_PERFORMANCE_MANAGER_SCENARIO_API_PERFORMANCE_SCENARIO_MEMORY_FORWARD_H_

@ -12,8 +12,10 @@
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
namespace performance_scenarios {

@ -17,6 +17,7 @@
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory_forward.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
namespace performance_scenarios {

@ -15,6 +15,7 @@
#include "base/scoped_multi_source_observation.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

@ -4,38 +4,17 @@
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include <optional>
#include <atomic>
#include <utility>
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/containers/enum_set.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/structured_shared_memory.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
namespace performance_scenarios {
namespace {
// Global pointers to the shared memory mappings.
scoped_refptr<RefCountedScenarioMapping>& MappingPtrForScope(
ScenarioScope scope) {
static base::NoDestructor<scoped_refptr<RefCountedScenarioMapping>>
current_process_mapping;
static base::NoDestructor<scoped_refptr<RefCountedScenarioMapping>>
global_mapping;
switch (scope) {
case ScenarioScope::kCurrentProcess:
return *current_process_mapping;
case ScenarioScope::kGlobal:
return *global_mapping;
}
NOTREACHED();
}
// Returns the scenario state from `mapping`, or a default empty state if
// `mapping` is null (which can happen if no ScopedReadOnlyScenarioMemory exists
// or if the mapping failed). Takes a raw pointer instead of a scoped_ptr to
@ -48,51 +27,20 @@ const ScenarioState& GetScenarioStateFromMapping(
} // namespace
// TODO(crbug.com/365586676): Currently these are only mapped into browser and
// renderer processes. The global scenarios should also be mapped into utility
// processes.
ScopedReadOnlyScenarioMemory::ScopedReadOnlyScenarioMemory(
ScenarioScope scope,
base::ReadOnlySharedMemoryRegion region)
: scope_(scope) {
using SharedScenarioState = base::StructuredSharedMemory<ScenarioState>;
std::optional<SharedScenarioState::ReadOnlyMapping> mapping =
SharedScenarioState::MapReadOnlyRegion(std::move(region));
if (mapping.has_value()) {
MappingPtrForScope(scope_) =
base::MakeRefCounted<RefCountedScenarioMapping>(
std::move(mapping.value()));
}
// The ObserverList must be created after mapping the memory, because it reads
// the scenario state in its constructor.
PerformanceScenarioObserverList::CreateForScope(
base::PassKey<ScopedReadOnlyScenarioMemory>(), scope_);
}
ScopedReadOnlyScenarioMemory::~ScopedReadOnlyScenarioMemory() {
PerformanceScenarioObserverList::DestroyForScope(
base::PassKey<ScopedReadOnlyScenarioMemory>(), scope_);
MappingPtrForScope(scope_).reset();
}
// static
scoped_refptr<RefCountedScenarioMapping>
ScopedReadOnlyScenarioMemory::GetMappingForTesting(ScenarioScope scope) {
return MappingPtrForScope(scope);
}
SharedAtomicRef<LoadingScenario> GetLoadingScenario(ScenarioScope scope) {
scoped_refptr<RefCountedScenarioMapping> mapping = MappingPtrForScope(scope);
return SharedAtomicRef<LoadingScenario>(
mapping, GetScenarioStateFromMapping(mapping.get()).loading);
scoped_refptr<RefCountedScenarioMapping> mapping =
GetScenarioMappingForScope(scope);
const std::atomic<LoadingScenario>& scenario =
GetScenarioStateFromMapping(mapping.get()).loading;
return SharedAtomicRef<LoadingScenario>(std::move(mapping), scenario);
}
SharedAtomicRef<InputScenario> GetInputScenario(ScenarioScope scope) {
scoped_refptr<RefCountedScenarioMapping> mapping = MappingPtrForScope(scope);
return SharedAtomicRef<InputScenario>(
mapping, GetScenarioStateFromMapping(mapping.get()).input);
scoped_refptr<RefCountedScenarioMapping> mapping =
GetScenarioMappingForScope(scope);
const std::atomic<InputScenario>& scenario =
GetScenarioStateFromMapping(mapping.get()).input;
return SharedAtomicRef<InputScenario>(std::move(mapping), scenario);
}
bool CurrentScenariosMatch(ScenarioScope scope, ScenarioPattern pattern) {

@ -11,11 +11,8 @@
#include "base/component_export.h"
#include "base/containers/enum_set.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/shared_memory_safety_checker.h"
#include "base/memory/structured_shared_memory.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory_forward.h"
namespace performance_scenarios {
@ -97,24 +94,6 @@ inline constexpr ScenarioPattern kDefaultIdleScenarios{
.input = {InputScenario::kNoInput},
};
// The full scenario state to copy over shared memory.
// TODO(crbug.com/365586676): Move this to a separate header since it's part of
// the plumbing, not the general API.
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wpadded"
struct COMPONENT_EXPORT(SCENARIO_API) ScenarioState {
base::subtle::SharedAtomic<LoadingScenario> loading;
base::subtle::SharedAtomic<InputScenario> input;
};
#pragma clang diagnostic pop
// Pointers to the mapped shared memory are held in thread-safe scoped_refptr's.
// The memory will be unmapped when the final reference is dropped. Functions
// that copy values out of the shared memory must hold a reference to it so that
// it's not unmapped while reading.
using RefCountedScenarioMapping = base::RefCountedData<
base::StructuredSharedMemory<ScenarioState>::ReadOnlyMapping>;
// A wrapper around a std::atomic<T> that's stored in shared memory. The wrapper
// prevents the shared memory from being unmapped while a caller has a reference
// to the atomic. Dereference the SharedAtomicRef to read from it as a
@ -152,30 +131,6 @@ class SharedAtomicRef {
RAW_PTR_EXCLUSION const std::atomic<T>& wrapped_atomic_;
};
// A scoped object that maps shared memory for the scenario state into the
// current process as long as it exists.
// TODO(crbug.com/365586676): Move this to a separate header since it's part of
// the plumbing, not the general API.
class COMPONENT_EXPORT(SCENARIO_API) ScopedReadOnlyScenarioMemory {
public:
// Maps `region` into the current process, as a read-only view of the memory
// holding the scenario state for `scope`.
ScopedReadOnlyScenarioMemory(ScenarioScope scope,
base::ReadOnlySharedMemoryRegion region);
~ScopedReadOnlyScenarioMemory();
ScopedReadOnlyScenarioMemory(const ScopedReadOnlyScenarioMemory&) = delete;
ScopedReadOnlyScenarioMemory& operator=(const ScopedReadOnlyScenarioMemory&) =
delete;
// Returns a pointer to the mapping registered for `scope`, if any.
static scoped_refptr<RefCountedScenarioMapping> GetMappingForTesting(
ScenarioScope scope);
private:
ScenarioScope scope_;
};
// Functions to query performance scenarios.
//
// Since the scenarios can be modified at any time from another process, they're

@ -12,6 +12,7 @@
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/structured_shared_memory.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_scenarios {

@ -20,6 +20,7 @@
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/process_node.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenarios/performance_scenario_data.h"

@ -18,6 +18,7 @@
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/process_node.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenarios/performance_scenario_data.h"

@ -14,6 +14,7 @@
#include "components/performance_manager/graph/graph_impl.h"
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenarios/browser_performance_scenarios.h"
#include "components/performance_manager/test_support/graph_test_harness.h"

@ -11,7 +11,7 @@
#include "base/memory/structured_shared_memory.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/public/tracing_support.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
namespace performance_manager {

@ -11,7 +11,7 @@
#include "base/memory/structured_shared_memory.h"
#include "base/types/optional_util.h"
#include "components/performance_manager/graph/node_inline_data.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory_forward.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
namespace base {

@ -12,6 +12,7 @@
#include "base/memory/shared_memory_mapper.h"
#include "base/memory/structured_shared_memory.h"
#include "base/types/pass_key.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenarios/browser_performance_scenarios.h"
#include "components/performance_manager/scenarios/performance_scenario_data.h"

@ -11,7 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

@ -14,6 +14,7 @@
#include "base/task/sequenced_task_runner.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
#include "components/performance_manager/scenario_api/performance_scenarios.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
@ -26,7 +27,6 @@ namespace {
using performance_manager::mojom::ChildProcessCoordinationUnit;
using performance_scenarios::ScenarioScope;
using performance_scenarios::ScenarioState;
using performance_scenarios::ScopedReadOnlyScenarioMemory;
using ::testing::_;
using ::testing::Invoke;
@ -101,9 +101,9 @@ TEST_F(ChildPerformanceCoordinatorTest, NoScenarioRegion) {
base::ReadOnlySharedMemoryRegion(),
base::ReadOnlySharedMemoryRegion());
EXPECT_FALSE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kGlobal));
EXPECT_FALSE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kCurrentProcess));
}
@ -116,9 +116,9 @@ TEST_F(ChildPerformanceCoordinatorTest, GlobalScenarioRegion) {
shared_memory->TakeReadOnlyRegion(),
base::ReadOnlySharedMemoryRegion());
EXPECT_TRUE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_TRUE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kGlobal));
EXPECT_FALSE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kCurrentProcess));
}
@ -131,9 +131,9 @@ TEST_F(ChildPerformanceCoordinatorTest, ProcessScenarioRegion) {
base::ReadOnlySharedMemoryRegion(),
shared_memory->TakeReadOnlyRegion());
EXPECT_FALSE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_FALSE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kGlobal));
EXPECT_TRUE(ScopedReadOnlyScenarioMemory::GetMappingForTesting(
EXPECT_TRUE(performance_scenarios::GetScenarioMappingForScope(
ScenarioScope::kCurrentProcess));
}