mediapipe/mediapipe/util/cpu_util.cc
MediaPipe Team e6c19885c6 Project import generated by Copybara.
GitOrigin-RevId: bb059a0721c92e8154d33ce8057b3915a25b3d7d
2021-12-13 15:56:02 -08:00

140 lines
4.0 KiB
C++

// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mediapipe/util/cpu_util.h"
#include <cmath>
#ifdef __ANDROID__
#include "ndk/sources/android/cpufeatures/cpu-features.h"
#elif _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <fstream>
#include "absl/algorithm/container.h"
#include "absl/flags/flag.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/statusor.h"
ABSL_FLAG(std::string, system_cpu_max_freq_file,
"/sys/devices/system/cpu/cpu$0/cpufreq/cpuinfo_max_freq",
"The file pattern for CPU max frequencies, where $0 will be replaced "
"with the CPU id.");
namespace mediapipe {
namespace {
constexpr uint32 kBufferLength = 64;
absl::StatusOr<std::string> GetFilePath(int cpu) {
if (!absl::StrContains(absl::GetFlag(FLAGS_system_cpu_max_freq_file), "$0")) {
return absl::InvalidArgumentError(
absl::StrCat("Invalid frequency file: ",
absl::GetFlag(FLAGS_system_cpu_max_freq_file)));
}
return absl::Substitute(absl::GetFlag(FLAGS_system_cpu_max_freq_file), cpu);
}
absl::StatusOr<uint64> GetCpuMaxFrequency(int cpu) {
auto path_or_status = GetFilePath(cpu);
if (!path_or_status.ok()) {
return path_or_status.status();
}
std::ifstream file;
file.open(path_or_status.value());
if (file.is_open()) {
char buffer[kBufferLength];
file.getline(buffer, kBufferLength);
file.close();
uint64 frequency;
if (absl::SimpleAtoi(buffer, &frequency)) {
return frequency;
} else {
return absl::InvalidArgumentError(
absl::StrCat("Invalid frequency: ", buffer));
}
} else {
return absl::NotFoundError(
absl::StrCat("Couldn't read ", path_or_status.value()));
}
}
std::set<int> InferLowerOrHigherCoreIds(bool lower) {
std::vector<std::pair<int, uint64>> cpu_freq_pairs;
for (int cpu = 0; cpu < NumCPUCores(); ++cpu) {
auto freq_or_status = GetCpuMaxFrequency(cpu);
if (freq_or_status.ok()) {
cpu_freq_pairs.push_back({cpu, freq_or_status.value()});
}
}
if (cpu_freq_pairs.empty()) {
return {};
}
absl::c_sort(cpu_freq_pairs, [lower](const std::pair<int, uint64>& left,
const std::pair<int, uint64>& right) {
return (lower && left.second < right.second) ||
(!lower && left.second > right.second);
});
uint64 edge_freq = cpu_freq_pairs[0].second;
std::set<int> inferred_cores;
for (const auto& cpu_freq_pair : cpu_freq_pairs) {
if ((lower && cpu_freq_pair.second > edge_freq) ||
(!lower && cpu_freq_pair.second < edge_freq)) {
break;
}
inferred_cores.insert(cpu_freq_pair.first);
}
// If all the cores have the same frequency, there are no "lower" or "higher"
// cores.
if (inferred_cores.size() == cpu_freq_pairs.size()) {
return {};
} else {
return inferred_cores;
}
}
} // namespace
int NumCPUCores() {
#ifdef __ANDROID__
return android_getCpuCount();
#elif _WIN32
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#else
return sysconf(_SC_NPROCESSORS_ONLN);
#endif
}
std::set<int> InferLowerCoreIds() {
return InferLowerOrHigherCoreIds(/* lower= */ true);
}
std::set<int> InferHigherCoreIds() {
return InferLowerOrHigherCoreIds(/* lower= */ false);
}
} // namespace mediapipe.