blob: d39859bf0f5c91c3f0ba20f18adaa96a5720d0b8 [file] [log] [blame]
Florian Mayer824274d2018-09-17 11:33:45 +01001/*
2 * Copyright (C) 2018 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#ifndef SRC_PROFILING_MEMORY_CLIENT_H_
18#define SRC_PROFILING_MEMORY_CLIENT_H_
19
Florian Mayer88665be2018-10-03 13:15:38 +010020#include <pthread.h>
Florian Mayer824274d2018-09-17 11:33:45 +010021#include <stddef.h>
Florian Mayeraf266022018-09-17 15:18:15 +010022
Florian Mayereff98042018-12-10 17:44:44 +000023#include <condition_variable>
Florian Mayer824274d2018-09-17 11:33:45 +010024#include <mutex>
25#include <vector>
26
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010027#include "perfetto/base/unix_socket.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010028#include "src/profiling/memory/wire_protocol.h"
Florian Mayer824274d2018-09-17 11:33:45 +010029
30namespace perfetto {
Florian Mayer8c0d0482018-10-22 14:23:40 +010031namespace profiling {
Florian Mayer824274d2018-09-17 11:33:45 +010032
Florian Mayerb85a9382018-09-27 13:59:01 +010033class BorrowedSocket;
Florian Mayer824274d2018-09-17 11:33:45 +010034
35class SocketPool {
36 public:
37 friend class BorrowedSocket;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010038 SocketPool(std::vector<base::UnixSocketRaw> sockets);
Florian Mayer824274d2018-09-17 11:33:45 +010039
40 BorrowedSocket Borrow();
Florian Mayer2da28412018-10-30 17:33:10 +000041 void Shutdown();
Florian Mayer824274d2018-09-17 11:33:45 +010042
43 private:
Florian Mayer2da28412018-10-30 17:33:10 +000044 bool shutdown_ = false;
45
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010046 void Return(base::UnixSocketRaw);
Florian Mayer65081572018-12-18 13:41:08 +000047 std::timed_mutex mutex_;
48 std::condition_variable_any cv_;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010049 std::vector<base::UnixSocketRaw> sockets_;
Florian Mayer824274d2018-09-17 11:33:45 +010050 size_t available_sockets_;
Florian Mayeraf266022018-09-17 15:18:15 +010051 size_t dead_sockets_ = 0;
Florian Mayer824274d2018-09-17 11:33:45 +010052};
53
Florian Mayerb85a9382018-09-27 13:59:01 +010054// Socket borrowed from a SocketPool. Gets returned once it goes out of scope.
55class BorrowedSocket {
56 public:
57 BorrowedSocket(const BorrowedSocket&) = delete;
58 BorrowedSocket& operator=(const BorrowedSocket&) = delete;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010059 BorrowedSocket(BorrowedSocket&& other) noexcept
60 : sock_(std::move(other.sock_)), socket_pool_(other.socket_pool_) {
Florian Mayerb85a9382018-09-27 13:59:01 +010061 other.socket_pool_ = nullptr;
62 }
63
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010064 BorrowedSocket(base::UnixSocketRaw sock, SocketPool* socket_pool)
65 : sock_(std::move(sock)), socket_pool_(socket_pool) {}
Florian Mayerb85a9382018-09-27 13:59:01 +010066
67 ~BorrowedSocket() {
68 if (socket_pool_ != nullptr)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010069 socket_pool_->Return(std::move(sock_));
Florian Mayerb85a9382018-09-27 13:59:01 +010070 }
71
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010072 base::UnixSocketRaw* operator->() { return &sock_; }
73 base::UnixSocketRaw* get() { return &sock_; }
74 void Shutdown() { sock_.Shutdown(); }
75 explicit operator bool() const { return !!sock_; }
Florian Mayerf1510c42018-10-17 11:40:52 +010076
Florian Mayerb85a9382018-09-27 13:59:01 +010077 private:
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010078 base::UnixSocketRaw sock_;
Florian Mayerb85a9382018-09-27 13:59:01 +010079 SocketPool* socket_pool_ = nullptr;
80};
81
82// Cache for frees that have been observed. It is infeasible to send every
83// free separately, so we batch and send the whole buffer once it is full.
84class FreePage {
85 public:
Florian Mayer192136e2019-01-30 18:04:34 +000086 FreePage(uint64_t client_generation) {
87 free_page_.client_generation = client_generation;
88 }
89
Florian Mayerb85a9382018-09-27 13:59:01 +010090 // Add address to buffer. Flush if necessary using a socket borrowed from
91 // pool.
92 // Can be called from any thread. Must not hold mutex_.`
Florian Mayer65081572018-12-18 13:41:08 +000093 bool Add(const uint64_t addr, uint64_t sequence_number, SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010094
95 private:
96 // Needs to be called holding mutex_.
Florian Mayer65081572018-12-18 13:41:08 +000097 bool FlushLocked(SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010098
99 FreeMetadata free_page_;
Florian Mayer65081572018-12-18 13:41:08 +0000100 std::timed_mutex mutex_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100101 size_t offset_ = 0;
102};
103
104const char* GetThreadStackBase();
105
Florian Mayer88665be2018-10-03 13:15:38 +0100106// RAII wrapper around pthread_key_t. This is different from a ScopedResource
107// because it needs a separate boolean indicating validity.
108class PThreadKey {
109 public:
110 PThreadKey(const PThreadKey&) = delete;
111 PThreadKey& operator=(const PThreadKey&) = delete;
112
113 PThreadKey(void (*destructor)(void*)) noexcept
114 : valid_(pthread_key_create(&key_, destructor) == 0) {}
115 ~PThreadKey() noexcept {
116 if (valid_)
117 pthread_key_delete(key_);
118 }
119 bool valid() const { return valid_; }
120 pthread_key_t get() const {
121 PERFETTO_DCHECK(valid_);
122 return key_;
123 }
124
125 private:
126 pthread_key_t key_;
127 bool valid_;
128};
129
Florian Mayerdac31272019-02-26 12:07:02 +0000130constexpr uint32_t kClientSockTimeoutMs = 1000;
Ryan Savitski14c12d62019-01-08 22:38:53 +0000131
Florian Mayerb85a9382018-09-27 13:59:01 +0100132// This is created and owned by the malloc hooks.
133class Client {
134 public:
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100135 Client(std::vector<base::UnixSocketRaw> sockets);
Florian Mayerb85a9382018-09-27 13:59:01 +0100136 Client(const std::string& sock_name, size_t conns);
Florian Mayer20c4b3c2019-01-24 18:25:35 +0000137 bool RecordMalloc(uint64_t alloc_size,
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100138 uint64_t total_size,
139 uint64_t alloc_address);
Florian Mayer20c4b3c2019-01-24 18:25:35 +0000140 bool RecordFree(uint64_t alloc_address);
141 bool MaybeSampleAlloc(uint64_t alloc_size,
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100142 uint64_t alloc_address,
143 void* (*unhooked_malloc)(size_t),
144 void (*unhooked_free)(void*));
Florian Mayer2da28412018-10-30 17:33:10 +0000145 void Shutdown();
Florian Mayerb85a9382018-09-27 13:59:01 +0100146
Florian Mayer1fe77732018-10-02 17:25:53 +0100147 ClientConfiguration client_config_for_testing() { return client_config_; }
Florian Mayerb12c4f22018-11-14 16:13:02 +0000148 bool inited() { return inited_; }
Florian Mayer1fe77732018-10-02 17:25:53 +0100149
Florian Mayerb85a9382018-09-27 13:59:01 +0100150 private:
Florian Mayer20c4b3c2019-01-24 18:25:35 +0000151 ssize_t ShouldSampleAlloc(uint64_t alloc_size,
152 void* (*unhooked_malloc)(size_t),
153 void (*unhooked_free)(void*));
Florian Mayerb85a9382018-09-27 13:59:01 +0100154 const char* GetStackBase();
155
Florian Mayer192136e2019-01-30 18:04:34 +0000156 static std::atomic<uint64_t> max_generation_;
157 const uint64_t generation_;
158
Florian Mayerf0867992018-11-16 10:12:18 +0000159 std::atomic<bool> inited_{false};
Florian Mayer1fe77732018-10-02 17:25:53 +0100160 ClientConfiguration client_config_;
Florian Mayer88665be2018-10-03 13:15:38 +0100161 PThreadKey pthread_key_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100162 SocketPool socket_pool_;
163 FreePage free_page_;
164 const char* main_thread_stack_base_ = nullptr;
165 std::atomic<uint64_t> sequence_number_{0};
166};
167
Florian Mayer8c0d0482018-10-22 14:23:40 +0100168} // namespace profiling
Florian Mayer824274d2018-09-17 11:33:45 +0100169} // namespace perfetto
170
171#endif // SRC_PROFILING_MEMORY_CLIENT_H_