• 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/cpu_utils.h"
17 
18 #include <fstream>
19 #include <limits>
20 #include <mutex>
21 
22 #if defined(_WIN32)
23 #include <windows.h>
24 #endif
25 
26 #include "tensorflow/core/platform/logging.h"
27 #include "tensorflow/core/platform/profile_utils/android_armv7a_cpu_utils_helper.h"
28 
29 namespace tensorflow {
30 namespace profile_utils {
31 
32 /* static */ constexpr int64 CpuUtils::INVALID_FREQUENCY;
33 
34 static ICpuUtilsHelper* cpu_utils_helper_instance_ = nullptr;
35 
36 #if (defined(__powerpc__) ||                                             \
37      defined(__ppc__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \
38     (defined(__s390x__))
GetCycleCounterFrequency()39 /* static */ uint64 CpuUtils::GetCycleCounterFrequency() {
40   static const uint64 cpu_frequency = GetCycleCounterFrequencyImpl();
41   return cpu_frequency;
42 }
43 #else
GetCycleCounterFrequency()44 /* static */ int64 CpuUtils::GetCycleCounterFrequency() {
45   static const int64 cpu_frequency = GetCycleCounterFrequencyImpl();
46   return cpu_frequency;
47 }
48 #endif
49 
GetMicroSecPerClock()50 /* static */ double CpuUtils::GetMicroSecPerClock() {
51   static const double micro_sec_per_clock =
52       (1000.0 * 1000.0) / static_cast<double>(GetCycleCounterFrequency());
53   return micro_sec_per_clock;
54 }
55 
ResetClockCycle()56 /* static */ void CpuUtils::ResetClockCycle() {
57   GetCpuUtilsHelperSingletonInstance().ResetClockCycle();
58 }
59 
EnableClockCycleProfiling(const bool enable)60 /* static */ void CpuUtils::EnableClockCycleProfiling(const bool enable) {
61   GetCpuUtilsHelperSingletonInstance().EnableClockCycleProfiling(enable);
62 }
63 
ConvertClockCycleToTime(const int64 clock_cycle)64 /* static */ std::chrono::duration<double> CpuUtils::ConvertClockCycleToTime(
65     const int64 clock_cycle) {
66   return std::chrono::duration<double>(static_cast<double>(clock_cycle) /
67                                        GetCycleCounterFrequency());
68 }
69 
GetCycleCounterFrequencyImpl()70 /* static */ int64 CpuUtils::GetCycleCounterFrequencyImpl() {
71 // TODO(satok): do not switch by macro here
72 #if defined(__ANDROID__)
73   return GetCpuUtilsHelperSingletonInstance().CalculateCpuFrequency();
74 #elif defined(__linux__)
75   // Read the contents of /proc/cpuinfo.
76   std::ifstream cpuinfo("/proc/cpuinfo");
77   if (!cpuinfo) {
78     LOG(WARNING) << "Failed to open /proc/cpuinfo";
79     return INVALID_FREQUENCY;
80   }
81   string line;
82   while (std::getline(cpuinfo, line)) {
83     double bogomips;
84     const int retval_of_bogomips =
85         sscanf(line.c_str(), "bogomips : %lf", &bogomips);
86     if (retval_of_bogomips > 0) {
87       const double freq_ghz = bogomips / 1000.0 / 2.0;
88       if (retval_of_bogomips != 1 || freq_ghz < 0.01) {
89         LOG(WARNING) << "Failed to get CPU frequency: " << freq_ghz << " Hz";
90         return INVALID_FREQUENCY;
91       }
92       const int64 freq_n =
93           static_cast<int64>(freq_ghz * 1000.0 * 1000.0 * 1000.0);
94       LOG(INFO) << "CPU Frequency: " << freq_n << " Hz";
95       return freq_n;
96     }
97   }
98   LOG(WARNING) << "Failed to find bogomips in /proc/cpuinfo; cannot determine "
99                   "CPU frequency";
100   return INVALID_FREQUENCY;
101 #elif defined(__APPLE__)
102   int64 freq_hz;
103   FILE* fp =
104       popen("sysctl hw | grep hw.cpufrequency_max: | cut -d' ' -f 2", "r");
105   if (fp == nullptr) {
106     return INVALID_FREQUENCY;
107   }
108   if (fscanf(fp, "%lld", &freq_hz) != 1) {
109     return INVALID_FREQUENCY;
110   }
111   pclose(fp);
112   if (freq_hz < 1e6) {
113     LOG(WARNING) << "Failed to get CPU frequency: " << freq_hz << " Hz";
114     return INVALID_FREQUENCY;
115   }
116   return freq_hz;
117 #elif defined(_WIN32)
118   LARGE_INTEGER freq;
119   QueryPerformanceFrequency(&freq);
120   return freq.QuadPart;
121 #else
122   // TODO(satok): Support other OS if needed
123   // Return INVALID_FREQUENCY on unsupported OS
124   return INVALID_FREQUENCY;
125 #endif
126 }
127 
GetCpuUtilsHelperSingletonInstance()128 /* static */ ICpuUtilsHelper& CpuUtils::GetCpuUtilsHelperSingletonInstance() {
129   static std::once_flag flag;
130   std::call_once(flag, []() {
131     if (cpu_utils_helper_instance_ != nullptr) {
132       LOG(FATAL) << "cpu_utils_helper_instance_ is already instantiated.";
133     }
134 #if defined(__ANDROID__) && (__ANDROID_API__ >= 21) && \
135     (defined(__ARM_ARCH_7A__) || defined(__aarch64__))
136     cpu_utils_helper_instance_ = new AndroidArmV7ACpuUtilsHelper();
137 #else
138       cpu_utils_helper_instance_ = new DefaultCpuUtilsHelper();
139 #endif
140   });
141   return *cpu_utils_helper_instance_;
142 }
143 
144 }  // namespace profile_utils
145 }  // namespace tensorflow
146