xref: /aosp_15_r20/external/tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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 #if defined(__APPLE__)
27 #include <sys/sysctl.h>
28 #endif
29 
30 #include "absl/base/call_once.h"
31 #include "tensorflow/core/platform/logging.h"
32 #include "tensorflow/core/platform/profile_utils/android_armv7a_cpu_utils_helper.h"
33 
34 namespace tensorflow {
35 namespace profile_utils {
36 
37 /* static */ constexpr int64_t CpuUtils::INVALID_FREQUENCY;
38 
39 static ICpuUtilsHelper* cpu_utils_helper_instance_ = nullptr;
40 
41 #if (defined(__powerpc__) ||                                             \
42      defined(__ppc__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \
43     (defined(__s390x__))
GetCycleCounterFrequency()44 /* static */ uint64 CpuUtils::GetCycleCounterFrequency() {
45   static const uint64 cpu_frequency = GetCycleCounterFrequencyImpl();
46   return cpu_frequency;
47 }
48 #else
GetCycleCounterFrequency()49 /* static */ int64_t CpuUtils::GetCycleCounterFrequency() {
50   static const int64_t cpu_frequency = GetCycleCounterFrequencyImpl();
51   return cpu_frequency;
52 }
53 #endif
54 
GetMicroSecPerClock()55 /* static */ double CpuUtils::GetMicroSecPerClock() {
56   static const double micro_sec_per_clock =
57       (1000.0 * 1000.0) / static_cast<double>(GetCycleCounterFrequency());
58   return micro_sec_per_clock;
59 }
60 
ResetClockCycle()61 /* static */ void CpuUtils::ResetClockCycle() {
62   GetCpuUtilsHelperSingletonInstance().ResetClockCycle();
63 }
64 
EnableClockCycleProfiling()65 /* static */ void CpuUtils::EnableClockCycleProfiling() {
66   GetCpuUtilsHelperSingletonInstance().EnableClockCycleProfiling();
67 }
68 
DisableClockCycleProfiling()69 /* static */ void CpuUtils::DisableClockCycleProfiling() {
70   GetCpuUtilsHelperSingletonInstance().DisableClockCycleProfiling();
71 }
72 
ConvertClockCycleToTime(const int64_t clock_cycle)73 /* static */ std::chrono::duration<double> CpuUtils::ConvertClockCycleToTime(
74     const int64_t clock_cycle) {
75   return std::chrono::duration<double>(static_cast<double>(clock_cycle) /
76                                        GetCycleCounterFrequency());
77 }
78 
GetCycleCounterFrequencyImpl()79 /* static */ int64_t CpuUtils::GetCycleCounterFrequencyImpl() {
80 // TODO(satok): do not switch by macro here
81 #if defined(__ANDROID__)
82   return GetCpuUtilsHelperSingletonInstance().CalculateCpuFrequency();
83 #elif defined(__linux__)
84   // Read the contents of /proc/cpuinfo.
85   std::ifstream cpuinfo("/proc/cpuinfo");
86   if (!cpuinfo) {
87     LOG(WARNING) << "Failed to open /proc/cpuinfo";
88     return INVALID_FREQUENCY;
89   }
90   string line;
91   while (std::getline(cpuinfo, line)) {
92     double cpu_freq = 0.0;
93     int retval = 0;
94     double freq_factor = 2.0;
95 #if (defined(__powerpc__) || \
96      defined(__ppc__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
97     retval = sscanf(line.c_str(), "clock              : %lfMHz", &cpu_freq);
98     freq_factor = 1.0;
99 #elif defined(__s390x__)
100     retval = sscanf(line.c_str(), "bogomips per cpu: %lf", &cpu_freq);
101 #elif defined(__aarch64__)
102     retval = sscanf(line.c_str(), "BogoMIPS : %lf", &cpu_freq);
103 #else
104     retval = sscanf(line.c_str(), "bogomips : %lf", &cpu_freq);
105 #endif
106     if (retval > 0) {
107       const double freq_ghz = cpu_freq / 1000.0 / freq_factor;
108       if (retval != 1 || freq_ghz < 0.01) {
109         LOG(WARNING) << "Failed to get CPU frequency: " << freq_ghz << " GHz";
110         return INVALID_FREQUENCY;
111       }
112       const int64_t freq_n =
113           static_cast<int64_t>(freq_ghz * 1000.0 * 1000.0 * 1000.0);
114       VLOG(1) << "CPU Frequency: " << freq_n << " Hz";
115       return freq_n;
116     }
117   }
118   LOG(WARNING)
119       << "Failed to find bogomips or clock in /proc/cpuinfo; cannot determine "
120          "CPU frequency";
121   return INVALID_FREQUENCY;
122 #elif defined(__APPLE__)
123   int64 freq_hz = 0;
124   size_t freq_size = sizeof(freq_hz);
125   int retval =
126       sysctlbyname("hw.cpufrequency_max", &freq_hz, &freq_size, NULL, 0);
127   if (retval != 0 || freq_hz < 1e6) {
128     LOG(WARNING) << "Failed to get CPU frequency: " << freq_hz << " Hz";
129     return INVALID_FREQUENCY;
130   }
131   return freq_hz;
132 #elif defined(_WIN32)
133   LARGE_INTEGER freq;
134   QueryPerformanceFrequency(&freq);
135   return freq.QuadPart;
136 #else
137   // TODO(satok): Support other OS if needed
138   // Return INVALID_FREQUENCY on unsupported OS
139   return INVALID_FREQUENCY;
140 #endif
141 }
142 
GetCpuUtilsHelperSingletonInstance()143 /* static */ ICpuUtilsHelper& CpuUtils::GetCpuUtilsHelperSingletonInstance() {
144   static absl::once_flag flag;
145   absl::call_once(flag, []() {
146     if (cpu_utils_helper_instance_ != nullptr) {
147       LOG(FATAL) << "cpu_utils_helper_instance_ is already instantiated.";
148     }
149 #if defined(__ANDROID__) && (__ANDROID_API__ >= 21) && \
150     (defined(__ARM_ARCH_7A__) || defined(__aarch64__))
151     cpu_utils_helper_instance_ = new AndroidArmV7ACpuUtilsHelper();
152 #else
153       cpu_utils_helper_instance_ = new DefaultCpuUtilsHelper();
154 #endif
155   });
156   return *cpu_utils_helper_instance_;
157 }
158 
159 }  // namespace profile_utils
160 }  // namespace tensorflow
161