blob: f71109b77d840035d8bdf5b46f5e3a9b2a7010c3 [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:
86 // Add address to buffer. Flush if necessary using a socket borrowed from
87 // pool.
88 // Can be called from any thread. Must not hold mutex_.`
Florian Mayer65081572018-12-18 13:41:08 +000089 bool Add(const uint64_t addr, uint64_t sequence_number, SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010090
91 private:
92 // Needs to be called holding mutex_.
Florian Mayer65081572018-12-18 13:41:08 +000093 bool FlushLocked(SocketPool* pool);
Florian Mayerb85a9382018-09-27 13:59:01 +010094
95 FreeMetadata free_page_;
Florian Mayer65081572018-12-18 13:41:08 +000096 std::timed_mutex mutex_;
Florian Mayerb85a9382018-09-27 13:59:01 +010097 size_t offset_ = 0;
98};
99
100const char* GetThreadStackBase();
101
Florian Mayer88665be2018-10-03 13:15:38 +0100102// RAII wrapper around pthread_key_t. This is different from a ScopedResource
103// because it needs a separate boolean indicating validity.
104class PThreadKey {
105 public:
106 PThreadKey(const PThreadKey&) = delete;
107 PThreadKey& operator=(const PThreadKey&) = delete;
108
109 PThreadKey(void (*destructor)(void*)) noexcept
110 : valid_(pthread_key_create(&key_, destructor) == 0) {}
111 ~PThreadKey() noexcept {
112 if (valid_)
113 pthread_key_delete(key_);
114 }
115 bool valid() const { return valid_; }
116 pthread_key_t get() const {
117 PERFETTO_DCHECK(valid_);
118 return key_;
119 }
120
121 private:
122 pthread_key_t key_;
123 bool valid_;
124};
125
Ryan Savitski14c12d62019-01-08 22:38:53 +0000126constexpr uint32_t kClientSockTxTimeoutMs = 1000;
127
Florian Mayerb85a9382018-09-27 13:59:01 +0100128// This is created and owned by the malloc hooks.
129class Client {
130 public:
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100131 Client(std::vector<base::UnixSocketRaw> sockets);
Florian Mayerb85a9382018-09-27 13:59:01 +0100132 Client(const std::string& sock_name, size_t conns);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100133 void RecordMalloc(uint64_t alloc_size,
134 uint64_t total_size,
135 uint64_t alloc_address);
Florian Mayerb85a9382018-09-27 13:59:01 +0100136 void RecordFree(uint64_t alloc_address);
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100137 void MaybeSampleAlloc(uint64_t alloc_size,
138 uint64_t alloc_address,
139 void* (*unhooked_malloc)(size_t),
140 void (*unhooked_free)(void*));
Florian Mayer2da28412018-10-30 17:33:10 +0000141 void Shutdown();
Florian Mayerb85a9382018-09-27 13:59:01 +0100142
Florian Mayer1fe77732018-10-02 17:25:53 +0100143 ClientConfiguration client_config_for_testing() { return client_config_; }
Florian Mayerb12c4f22018-11-14 16:13:02 +0000144 bool inited() { return inited_; }
Florian Mayer1fe77732018-10-02 17:25:53 +0100145
Florian Mayerb85a9382018-09-27 13:59:01 +0100146 private:
Florian Mayer9a7fb2b2018-10-17 18:17:40 +0100147 size_t ShouldSampleAlloc(uint64_t alloc_size,
148 void* (*unhooked_malloc)(size_t),
149 void (*unhooked_free)(void*));
Florian Mayerb85a9382018-09-27 13:59:01 +0100150 const char* GetStackBase();
151
Florian Mayerf0867992018-11-16 10:12:18 +0000152 std::atomic<bool> inited_{false};
Florian Mayer1fe77732018-10-02 17:25:53 +0100153 ClientConfiguration client_config_;
Florian Mayer88665be2018-10-03 13:15:38 +0100154 PThreadKey pthread_key_;
Florian Mayerb85a9382018-09-27 13:59:01 +0100155 SocketPool socket_pool_;
156 FreePage free_page_;
157 const char* main_thread_stack_base_ = nullptr;
158 std::atomic<uint64_t> sequence_number_{0};
159};
160
Florian Mayer8c0d0482018-10-22 14:23:40 +0100161} // namespace profiling
Florian Mayer824274d2018-09-17 11:33:45 +0100162} // namespace perfetto
163
164#endif // SRC_PROFILING_MEMORY_CLIENT_H_