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 17 #include "inplace_sampler_lib.h" 18 19 #include <inttypes.h> 20 #include <pthread.h> 21 #include <signal.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/syscall.h> 26 #include <sys/ucontext.h> 27 #include <unistd.h> 28 29 #include <map> 30 #include <memory> 31 #include <queue> 32 #include <set> 33 #include <string> 34 #include <unordered_map> 35 36 #include <android-base/logging.h> 37 #include <android-base/macros.h> 38 #include <backtrace/Backtrace.h> 39 #define LOG_TAG "InplaceSampler" 40 #include <log/log.h> 41 42 #include "environment.h" 43 #include "UnixSocket.h" 44 #include "utils.h" 45 46 #define DEFAULT_SIGNO SIGRTMAX 47 static constexpr int DEFAULT_SAMPLE_FREQ = 4000; 48 static constexpr int CHECK_THREADS_INTERVAL_IN_MS = 200; 49 50 namespace { 51 52 struct ThreadInfo { 53 std::string name; 54 }; 55 56 // SampleManager controls the whole sampling process: 57 // Read commands from simpleperf 58 // Set up timers to send signals for each profiled thread regularly. 59 // Send thread info and map info to simpleperf. 60 class SampleManager { 61 public: 62 SampleManager(std::unique_ptr<UnixSocketConnection> conn) : conn_(std::move(conn)), 63 tid_(gettid()), signo_(DEFAULT_SIGNO), sample_freq_(DEFAULT_SAMPLE_FREQ), 64 sample_period_in_ns_(0), dump_callchain_(false), monitor_all_threads_(true) { 65 } 66 void Run(); 67 68 private: 69 bool HandleMessage(const UnixSocketMessage& msg); 70 bool ParseStartProfilingMessage(const UnixSocketMessage& msg); 71 bool SendStartProfilingReplyMessage(bool ok); 72 bool StartProfiling(); 73 bool InstallSignalHandler(); 74 bool CheckThreads(); 75 bool CheckThreadNameChange(uint64_t timestamp); 76 bool CheckMapChange(uint64_t timestamp); 77 void SendThreadMapInfo(); 78 void SendFakeSampleRecord(); 79 80 std::unique_ptr<UnixSocketConnection> conn_; 81 82 int tid_; 83 int signo_; 84 uint32_t sample_freq_; 85 uint32_t sample_period_in_ns_; 86 bool dump_callchain_; 87 bool monitor_all_threads_; 88 std::set<int> monitor_tid_filter_; 89 std::map<int, ThreadInfo> threads_; 90 std::map<uint64_t, ThreadMmap> maps_; 91 std::queue<std::unique_ptr<char[]>> thread_map_info_q_; 92 93 IOEventLoop loop_; 94 }; 95 96 void SampleManager::Run() { 97 auto read_callback = [&](const UnixSocketMessage& msg) { 98 return HandleMessage(msg); 99 }; 100 auto close_callback = [&]() { 101 return loop_.ExitLoop(); 102 }; 103 if (!conn_->PrepareForIO(loop_, read_callback, close_callback)) { 104 return; 105 } 106 loop_.RunLoop(); 107 } 108 109 bool SampleManager::HandleMessage(const UnixSocketMessage& msg) { 110 if (msg.type == START_PROFILING) { 111 if (!ParseStartProfilingMessage(msg)) { 112 if (!SendStartProfilingReplyMessage(false)) { 113 return false; 114 } 115 return conn_->NoMoreMessage(); 116 } 117 if (!SendStartProfilingReplyMessage(true)) { 118 return false; 119 } 120 return StartProfiling(); 121 } 122 if (msg.type == END_PROFILING) { 123 // Close connection after clearing send buffer. 124 return conn_->NoMoreMessage(); 125 } 126 LOG(ERROR) << "Unexpected msg type: " << msg.type; 127 return false; 128 } 129 130 bool SampleManager::ParseStartProfilingMessage(const UnixSocketMessage& msg) { 131 char* option = const_cast<char*>(msg.data); 132 while (option != nullptr && *option != '\0') { 133 char* next_option = strchr(option, ' '); 134 if (next_option != nullptr) { 135 *next_option++ = '\0'; 136 } 137 char* equal_op = strchr(option, '='); 138 if (equal_op != nullptr) { 139 char* key = option; 140 *equal_op = '\0'; 141 char* value = equal_op + 1; 142 if (strcmp(key, "freq") == 0) { 143 sample_freq_ = atoi(value); 144 } else if (strcmp(key, "signal") == 0) { 145 signo_ = atoi(value); 146 } else if (strcmp(key, "tids") == 0) { 147 monitor_all_threads_ = false; 148 while (*value != '\0') { 149 int tid = static_cast<int>(strtol(value, &value, 10)); 150 monitor_tid_filter_.insert(tid); 151 if (*value == ',') { 152 ++value; 153 } 154 } 155 } else if (strcmp(key, "dump_callchain") == 0) { 156 dump_callchain_ = (strcmp(value, "1") == 0); 157 } 158 } 159 option = next_option; 160 } 161 if (sample_freq_ == 0 || sample_freq_ > 1000000000) { 162 LOG(ERROR) << "Unexpected sample_freq: " << sample_freq_; 163 return false; 164 } 165 if (sample_freq_ == 1) { 166 sample_period_in_ns_ = 999999999; 167 } else { 168 sample_period_in_ns_ = 1000000000 / sample_freq_; 169 } 170 return true; 171 } 172 173 bool SampleManager::SendStartProfilingReplyMessage(bool ok) { 174 const char* s = ok ? "ok" : "error"; 175 size_t size = sizeof(UnixSocketMessage) + strlen(s) + 1; 176 std::unique_ptr<char[]> data(new char[size]); 177 UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get()); 178 msg->len = size; 179 msg->type = START_PROFILING_REPLY; 180 strcpy(msg->data, s); 181 return conn_->SendMessage(*msg, true); 182 } 183 184 bool SampleManager::StartProfiling() { 185 if (!InstallSignalHandler()) { 186 return false; 187 } 188 if (!CheckThreads()) { 189 return false; 190 } 191 timeval tv; 192 tv.tv_sec = CHECK_THREADS_INTERVAL_IN_MS / 1000; 193 tv.tv_usec = CHECK_THREADS_INTERVAL_IN_MS % 1000 * 1000; 194 return loop_.AddPeriodicEvent(tv, [&]() { 195 return CheckThreads(); 196 }); 197 } 198 199 bool SampleManager::InstallSignalHandler() { 200 return true; 201 } 202 203 bool SampleManager::CheckThreads() { 204 uint64_t timestamp = GetSystemClock(); 205 if (!CheckMapChange(timestamp)) { 206 return false; 207 } 208 if (!CheckThreadNameChange(timestamp)) { 209 return false; 210 } 211 SendThreadMapInfo(); 212 // For testing. 213 SendFakeSampleRecord(); 214 return true; 215 } 216 217 bool SampleManager::CheckThreadNameChange(uint64_t timestamp) { 218 std::vector<pid_t> tids = GetThreadsInProcess(getpid()); 219 std::map<pid_t, std::string> current; 220 for (auto& tid : tids) { 221 if (tid == tid_) { 222 // Skip sample thread. 223 continue; 224 } 225 if (monitor_all_threads_ || monitor_tid_filter_.find(tid) != monitor_tid_filter_.end()) { 226 std::string name; 227 if (GetThreadName(tid, &name)) { 228 current[tid] = name; 229 } 230 } 231 } 232 // Check new threads or threads with new names. 233 for (auto& pair : current) { 234 pid_t tid = pair.first; 235 auto it = threads_.find(tid); 236 if (it == threads_.end() || it->second.name != pair.second) { 237 threads_[tid].name = pair.second; 238 size_t size = sizeof(UnixSocketMessage) + sizeof(uint64_t) + sizeof(uint32_t) + 239 pair.second.size() + 1; 240 std::unique_ptr<char[]> data(new char[size]); 241 UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get()); 242 msg->len = size; 243 msg->type = THREAD_INFO; 244 char* p = msg->data; 245 MoveToBinaryFormat(timestamp, p); 246 MoveToBinaryFormat(static_cast<uint32_t>(tid), p); 247 MoveToBinaryFormat(pair.second.c_str(), pair.second.size() + 1, p); 248 thread_map_info_q_.push(std::move(data)); 249 } 250 } 251 // Check deleted threads. 252 for (auto it = threads_.begin(); it != threads_.end();) { 253 int tid = it->first; 254 if (current.find(tid) == current.end()) { 255 it = threads_.erase(it); 256 } else { 257 ++it; 258 } 259 } 260 return true; 261 } 262 263 bool SampleManager::CheckMapChange(uint64_t timestamp) { 264 std::vector<ThreadMmap> maps; 265 if (!GetThreadMmapsInProcess(getpid(), &maps)) { 266 return false; 267 } 268 // Check new maps or changed maps. 269 for (auto& map : maps) { 270 if (!map.executable) { 271 continue; 272 } 273 auto it = maps_.find(map.start_addr); 274 if (it == maps_.end() || it->second.len != map.len || it->second.pgoff != map.pgoff || 275 it->second.name != map.name) { 276 maps_[map.start_addr] = map; 277 size_t size = sizeof(UnixSocketMessage) + sizeof(uint64_t) * 4 + map.name.size() + 1; 278 std::unique_ptr<char[]> data(new char[size]); 279 UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get()); 280 msg->len = size; 281 msg->type = MAP_INFO; 282 char* p = msg->data; 283 MoveToBinaryFormat(timestamp, p); 284 MoveToBinaryFormat(map.start_addr, p); 285 MoveToBinaryFormat(map.len, p); 286 MoveToBinaryFormat(map.pgoff, p); 287 MoveToBinaryFormat(map.name.c_str(), map.name.size() + 1, p); 288 thread_map_info_q_.push(std::move(data)); 289 } 290 } 291 return true; 292 } 293 294 void SampleManager::SendThreadMapInfo() { 295 while (!thread_map_info_q_.empty()) { 296 auto& data = thread_map_info_q_.front(); 297 UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get()); 298 if (!conn_->SendMessage(*msg, false)) { 299 break; 300 } 301 thread_map_info_q_.pop(); 302 } 303 } 304 305 static void FakeFunction() { 306 } 307 308 void SampleManager::SendFakeSampleRecord() { 309 size_t size = sizeof(UnixSocketMessage) + sizeof(uint64_t) * 2 + sizeof(uint32_t) * 3; 310 std::unique_ptr<char[]> data(new char[size]); 311 UnixSocketMessage* msg = reinterpret_cast<UnixSocketMessage*>(data.get()); 312 uint64_t ip = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&FakeFunction)); 313 msg->len = size; 314 msg->type = SAMPLE_INFO; 315 char* p = msg->data; 316 MoveToBinaryFormat(GetSystemClock(), p); 317 MoveToBinaryFormat(static_cast<uint32_t>(tid_), p); 318 MoveToBinaryFormat(1u, p); 319 MoveToBinaryFormat(1u, p); 320 MoveToBinaryFormat(ip, p); 321 conn_->SendMessage(*msg, false); 322 } 323 324 static void* CommunicationThread(void*) { 325 pthread_setname_np(pthread_self(), "inplace_sampler"); 326 std::string server_path = "inplace_sampler_server_" + std::to_string(getpid()); 327 std::unique_ptr<UnixSocketServer> server = UnixSocketServer::Create(server_path, true); 328 if (server == nullptr) { 329 LOG(ERROR) << "failed to create server at path " << server_path; 330 return nullptr; 331 } 332 LOG(INFO) << "Create inplace_sampler_server at " << server_path; 333 while (true) { 334 std::unique_ptr<UnixSocketConnection> conn = server->AcceptConnection(); 335 if (conn == nullptr) { 336 break; 337 } 338 SampleManager manager(std::move(conn)); 339 manager.Run(); 340 } 341 return nullptr; 342 } 343 344 __attribute__((constructor)) void InitSampler() { 345 pthread_attr_t attr; 346 if (pthread_attr_init(&attr) != 0) { 347 LOG(ERROR) << "pthread_attr_init failed"; 348 return; 349 } 350 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) { 351 LOG(ERROR) << "pthread_attr_setdetachstate failed"; 352 return; 353 } 354 pthread_t thread; 355 if (pthread_create(&thread, &attr, CommunicationThread, nullptr) != 0) { 356 LOG(ERROR) << "pthread_create failed"; 357 return; 358 } 359 pthread_attr_destroy(&attr); 360 } 361 362 } // namespace 363