1aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui/* 2aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * Copyright (C) 2016 The Android Open Source Project 3aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * 4aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * Licensed under the Apache License, Version 2.0 (the "License"); 5aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * you may not use this file except in compliance with the License. 6aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * You may obtain a copy of the License at 7aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * 8aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * http://www.apache.org/licenses/LICENSE-2.0 9aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * 10aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * Unless required by applicable law or agreed to in writing, software 11aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * distributed under the License is distributed on an "AS IS" BASIS, 12aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * See the License for the specific language governing permissions and 14aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui * limitations under the License. 15aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui */ 16aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 17aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include "perf_clock.h" 18aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 19aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <sys/mman.h> 20aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <sys/syscall.h> 21aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 22aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <atomic> 23aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <chrono> 24aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <thread> 25aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 26aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include <android-base/logging.h> 27aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 28003b245939bae5e86ed53b3c6b333637dbc571b4Yabin Cui#include "environment.h" 29aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include "event_attr.h" 30aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include "event_fd.h" 31aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include "event_type.h" 32aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui#include "record.h" 33aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 34aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuistatic bool perf_clock_initialized = false; 35aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuistatic int64_t perf_clock_and_system_clock_diff_in_ns = 0; 36aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 37aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuistruct ThreadArg { 38aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::atomic<pid_t> thread_a_tid; 39aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::atomic<bool> start_mmap; 40aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::atomic<uint64_t> mmap_start_addr; 41aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t system_time_in_ns; 42aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::atomic<bool> has_error; 43aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui}; 44aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 45aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuistatic void ThreadA(ThreadArg* thread_arg) { 46aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg->thread_a_tid = syscall(SYS_gettid); 47aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui while (!thread_arg->start_mmap) { 48aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui usleep(1000); 49aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 50aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 51aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui size_t TRY_MMAP_COUNT = 10; 52aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 53aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui struct TryMmap { 54aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui void* mmap_start_addr; 55aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t start_system_time_in_ns; 56aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t end_system_time_in_ns; 57aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui }; 58aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui TryMmap array[TRY_MMAP_COUNT]; 59aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 60aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui // In case current thread is preempted by other threads, we run mmap() 61aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui // multiple times and use the one with the smallest time interval. 62aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui for (size_t i = 0; i < TRY_MMAP_COUNT; ++i) { 63003b245939bae5e86ed53b3c6b333637dbc571b4Yabin Cui array[i].start_system_time_in_ns = GetSystemClock(); 64aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui array[i].mmap_start_addr = 65aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui mmap(NULL, 4096, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 66aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (array[i].mmap_start_addr == MAP_FAILED) { 67aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui PLOG(ERROR) << "mmap() failed"; 68aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg->has_error = true; 69aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return; 70aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 71aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 72003b245939bae5e86ed53b3c6b333637dbc571b4Yabin Cui array[i].end_system_time_in_ns = GetSystemClock(); 73aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 74aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui size_t best_index = 0; 75aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t min_duration_in_ns = UINT64_MAX; 76aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui for (size_t i = 0; i < TRY_MMAP_COUNT; ++i) { 77aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t d = 78aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui array[i].end_system_time_in_ns - array[i].start_system_time_in_ns; 79aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (min_duration_in_ns > d) { 80aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui min_duration_in_ns = d; 81aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui best_index = i; 82aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 83aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui munmap(array[i].mmap_start_addr, 4096); 84aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 85aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg->mmap_start_addr = 86aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui reinterpret_cast<uint64_t>(array[best_index].mmap_start_addr); 87aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui // Perf time is generated at the end of mmap() syscall, which is close to 88aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui // the end time instead of the start time. 89aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg->system_time_in_ns = array[best_index].end_system_time_in_ns; 90aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui} 91aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 92aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuistatic bool GetClockDiff(int64_t* clock_diff_in_ns) { 93aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui ThreadArg thread_arg; 94aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg.thread_a_tid = 0; 95aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg.start_mmap = false; 96aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg.has_error = false; 97aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::thread thread_a(ThreadA, &thread_arg); 98aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui while (thread_arg.thread_a_tid == 0) { 99aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui usleep(1000); 100aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 101aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::unique_ptr<EventTypeAndModifier> event_type = 102aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui ParseEventType("cpu-clock"); 103aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (event_type == nullptr) { 104aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 105aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 106aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui perf_event_attr attr = CreateDefaultPerfEventAttr(event_type->event_type); 107aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.comm = 0; 108aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.mmap_data = 1; 109aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.mmap = 0; 110aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.inherit = 0; 111aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.sample_id_all = 1; 112aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.freq = 0; 113aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui attr.sample_period = 1ULL << 62; // Sample records are not needed. 114aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::unique_ptr<EventFd> event_fd = 115aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui EventFd::OpenEventFile(attr, thread_arg.thread_a_tid, -1, nullptr); 116aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (event_fd == nullptr) { 117aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 118aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 119aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (!event_fd->CreateMappedBuffer(4, true)) { 120aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 121aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 122aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 123aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_arg.start_mmap = true; 124aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui thread_a.join(); 125aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 126aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (thread_arg.has_error) { 127aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 128aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 129aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 1302ea6de11962fea5613f15308b202fb505e57ae9bYabin Cui std::vector<char> buffer; 1312ea6de11962fea5613f15308b202fb505e57ae9bYabin Cui size_t buffer_pos = 0; 1322ea6de11962fea5613f15308b202fb505e57ae9bYabin Cui size_t size = event_fd->GetAvailableMmapData(buffer, buffer_pos); 133aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui std::vector<std::unique_ptr<Record>> records = 1342ea6de11962fea5613f15308b202fb505e57ae9bYabin Cui ReadRecordsFromBuffer(attr, buffer.data(), size); 135aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui uint64_t perf_time_in_ns = 0; 136aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui for (auto& r : records) { 137aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (r->type() == PERF_RECORD_MMAP) { 138aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui auto& record = *static_cast<MmapRecord*>(r.get()); 139aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (record.data->addr == thread_arg.mmap_start_addr) { 140aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui perf_time_in_ns = record.Timestamp(); 141aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 142aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 143aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 144aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (perf_time_in_ns == 0) { 145aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui LOG(ERROR) << "GetPerfClockAndSystemClockDiff: can't get perf time."; 146aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 147aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 148aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 149aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui *clock_diff_in_ns = perf_time_in_ns - thread_arg.system_time_in_ns; 150aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui LOG(VERBOSE) << "perf_time is " << perf_time_in_ns << " ns, system_time is " 151aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui << thread_arg.system_time_in_ns << " ns , clock_diff is " 152aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui << *clock_diff_in_ns << " ns."; 153aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return true; 154aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui} 155aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 156aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cuibool InitPerfClock() { 157aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (!perf_clock_initialized) { 158aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui if (!GetClockDiff(&perf_clock_and_system_clock_diff_in_ns)) { 159aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return false; 160aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 161aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui perf_clock_initialized = true; 162aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui } 163aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui return true; 164aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui} 165aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui 166003b245939bae5e86ed53b3c6b333637dbc571b4Yabin Cuiuint64_t GetPerfClock() { 167aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui CHECK(perf_clock_initialized); 168003b245939bae5e86ed53b3c6b333637dbc571b4Yabin Cui return GetSystemClock() + perf_clock_and_system_clock_diff_in_ns; 169aa65c8b250b99f1684f46e2c40b77e42bf7c5f31Yabin Cui} 170