xref: /aosp_15_r20/external/pytorch/c10/util/ApproximateClock.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker // Copyright 2023-present Facebook. All Rights Reserved.
2*da0073e9SAndroid Build Coastguard Worker 
3*da0073e9SAndroid Build Coastguard Worker #pragma once
4*da0073e9SAndroid Build Coastguard Worker 
5*da0073e9SAndroid Build Coastguard Worker #include <c10/macros/Export.h>
6*da0073e9SAndroid Build Coastguard Worker #include <array>
7*da0073e9SAndroid Build Coastguard Worker #include <chrono>
8*da0073e9SAndroid Build Coastguard Worker #include <cstddef>
9*da0073e9SAndroid Build Coastguard Worker #include <cstdint>
10*da0073e9SAndroid Build Coastguard Worker #include <ctime>
11*da0073e9SAndroid Build Coastguard Worker #include <functional>
12*da0073e9SAndroid Build Coastguard Worker #include <type_traits>
13*da0073e9SAndroid Build Coastguard Worker 
14*da0073e9SAndroid Build Coastguard Worker #if defined(C10_IOS) && defined(C10_MOBILE)
15*da0073e9SAndroid Build Coastguard Worker #include <sys/time.h> // for gettimeofday()
16*da0073e9SAndroid Build Coastguard Worker #endif
17*da0073e9SAndroid Build Coastguard Worker 
18*da0073e9SAndroid Build Coastguard Worker #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
19*da0073e9SAndroid Build Coastguard Worker #define C10_RDTSC
20*da0073e9SAndroid Build Coastguard Worker #if defined(_MSC_VER)
21*da0073e9SAndroid Build Coastguard Worker #include <intrin.h>
22*da0073e9SAndroid Build Coastguard Worker #elif defined(__CUDACC__) || defined(__HIPCC__)
23*da0073e9SAndroid Build Coastguard Worker #undef C10_RDTSC
24*da0073e9SAndroid Build Coastguard Worker #elif defined(__clang__)
25*da0073e9SAndroid Build Coastguard Worker // `__rdtsc` is available by default.
26*da0073e9SAndroid Build Coastguard Worker // NB: This has to be first, because Clang will also define `__GNUC__`
27*da0073e9SAndroid Build Coastguard Worker #elif defined(__GNUC__)
28*da0073e9SAndroid Build Coastguard Worker #include <x86intrin.h>
29*da0073e9SAndroid Build Coastguard Worker #else
30*da0073e9SAndroid Build Coastguard Worker #undef C10_RDTSC
31*da0073e9SAndroid Build Coastguard Worker #endif
32*da0073e9SAndroid Build Coastguard Worker #endif
33*da0073e9SAndroid Build Coastguard Worker 
34*da0073e9SAndroid Build Coastguard Worker namespace c10 {
35*da0073e9SAndroid Build Coastguard Worker 
36*da0073e9SAndroid Build Coastguard Worker using time_t = int64_t;
37*da0073e9SAndroid Build Coastguard Worker using steady_clock_t = std::conditional_t<
38*da0073e9SAndroid Build Coastguard Worker     std::chrono::high_resolution_clock::is_steady,
39*da0073e9SAndroid Build Coastguard Worker     std::chrono::high_resolution_clock,
40*da0073e9SAndroid Build Coastguard Worker     std::chrono::steady_clock>;
41*da0073e9SAndroid Build Coastguard Worker 
getTimeSinceEpoch()42*da0073e9SAndroid Build Coastguard Worker inline time_t getTimeSinceEpoch() {
43*da0073e9SAndroid Build Coastguard Worker   auto now = std::chrono::system_clock::now().time_since_epoch();
44*da0073e9SAndroid Build Coastguard Worker   return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
45*da0073e9SAndroid Build Coastguard Worker }
46*da0073e9SAndroid Build Coastguard Worker 
47*da0073e9SAndroid Build Coastguard Worker inline time_t getTime(bool allow_monotonic = false) {
48*da0073e9SAndroid Build Coastguard Worker #if defined(C10_IOS) && defined(C10_MOBILE)
49*da0073e9SAndroid Build Coastguard Worker   // clock_gettime is only available on iOS 10.0 or newer. Unlike OS X, iOS
50*da0073e9SAndroid Build Coastguard Worker   // can't rely on CLOCK_REALTIME, as it is defined no matter if clock_gettime
51*da0073e9SAndroid Build Coastguard Worker   // is implemented or not
52*da0073e9SAndroid Build Coastguard Worker   struct timeval now;
53*da0073e9SAndroid Build Coastguard Worker   gettimeofday(&now, NULL);
54*da0073e9SAndroid Build Coastguard Worker   return static_cast<time_t>(now.tv_sec) * 1000000000 +
55*da0073e9SAndroid Build Coastguard Worker       static_cast<time_t>(now.tv_usec) * 1000;
56*da0073e9SAndroid Build Coastguard Worker #elif defined(_WIN32) || defined(__MACH__)
57*da0073e9SAndroid Build Coastguard Worker   return std::chrono::duration_cast<std::chrono::nanoseconds>(
58*da0073e9SAndroid Build Coastguard Worker              steady_clock_t::now().time_since_epoch())
59*da0073e9SAndroid Build Coastguard Worker       .count();
60*da0073e9SAndroid Build Coastguard Worker #else
61*da0073e9SAndroid Build Coastguard Worker   // clock_gettime is *much* faster than std::chrono implementation on Linux
62*da0073e9SAndroid Build Coastguard Worker   struct timespec t {};
63*da0073e9SAndroid Build Coastguard Worker   auto mode = CLOCK_REALTIME;
64*da0073e9SAndroid Build Coastguard Worker   if (allow_monotonic) {
65*da0073e9SAndroid Build Coastguard Worker     mode = CLOCK_MONOTONIC;
66*da0073e9SAndroid Build Coastguard Worker   }
67*da0073e9SAndroid Build Coastguard Worker   clock_gettime(mode, &t);
68*da0073e9SAndroid Build Coastguard Worker   return static_cast<time_t>(t.tv_sec) * 1000000000 +
69*da0073e9SAndroid Build Coastguard Worker       static_cast<time_t>(t.tv_nsec);
70*da0073e9SAndroid Build Coastguard Worker #endif
71*da0073e9SAndroid Build Coastguard Worker }
72*da0073e9SAndroid Build Coastguard Worker 
73*da0073e9SAndroid Build Coastguard Worker // We often do not need to capture true wall times. If a fast mechanism such
74*da0073e9SAndroid Build Coastguard Worker // as TSC is available we can use that instead and convert back to epoch time
75*da0073e9SAndroid Build Coastguard Worker // during post processing. This greatly reduce the clock's contribution to
76*da0073e9SAndroid Build Coastguard Worker // profiling.
77*da0073e9SAndroid Build Coastguard Worker //   http://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/
78*da0073e9SAndroid Build Coastguard Worker //   https://quick-bench.com/q/r8opkkGZSJMu9wM_XTbDouq-0Io
79*da0073e9SAndroid Build Coastguard Worker // TODO: We should use
80*da0073e9SAndroid Build Coastguard Worker // `https://github.com/google/benchmark/blob/main/src/cycleclock.h`
getApproximateTime()81*da0073e9SAndroid Build Coastguard Worker inline auto getApproximateTime() {
82*da0073e9SAndroid Build Coastguard Worker #if defined(C10_RDTSC)
83*da0073e9SAndroid Build Coastguard Worker   return static_cast<uint64_t>(__rdtsc());
84*da0073e9SAndroid Build Coastguard Worker #else
85*da0073e9SAndroid Build Coastguard Worker   return getTime();
86*da0073e9SAndroid Build Coastguard Worker #endif
87*da0073e9SAndroid Build Coastguard Worker }
88*da0073e9SAndroid Build Coastguard Worker 
89*da0073e9SAndroid Build Coastguard Worker using approx_time_t = decltype(getApproximateTime());
90*da0073e9SAndroid Build Coastguard Worker static_assert(
91*da0073e9SAndroid Build Coastguard Worker     std::is_same_v<approx_time_t, int64_t> ||
92*da0073e9SAndroid Build Coastguard Worker         std::is_same_v<approx_time_t, uint64_t>,
93*da0073e9SAndroid Build Coastguard Worker     "Expected either int64_t (`getTime`) or uint64_t (some TSC reads).");
94*da0073e9SAndroid Build Coastguard Worker 
95*da0073e9SAndroid Build Coastguard Worker // Convert `getCount` results to Nanoseconds since unix epoch.
96*da0073e9SAndroid Build Coastguard Worker class C10_API ApproximateClockToUnixTimeConverter final {
97*da0073e9SAndroid Build Coastguard Worker  public:
98*da0073e9SAndroid Build Coastguard Worker   ApproximateClockToUnixTimeConverter();
99*da0073e9SAndroid Build Coastguard Worker   std::function<time_t(approx_time_t)> makeConverter();
100*da0073e9SAndroid Build Coastguard Worker 
101*da0073e9SAndroid Build Coastguard Worker   struct UnixAndApproximateTimePair {
102*da0073e9SAndroid Build Coastguard Worker     time_t t_;
103*da0073e9SAndroid Build Coastguard Worker     approx_time_t approx_t_;
104*da0073e9SAndroid Build Coastguard Worker   };
105*da0073e9SAndroid Build Coastguard Worker   static UnixAndApproximateTimePair measurePair();
106*da0073e9SAndroid Build Coastguard Worker 
107*da0073e9SAndroid Build Coastguard Worker  private:
108*da0073e9SAndroid Build Coastguard Worker   static constexpr size_t replicates = 1001;
109*da0073e9SAndroid Build Coastguard Worker   using time_pairs = std::array<UnixAndApproximateTimePair, replicates>;
110*da0073e9SAndroid Build Coastguard Worker   time_pairs measurePairs();
111*da0073e9SAndroid Build Coastguard Worker 
112*da0073e9SAndroid Build Coastguard Worker   time_pairs start_times_;
113*da0073e9SAndroid Build Coastguard Worker };
114*da0073e9SAndroid Build Coastguard Worker 
115*da0073e9SAndroid Build Coastguard Worker } // namespace c10
116