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