126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui/*
226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * Copyright (C) 2017 The Android Open Source Project
326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui *
426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * Licensed under the Apache License, Version 2.0 (the "License");
526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * you may not use this file except in compliance with the License.
626968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * You may obtain a copy of the License at
726968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui *
826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui *      http://www.apache.org/licenses/LICENSE-2.0
926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui *
1026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * Unless required by applicable law or agreed to in writing, software
1126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * distributed under the License is distributed on an "AS IS" BASIS,
1226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * See the License for the specific language governing permissions and
1426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui * limitations under the License.
1526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui */
1626968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
1726968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui#include "InplaceSamplerClient.h"
1826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
19b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui#include <algorithm>
2026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
2126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui#include "environment.h"
22b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui#include "inplace_sampler_lib.h"
2326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui#include "utils.h"
2426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
2526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cuistatic constexpr uint64_t EVENT_ID_FOR_INPLACE_SAMPLER = ULONG_MAX;
2626968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
2726968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cuistd::unique_ptr<InplaceSamplerClient> InplaceSamplerClient::Create(const perf_event_attr& attr,
2826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui                                                                   pid_t pid,
2926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui                                                                   const std::set<pid_t>& tids) {
3026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  if (pid == -1) {
3126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    LOG(ERROR) << "inplace-sampler can't monitor system wide events.";
3226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    return nullptr;
3326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  }
3426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  std::unique_ptr<InplaceSamplerClient> sampler(new InplaceSamplerClient(attr, pid, tids));
3526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  if (!sampler->ConnectServer()) {
3626968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    return nullptr;
3726968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  }
3826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  return sampler;
3926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui}
4026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
4126968e6c48dea2eaa217991ade5a04e801f1be8fYabin CuiInplaceSamplerClient::InplaceSamplerClient(const perf_event_attr& attr, pid_t pid,
4226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui                                           const std::set<pid_t>& tids)
43b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    : attr_(attr), pid_(pid), tids_(tids), got_start_profiling_reply_msg_(false) {
44b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (attr_.freq) {
45b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    sample_freq_ = attr_.sample_freq;
46b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  } else {
47b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    sample_freq_ = std::max(1u, static_cast<uint32_t>(1000000000 / attr_.sample_period));
48b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
4926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui}
5026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
5126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cuiuint64_t InplaceSamplerClient::Id() const {
5226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  return EVENT_ID_FOR_INPLACE_SAMPLER;
5326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui}
5426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
5526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cuibool InplaceSamplerClient::ConnectServer() {
56b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  std::string server_path = "inplace_sampler_server_" + std::to_string(pid_);
57b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  // Try to connect server in 1s.
58b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  uint64_t timeout = GetSystemClock() + 10000000000ull;
59b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  while (GetSystemClock() < timeout) {
60b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    conn_ = UnixSocketConnection::Connect(server_path, true);
61b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    if (conn_ != nullptr) {
62b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      return true;
63b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    }
64b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    usleep(10);
65b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
66b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  LOG(ERROR) << "Can't find inplace_sampler_server for process " << pid_;
67b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  return false;
6826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui}
6926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui
7026968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cuibool InplaceSamplerClient::StartPolling(IOEventLoop& loop,
7126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui                                        const std::function<bool(Record*)>& record_callback,
7226968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui                                        const std::function<bool()>& close_callback) {
7326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui  record_callback_ = record_callback;
74b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  CHECK(conn_ != nullptr);
75b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  auto read_callback = [&](const UnixSocketMessage& msg) {
76b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return HandleMessage(msg);
77b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  };
78b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (!conn_->PrepareForIO(loop, read_callback, close_callback)) {
79b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return false;
80b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
81b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (!SendStartProfilingMessage()) {
82b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return false;
83b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
84b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  // If the inplace sampler doesn't reply in 3 seconds, report the error.
85b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  timeval tv;
86b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  tv.tv_sec = 3;
87b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  tv.tv_usec = 0;
88b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  auto check_reply_callback = [this]() {
89b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    if (!got_start_profiling_reply_msg_) {
90b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      LOG(ERROR) << "can't receive START_PROFILING_REPLY from process " << pid_;
91b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      return false;
92b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    }
93b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return true;
94b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  };
95b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  return loop.AddPeriodicEvent(tv, check_reply_callback);
96b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui}
97b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui
98b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cuibool InplaceSamplerClient::SendStartProfilingMessage() {
99b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  std::string options;
100b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  options += "freq=" + std::to_string(sample_freq_);
101b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (attr_.sample_type & PERF_SAMPLE_CALLCHAIN) {
102b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    options += " dump_callchain=1";
103b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
104b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (!tids_.empty()) {
105b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    options += " tids=";
106b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    bool first = true;
107b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    for (auto& tid : tids_) {
108b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      if (first) {
109b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui        first = false;
110b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      } else {
111b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui        options.push_back(',');
112b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      }
113b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      options += std::to_string(tid);
114b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    }
115b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
116b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  size_t size = sizeof(UnixSocketMessage) + options.size() + 1;
117b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  std::unique_ptr<char[]> data(new char[size]);
118b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get());
119b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  msg->len = size;
120b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  msg->type = START_PROFILING;
121b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  strcpy(msg->data, options.c_str());
122b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  return conn_->SendMessage(*msg, true);
123b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui}
124b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui
125b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cuibool InplaceSamplerClient::StopProfiling(IOEventLoop& loop,
126b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui                                         const std::function<bool()>& close_callback) {
127b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  auto read_callback = [&](const UnixSocketMessage& msg) {
128b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return HandleMessage(msg);
129b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  };
130b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (!conn_->PrepareForIO(loop, read_callback, close_callback)) {
131b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return false;
132b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
133b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  // Notify inplace sampler to send buffered data and close the connection.
134b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  UnixSocketMessage msg;
135b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  msg.len = sizeof(UnixSocketMessage);
136b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  msg.type = END_PROFILING;
137b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  return conn_->SendMessage(msg, true);
138b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui}
139b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui
140b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cuibool InplaceSamplerClient::HandleMessage(const UnixSocketMessage& msg) {
141b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  const char* p = msg.data;
142b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  if (msg.type == START_PROFILING_REPLY) {
143b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      got_start_profiling_reply_msg_ = true;
144b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      if (strcmp(p, "ok") != 0) {
145b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui        LOG(ERROR) << "receive reply from inplace_sampler_server of " << pid_ << ": " << p;
146b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui        return false;
147b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui      }
148b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  } else if (msg.type == THREAD_INFO) {
149b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t time;
150b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint32_t tid;
151b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(time, p);
152b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(tid, p);
153b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    CommRecord r(attr_, pid_, tid, p, Id(), time);
154b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    if (!record_callback_(&r)) {
15526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui      return false;
15626968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    }
157b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  } else if (msg.type == MAP_INFO) {
158b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t time;
159b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t start;
160b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t len;
161b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t pgoff;
162b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(time, p);
163b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(start, p);
164b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(len, p);
165b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(pgoff, p);
166b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MmapRecord r(attr_, false, pid_, pid_, start, len, pgoff, p, Id(), time);
167b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    if (!record_callback_(&r)) {
16826968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui      return false;
16926968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    }
170b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  } else if (msg.type == SAMPLE_INFO) {
171b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint64_t time;
172b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint32_t tid;
173b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint32_t period;
174b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    uint32_t ip_nr;
175b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(time, p);
176b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(tid, p);
177b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(period, p);
178b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(ip_nr, p);
179b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    std::vector<uint64_t> ips(ip_nr);
180b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    MoveFromBinaryFormat(ips.data(), ip_nr, p);
181b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    // Don't know which cpu tid is running on, use cpu 0.
182b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    SampleRecord r(attr_, Id(), ips[0], pid_, tid, time, 0, period, ips);
18326968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    if (!record_callback_(&r)) {
18426968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui      return false;
18526968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui    }
186b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  } else {
187b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    LOG(ERROR) << "Unexpected msg type: " << msg.type;
188b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui    return false;
189b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  }
190b92bae84b27889b548214bee8d0730ef10da0c6dYabin Cui  return true;
19126968e6c48dea2eaa217991ade5a04e801f1be8fYabin Cui}
192