1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/core/platform/profile_utils/android_armv7a_cpu_utils_helper.h"
17
18 #if defined(__ANDROID__) && (__ANDROID_API__ >= 21) && \
19 (defined(__ARM_ARCH_7A__) || defined(__aarch64__))
20
21 #include <asm/unistd.h>
22 #include <linux/perf_event.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/ioctl.h>
27 #include <sys/syscall.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include "tensorflow/core/lib/strings/stringprintf.h"
32 #include "tensorflow/core/platform/logging.h"
33
34 namespace tensorflow {
35 namespace profile_utils {
36
37 /* static */ constexpr int AndroidArmV7ACpuUtilsHelper::INVALID_FD;
38 /* static */ constexpr int64 AndroidArmV7ACpuUtilsHelper::INVALID_CPU_FREQUENCY;
39
ResetClockCycle()40 void AndroidArmV7ACpuUtilsHelper::ResetClockCycle() {
41 if (!is_initialized_) {
42 return;
43 }
44 ioctl(fd_, PERF_EVENT_IOC_RESET, 0);
45 }
46
GetCurrentClockCycle()47 uint64 AndroidArmV7ACpuUtilsHelper::GetCurrentClockCycle() {
48 if (!is_initialized_) {
49 return 1; // DUMMY
50 }
51 long long count;
52 read(fd_, &count, sizeof(long long));
53 return static_cast<uint64>(count);
54 }
55
EnableClockCycleProfiling(const bool enable)56 void AndroidArmV7ACpuUtilsHelper::EnableClockCycleProfiling(const bool enable) {
57 if (!is_initialized_) {
58 // Initialize here to avoid unnecessary initialization
59 InitializeInternal();
60 }
61 if (enable) {
62 const int64 cpu0_scaling_min = ReadCpuFrequencyFile(0, "scaling_min");
63 const int64 cpu0_scaling_max = ReadCpuFrequencyFile(0, "scaling_max");
64 if (cpu0_scaling_max != cpu0_scaling_min) {
65 LOG(WARNING) << "You enabled clock cycle profile but frequency may "
66 << "be scaled. (max = " << cpu0_scaling_max << ", min "
67 << cpu0_scaling_min << ")";
68 }
69 ResetClockCycle();
70 ioctl(fd_, PERF_EVENT_IOC_ENABLE, 0);
71 } else {
72 ioctl(fd_, PERF_EVENT_IOC_DISABLE, 0);
73 }
74 }
75
CalculateCpuFrequency()76 int64 AndroidArmV7ACpuUtilsHelper::CalculateCpuFrequency() {
77 return ReadCpuFrequencyFile(0, "scaling_cur");
78 }
79
InitializeInternal()80 void AndroidArmV7ACpuUtilsHelper::InitializeInternal() {
81 perf_event_attr pe;
82
83 memset(&pe, 0, sizeof(perf_event_attr));
84 pe.type = PERF_TYPE_HARDWARE;
85 pe.size = sizeof(perf_event_attr);
86 pe.config = PERF_COUNT_HW_CPU_CYCLES;
87 pe.disabled = 1;
88 pe.exclude_kernel = 1;
89 pe.exclude_hv = 1;
90
91 fd_ = OpenPerfEvent(&pe, 0, -1, -1, 0);
92 if (fd_ == INVALID_FD) {
93 LOG(WARNING) << "Error opening perf event";
94 is_initialized_ = false;
95 } else {
96 is_initialized_ = true;
97 }
98 }
99
OpenPerfEvent(perf_event_attr * const hw_event,const pid_t pid,const int cpu,const int group_fd,const unsigned long flags)100 int AndroidArmV7ACpuUtilsHelper::OpenPerfEvent(perf_event_attr *const hw_event,
101 const pid_t pid, const int cpu,
102 const int group_fd,
103 const unsigned long flags) {
104 const int ret =
105 syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
106 return ret;
107 }
108
ReadCpuFrequencyFile(const int cpu_id,const char * const type)109 int64 AndroidArmV7ACpuUtilsHelper::ReadCpuFrequencyFile(
110 const int cpu_id, const char *const type) {
111 const string file_path = strings::Printf(
112 "/sys/devices/system/cpu/cpu%d/cpufreq/%s_freq", cpu_id, type);
113 FILE *fp = fopen(file_path.c_str(), "r");
114 if (fp == nullptr) {
115 return INVALID_CPU_FREQUENCY;
116 }
117 int64 freq_in_khz = INVALID_CPU_FREQUENCY;
118 const int retval = fscanf(fp, "%lld", &freq_in_khz);
119 if (retval < 0) {
120 LOG(WARNING) << "Failed to \"" << file_path << "\"";
121 fclose(fp);
122 return INVALID_CPU_FREQUENCY;
123 }
124 fclose(fp);
125 return freq_in_khz * 1000; // The file contains cpu frequency in khz
126 }
127
128 } // namespace profile_utils
129 } // namespace tensorflow
130
131 #endif // defined(__ANDROID__) && (__ANDROID_API__ >= 21) &&
132 // (defined(__ARM_ARCH_7A__) || defined(__aarch64__))
133