Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 99053b9

Browse files
author
Jonah Williams
authored
[Impeller] Affinity adjustments for Vulkan backend. (#46063)
Runs the waiter threads with efficiency affinity and the worker thread with "not performance" affinity.
1 parent bf58df8 commit 99053b9

File tree

10 files changed

+83
-19
lines changed

10 files changed

+83
-19
lines changed

fml/cpu_affinity.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,34 @@
33
// found in the LICENSE file.
44

55
#include "flutter/fml/cpu_affinity.h"
6+
#include "flutter/fml/build_config.h"
67

78
#include <fstream>
89
#include <optional>
910
#include <string>
1011

12+
#ifdef FML_OS_ANDROID
13+
#include "flutter/fml/platform/android/cpu_affinity.h"
14+
#endif // FML_OS_ANDROID
15+
1116
namespace fml {
1217

18+
std::optional<size_t> EfficiencyCoreCount() {
19+
#ifdef FML_OS_ANDROID
20+
return AndroidEfficiencyCoreCount();
21+
#else
22+
return std::nullopt;
23+
#endif
24+
}
25+
26+
bool RequestAffinity(CpuAffinity affinity) {
27+
#ifdef FML_OS_ANDROID
28+
return AndroidRequestAffinity(affinity);
29+
#else
30+
return true;
31+
#endif
32+
}
33+
1334
CPUSpeedTracker::CPUSpeedTracker(std::vector<CpuIndexAndSpeed> data)
1435
: cpu_speeds_(std::move(data)) {
1536
std::optional<int64_t> max_speed = std::nullopt;
@@ -61,7 +82,6 @@ const std::vector<size_t>& CPUSpeedTracker::GetIndices(
6182
// required because files under /proc do not always return a valid size
6283
// when using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.
6384
std::optional<int64_t> ReadIntFromFile(const std::string& path) {
64-
// size_t data_length = 0u;
6585
std::ifstream file;
6686
file.open(path.c_str());
6787

fml/cpu_affinity.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ enum class CpuAffinity {
2727
kNotPerformance,
2828
};
2929

30+
/// @brief Request count of efficiency cores.
31+
///
32+
/// Efficiency cores are defined as those with the lowest reported
33+
/// cpu_max_freq. If the CPU speed could not be determined, or if all
34+
/// cores have the same reported speed then this returns std::nullopt.
35+
/// That is, the result will never be 0.
36+
std::optional<size_t> EfficiencyCoreCount();
37+
38+
/// @brief Request the given affinity for the current thread.
39+
///
40+
/// Returns true if successfull, or if it was a no-op. This function is
41+
/// only supported on Android devices.
42+
///
43+
/// Affinity requests are based on documented CPU speed. This speed data
44+
/// is parsed from cpuinfo_max_freq files, see also:
45+
/// https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt
46+
bool RequestAffinity(CpuAffinity affinity);
47+
3048
struct CpuIndexAndSpeed {
3149
// The index of the given CPU.
3250
size_t index;

fml/cpu_affinity_unittests.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
namespace fml {
1313
namespace testing {
1414

15+
TEST(CpuAffinity, NonAndroidPlatformDefaults) {
16+
ASSERT_FALSE(fml::EfficiencyCoreCount().has_value());
17+
ASSERT_TRUE(fml::RequestAffinity(fml::CpuAffinity::kEfficiency));
18+
}
19+
1520
TEST(CpuAffinity, NormalSlowMedFastCores) {
1621
auto speeds = {CpuIndexAndSpeed{.index = 0, .speed = 1},
1722
CpuIndexAndSpeed{.index = 1, .speed = 2},

fml/platform/android/cpu_affinity.cc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <mutex>
1212
#include <optional>
1313
#include <thread>
14+
#include "flutter/fml/logging.h"
1415

1516
namespace fml {
1617

@@ -36,15 +37,27 @@ void InitCPUInfo(size_t cpu_count) {
3637
gCPUTracker = new CPUSpeedTracker(cpu_speeds);
3738
}
3839

39-
bool RequestAffinity(CpuAffinity affinity) {
40+
bool SetUpCPUTracker() {
4041
// Populate CPU Info if uninitialized.
4142
auto count = std::thread::hardware_concurrency();
4243
std::call_once(gCPUTrackerFlag, [count]() { InitCPUInfo(count); });
43-
if (gCPUTracker == nullptr) {
44+
if (gCPUTracker == nullptr || !gCPUTracker->IsValid()) {
45+
return false;
46+
}
47+
return true;
48+
}
49+
50+
std::optional<size_t> AndroidEfficiencyCoreCount() {
51+
if (!SetUpCPUTracker()) {
4452
return true;
4553
}
54+
auto result = gCPUTracker->GetIndices(CpuAffinity::kEfficiency).size();
55+
FML_DCHECK(result > 0);
56+
return result;
57+
}
4658

47-
if (!gCPUTracker->IsValid()) {
59+
bool AndroidRequestAffinity(CpuAffinity affinity) {
60+
if (!SetUpCPUTracker()) {
4861
return true;
4962
}
5063

fml/platform/android/cpu_affinity.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,10 @@
88

99
namespace fml {
1010

11-
/// @brief Request the given affinity for the current thread.
12-
///
13-
/// Returns true if successfull, or if it was a no-op. This function is
14-
/// only supported on Android devices.
15-
///
16-
/// Affinity requests are based on documented CPU speed. This speed data
17-
/// is parsed from cpuinfo_max_freq files, see also:
18-
/// https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt
19-
bool RequestAffinity(CpuAffinity affinity);
11+
/// @brief Android specific implementation of EfficiencyCoreCount.
12+
std::optional<size_t> AndroidEfficiencyCoreCount();
13+
14+
/// @brief Android specific implementation of RequestAffinity.
15+
bool AndroidRequestAffinity(CpuAffinity affinity);
2016

2117
} // namespace fml

impeller/renderer/backend/vulkan/context_vk.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <string>
1717
#include <vector>
1818

19+
#include "flutter/fml/cpu_affinity.h"
1920
#include "flutter/fml/trace_event.h"
2021
#include "impeller/base/validation.h"
2122
#include "impeller/renderer/backend/vulkan/allocator_vk.h"
@@ -130,13 +131,16 @@ void ContextVK::Setup(Settings settings) {
130131

131132
raster_message_loop_ = fml::ConcurrentMessageLoop::Create(
132133
std::min(4u, std::thread::hardware_concurrency()));
133-
#ifdef FML_OS_ANDROID
134134
raster_message_loop_->PostTaskToAllWorkers([]() {
135+
// Currently we only use the worker task pool for small parts of a frame
136+
// workload, if this changes this setting may need to be adjusted.
137+
fml::RequestAffinity(fml::CpuAffinity::kNotPerformance);
138+
#ifdef FML_OS_ANDROID
135139
if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
136140
FML_LOG(ERROR) << "Failed to set Workers task runner priority";
137141
}
138-
});
139142
#endif // FML_OS_ANDROID
143+
});
140144

141145
auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
142146
dispatcher.init(settings.proc_address_callback);

impeller/renderer/backend/vulkan/fence_waiter_vk.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <chrono>
99
#include <utility>
1010

11+
#include "flutter/fml/cpu_affinity.h"
1112
#include "flutter/fml/thread.h"
1213
#include "flutter/fml/trace_event.h"
1314
#include "impeller/base/validation.h"
@@ -86,8 +87,8 @@ static std::vector<vk::Fence> GetFencesForWaitSet(const WaitSet& set) {
8687
void FenceWaiterVK::Main() {
8788
fml::Thread::SetCurrentThreadName(
8889
fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"});
89-
90-
using namespace std::literals::chrono_literals;
90+
// Since this thread mostly waits on fences, it doesn't need to be fast.
91+
fml::RequestAffinity(fml::CpuAffinity::kEfficiency);
9192

9293
while (true) {
9394
// We'll read the terminate_ flag within the lock below.

impeller/renderer/backend/vulkan/resource_manager_vk.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
66

7+
#include "flutter/fml/cpu_affinity.h"
78
#include "flutter/fml/thread.h"
89
#include "flutter/fml/trace_event.h"
910
#include "fml/logging.h"
@@ -39,6 +40,9 @@ void ResourceManagerVK::Start() {
3940

4041
fml::Thread::SetCurrentThreadName(
4142
fml::Thread::ThreadConfig{"io.flutter.impeller.resource_manager"});
43+
// While this code calls destructors it doesn't need to be particularly fast
44+
// with them, as long as it doesn't interrupt raster thread.
45+
fml::RequestAffinity(fml::CpuAffinity::kEfficiency);
4246

4347
bool should_exit = false;
4448
while (!should_exit) {

runtime/dart_vm.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "flutter/common/settings.h"
1313
#include "flutter/fml/compiler_specific.h"
14+
#include "flutter/fml/cpu_affinity.h"
1415
#include "flutter/fml/logging.h"
1516
#include "flutter/fml/mapping.h"
1617
#include "flutter/fml/size.h"
@@ -285,7 +286,9 @@ size_t DartVM::GetVMLaunchCount() {
285286
DartVM::DartVM(const std::shared_ptr<const DartVMData>& vm_data,
286287
std::shared_ptr<IsolateNameServer> isolate_name_server)
287288
: settings_(vm_data->GetSettings()),
288-
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()),
289+
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create(
290+
fml::EfficiencyCoreCount().value_or(
291+
std::thread::hardware_concurrency()))),
289292
skia_concurrent_executor_(
290293
[runner = concurrent_message_loop_->GetTaskRunner()](
291294
const fml::closure& work) { runner->PostTask(work); }),

shell/platform/android/android_shell_holder.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
#include <string>
1717
#include <utility>
1818

19+
#include "flutter/fml/cpu_affinity.h"
1920
#include "flutter/fml/logging.h"
2021
#include "flutter/fml/make_copyable.h"
2122
#include "flutter/fml/message_loop.h"
2223
#include "flutter/fml/native_library.h"
23-
#include "flutter/fml/platform/android/cpu_affinity.h"
2424
#include "flutter/fml/platform/android/jni_util.h"
2525
#include "flutter/lib/ui/painting/image_generator_registry.h"
2626
#include "flutter/shell/common/rasterizer.h"

0 commit comments

Comments
 (0)