| /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. |
| |
| 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 "tensorflow/core/platform/profile_utils/android_armv7a_cpu_utils_helper.h" |
| |
| #if defined(__ANDROID__) && (__ANDROID_API__ >= 21) && \ |
| (defined(__ARM_ARCH_7A__) || defined(__aarch64__)) |
| |
| #include <asm/unistd.h> |
| #include <linux/perf_event.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/ioctl.h> |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "tensorflow/core/lib/strings/stringprintf.h" |
| #include "tensorflow/core/platform/logging.h" |
| |
| namespace tensorflow { |
| namespace profile_utils { |
| |
| /* static */ constexpr int AndroidArmV7ACpuUtilsHelper::INVALID_FD; |
| /* static */ constexpr int64 AndroidArmV7ACpuUtilsHelper::INVALID_CPU_FREQUENCY; |
| |
| void AndroidArmV7ACpuUtilsHelper::ResetClockCycle() { |
| if (!is_initialized_) { |
| return; |
| } |
| ioctl(fd_, PERF_EVENT_IOC_RESET, 0); |
| } |
| |
| uint64 AndroidArmV7ACpuUtilsHelper::GetCurrentClockCycle() { |
| if (!is_initialized_) { |
| return 1; // DUMMY |
| } |
| long long count; |
| read(fd_, &count, sizeof(long long)); |
| return static_cast<uint64>(count); |
| } |
| |
| void AndroidArmV7ACpuUtilsHelper::EnableClockCycleProfiling(const bool enable) { |
| if (!is_initialized_) { |
| // Initialize here to avoid unnecessary initialization |
| InitializeInternal(); |
| } |
| if (enable) { |
| const int64 cpu0_scaling_min = ReadCpuFrequencyFile(0, "scaling_min"); |
| const int64 cpu0_scaling_max = ReadCpuFrequencyFile(0, "scaling_max"); |
| if (cpu0_scaling_max != cpu0_scaling_min) { |
| LOG(WARNING) << "You enabled clock cycle profile but frequency may " |
| << "be scaled. (max = " << cpu0_scaling_max << ", min " |
| << cpu0_scaling_min << ")"; |
| } |
| ResetClockCycle(); |
| ioctl(fd_, PERF_EVENT_IOC_ENABLE, 0); |
| } else { |
| ioctl(fd_, PERF_EVENT_IOC_DISABLE, 0); |
| } |
| } |
| |
| int64 AndroidArmV7ACpuUtilsHelper::CalculateCpuFrequency() { |
| return ReadCpuFrequencyFile(0, "scaling_cur"); |
| } |
| |
| void AndroidArmV7ACpuUtilsHelper::InitializeInternal() { |
| perf_event_attr pe; |
| |
| memset(&pe, 0, sizeof(perf_event_attr)); |
| pe.type = PERF_TYPE_HARDWARE; |
| pe.size = sizeof(perf_event_attr); |
| pe.config = PERF_COUNT_HW_CPU_CYCLES; |
| pe.disabled = 1; |
| pe.exclude_kernel = 1; |
| pe.exclude_hv = 1; |
| |
| fd_ = OpenPerfEvent(&pe, 0, -1, -1, 0); |
| if (fd_ == INVALID_FD) { |
| LOG(WARNING) << "Error opening perf event"; |
| is_initialized_ = false; |
| } else { |
| is_initialized_ = true; |
| } |
| } |
| |
| int AndroidArmV7ACpuUtilsHelper::OpenPerfEvent(perf_event_attr *const hw_event, |
| const pid_t pid, const int cpu, |
| const int group_fd, |
| const unsigned long flags) { |
| const int ret = |
| syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); |
| return ret; |
| } |
| |
| int64 AndroidArmV7ACpuUtilsHelper::ReadCpuFrequencyFile( |
| const int cpu_id, const char *const type) { |
| const string file_path = strings::Printf( |
| "/sys/devices/system/cpu/cpu%d/cpufreq/%s_freq", cpu_id, type); |
| FILE *fp = fopen(file_path.c_str(), "r"); |
| if (fp == nullptr) { |
| return INVALID_CPU_FREQUENCY; |
| } |
| int64 freq_in_khz = INVALID_CPU_FREQUENCY; |
| const int retval = fscanf(fp, "%lld", &freq_in_khz); |
| if (retval < 0) { |
| LOG(WARNING) << "Failed to \"" << file_path << "\""; |
| fclose(fp); |
| return INVALID_CPU_FREQUENCY; |
| } |
| fclose(fp); |
| return freq_in_khz * 1000; // The file contains cpu frequency in khz |
| } |
| |
| } // namespace profile_utils |
| } // namespace tensorflow |
| |
| #endif // defined(__ANDROID__) && (__ANDROID_API__ >= 21) && |
| // (defined(__ARM_ARCH_7A__) || defined(__aarch64__)) |