1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_BASE_TIME_H_ 18 #define INCLUDE_PERFETTO_BASE_TIME_H_ 19 20 #include <time.h> 21 22 #include <chrono> 23 24 #include "perfetto/base/build_config.h" 25 #include "perfetto/base/logging.h" 26 27 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) 28 #include <mach/mach_init.h> 29 #include <mach/mach_port.h> 30 #include <mach/mach_time.h> 31 #include <mach/thread_act.h> 32 #endif 33 34 namespace perfetto { 35 namespace base { 36 37 using TimeSeconds = std::chrono::seconds; 38 using TimeMillis = std::chrono::milliseconds; 39 using TimeNanos = std::chrono::nanoseconds; 40 41 inline TimeNanos FromPosixTimespec(const struct timespec& ts) { 42 return TimeNanos(ts.tv_sec * 1000000000LL + ts.tv_nsec); 43 } 44 45 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) 46 47 constexpr clockid_t kWallTimeClockSource = CLOCK_MONOTONIC; 48 49 inline TimeNanos GetTimeInternalNs(clockid_t clk_id) { 50 struct timespec ts = {}; 51 PERFETTO_CHECK(clock_gettime(clk_id, &ts) == 0); 52 return FromPosixTimespec(ts); 53 } 54 55 inline TimeNanos GetWallTimeNs() { 56 return GetTimeInternalNs(kWallTimeClockSource); 57 } 58 59 inline TimeNanos GetThreadCPUTimeNs() { 60 return GetTimeInternalNs(CLOCK_THREAD_CPUTIME_ID); 61 } 62 63 #else // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) 64 65 inline TimeNanos GetWallTimeNs() { 66 auto init_time_factor = []() -> uint64_t { 67 mach_timebase_info_data_t timebase_info; 68 mach_timebase_info(&timebase_info); 69 return timebase_info.numer / timebase_info.denom; 70 }; 71 72 static uint64_t monotonic_timebase_factor = init_time_factor(); 73 return TimeNanos(mach_absolute_time() * monotonic_timebase_factor); 74 } 75 76 inline TimeNanos GetThreadCPUTimeNs() { 77 mach_port_t this_thread = mach_thread_self(); 78 mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; 79 thread_basic_info_data_t info{}; 80 kern_return_t kr = 81 thread_info(this_thread, THREAD_BASIC_INFO, 82 reinterpret_cast<thread_info_t>(&info), &count); 83 mach_port_deallocate(mach_task_self(), this_thread); 84 85 if (kr != KERN_SUCCESS) { 86 PERFETTO_DCHECK(false); 87 return TimeNanos(0); 88 } 89 return TimeNanos(info.user_time.seconds * 1000000000LL + 90 info.user_time.microseconds * 1000LL + 91 info.system_time.seconds * 1000000000LL + 92 info.system_time.microseconds * 1000LL); 93 } 94 95 #endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) 96 97 inline TimeMillis GetWallTimeMs() { 98 return std::chrono::duration_cast<TimeMillis>(GetWallTimeNs()); 99 } 100 101 inline TimeSeconds GetWallTimeS() { 102 return std::chrono::duration_cast<TimeSeconds>(GetWallTimeNs()); 103 } 104 105 inline struct timespec ToPosixTimespec(TimeMillis time) { 106 struct timespec ts {}; 107 const long time_s = static_cast<long>(time.count() / 1000); 108 ts.tv_sec = time_s; 109 ts.tv_nsec = (static_cast<long>(time.count()) - time_s * 1000L) * 1000000L; 110 return ts; 111 } 112 113 } // namespace base 114 } // namespace perfetto 115 116 #endif // INCLUDE_PERFETTO_BASE_TIME_H_ 117