| // Copyright 2013 The Flutter 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 "flutter/fml/platform/android/cpu_affinity.h" | |
| #include <pthread.h> | |
| #include <sys/resource.h> | |
| #include <sys/time.h> | |
| #include <unistd.h> | |
| #include <mutex> | |
| #include <optional> | |
| #include <thread> | |
| #include "flutter/fml/logging.h" | |
| namespace fml { | |
| /// The CPUSpeedTracker is initialized once the first time a thread affinity is | |
| /// requested. | |
| std::once_flag gCPUTrackerFlag; | |
| static CPUSpeedTracker* gCPUTracker; | |
| // For each CPU index provided, attempts to open the file | |
| // /sys/devices/system/cpu/cpu$NUM/cpufreq/cpuinfo_max_freq and parse a number | |
| // containing the CPU frequency. | |
| void InitCPUInfo(size_t cpu_count) { | |
| std::vector<CpuIndexAndSpeed> cpu_speeds; | |
| for (auto i = 0u; i < cpu_count; i++) { | |
| auto path = "/sys/devices/system/cpu/cpu" + std::to_string(i) + | |
| "/cpufreq/cpuinfo_max_freq"; | |
| auto speed = ReadIntFromFile(path); | |
| if (speed.has_value()) { | |
| cpu_speeds.push_back({.index = i, .speed = speed.value()}); | |
| } | |
| } | |
| gCPUTracker = new CPUSpeedTracker(cpu_speeds); | |
| } | |
| bool SetUpCPUTracker() { | |
| // Populate CPU Info if uninitialized. | |
| auto count = std::thread::hardware_concurrency(); | |
| std::call_once(gCPUTrackerFlag, [count]() { InitCPUInfo(count); }); | |
| 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; | |
| } | |
| bool AndroidRequestAffinity(CpuAffinity affinity) { | |
| if (!SetUpCPUTracker()) { | |
| return true; | |
| } | |
| cpu_set_t set; | |
| CPU_ZERO(&set); | |
| for (const auto index : gCPUTracker->GetIndices(affinity)) { | |
| CPU_SET(index, &set); | |
| } | |
| return sched_setaffinity(gettid(), sizeof(set), &set) == 0; | |
| } | |
| } // namespace fml |