InplaceSamplerClient.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (C) 2017 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. #include "InplaceSamplerClient.h"
  17. #include <algorithm>
  18. #include "environment.h"
  19. #include "inplace_sampler_lib.h"
  20. #include "utils.h"
  21. static constexpr uint64_t EVENT_ID_FOR_INPLACE_SAMPLER = ULONG_MAX;
  22. std::unique_ptr<InplaceSamplerClient> InplaceSamplerClient::Create(const perf_event_attr& attr,
  23. pid_t pid,
  24. const std::set<pid_t>& tids) {
  25. if (pid == -1) {
  26. LOG(ERROR) << "inplace-sampler can't monitor system wide events.";
  27. return nullptr;
  28. }
  29. std::unique_ptr<InplaceSamplerClient> sampler(new InplaceSamplerClient(attr, pid, tids));
  30. if (!sampler->ConnectServer()) {
  31. return nullptr;
  32. }
  33. return sampler;
  34. }
  35. InplaceSamplerClient::InplaceSamplerClient(const perf_event_attr& attr, pid_t pid,
  36. const std::set<pid_t>& tids)
  37. : attr_(attr), pid_(pid), tids_(tids), got_start_profiling_reply_msg_(false) {
  38. if (attr_.freq) {
  39. sample_freq_ = attr_.sample_freq;
  40. } else {
  41. sample_freq_ = std::max(1u, static_cast<uint32_t>(1000000000 / attr_.sample_period));
  42. }
  43. }
  44. uint64_t InplaceSamplerClient::Id() const {
  45. return EVENT_ID_FOR_INPLACE_SAMPLER;
  46. }
  47. bool InplaceSamplerClient::ConnectServer() {
  48. std::string server_path = "inplace_sampler_server_" + std::to_string(pid_);
  49. // Try to connect server in 1s.
  50. uint64_t timeout = GetSystemClock() + 10000000000ull;
  51. while (GetSystemClock() < timeout) {
  52. conn_ = UnixSocketConnection::Connect(server_path, true);
  53. if (conn_ != nullptr) {
  54. return true;
  55. }
  56. usleep(10);
  57. }
  58. LOG(ERROR) << "Can't find inplace_sampler_server for process " << pid_;
  59. return false;
  60. }
  61. bool InplaceSamplerClient::StartPolling(IOEventLoop& loop,
  62. const std::function<bool(Record*)>& record_callback,
  63. const std::function<bool()>& close_callback) {
  64. record_callback_ = record_callback;
  65. CHECK(conn_ != nullptr);
  66. auto read_callback = [&](const UnixSocketMessage& msg) {
  67. return HandleMessage(msg);
  68. };
  69. if (!conn_->PrepareForIO(loop, read_callback, close_callback)) {
  70. return false;
  71. }
  72. if (!SendStartProfilingMessage()) {
  73. return false;
  74. }
  75. // If the inplace sampler doesn't reply in 3 seconds, report the error.
  76. timeval tv;
  77. tv.tv_sec = 3;
  78. tv.tv_usec = 0;
  79. auto check_reply_callback = [this]() {
  80. if (!got_start_profiling_reply_msg_) {
  81. LOG(ERROR) << "can't receive START_PROFILING_REPLY from process " << pid_;
  82. return false;
  83. }
  84. return true;
  85. };
  86. return loop.AddPeriodicEvent(tv, check_reply_callback);
  87. }
  88. bool InplaceSamplerClient::SendStartProfilingMessage() {
  89. std::string options;
  90. options += "freq=" + std::to_string(sample_freq_);
  91. if (attr_.sample_type & PERF_SAMPLE_CALLCHAIN) {
  92. options += " dump_callchain=1";
  93. }
  94. if (!tids_.empty()) {
  95. options += " tids=";
  96. bool first = true;
  97. for (auto& tid : tids_) {
  98. if (first) {
  99. first = false;
  100. } else {
  101. options.push_back(',');
  102. }
  103. options += std::to_string(tid);
  104. }
  105. }
  106. size_t size = sizeof(UnixSocketMessage) + options.size() + 1;
  107. std::unique_ptr<char[]> data(new char[size]);
  108. UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get());
  109. msg->len = size;
  110. msg->type = START_PROFILING;
  111. strcpy(msg->data, options.c_str());
  112. return conn_->SendMessage(*msg, true);
  113. }
  114. bool InplaceSamplerClient::StopProfiling(IOEventLoop& loop,
  115. const std::function<bool()>& close_callback) {
  116. auto read_callback = [&](const UnixSocketMessage& msg) {
  117. return HandleMessage(msg);
  118. };
  119. if (!conn_->PrepareForIO(loop, read_callback, close_callback)) {
  120. return false;
  121. }
  122. // Notify inplace sampler to send buffered data and close the connection.
  123. UnixSocketMessage msg;
  124. msg.len = sizeof(UnixSocketMessage);
  125. msg.type = END_PROFILING;
  126. return conn_->SendMessage(msg, true);
  127. }
  128. bool InplaceSamplerClient::HandleMessage(const UnixSocketMessage& msg) {
  129. const char* p = msg.data;
  130. if (msg.type == START_PROFILING_REPLY) {
  131. got_start_profiling_reply_msg_ = true;
  132. if (strcmp(p, "ok") != 0) {
  133. LOG(ERROR) << "receive reply from inplace_sampler_server of " << pid_ << ": " << p;
  134. return false;
  135. }
  136. } else if (msg.type == THREAD_INFO) {
  137. uint64_t time;
  138. uint32_t tid;
  139. MoveFromBinaryFormat(time, p);
  140. MoveFromBinaryFormat(tid, p);
  141. CommRecord r(attr_, pid_, tid, p, Id(), time);
  142. if (!record_callback_(&r)) {
  143. return false;
  144. }
  145. } else if (msg.type == MAP_INFO) {
  146. uint64_t time;
  147. uint64_t start;
  148. uint64_t len;
  149. uint64_t pgoff;
  150. MoveFromBinaryFormat(time, p);
  151. MoveFromBinaryFormat(start, p);
  152. MoveFromBinaryFormat(len, p);
  153. MoveFromBinaryFormat(pgoff, p);
  154. MmapRecord r(attr_, false, pid_, pid_, start, len, pgoff, p, Id(), time);
  155. if (!record_callback_(&r)) {
  156. return false;
  157. }
  158. } else if (msg.type == SAMPLE_INFO) {
  159. uint64_t time;
  160. uint32_t tid;
  161. uint32_t period;
  162. uint32_t ip_nr;
  163. MoveFromBinaryFormat(time, p);
  164. MoveFromBinaryFormat(tid, p);
  165. MoveFromBinaryFormat(period, p);
  166. MoveFromBinaryFormat(ip_nr, p);
  167. std::vector<uint64_t> ips(ip_nr);
  168. MoveFromBinaryFormat(ips.data(), ip_nr, p);
  169. // Don't know which cpu tid is running on, use cpu 0.
  170. SampleRecord r(attr_, Id(), ips[0], pid_, tid, time, 0, period, ips, {}, 0);
  171. if (!record_callback_(&r)) {
  172. return false;
  173. }
  174. } else {
  175. LOG(ERROR) << "Unexpected msg type: " << msg.type;
  176. return false;
  177. }
  178. return true;
  179. }