Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Affinity adjustments for Vulkan backend. #46063

Merged
merged 6 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 21 additions & 1 deletion fml/cpu_affinity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,34 @@
// found in the LICENSE file.

#include "flutter/fml/cpu_affinity.h"
#include "flutter/fml/build_config.h"

#include <fstream>
#include <optional>
#include <string>

#ifdef FML_OS_ANDROID
#include "flutter/fml/platform/android/cpu_affinity.h"
#endif // FML_OS_ANDROID

namespace fml {

std::optional<size_t> EfficiencyCoreCount() {
#ifdef FML_OS_ANDROID
return AndroidEfficiencyCoreCount();
#else
return std::nullopt;
#endif
}

bool RequestAffinity(CpuAffinity affinity) {
#ifdef FML_OS_ANDROID
return AndroidRequestAffinity(affinity);
#else
return true;
#endif
}

CPUSpeedTracker::CPUSpeedTracker(std::vector<CpuIndexAndSpeed> data)
: cpu_speeds_(std::move(data)) {
std::optional<int64_t> max_speed = std::nullopt;
Expand Down Expand Up @@ -61,7 +82,6 @@ const std::vector<size_t>& CPUSpeedTracker::GetIndices(
// required because files under /proc do not always return a valid size
// when using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.
std::optional<int64_t> ReadIntFromFile(const std::string& path) {
// size_t data_length = 0u;
std::ifstream file;
file.open(path.c_str());

Expand Down
18 changes: 18 additions & 0 deletions fml/cpu_affinity.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ enum class CpuAffinity {
kNotPerformance,
};

/// @brief Request count of efficiency cores.
///
/// Efficiency cores are defined as those with the lowest reported
/// cpu_max_freq. If the CPU speed could not be determined, or if all
/// cores have the same reported speed then this returns std::nullopt.
/// That is, the result will never be 0.
std::optional<size_t> EfficiencyCoreCount();

/// @brief Request the given affinity for the current thread.
///
/// Returns true if successfull, or if it was a no-op. This function is
/// only supported on Android devices.
///
/// Affinity requests are based on documented CPU speed. This speed data
/// is parsed from cpuinfo_max_freq files, see also:
/// https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt
bool RequestAffinity(CpuAffinity affinity);

struct CpuIndexAndSpeed {
// The index of the given CPU.
size_t index;
Expand Down
5 changes: 5 additions & 0 deletions fml/cpu_affinity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
namespace fml {
namespace testing {

TEST(CpuAffinity, NonAndroidPlatformDefaults) {
ASSERT_FALSE(fml::EfficiencyCoreCount().has_value());
ASSERT_TRUE(fml::RequestAffinity(fml::CpuAffinity::kEfficiency));
}

TEST(CpuAffinity, NormalSlowMedFastCores) {
auto speeds = {CpuIndexAndSpeed{.index = 0, .speed = 1},
CpuIndexAndSpeed{.index = 1, .speed = 2},
Expand Down
19 changes: 16 additions & 3 deletions fml/platform/android/cpu_affinity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <mutex>
#include <optional>
#include <thread>
#include "flutter/fml/logging.h"

namespace fml {

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

bool RequestAffinity(CpuAffinity affinity) {
bool SetUpCPUTracker() {
// Populate CPU Info if uninitialized.
auto count = std::thread::hardware_concurrency();
std::call_once(gCPUTrackerFlag, [count]() { InitCPUInfo(count); });
if (gCPUTracker == nullptr) {
if (gCPUTracker == nullptr || !gCPUTracker->IsValid()) {
return false;
}
return true;
}

std::optional<size_t> AndroidEfficiencyCoreCount() {
if (!SetUpCPUTracker()) {
return true;
}
auto result = gCPUTracker->GetIndices(CpuAffinity::kEfficiency).size();
FML_DCHECK(result > 0);
return result;
}

if (!gCPUTracker->IsValid()) {
bool AndroidRequestAffinity(CpuAffinity affinity) {
if (!SetUpCPUTracker()) {
return true;
}

Expand Down
14 changes: 5 additions & 9 deletions fml/platform/android/cpu_affinity.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@

namespace fml {

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

/// @brief Android specific implementation of RequestAffinity.
bool AndroidRequestAffinity(CpuAffinity affinity);

} // namespace fml
8 changes: 6 additions & 2 deletions impeller/renderer/backend/vulkan/context_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <string>
#include <vector>

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

raster_message_loop_ = fml::ConcurrentMessageLoop::Create(
std::min(4u, std::thread::hardware_concurrency()));
#ifdef FML_OS_ANDROID
raster_message_loop_->PostTaskToAllWorkers([]() {
// Currently we only use the worker task pool for small parts of a frame
// workload, if this changes this setting may need to be adjusted.
fml::RequestAffinity(fml::CpuAffinity::kNotPerformance);
#ifdef FML_OS_ANDROID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a later patch, we should also move these set priority calls into a base library. We need to do the same for other platforms too (though I guess we don't care about Vulkan on macOS). Just seems odd to have platform specific ifdefs in platform agnostic code.

if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
FML_LOG(ERROR) << "Failed to set Workers task runner priority";
}
});
#endif // FML_OS_ANDROID
});

auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
dispatcher.init(settings.proc_address_callback);
Expand Down
5 changes: 3 additions & 2 deletions impeller/renderer/backend/vulkan/fence_waiter_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <chrono>
#include <utility>

#include "flutter/fml/cpu_affinity.h"
#include "flutter/fml/thread.h"
#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"
Expand Down Expand Up @@ -86,8 +87,8 @@ static std::vector<vk::Fence> GetFencesForWaitSet(const WaitSet& set) {
void FenceWaiterVK::Main() {
fml::Thread::SetCurrentThreadName(
fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"});

using namespace std::literals::chrono_literals;
// Since this thread mostly waits on fences, it doesn't need to be fast.
fml::RequestAffinity(fml::CpuAffinity::kEfficiency);

while (true) {
// We'll read the terminate_ flag within the lock below.
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/vulkan/resource_manager_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

#include "flutter/fml/cpu_affinity.h"
#include "flutter/fml/thread.h"
#include "flutter/fml/trace_event.h"
#include "fml/logging.h"
Expand Down Expand Up @@ -39,6 +40,9 @@ void ResourceManagerVK::Start() {

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

bool should_exit = false;
while (!should_exit) {
Expand Down
5 changes: 4 additions & 1 deletion runtime/dart_vm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "flutter/common/settings.h"
#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/cpu_affinity.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/size.h"
Expand Down Expand Up @@ -285,7 +286,9 @@ size_t DartVM::GetVMLaunchCount() {
DartVM::DartVM(const std::shared_ptr<const DartVMData>& vm_data,
std::shared_ptr<IsolateNameServer> isolate_name_server)
: settings_(vm_data->GetSettings()),
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()),
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create(
fml::EfficiencyCoreCount().value_or(
std::thread::hardware_concurrency()))),
skia_concurrent_executor_(
[runner = concurrent_message_loop_->GetTaskRunner()](
const fml::closure& work) { runner->PostTask(work); }),
Expand Down
2 changes: 1 addition & 1 deletion shell/platform/android/android_shell_holder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
#include <string>
#include <utility>

#include "flutter/fml/cpu_affinity.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/native_library.h"
#include "flutter/fml/platform/android/cpu_affinity.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "flutter/lib/ui/painting/image_generator_registry.h"
#include "flutter/shell/common/rasterizer.h"
Expand Down