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