• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <inttypes.h>
23 #include <linux/perf_event.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 
32 #include "tensorflow/core/platform/logging.h"
33 #include "tensorflow/core/platform/stringprintf.h"
34 
35 namespace tensorflow {
36 namespace profile_utils {
37 
38 /* static */ constexpr int AndroidArmV7ACpuUtilsHelper::INVALID_FD;
39 /* static */ constexpr int64 AndroidArmV7ACpuUtilsHelper::INVALID_CPU_FREQUENCY;
40 
ResetClockCycle()41 void AndroidArmV7ACpuUtilsHelper::ResetClockCycle() {
42   if (!is_initialized_) {
43     return;
44   }
45   ioctl(fd_, PERF_EVENT_IOC_RESET, 0);
46 }
47 
GetCurrentClockCycle()48 uint64 AndroidArmV7ACpuUtilsHelper::GetCurrentClockCycle() {
49   if (!is_initialized_) {
50     return 1;  // DUMMY
51   }
52   long long count;
53   read(fd_, &count, sizeof(long long));
54   return static_cast<uint64>(count);
55 }
56 
EnableClockCycleProfiling()57 void AndroidArmV7ACpuUtilsHelper::EnableClockCycleProfiling() {
58   if (!is_initialized_) {
59     // Initialize here to avoid unnecessary initialization
60     InitializeInternal();
61   }
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 }
72 
DisableClockCycleProfiling()73 void AndroidArmV7ACpuUtilsHelper::DisableClockCycleProfiling() {
74   if (!is_initialized_) {
75     // Initialize here to avoid unnecessary initialization
76     InitializeInternal();
77   }
78   ioctl(fd_, PERF_EVENT_IOC_DISABLE, 0);
79 }
80 
CalculateCpuFrequency()81 int64 AndroidArmV7ACpuUtilsHelper::CalculateCpuFrequency() {
82   return ReadCpuFrequencyFile(0, "scaling_cur");
83 }
84 
InitializeInternal()85 void AndroidArmV7ACpuUtilsHelper::InitializeInternal() {
86   perf_event_attr pe;
87 
88   memset(&pe, 0, sizeof(perf_event_attr));
89   pe.type = PERF_TYPE_HARDWARE;
90   pe.size = sizeof(perf_event_attr);
91   pe.config = PERF_COUNT_HW_CPU_CYCLES;
92   pe.disabled = 1;
93   pe.exclude_kernel = 1;
94   pe.exclude_hv = 1;
95 
96   fd_ = OpenPerfEvent(&pe, 0, -1, -1, 0);
97   if (fd_ == INVALID_FD) {
98     LOG(WARNING) << "Error opening perf event";
99     is_initialized_ = false;
100   } else {
101     is_initialized_ = true;
102   }
103 }
104 
OpenPerfEvent(perf_event_attr * const hw_event,const pid_t pid,const int cpu,const int group_fd,const unsigned long flags)105 int AndroidArmV7ACpuUtilsHelper::OpenPerfEvent(perf_event_attr *const hw_event,
106                                                const pid_t pid, const int cpu,
107                                                const int group_fd,
108                                                const unsigned long flags) {
109   const int ret =
110       syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
111   return ret;
112 }
113 
ReadCpuFrequencyFile(const int cpu_id,const char * const type)114 int64 AndroidArmV7ACpuUtilsHelper::ReadCpuFrequencyFile(
115     const int cpu_id, const char *const type) {
116   const string file_path = strings::Printf(
117       "/sys/devices/system/cpu/cpu%d/cpufreq/%s_freq", cpu_id, type);
118   FILE *fp = fopen(file_path.c_str(), "r");
119   if (fp == nullptr) {
120     return INVALID_CPU_FREQUENCY;
121   }
122   int64_t freq_in_khz = INVALID_CPU_FREQUENCY;
123   const int retval = fscanf(fp, "%" SCNd64, &freq_in_khz);
124   if (retval < 0) {
125     LOG(WARNING) << "Failed to \"" << file_path << "\"";
126     if (fclose(fp) != 0) {
127       LOG(WARNING) << "fclose() failed: " << strerror(errno);
128     }
129     return INVALID_CPU_FREQUENCY;
130   }
131   if (fclose(fp) != 0) {
132     LOG(WARNING) << "fclose() failed: " << strerror(errno);
133   }
134   return freq_in_khz * 1000;  // The file contains cpu frequency in khz
135 }
136 
137 }  // namespace profile_utils
138 }  // namespace tensorflow
139 
140 #endif  // defined(__ANDROID__) && (__ANDROID_API__ >= 21) &&
141         // (defined(__ARM_ARCH_7A__) || defined(__aarch64__))
142